[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