Commits

Robert Brewer committed 18c15e0

Fix for #1008 (Oversized request URL can result in an exception).

Comments (0)

Files changed (1)

cherrypy/wsgiserver/__init__.py

         self.scheme = "http"
         if self.server.ssl_adapter is not None:
             self.scheme = "https"
+        # Use the lowest-common protocol in case read_request_line errors.
+        self.response_protocol = 'HTTP/1.0'
         self.inheaders = {}
         
         self.status = ""
         self.rfile = SizeCheckWrapper(self.conn.rfile,
                                       self.server.max_request_header_size)
         try:
-            self._parse_request()
+            self.read_request_line()
+        except MaxSizeExceeded:
+            self.simple_response("414 Request-URI Too Long",
+                "The Request-URI sent with the request exceeds the maximum "
+                "allowed bytes.")
+            return
+        
+        try:
+            self.read_request_headers()
         except MaxSizeExceeded:
             self.simple_response("413 Request Entity Too Large",
                 "The headers sent with the request exceed the maximum "
                 "allowed bytes.")
             return
+        
+        self.ready = True
     
-    def _parse_request(self):
+    def read_request_line(self):
         # HTTP/1.1 connections are persistent by default. If a client
         # requests a page, then idles (leaves the connection open),
         # then rfile.readline() will raise socket.error("timed out").
                 return
         
         if not request_line.endswith(CRLF):
-            self.simple_response(400, "HTTP requires CRLF terminators")
+            self.simple_response("400 Bad Request", "HTTP requires CRLF terminators")
             return
         
         try:
             method, uri, req_protocol = request_line.strip().split(" ", 2)
         except ValueError:
-            self.simple_response(400, "Malformed Request-Line")
+            self.simple_response("400 Bad Request", "Malformed Request-Line")
             return
         
         self.uri = uri
             return
         self.request_protocol = req_protocol
         self.response_protocol = "HTTP/%s.%s" % min(rp, sp)
+    
+    def read_request_headers(self):
         
         # then all the http headers
         try:
             except socket.error, x:
                 if x.args[0] not in socket_errors_to_ignore:
                     raise
-        
-        self.ready = True
     
     def parse_request_uri(self, uri):
         """Parse a Request-URI into (scheme, authority, path).
     def simple_response(self, status, msg=""):
         """Write a simple response back to the client."""
         status = str(status)
-        buf = [self.server.protocol + " " +
-               status + CRLF,
-               "Content-Length: %s\r\n" % len(msg),
+        buf = ["Content-Length: %s\r\n" % len(msg),
                "Content-Type: text/plain\r\n"]
         
-        if status[:3] == "413" and self.response_protocol == 'HTTP/1.1':
-            # Request Entity Too Large
+        if status[:3] in ("413", "414"):
+            # Request Entity Too Large / Request-URI Too Long
             self.close_connection = True
-            buf.append("Connection: close\r\n")
+            if self.response_protocol == 'HTTP/1.1':
+                # This will not be true for 414, since read_request_line
+                # usually raises 414 before reading the whole line, and we
+                # therefore cannot know the proper response_protocol.
+                buf.append("Connection: close\r\n")
+            else:
+                # HTTP/1.0 had no 413/414 status nor Connection header.
+                # Emit 400 instead and trust the message body is enough.
+                status = "400 Bad Request"
         
         buf.append(CRLF)
         if msg:
                 msg = msg.encode("ISO-8859-1")
             buf.append(msg)
         
+        status_line = self.server.protocol + " " + status + CRLF
         try:
-            self.conn.wfile.sendall("".join(buf))
+            self.conn.wfile.sendall(status_line + "".join(buf))
         except socket.error, x:
             if x.args[0] not in socket_errors_to_ignore:
                 raise
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.