Robert Brewer avatar Robert Brewer committed 7ed91b3

Backport of [2132] (Fix for #887 (traceback errors if http client connects to https cherrypy server)).

Comments (0)

Files changed (2)

cherrypy/test/test_http.py

         self.assertEqual(response.fp.read(), "Malformed Request-Line")
         c.close()
 
+    def test_http_over_https(self):
+        if self.scheme != 'https':
+            print "skipped (not running HTTPS)...",
+            return
+        
+        # Try connecting without SSL.
+        conn = httplib.HTTPConnection('%s:%s' % (self.interface(), self.PORT))
+        conn.putrequest("GET", "/", skip_host=True)
+        conn.putheader("Host", self.HOST)
+        conn.endheaders()
+        response = conn.response_class(conn.sock, method="GET")
+        response.begin()
+        self.assertEqual(response.status, 400)
+        self.body = response.read()
+        self.assertBody("The client sent a plain HTTP request, but this "
+                        "server only speaks HTTPS on this port.")
+
 
 if __name__ == '__main__':
     setup_server()

cherrypy/wsgiserver/__init__.py

             # Close the connection.
             return
         except NoSSLError:
-            # Unwrap our wfile
-            req.wfile = CP_fileobject(self.socket, "wb", -1)
             if req and not req.sent_headers:
+                # Unwrap our wfile
+                req.wfile = CP_fileobject(self.socket._sock, "wb", -1)
                 req.simple_response("400 Bad Request",
                     "The client sent a plain HTTP request, but "
                     "this server only speaks HTTPS on this port.")
+                self.linger = True
         except Exception, e:
             if req and not req.sent_headers:
                 req.simple_response("500 Internal Server Error", format_exc())
     
+    linger = False
+    
     def close(self):
         """Close the socket underlying this connection."""
         self.rfile.close()
         
-        # Python's socket module does NOT call close on the kernel socket
-        # when you call socket.close(). We do so manually here because we
-        # want this server to send a FIN TCP segment immediately. Note this
-        # must be called *before* calling socket.close(), because the latter
-        # drops its reference to the kernel socket.
-        self.socket._sock.close()
-        
-        self.socket.close()
+        if not self.linger:
+            # Python's socket module does NOT call close on the kernel socket
+            # when you call socket.close(). We do so manually here because we
+            # want this server to send a FIN TCP segment immediately. Note this
+            # must be called *before* calling socket.close(), because the latter
+            # drops its reference to the kernel socket.
+            self.socket._sock.close()
+            self.socket.close()
+        else:
+            # On the other hand, sometimes we want to hang around for a bit
+            # to make sure the client has a chance to read our entire
+            # response. Skipping the close() calls here delays the FIN
+            # packet until the socket object is garbage-collected later.
+            # Someday, perhaps, we'll do the full lingering_close that
+            # Apache does, but not today.
+            pass
 
 
 def format_exc(limit=None):
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.