Download Install Tutorial Docs FAQ Tools WikiLicense Team IRC Planet Involvement Shop Book

Changeset 1257

Show
Ignore:
Timestamp:
08/20/06 21:54:14
Author:
fumanchu
Message:

Better support for Expect/100 Continue.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/cherrypy/_cpwsgi.py

    r1253 r1257  
    128128            _cpwsgiserver.HTTPRequest.parse_request(self) 
    129129        except http.MaxSizeExceeded: 
    130             self.abort(413, "Request Entity Too Large") 
     130            self.simple_response(413, "Request Entity Too Large") 
    131131            cherrypy.log(traceback=True) 
    132132 
  • trunk/cherrypy/_cpwsgiserver.py

    r1253 r1257  
    5454            request_line = self.rfile.readline() 
    5555        except socket.timeout: 
    56             self.abort("408 Request Timeout") 
     56            self.simple_response("408 Request Timeout") 
     57            return 
    5758         
    5859        if not request_line: 
     
    9596                break 
    9697        else: 
    97             self.abort("404 Not Found") 
     98            self.simple_response("404 Not Found") 
    9899            return 
    99100         
     
    117118        sp = int(server.protocol[5]), int(server.protocol[7]) 
    118119        if sp[0] != rp[0]: 
    119             self.abort("505 HTTP Version Not Supported") 
     120            self.simple_response("505 HTTP Version Not Supported") 
    120121            return 
    121122        self.environ["SERVER_PROTOCOL"] = "HTTP/%s.%s" % min(rp, sp) 
     
    136137            # encoding, always respond with 411 Length Required. 
    137138            # See http://www.cherrypy.org/ticket/493. 
    138             self.abort("411 Length Required") 
     139            self.simple_response("411 Length Required") 
    139140            return 
    140141        self.environ["CONTENT_LENGTH"] = cl or "" 
     
    158159                self.close_connection = True 
    159160         
     161        # From PEP 333: 
     162        # "Servers and gateways that implement HTTP 1.1 must provide 
     163        # transparent support for HTTP 1.1's "expect/continue" mechanism. 
     164        # This may be done in any of several ways: 
     165        #   1. Respond to requests containing an Expect: 100-continue request 
     166        #      with an immediate "100 Continue" response, and proceed normally. 
     167        #   2. Proceed with the request normally, but provide the application 
     168        #      with a wsgi.input stream that will send the "100 Continue" 
     169        #      response if/when the application first attempts to read from 
     170        #      the input stream. The read request must then remain blocked 
     171        #      until the client responds. 
     172        #   3. Wait until the client decides that the server does not support 
     173        #      expect/continue, and sends the request body on its own. 
     174        #      (This is suboptimal, and is not recommended.) 
     175        # 
     176        # We used to do 3, but are now doing 1. Maybe we'll do 2 someday, 
     177        # but it seems like it would be a big slowdown for such a rare case. 
     178        if headers.getheader("Expect", "") == "100-continue": 
     179            self.simple_response(100) 
     180         
    160181        self.ready = True 
    161182     
     
    168189        self.terminate() 
    169190     
    170     def abort(self, status, msg=""): 
    171         """Write a simple error message back to the client.""" 
     191    def simple_response(self, status, msg=""): 
     192        """Write a simple response back to the client.""" 
    172193        status = str(status) 
    173194        wfile = self.connection.wfile 
     
    184205            wfile.write(msg) 
    185206        wfile.flush() 
    186         self.ready = False 
    187207     
    188208    def start_response(self, status, headers, exc_info = None): 
  • trunk/cherrypy/test/test_conn.py

    r1256 r1257  
    66 
    77import cherrypy 
     8from cherrypy.test import webtest 
    89 
    910 
     
    2930        stream.exposed = True 
    3031        stream._cp_config = {'stream_response': True} 
     32         
     33        def upload(self): 
     34            return "thanks for the %s bytes!" % len(cherrypy.request.body.read()) 
     35        upload.exposed = True 
    3136     
    3237    cherrypy.tree.mount(Root()) 
     
    111116        conn.close() 
    112117     
     118    def test_100_Continue(self): 
     119        conn = httplib.HTTPConnection(self.HOST, self.PORT) 
     120        conn.auto_open = False 
     121        conn.connect() 
     122         
     123        # Try a page without an Expect request header first. 
     124        # Note that httplib's response.begin automatically ignores 
     125        # 100 Continue responses, so we must manually check for it. 
     126        conn.putrequest("POST", "/upload", skip_host=True) 
     127        conn.putheader("Host", self.HOST) 
     128        conn.putheader("Content-Type", "text/plain") 
     129        conn.putheader("Content-Length", "4") 
     130        conn.endheaders() 
     131        conn.send("d'oh") 
     132        response = conn.response_class(conn.sock, method="POST") 
     133        version, status, reason = response._read_status() 
     134        self.assertNotEqual(status, 100) 
     135        conn.close() 
     136         
     137        # Now try a page with an Expect header... 
     138        conn.connect() 
     139        conn.putrequest("POST", "/upload", skip_host=True) 
     140        conn.putheader("Host", self.HOST) 
     141        conn.putheader("Content-Type", "text/plain") 
     142        conn.putheader("Content-Length", "17") 
     143        conn.putheader("Expect", "100-continue") 
     144        conn.endheaders() 
     145        response = conn.response_class(conn.sock, method="POST") 
     146         
     147        # ...assert and then skip the 100 response 
     148        version, status, reason = response._read_status() 
     149        self.assertEqual(status, 100) 
     150        while True: 
     151            skip = response.fp.readline().strip() 
     152            if not skip: 
     153                break 
     154         
     155        # ...send the body 
     156        conn.send("I am a small file") 
     157         
     158        # ...get the final response 
     159        response.begin() 
     160        self.status, self.headers, self.body = webtest.shb(response) 
     161        self.assertStatus(200) 
     162        self.assertBody("thanks for the 17 bytes!") 
     163     
    113164    def test_HTTP10(self): 
    114         self.PROTOCOL = "HTTP/1.1
     165        self.PROTOCOL = "HTTP/1.0
    115166        self.HTTP_CONN = httplib.HTTPConnection 
    116167         
    117168        # Test a normal HTTP/1.0 request. 
    118         self.getPage("/page2", protocol="HTTP/1.0"
     169        self.getPage("/page2"
    119170        self.assertStatus('200 OK') 
    120171        self.assertBody(pov) 
     
    123174        # Test a keep-alive HTTP/1.0 request. 
    124175        self.HTTP_CONN = httplib.HTTPConnection(self.HOST, self.PORT) 
    125         self.getPage("/page3", headers=[("Connection", "Keep-Alive")], 
    126                      protocol="HTTP/1.0") 
     176        self.HTTP_CONN.auto_open = False 
     177        self.HTTP_CONN.connect() 
     178         
     179        self.getPage("/page3", headers=[("Connection", "Keep-Alive")]) 
    127180        self.assertStatus('200 OK') 
    128181        self.assertBody(pov) 
    129182        self.assertHeader("Connection", "Keep-Alive") 
    130183         
    131         # Test a keep-alive HTTP/1.0 request
    132         self.getPage("/page3", protocol="HTTP/1.0"
     184        # Remove the keep-alive header again
     185        self.getPage("/page3"
    133186        self.assertStatus('200 OK') 
    134187        self.assertBody(pov) 
  • trunk/cherrypy/test/webtest.py

    r1253 r1257  
    356356 
    357357 
     358def shb(response): 
     359    """Return status, headers, body the way we like from a response.""" 
     360    h = [] 
     361    key, value = None, None 
     362    for line in response.msg.headers: 
     363        if line: 
     364            if line[0] in " \t": 
     365                value += line.strip() 
     366            else: 
     367                if key and value: 
     368                    h.append((key, value)) 
     369                key, value = line.split(":", 1) 
     370                key = key.strip() 
     371                value = value.strip() 
     372    if key and value: 
     373        h.append((key, value)) 
     374     
     375    return "%s %s" % (response.status, response.reason), h, response.read() 
     376 
     377 
    358378def openURL(url, headers=None, method="GET", body=None, 
    359379            host="127.0.0.1", port=8000, http_conn=httplib.HTTPConnection, 
     
    394414            response = conn.getresponse() 
    395415             
    396             status = "%s %s" % (response.status, response.reason) 
    397              
    398             outheaders = [] 
    399             key, value = None, None 
    400             for line in response.msg.headers: 
    401                 if line: 
    402                     if line[0] in " \t": 
    403                         value += line.strip() 
    404                     else: 
    405                         if key and value: 
    406                             outheaders.append((key, value)) 
    407                         key, value = line.split(":", 1) 
    408                         key = key.strip() 
    409                         value = value.strip() 
    410             if key and value: 
    411                 outheaders.append((key, value)) 
    412              
    413             outbody = response.read() 
     416            s, h, b = shb(response) 
    414417             
    415418            if not hasattr(http_conn, "host"): 
     
    417420                conn.close() 
    418421             
    419             return status, outheaders, outbody 
     422            return s, h, b 
    420423        except socket.error: 
    421424            trial += 1 

Hosted by WebFaction

Log in as guest/cpguest to create tickets