def test_HTTP11_pipelining(self): self.httpserver.protocol = "HTTP/1.1" self.PROTOCOL = "HTTP/1.1" # Test pipelining. httplib doesn't support this directly. self.persistent = True conn = self.HTTP_CONN # Put request 1 conn.putrequest("GET", "/hello", skip_host=True) conn.putheader("Host", self.HOST) conn.endheaders() for trial in range(5): # Put next request conn._output(ntob('GET /hello?%s HTTP/1.1' % trial)) conn._output(ntob("Host: %s" % self.HOST, 'ascii')) conn._send_output() # Retrieve previous response response = conn.response_class(conn.sock, method="GET") response.begin() body = response.read(13) self.assertEqual(response.status, 200) self.assertEqual(body, b"Hello, world!") # Retrieve final response response = conn.response_class(conn.sock, method="GET") response.begin() body = response.read() self.assertEqual(response.status, 200) self.assertEqual(body, b"Hello, world!") conn.close()
def output(self): if self.body is None: return [] elif isinstance(self.body, (tuple, list)): return [ntob(x) for x in self.body] elif isinstance(self.body, basestring): return [ntob(self.body)] else: return self.body
def start_response(self, status, headers, exc_info=None): """WSGI callable to begin the HTTP response.""" # "The application may call start_response more than once, # if and only if the exc_info argument is provided." if self.started_response and not exc_info: raise AssertionError("WSGI start_response called a second " "time with no exc_info.") self.started_response = True # "if exc_info is provided, and the HTTP headers have already been # sent, start_response must raise an error, and should raise the # exc_info tuple." if (exc_info is not None) and self.req.sent_headers: try: if py3k: raise exc_info[0](exc_info[1]).with_traceback(exc_info[2]) else: raise (exc_info[0], exc_info[1], exc_info[2]) finally: exc_info = None # According to PEP 3333, when using Python 3, the response status # and headers must be bytes masquerading as unicode; that is, they # must be of type "str" but are restricted to code points in the # "latin-1" set. if not isinstance(status, str): raise TypeError("WSGI response status is not of type str.") self.req.status = ntob(status) for k, v in headers: if not isinstance(k, str): raise TypeError( "WSGI response header key %s is not of type str." % repr(k)) if not isinstance(v, str): raise TypeError( "WSGI response header value %s is not of type str." % repr(v)) if k.lower() == 'content-length': self.remaining_bytes_out = int(v) self.req.outheaders.append((ntob(k), ntob(v))) return self.write
def test_app(environ, start_response): status = '200 OK' response_headers = [('Content-type', 'text/plain')] start_response(status, response_headers) output = [ 'Hello, world!\n', 'This is a wsgi app running within Cheroot!\n\n' ] keys = list(environ.keys()) keys.sort() for k in keys: output.append('%s: %s\n' % (k, environ[k])) return [ntob(x, 'utf-8') for x in output]
def openURL(url, headers=None, method="GET", body=None, host="127.0.0.1", port=8000, http_conn=HTTPConnection, protocol="HTTP/1.1"): """Open the given HTTP resource and return status, headers, and body.""" headers = cleanHeaders(headers, method, body, host, port) # Trying 10 times is simply in case of socket errors. # Normal case--it should run once. for trial in range(10): try: # Allow http_conn to be a class or an instance if hasattr(http_conn, "host"): conn = http_conn else: conn = http_conn(interface(host), port) conn._http_vsn_str = protocol conn._http_vsn = int("".join([x for x in protocol if x.isdigit()])) if not py3k: conn.putrequest(method.upper(), url, skip_host=True, skip_accept_encoding=True) else: import http.client # Replace the stdlib method, which only accepts ASCII url's def putrequest(self, method, url): if (self._HTTPConnection__response and self._HTTPConnection__response.isclosed()): self._HTTPConnection__response = None if self._HTTPConnection__state == http.client._CS_IDLE: self._HTTPConnection__state = ( http.client._CS_REQ_STARTED) else: raise http.client.CannotSendRequest() self._method = method if not url: url = b'/' request = b' '.join((method.encode("ASCII"), url, self._http_vsn_str.encode("ASCII"))) self._output(request) import types conn.putrequest = types.MethodType(putrequest, conn) conn.putrequest(method.upper(), url) for key, value in headers: conn.putheader(key, ntob(value, "Latin-1")) conn.endheaders() if body is not None: conn.send(body) # Handle response response = conn.getresponse() s, h, b = shb(response) if not hasattr(http_conn, "host"): # We made our own conn instance. Close it. conn.close() return s, h, b except socket.error: time.sleep(0.5) if trial == 9: raise
def test_readall_or_close(self): self.httpserver.protocol = "HTTP/1.1" self.PROTOCOL = "HTTP/1.1" if self.scheme == "https": self.HTTP_CONN = HTTPSConnection else: self.HTTP_CONN = HTTPConnection # Test a max of 0 (the default) and then reset to what it was above. old_max = self.httpserver.max_request_body_size for new_max in (0, old_max): self.httpserver.max_request_body_size = new_max self.persistent = True conn = self.HTTP_CONN # Get a POST page with an error conn.putrequest("POST", "/err_before_read", skip_host=True) conn.putheader("Host", self.HOST) conn.putheader("Content-Type", "text/plain") conn.putheader("Content-Length", "1000") conn.putheader("Expect", "100-continue") conn.endheaders() response = conn.response_class(conn.sock, method="POST") # ...assert and then skip the 100 response version, status, reason = response._read_status() self.assertEqual(status, 100) while True: skip = response.fp.readline().strip() if not skip: break # ...send the body conn.send(b"x" * 1000) # ...get the final response response.begin() self.status, self.headers, self.body = webtest.shb(response) self.assertStatus(500) # Now try a working page with an Expect header... conn._output(b'POST /upload HTTP/1.1') conn._output(ntob("Host: %s" % self.HOST, 'ascii')) conn._output(b"Content-Type: text/plain") conn._output(b"Content-Length: 17") conn._output(b"Expect: 100-continue") conn._send_output() response = conn.response_class(conn.sock, method="POST") # ...assert and then skip the 100 response version, status, reason = response._read_status() self.assertEqual(status, 100) while True: skip = response.fp.readline().strip() if not skip: break # ...send the body body = b"I am a small file" conn.send(body) # ...get the final response response.begin() self.status, self.headers, self.body = webtest.shb(response) self.assertStatus(200) self.assertBody("thanks for '%s'" % body) conn.close()
def test_HTTP11_Timeout_after_request(self): # If we timeout after at least one request has succeeded, # the server will close the conn without 408. self.httpserver.protocol = "HTTP/1.1" self.PROTOCOL = "HTTP/1.1" # Make an initial request self.persistent = True conn = self.HTTP_CONN conn.putrequest("GET", "/timeout?t=%s" % timeout, skip_host=True) conn.putheader("Host", self.HOST) conn.endheaders() response = conn.response_class(conn.sock, method="GET") response.begin() self.assertEqual(response.status, 200) self.body = response.read() self.assertBody(str(timeout)) # Make a second request on the same socket conn._output(b'GET /hello HTTP/1.1') conn._output(ntob("Host: %s" % self.HOST, 'ascii')) conn._send_output() response = conn.response_class(conn.sock, method="GET") response.begin() self.assertEqual(response.status, 200) self.body = response.read() self.assertBody("Hello, world!") # Wait for our socket timeout time.sleep(timeout * 2) # Make another request on the same socket, which should error conn._output(b'GET /hello HTTP/1.1') conn._output(ntob("Host: %s" % self.HOST, 'ascii')) conn._send_output() response = conn.response_class(conn.sock, method="GET") try: response.begin() except: if not isinstance(sys.exc_info()[1], (socket.error, BadStatusLine)): self.fail("Writing to timed out socket didn't fail" " as it should have: %s" % sys.exc_info()[1]) else: if response.status != 408: self.fail("Writing to timed out socket didn't fail" " as it should have: %s" % response.read()) conn.close() # Make another request on a new socket, which should work self.persistent = True conn = self.HTTP_CONN conn.putrequest("GET", "/pov", skip_host=True) conn.putheader("Host", self.HOST) conn.endheaders() response = conn.response_class(conn.sock, method="GET") response.begin() self.assertEqual(response.status, 200) self.body = response.read() self.assertBody(pov) # Make another request on the same socket, # but timeout on the headers conn.send(b'GET /hello HTTP/1.1') # Wait for our socket timeout time.sleep(timeout * 2) response = conn.response_class(conn.sock, method="GET") try: response.begin() except: if not isinstance(sys.exc_info()[1], (socket.error, BadStatusLine)): self.fail("Writing to timed out socket didn't fail" " as it should have: %s" % sys.exc_info()[1]) else: self.fail("Writing to timed out socket didn't fail" " as it should have: %s" % response.read()) conn.close() # Retry the request on a new connection, which should work self.persistent = True conn = self.HTTP_CONN conn.putrequest("GET", "/pov", skip_host=True) conn.putheader("Host", self.HOST) conn.endheaders() response = conn.response_class(conn.sock, method="GET") response.begin() self.assertEqual(response.status, 200) self.body = response.read() self.assertBody(pov) conn.close()