Hello:
I looked into what it takes to have connections persist (as is default in HTTP 1.1). The main idea is to save on the SSL handshakes, if using something like this: http://pl.atyp.us/wordpress/?p=3232
As it turned out, the main difficulty is in the Python's sample HTTP server, and presumably all of this is a non-issue if a real webserver is used. Still, it looks like this:
diff --git a/scripts/hekafsd.py b/scripts/hekafsd.py index 3936bb4..9819f45 100755 --- a/scripts/hekafsd.py +++ b/scripts/hekafsd.py @@ -18,11 +18,14 @@ # along with HekaFS. If not, see http://www.gnu.org/licenses/.
from bottle import route, post, run, view, debug, request, response, \ - TEMPLATE_PATH + TEMPLATE_PATH, ServerAdapter + +import wsgiref.simple_server as ss
import os import sys import socket +import ssl import string
import hfs_paths @@ -237,10 +240,85 @@ def get_style (sheet): fqpath = sys.argv[0].rsplit('/', 1) return file("%s/styles/%s" % (fqpath[0], sheet), "r")
+class SecureHandler (ss.WSGIRequestHandler): + + ## Overriding __init__ does not work as one might expect, because + ## the initialization of WSGIRequestHandler falls all the way through + ## to SocketHandler, and the whole processing happens in __init__. + ## Setting protocol_version ahead of the call-down is ineffective + ## as it's reset. Setting it after the call-down is ineffective + ## because it's too late (uncomment and try it if you don't belive us). + ## Fortunately, none of this is necessary because protocol_version + ## of an instance is inherited from the class (see below). + #def __init__ (self, request, address, srv): + # ss.WSGIRequestHandler.__init__(self,request,address,srv) + # print "protocol_version at __init__", self.protocol_version + # self.protocol_version = "HTTP/1.1" + + def handle (self): + ## Keep this part of Jeff's example code for the future. + #for part in self.connection.getpeercert()["subject"]: + # if part[0][0] == "commonName": + # print "### client is %s" % part[0][1] + # break + #else: + # raise ssl.CertificateError, "no matching user" + + # Nothing we can do with parameters permits us to process + # several requests per connection otherwise, so we cannot + # just tail-call here. Must copy-paste and modify. + #ss.WSGIRequestHandler.handle(self) # nope + + # The BaseHTTPRequestHandler has code in handle() that catches + # socket.timeout, which ss.WSGIRequestHandler discards. + # We do not do that either, for now. + + # In Apache, i counts against MaxKeepAliveRequests, default 100. + i = 0; + while i < 5: # 100 in Apache. Just do 5 for testing. + + self.raw_requestline = self.rfile.readline() + if not self.parse_request(): + # An error code has been sent, just exit + return + + handler = ss.ServerHandler( + self.rfile, self.wfile, + self.get_stderr(), self.get_environ() + ) + # Set the HTTP version string that is sent over the wire. + # Note that it does not affect the way persistent connections + # are implemented, only the string that goes out to client. + handler.http_version = "1.1" + handler.request_handler = self # backpointer for logging + handler.run(self.server.get_app()) + + if self.close_connection: # Set by parse_request + return + + i += 1 + +class EasySSLServer(ServerAdapter): + def run(self, app): + handler_cl = SecureHandler + # Set the class variable so that parse_request() works. + handler_cl.protocol_version = "HTTP/1.1" + srv = ss.make_server(self.host, self.port, app, + handler_class=handler_cl, + **self.options) + # TBD: is this the same as "server.pem" above, or different? + cert_path = os.path.join(hfs_paths.info_dir,"hekafsd.pem") + # srv is ss.WSGIServer, which should be a subclass + # of BaseHTTPServer.HTTPServer, subclass of TCPServer that has socket. + srv.socket = ssl.wrap_socket(srv.socket, + certfile=cert_path, server_side=True) + srv.serve_forever() + if __name__ == "__main__": debug(True) #run(host='0.0.0.0',port=hfs_paths.HEKAFSD_PORT,server=CherryPyServer) fqpath = sys.argv[0].rsplit('/', 1) TEMPLATE_PATH.append("%s/views" % fqpath[0]) - run(host='0.0.0.0',port=hfs_paths.HEKAFSD_PORT) + #run(host='0.0.0.0',port=hfs_paths.HEKAFSD_PORT) + run(host='',port=8443,server=EasySSLServer)
If we were to use it for real, it would also need timing out the connection, which is what socket.timeout is for.
-- Pete
cloudfs-devel@lists.fedorahosted.org