[Bese-devel] Bug in aserve backend
Antonio Menezes Leitao
aml at gia.ist.utl.pt
Sat Jul 9 10:03:55 UTC 2005
Hi,
I noticed that, in ucw's aserve backend, the implementation of the
getter and setter of the response headers is:
(defmethod get-header ((response aserve-response) header-name)
(net.aserve:reply-header-slot-value (request response) header-name))
(defmethod (setf get-header) (value (response aserve-response) header-name)
(setf (net.aserve:reply-header-slot-value (request response) header-name)
value))
We call these accessors as, e.g.,
(setf (get-header response "Status") "500"
(get-header response "Content-Type") "text/html")
However, according to the aserve documentation (also valid for
reply-header-slot-value):
(header-slot-value request header-name)
Return the value given in the request for the given header-name (a
keyword symbol). If the header wasn't present in this request
then nil will be returned. header-slot-value is a macro that will
expand into a fast accessor if the header-name is a constant
naming a known header slot
In older versions of aserve the header-name was a string..
It is not very well explained but the code is clear: the function uses
an assoc-list to find the header, but searches using #'eq. This means
that (setf get-header) will not redefine an existing header but will
accumulate identical headers, instead.
However, it's even worse: some of the headers (the so called
'fast-reply-headers') are not stored in the assoc-list but in the
request object itself, namely 'date', 'content-type' and
'content-length'. Even more worse (if possible) is the fact that
net.aserve:reply-header-slot-value is a macro that can only work
properly with the fast-reply-headers if they are visible at macro
expansion time.
To solve this problem, I suggest that the methods:
(defmethod get-header ((response aserve-response) header-name)
(net.aserve:reply-header-slot-value (request response) header-name))
(defmethod (setf get-header) (value (response aserve-response) header-name)
(setf (net.aserve:reply-header-slot-value (request response) header-name)
value))
should be replaced by something like:
(defmethod get-header ((response aserve-response) header-name)
(switch (header-name :test #'string-equal)
("Date" (net.aserve:reply-header-slot-value (request response) :date))
("Content-Type" (net.aserve:reply-header-slot-value (request response) :content-type))
("Content-Length" (net.aserve:reply-header-slot-value (request response) :content-length))
(t (net.aserve:reply-header-slot-value
(request response)
(read-from-string (format nil ":~A" header-name))))))
(defmethod (setf get-header) (value (response aserve-response) header-name)
(switch (header-name :test #'string-equal)
("Date" (error "Can't update header Date"))
("Content-Type" (setf (net.aserve:reply-header-slot-value (request response) :content-type) value))
("Content-Length" (setf (net.aserve:reply-header-slot-value (request response) :content-length) value))
(t (setf (net.aserve:reply-header-slot-value
(request response)
(read-from-string (format nil ":~A" header-name)))
value))))
The identical methods for aserve-request should require a similar
correction.
Best regards,
António Leitão.
More information about the bese-devel
mailing list