Consult the HTTP 1.1 specification:
http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
You will need to verify that http 1.0 clients behave as expected, and report
back if
there are issues.
People doing more advanced redirects should probably use standard-url-redirect
for
added control.
The patch below corrects CL-HTTP to use 303 for redirects within a POST
response.
;; Use the forward condition for all redirects within a post method per HTTP
1.1 spec
;; http:server;report.lisp
(defun %standard-url-redirect (url target-url redirection-type method
target-window)
(check-type target-window (or null string))
(let ((alternate-urls (ensure-list target-url)))
(unless alternate-urls
(signal 'document-not-found :url url))
(ecase redirection-type
(:temporary-redirect
(case method
(:get (signal 'document-found :url url :method method :new-urls
alternate-urls :target-window target-window))
(t (signal 'document-moved-temporarily :url url :method method
:new-urls alternate-urls :target-window target-window))))
(:permanent-redirect
(signal 'document-moved-permanently :url url :method method :new-urls
alternate-urls :target-window target-window))
(:forward
(if (case method
(:get (not (explicit-expiration-p url)))
(:post t))
(signal 'document-forwarded :url url :method method :new-urls
alternate-urls :target-window target-window)
(signal 'document-moved-temporarily :url url :method method :new-urls
alternate-urls :target-window target-window)))
(:proxy
(signal 'document-access-via-proxy :url url :method method :new-urls
alternate-urls :target-window target-window))
(:multiple-choices
(signal 'document-multiple-choices :url url :method method :new-urls
alternate-urls :target-window target-window)))))
;; http:server;server.lisp
(defmethod redirect-request ((server basic-server-mixin) (target-uri uri)
&optional target-window)
(with-slots (url method) server
(let ((redirection (case method (:post :forward) (t :temporary-redirect))))
(%standard-url-redirect url target-uri redirection method
target-window))))
(defmethod redirect-request ((server basic-server-mixin) (target-uris cons)
&optional target-window)
(with-slots (url method) server
(let ((redirection (case method (:post :forward) (t :multiple-choice))))
(if (every #'url::uri-p target-uris)
(%standard-url-redirect url target-uris redirection method
target-window)
(let ((alternate-uris (mapcar #'(lambda (uri) (intern-url uri
:if-does-not-exist :create)) target-uris)))
(declare (dynamic-extent alternate-uris))
(%standard-url-redirect url alternate-uris redirection method
target-window))))))
I tested the patch on Mozilla 1.6 and Safari running under Mac OS X 10.3.4
This will be incorporated into the next release.
Good test case. Thanks for Martin's comment.
This is a rather interesting example of the high-level abstraction in CL-HTTP,
where a small change here implements
the desired functionality without forcing the application to know what is going
on below. Note also that
(report-status-line (condition http/1.1-redirection-downgrade-mixin) (stream t))
automatically conditionalizes the output for http 1.0 clients.
|