[version 1.2.1 ediware**20100520042313 Ignore-this: b78caeb6088eec4e67609dae85c84f0 ] { hunk ./CHANGELOG.txt 1 +Version 1.2.1 +2010-05-19 +Fix a couple of typos (thanks to Stelian Ionescu and Giovanni Gigante) + +Version 1.2.0 +2010-05-19 +Introduced *REMOVE-DUPLICATE-COOKIES-P* (Ryan Davis) +Enabled https through a proxy (Bill St. Clair and Dave Lambert) +Bugfix for redirect of a request through a proxy (Bill St. Clair) +Export PARSE-COOKIE-DATE +Safer method to render URIs +Allowed for GET/POST parameters without a value (seen on Lotus webservers) + hunk ./conditions.lisp 4 -;;; Copyright (c) 2008-2009, Dr. Edmund Weitz. All rights reserved. +;;; Copyright (c) 2008-2010, Dr. Edmund Weitz. All rights reserved. hunk ./cookies.lisp 4 -;;; Copyright (c) 2006-2009, Dr. Edmund Weitz. All rights reserved. +;;; Copyright (c) 2006-2010, Dr. Edmund Weitz. All rights reserved. hunk ./cookies.lisp 284 - :http-only-p (not (not (parameter-present-p "HttpOnly" parameters)))))) + :http-only-p (not (not (parameter-present-p "HttpOnly" parameters)))) + into new-cookies + finally (return (ccase *remove-duplicate-cookies-p* + ((nil) new-cookies) + ((:keep-last t) (delete-duplicates new-cookies :test #'cookie=)) + (:keep-first (delete-duplicates new-cookies :test #'cookie= + :from-end T)))))) hunk ./doc/index.html 89 +
*remove-duplicate-cookies-p*
+ parse-cookie-date
hunk ./doc/index.html 659
-The current version is 1.1.0. Drakma can be installed
+The current version is 1.2.1. Drakma can be installed
hunk ./doc/index.html 664
-on KMRCL), Puri, FLEXI-STREAMS,
+on KMRCL), Puri (1.5.5 or higher), FLEXI-STREAMS,
hunk ./doc/index.html 794
-see content
below.) The
+see content
below.)
+The values can also be
+NIL
in which case only the name (without an equal sign) is used in
+the query string. The
hunk ./doc/index.html 1331
+
+
+
[Function]
parse-cookie-date string => universal-time
+
+ + + + + + +
+ +Parses (the string representation of) a cookie expiry datestring
and returns it as a Lisp universal time. Currently understands the following formats: ++"Wed, 06-Feb-2008 21:01:38 GMT" +"Wed, 06-Feb-08 21:01:38 GMT" +"Tue Feb 13 08:00:00 2007 GMT" +"Wednesday, 07-February-2027 08:55:23 GMT" +"Wed, 07-02-2017 10:34:45 GMT" ++Instead of"GMT"
, time zone abbreviations +like"CEST"
+and UTC +offsets like"GMT-01:30"
are also allowed. ++While this function has cookie in its name, it might come in +handy in other situations as well and it is thus exported as a +convenience function. +
[Special variable]
*remove-duplicate-cookies-p*
+
+ + + + + hunk ./drakma.asd 4 -;;; Copyright (c) 2006-2009, Dr. Edmund Weitz. All rights reserved. +;;; Copyright (c) 2006-2010, Dr. Edmund Weitz. All rights reserved. hunk ./drakma.asd 41 -(defvar *drakma-version-string* "1.1.0" +(defvar *drakma-version-string* "1.2.1" hunk ./packages.lisp 4 -;;; Copyright (c) 2006-2009, Dr. Edmund Weitz. All rights reserved. +;;; Copyright (c) 2006-2010, Dr. Edmund Weitz. All rights reserved. hunk ./packages.lisp 39 + :*remove-duplicate-cookies-p* hunk ./packages.lisp 68 + :parse-cookie-date hunk ./read.lisp 4 -;;; Copyright (c) 2006-2009, Dr. Edmund Weitz. All rights reserved. +;;; Copyright (c) 2006-2010, Dr. Edmund Weitz. All rights reserved. hunk ./request.lisp 4 -;;; Copyright (c) 2006-2009, Dr. Edmund Weitz. All rights reserved. +;;; Copyright (c) 2006-2010, Dr. Edmund Weitz. All rights reserved. hunk ./request.lisp 240 -body of the request. (But see CONTENT below.) The name/value pairs -are URL-encoded using the FLEXI-STREAMS external format -EXTERNAL-FORMAT-OUT before they are sent to the server unless -FORM-DATA is true in which case the POST request body is sent as -`multipart/form-data' using EXTERNAL-FORMAT-OUT. The values of the -PARAMETERS alist can also be pathnames, open binary input streams, -unary functions, or lists where the first element is of one of the -former types. These values denote files which should be sent as part -of the request body. If files are present in PARAMETERS, the content -type of the request is always `multipart/form-data'. If the value is -a list, the part of the list behind the first element is treated as a -plist which can be used to specify a content type and/or a filename -for the file, i.e. such a value could look like, e.g., +body of the request. (But see CONTENT below.) The values can also be +NIL in which case only the name \(without an equal sign) is used in +the query string. The name/value pairs are URL-encoded using the +FLEXI-STREAMS external format EXTERNAL-FORMAT-OUT before they are sent +to the server unless FORM-DATA is true in which case the POST request +body is sent as `multipart/form-data' using EXTERNAL-FORMAT-OUT. The +values of the PARAMETERS alist can also be pathnames, open binary +input streams, unary functions, or lists where the first element is of +one of the former types. These values denote files which should be +sent as part of the request body. If files are present in PARAMETERS, +the content type of the request is always `multipart/form-data'. If +the value is a list, the part of the list behind the first element is +treated as a plist which can be used to specify a content type and/or +a filename for the file, i.e. such a value could look like, e.g., hunk ./request.lisp 410 - (file-parameters-p (find-if-not #'stringp parameters :key #'cdr)) + (file-parameters-p (find-if-not (lambda (thing) + (or (stringp thing) + (null thing))) + parameters :key #'cdr)) hunk ./request.lisp 433 - (let (http-stream must-close done) + (let ((proxying-https-p (and proxy (not stream) (eq :https (puri:uri-scheme uri)))) + http-stream raw-http-stream must-close done) hunk ./request.lisp 442 - (use-ssl (or force-ssl - (eq (uri-scheme uri) :https)))) + (use-ssl (and (not proxying-https-p) + (or force-ssl + (eq (uri-scheme uri) :https))))) hunk ./request.lisp 468 - :nodelay t)))) + :nodelay t))) + raw-http-stream http-stream) hunk ./request.lisp 476 - ;; for every request. + ;; for every request hunk ./request.lisp 478 + (labels ((write-http-line (fmt &rest args) + (when *header-stream* + (format *header-stream* "~?~%" fmt args)) + (format http-stream "~?~C~C" fmt args #\Return #\Linefeed)) + (write-header (name value-fmt &rest value-args) + (write-http-line "~A: ~?" name value-fmt value-args)) + (wrap-stream (http-stream) + (make-flexi-stream (make-chunked-stream http-stream) + :external-format +latin-1+))) hunk ./request.lisp 493 - (setq http-stream - #+:allegro - (socket:make-ssl-client-stream http-stream) - #-:allegro - (let ((s http-stream)) - (cl+ssl:make-ssl-client-stream - (cl+ssl:stream-fd s) - :close-callback (lambda () (close s))))))) - (cond (stream - (setf (flexi-stream-element-type http-stream) - #+:lispworks 'lw:simple-char #-:lispworks 'character - (flexi-stream-external-format http-stream) +latin-1+)) - (t - (setq http-stream - (make-flexi-stream (make-chunked-stream http-stream) - :external-format +latin-1+)))) - (labels ((write-http-line (fmt &rest args) - (when *header-stream* - (format *header-stream* "~?~%" fmt args)) - (format http-stream "~?~C~C" fmt args #\Return #\Linefeed)) - (write-header (name value-fmt &rest value-args) - (write-http-line "~A: ~?" name value-fmt value-args))) + (setq http-stream (make-ssl-stream http-stream))) + (cond (stream + (setf (flexi-stream-element-type http-stream) + #+:lispworks 'lw:simple-char #-:lispworks 'character + (flexi-stream-external-format http-stream) +latin-1+)) + (t + (setq http-stream (wrap-stream http-stream)))) + (when proxying-https-p + ;; set up a tunnel through the proxy server to the + ;; final destination + (write-http-line "CONNECT ~A:~:[443~;~:*~A~] HTTP/1.1" + (uri-host uri) (uri-port uri)) + (write-http-line "Host: ~A:~:[443~;~:*~A~]" + (uri-host uri) (uri-port uri)) + (write-http-line "") + (force-output http-stream) + ;; check we get a 200 response before proceeding + (unless (eql (second (read-status-line http-stream *header-stream*)) 200) + (error "Unable to establish HTTPS tunnel through proxy.")) + ;; got a connection; we have to read a blank line, + ;; turn on SSL, and then we can transmit + (read-line* http-stream) + #+:lispworks + (comm:attach-ssl raw-http-stream :ssl-side :client) + #-:lispworks + (setq http-stream (wrap-stream (make-ssl-stream raw-http-stream)))) hunk ./request.lisp 533 - (cond (proxy (render-uri uri nil)) - (t (format nil "~A~@[?~A~]" - (or (uri-path uri) "/") - (uri-query uri)))) + (render-uri (cond ((and proxy + (null stream) + (not proxying-https-p)) uri) + (t (copy-uri uri + :scheme nil + :host nil + :port nil + :parsed-path nil + :plist nil))) + nil) hunk ./request.lisp 724 - (finish-request content)))) + (finish-request content))))) hunk ./specials.lisp 4 -;;; Copyright (c) 2006-2009, Dr. Edmund Weitz. All rights reserved. +;;; Copyright (c) 2006-2010, Dr. Edmund Weitz. All rights reserved. hunk ./specials.lisp 85 +(defvar *remove-duplicate-cookies-p* t + "Determines how duplicate cookies are handled. Valid values are NIL +\(duplicates will not be removed), :KEEP-LAST or T \(for duplicates, +only the last cookie value will be kept based on the order of the +response header), or :KEEP-FIRST (only the first value will be +kept).") + hunk ./util.lisp 4 -;;; Copyright (c) 2006-2009, Dr. Edmund Weitz. All rights reserved. +;;; Copyright (c) 2006-2010, Dr. Edmund Weitz. All rights reserved. hunk ./util.lisp 114 -names and values are strings. This function returns a string where -this list is represented as for the content type -`application/x-www-form-urlencoded', i.e. the values are URL-encoded -using the external format EXTERNAL-FORMAT, the pairs are joined with a -#\\& character, and each name is separated from its value with a #\\= -character." +names and values are strings \(or, for values, NIL). This function +returns a string where this list is represented as for the content +type `application/x-www-form-urlencoded', i.e. the values are +URL-encoded using the external format EXTERNAL-FORMAT, the pairs are +joined with a #\\& character, and each name is separated from its +value with a #\\= character. If the value is NIL, no #\\= is used." hunk ./util.lisp 124 - do (format out "~A=~A" + do (format out "~A~:[~;=~A~]" hunk ./util.lisp 126 + value hunk ./util.lisp 328 - hunk ./util.lisp 329 +#-:lispworks +(defun make-ssl-stream (http-stream) + "Attaches SSL to the stream HTTP-STREAM and returns the SSL stream +\(which will not be equal to HTTP-STREAM)." + #+:allegro + (socket:make-ssl-client-stream http-stream) + #-:allegro + (let ((s http-stream)) + (cl+ssl:make-ssl-client-stream + (cl+ssl:stream-fd s) + :close-callback (lambda () (close s))))) }
+Determines how duplicate cookies in the response are handled, defaults +toT
. Cookies are considered duplicate using +COOKIE=
. + +Valid values are: ++
+ +Misbehaving servers may send duplicate cookies back in the same +- +
NIL
- duplicates will not be removed,- +
T
or:KEEP-LAST
- for duplicates, only the last cookie + value will be kept, based on the order of the response header,- +
:KEEP-FIRST
- for duplicates, only the first cookie + value will be kept, based on the order of the response header.Set-Cookie
header: ++HTTP/1.1 200 OK +Server: My-hand-rolled-server +Date: Wed, 07 Apr 2010 15:12:30 GMT +Connection: Close +Content-Type: text/html +Content-Length: 82 +Set-Cookie: a=1; Path=/; Secure, a=2; Path=/; Secure +++In this case Drakma has to choose whether cookie "a" has the value +"1" or "2". By default, Drakma will choose the last value specified, +in this case "2". +
++By default, Drakma conforms to RFC2109 HTTP State +Management Mechanism, section 4.3.3 Cookie Management: +
+If a user agent receives a Set-Cookie response header whose NAME is +the same as a pre-existing cookie, and whose Domain and Path +attribute values exactly (string) match those of a pre-existing +cookie, the new cookie supersedes the old. ++ + +