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:
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
@@ -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, ServerAdapter
+import wsgiref.simple_server as ss
@@ -237,10 +240,85 @@ def get_style (sheet):
fqpath = sys.argv.rsplit('/', 1)
return file("%s/styles/%s" % (fqpath, 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 == "commonName":
+ # print "### client is %s" % part
+ # break
+ # 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
+ 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
+ if self.close_connection: # Set by parse_request
+ i += 1
+ 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,
+ # 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)
if __name__ == "__main__":
fqpath = sys.argv.rsplit('/', 1)
TEMPLATE_PATH.append("%s/views" % fqpath)
If we were to use it for real, it would also need timing out the connection,
which is what socket.timeout is for.