Bug 736024 - hekafsd with persistent connections
Summary: hekafsd with persistent connections
Keywords:
Status: CLOSED WONTFIX
Alias: None
Product: Fedora
Classification: Fedora
Component: hekafs
Version: 16
Hardware: All
OS: Linux
low
low
Target Milestone: ---
Assignee: Kaleb KEITHLEY
QA Contact: Fedora Extras Quality Assurance
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2011-09-06 12:52 UTC by Kaleb KEITHLEY
Modified: 2012-07-16 13:37 UTC (History)
3 users (show)

Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Clone Of:
Environment:
Last Closed: 2012-07-16 13:37:07 UTC
Type: ---
Embargoed:


Attachments (Terms of Use)

Description Kaleb KEITHLEY 2011-09-06 12:52:34 UTC
Description of problem:

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

Version-Release number of selected component (if applicable):

0-7.11

How reproducible:

N/A

Steps to Reproduce:
1.
2.
3.
  
Actual results:


Expected results:


Additional info:

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)

Comment 1 Kaleb KEITHLEY 2011-09-06 13:04:05 UTC
Note that "I" in 'I looked into what it takes to have connections persist ...' is Peter Zaitcev

Comment 2 Jeff Darcy 2011-09-06 13:48:55 UTC
Nice work untangling the contorted WSGI control flows.  Some questions/answers/issues:

(1) The certfile argument is the same as "server.pem" in the original example, but the other wrap_socket arguments in that example - keyfile, cert_reqs, ca_certs - are also required.  Giving out a cert with no key, or blindly accepting others' certs, is not consistent with secure operation.

(2) Setting SecureHandler.protocol_version (which is a class constant rather than an instance variable) could be done more cleanly, readably, and efficiently from within the SecureHandler definition itself than by reaching in from EasySSLServer.run every time it's called.

(3) Please don't change (and hard-code) the port that the service runs on.

(4) There have been recent commits on master (e.g. fec3f79b8a3078c28a6c5ad372a578ab4ad2d935) which might cause application of this patch to fail, so please rebase before re-submitting.

Comment 3 Kaleb KEITHLEY 2012-07-16 13:37:07 UTC
HekaFS will be merged into core GlusterFS


Note You need to log in before you can comment on or make changes to this bug.