AllegroServer's http client with keep alive support?

Programming in the Lisp Language

Pebblestone
I'm using AllegroServe's http client. but according to the document,
keep-alive option is not supports, it only sends the header but will
close the socket connection anyway.

I changed the source code a little bit, but during the test, I got
these two errors:

1) writing buffer for
#<MULTIVALENT #1=hiper socket #1#connected from
resulted in error (code 32): Broken pipe.
   [Condition of type ERRNO-STREAM-ERROR]

2) When writing buffer for #<SSL-CLIENT-STREAM
                      fd #<MULTIVALENT hiper socket connected from
                           7.1.168.192.in-addr.arpa/45790 to
 code 336031996: error:140770FC:SSL
routines:SSL23_GET_SERVER_HELLO:unknown protocol
   [Condition of type EXCL::SSL-ERROR]


Here's what I've done to the code:

1) remove client-request-close in make-http-client-request (2 places)
2) change creq to use established socket (in
do-http-request-keep-alive)
3) replace all do-http-request into do-http-request-keep-alive
4) return sock as second value in make-http-client-request.
5) if socket is provided in make-http-client-request, then do not
create a new socket.


Does anyone have a clue?                                            
Klaus
...

I submitted a patch to Portable AllegroServe mailing list with
keep-alive functionality for the http client, cf. below.

-Klaus.

================================================================================
Subject: [Portableaserve-discuss] PATCH: Support for persistent connections in the HTTP client
To: [email protected]


Here's a patch to persistent TCP connections between calls to
do-http-request.  It works simply by manually opening the connection
and passing it to do-http-request using the (newly added) :sock
keyword argument.

It can be combined with the recently posted patch to support SSL in
the HTTP client (for LW only, admittedly, but it ought to work for
other ways of supporting SSL as well, though I havent tested this).
Since there is considerable overhead associated with establishing an
SSL connection, I have seen major improvements in response times by
switching to persitent HTTP connections in my use of the HTTP client.

-K.



@@ -170,27 +170,29 @@
 			(external-format *default-aserve-external-format*)
 			ssl		; do an ssl connection
 			skip-body ; fcn of request object
+			sock
 			)
   
   ;; send an http request and return the result as four values:
   ;; the body, the response code, the headers and the uri 
   (let ((creq (make-http-client-request 
-	       uri  
-	       :method method
-	       :protocol protocol
-	       :accept  accept
-	       :content content
-	       :content-type content-type
-	       :query query
-	       :cookies cookies
-	       :basic-authorization basic-authorization
-	       :keep-alive keep-alive
-	       :headers headers
-	       :proxy proxy
-	       :user-agent user-agent
-	       :external-format external-format
-	       :ssl ssl
-	       )))
+		   uri  
+		   :method method
+		   :protocol protocol
+		   :accept  accept
+		   :content content
+		   :content-type content-type
+		   :query query
+		   :cookies cookies
+		   :basic-authorization basic-authorization
+		   :keep-alive keep-alive
+		   :headers headers
+		   :proxy proxy
+		   :user-agent user-agent
+		   :external-format external-format
+		   :ssl ssl
+		   :sock sock
+		   )))
 
     (unwind-protect
 	(let (new-location) 
@@ -301,12 +303,11 @@
 		     (client-request-uri creq)))))
       
       ;; protected form:
-      (client-request-close creq))))
-
-
-    
-		
-		
+      (when (or (not keep-alive)
+		(equalp (assoc :connection
+			       (client-request-headers creq))
+			"close"))
+	(client-request-close creq)))))
 		
 		
 		
@@ -316,26 +317,28 @@
 
 
 (defun make-http-client-request (uri &key 
-				     (method  :get)  ; :get, :post, ....
-				     (protocol  :http/1.1)
-				     keep-alive 
-				     (accept "*/*") 
-				     cookies  ; nil or a cookie-jar
-				     basic-authorization
-				     content
-				     content-length 
-				     content-type
-				     query
-				     headers
-				     proxy
-				     user-agent
-				     (external-format 
-				      *default-aserve-external-format*)
-				     ssl
-				     )
+				 (method  :get)	; :get, :post, ....
+				 (protocol  :http/1.1)
+				 keep-alive 
+				 (accept "*/*") 
+				 cookies ; nil or a cookie-jar
+				 basic-authorization
+				 content
+				 content-length 
+				 content-type
+				 query
+				 headers
+				 proxy
+				 user-agent
+				 (external-format 
+				  *default-aserve-external-format*)
+				 ssl
+				 sock
+				 (keep-alive-period 300)
+				 )
   
 
-  (let (host sock port fresh-uri scheme-default-port)
+  (let (host port fresh-uri scheme-default-port)
     ;; start a request 
   
     ; parse the uri we're accessing
@@ -373,22 +376,24 @@
 		 then (error "proxy arg should have form \"foo.com\" ~
 or \"foo.com:8000\", not ~s" proxy))
 	      
-	      (setq sock (acl-compat.socket:make-socket :remote-host phost
-					     :remote-port pport
-					     :format :bivalent
-					     :type net.aserve::*socket-stream-type*
-					     :nodelay t
-					     )))
+	      (setq sock (or sock 
+			     (acl-compat.socket:make-socket
+			      :remote-host phost
+			      :remote-port pport
+			      :format :bivalent
+			      :type net.aserve::*socket-stream-type*
+			      :nodelay t
+			      ))))
        else (setq sock 
-	      (acl-compat.socket:make-socket :remote-host host
-				  :remote-port port
-				  :format :bivalent
-				  :type 
-				  net.aserve::*socket-stream-type*
-				  :nodelay t
-					     
-				  ))
-	    (if* ssl
+		  (or sock 
+		      (acl-compat.socket:make-socket :remote-host host
+						     :remote-port port
+						     :format :bivalent
+						     :type 
+						     net.aserve::*socket-stream-type*
+						     :nodelay t
+						     )))
+	    (if* (and ssl (not sock))
 	       then (setq sock
 		      (funcall 'acl-compat.socket::make-ssl-client-stream sock)))
 	    )
@@ -439,8 +444,11 @@
     
     ; now the headers
     (if* keep-alive
-       then (net.aserve::format-dif :xmit
-				    sock "Connection: Keep-Alive~a" crlf))
+       then (progn
+	      (net.aserve::format-dif :xmit
+				      sock "Keep-Alive: ~d~a" keep-alive-period crlf)
+	      (net.aserve::format-dif :xmit
+				      sock "Connection: Keep-Alive~a" crlf)))
 
     (if* accept
        then (net.aserve::format-dif :xmit