On 5/8/10 12:00PM, drakma-devel-requ...@common-lisp.net wrote:

> Date: Fri, 7 May 2010 21:43:17 +0200
> From: Edi Weitz <e...@agharta.de>
> Subject: Re: [drakma-devel] https through a proxy
> To: General interest list for Drakma and Chunga
>       <drakma-devel@common-lisp.net>

> Thanks for the patch.  I can't really read it because your email
> client broke it, but I think I get the idea.  Yes, I didn't integrate
> the old patch and IIRC I didn't do it because it was a LW-only
> solution.  Obviously, I don't like the new solution either because it
> uses unexported symbols (and you can't change the underlying stream
> for a reason).
>
> As far as I understand, all this happens while the headers are still
> sent and while chunking isn't really needed.  I haven't really thought
> about the details, but maybe it would be possible to change the order
> of how and when the streams are wrapped and use only exported
> functionality.  In the worst case, one could "unwrap" the stream,
> attach SSL, and then "rewrap" it.  Of course, the easiest solution
> would be if CL+SSL and AllegroCL had something similar to LispWorks'
> comm:attach-ssl.
>
> Anyway, if someone wants to work on a "clean" solution to this
> problem, I'll happily review it.

I cleaned up my patch. It now contains no double-colons. It ends up
wrapping with the flexi-stream and chunking-stream twice in the https
through a proxy case, as not wrapping didn't work (it may work to wrap
the proxy communication with only a flexi-stream, but I didn't try
that). I also fixed a bug that caused it to include on the first (GET)
line to the server the entire URI instead of only the path part of it
when a request through a proxy with keep-alive gets redirected. Patch
attached.

-Bill



diff -rN -u old-drakma/request.lisp new-drakma/request.lisp
--- old-drakma/request.lisp     2010-05-08 16:30:34.000000000 -0400
+++ new-drakma/request.lisp     2010-05-08 16:30:34.000000000 -0400
@@ -426,7 +426,8 @@
               (t
                (setq content (alist-to-url-encoded-string parameters 
external-format-out)
                      content-type "application/x-www-form-urlencoded")))))
-    (let (http-stream must-close done)
+    (let ((proxying-https? (and proxy (not stream) (eq :https (puri:uri-scheme 
uri))))
+           http-stream raw-http-stream must-close done)
       (unwind-protect
           (progn
             (let ((host (or (and proxy (first proxy))
@@ -434,8 +435,9 @@
                   (port (cond (proxy (second proxy))
                               ((uri-port uri))
                               (t (default-port uri))))
-                  (use-ssl (or force-ssl
-                               (eq (uri-scheme uri) :https))))
+                  (use-ssl (and (not proxying-https?)
+                                (or force-ssl
+                                    (eq (uri-scheme uri) :https)))))
               #+(and :lispworks5.0 :mswindows
                      (not :lw-does-not-have-write-timeout))
               (when use-ssl
@@ -459,7 +461,8 @@
                                                              :element-type 
'octet
                                                              #+:openmcl 
:deadline
                                                              #+:openmcl 
deadline
-                                                             :nodelay t))))
+                                                             :nodelay t)))
+                    raw-http-stream http-stream)
               #+:openmcl
               (when deadline
                 ;; it is correct to set the deadline here even though
@@ -468,34 +471,55 @@
                 ;; user and the user may want to adjust the deadline
                 ;; for every request.
                 (setf (ccl:stream-deadline http-stream) deadline))
-              (when (and use-ssl
-                         ;; don't attach SSL to existing streams
-                         (not stream))
-                #+:lispworks
-                (comm:attach-ssl http-stream :ssl-side :client)
-                #-:lispworks
-                (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)))
+                       (write-http-line "~A: ~?" name value-fmt value-args))
+                     (make-ssl-stream (http-stream)
+                       #+:lispworks
+                       (progn
+                         (comm:attach-ssl http-stream :ssl-side :client)
+                         http-stream)
+                       #-:lispworks
+                       #+: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)))))
+                     (wrap-stream (http-stream)
+                       (make-flexi-stream (make-chunked-stream http-stream)
+                                          :external-format +latin-1+)))
+              (when (and use-ssl
+                         ;; don't attach SSL to existing streams
+                         (not stream))
+                (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?
+                ;; Setup a tunnel through the proxy server to the
+                ;; final destination.
+                (write-http-line "CONNECT ~A:~A HTTP/1.1" (puri:uri-host uri)
+                                 (or (puri:uri-port uri) 443))
+                (write-http-line "Host: ~A:~A" (puri:uri-host uri)
+                                 (or (puri:uri-port uri) 443))
+                (write-http-line "")
+                (force-output http-stream)
+                ;; Check we get a 200 response before proceeding.
+                (let ((line (read-status-line http-stream *header-stream*)))
+                  (unless (eq (second line) 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)
+                (setq http-stream (wrap-stream (make-ssl-stream 
raw-http-stream))))
               (when (and (not parameters-used-p)
                          parameters)
                 (setf (uri-query uri)
@@ -510,7 +534,7 @@
                       (uri-query uri) nil))
               (write-http-line "~A ~A ~A"
                                (string-upcase method)
-                               (cond (proxy (render-uri uri nil))
+                               (cond ((and proxy (not stream) (not 
proxying-https?)) (render-uri uri nil))
                                      (t (format nil "~...@[?~a~]"
                                                 (or (uri-path uri) "/")
                                                 (uri-query uri))))
@@ -695,7 +719,7 @@
                                        status-text))))))
                 (when (eq content :continuation)
                   (return-from http-request #'finish-request))
-                (finish-request content))))
+                (finish-request content)))))
         ;; the cleanup form of the UNWIND-PROTECT above
         (when (and http-stream
                    (or (not done)

_______________________________________________
drakma-devel mailing list
drakma-devel@common-lisp.net
http://common-lisp.net/cgi-bin/mailman/listinfo/drakma-devel

Reply via email to