def test_pipelining(self): s = ("GET / HTTP/1.0\r\n" "Connection: %s\r\n" "Content-Length: %d\r\n" "\r\n" "%s") to_send = b'' count = 25 for n in range(count): body = "Response #%d\r\n" % (n + 1) if n + 1 < count: conn = 'keep-alive' else: conn = 'close' to_send += tobytes(s % (conn, len(body), body)) self.sock.connect((self.host, self.port)) self.sock.send(to_send) fp = self.sock.makefile('rb', 0) for n in range(count): expect_body = tobytes("Response #%d\r\n" % (n + 1)) line = fp.readline() # status line version, status, reason = (x.strip() for x in line.split(None, 2)) headers = parse_headers(fp) length = int(headers.get('content-length')) or None response_body = fp.read(length) self.assertEqual(int(status), 200) self.assertEqual(length, len(response_body)) self.assertEqual(response_body, expect_body)
def test_short_body(self): # check to see if server closes connection when body is too short # for cl header to_send = tobytes( "GET /short_body HTTP/1.0\n" "Connection: Keep-Alive\n" "Content-Length: 0\n" "\n" ) self.sock.connect((self.host, self.port)) self.sock.send(to_send) fp = self.sock.makefile('rb', 0) line = fp.readline() # status line version, status, reason = (x.strip() for x in line.split(None, 2)) headers = parse_headers(fp) content_length = int(headers.get('content-length')) response_body = fp.read(content_length) self.assertEqual(int(status), 200) self.assertNotEqual(content_length, len(response_body)) self.assertEqual(len(response_body), content_length-1) self.assertEqual(response_body, tobytes('abcdefghi')) # remote closed connection (despite keepalive header); not sure why # first send succeeds self.sock.send(to_send) self.assertRaises(ConnectionClosed, read_http, fp)
def test_expect_continue(self): # specifying Connection: close explicitly data = "I have expectations" to_send = tobytes( "GET / HTTP/1.1\n" "Connection: close\n" "Content-Length: %d\n" "Expect: 100-continue\n" "\n" "%s" % (len(data), data) ) self.sock.connect((self.host, self.port)) self.sock.send(to_send) fp = self.sock.makefile('rb', 0) line = fp.readline() # continue status line version, status, reason = (x.strip() for x in line.split(None, 2)) self.assertEqual(int(status), 100) self.assertEqual(reason, b'Continue') self.assertEqual(version, b'HTTP/1.1') fp.readline() # blank line line = fp.readline() # next status line version, status, reason = (x.strip() for x in line.split(None, 2)) headers = parse_headers(fp) length = int(headers.get('content-length')) or None response_body = fp.read(length) self.assertEqual(int(status), 200) self.assertEqual(length, len(response_body)) self.assertEqual(response_body, tobytes(data))
def test_long_body(self): # check server doesnt close connection when body is too short # for cl header to_send = tobytes( "GET /long_body HTTP/1.0\n" "Connection: Keep-Alive\n" "Content-Length: 0\n" "\n" ) self.sock.connect((self.host, self.port)) self.sock.send(to_send) fp = self.sock.makefile('rb', 0) line = fp.readline() # status line version, status, reason = (x.strip() for x in line.split(None, 2)) headers = parse_headers(fp) content_length = int(headers.get('content-length')) or None response_body = fp.read(content_length) self.assertEqual(int(status), 200) self.assertEqual(content_length, len(response_body)) self.assertEqual(response_body, tobytes('abcdefgh')) # remote does not close connection (keepalive header) self.sock.send(to_send) fp = self.sock.makefile('rb', 0) line = fp.readline() # status line version, status, reason = (x.strip() for x in line.split(None, 2)) headers = parse_headers(fp) content_length = int(headers.get('content-length')) or None response_body = fp.read(content_length) self.assertEqual(int(status), 200)
def test_without_crlf(self): data = "Echo\nthis\r\nplease" s = tobytes("GET / HTTP/1.0\n" "Connection: close\n" "Content-Length: %d\n" "\n" "%s" % (len(data), data)) self.sock.connect((self.host, self.port)) self.sock.send(s) fp = self.sock.makefile("rb", 0) line, headers, response_body = read_http(fp) self.assertline(line, "200", "OK", "HTTP/1.0") headers["content-length"] self.assertEqual(len(response_body), len(data)) self.assertEqual(response_body, tobytes(data))
def test_large_body(self): # 1024 characters. body = "This string has 32 characters.\r\n" * 32 s = tobytes("GET / HTTP/1.0\n" "Content-Length: %d\n" "\n" "%s" % (len(body), body)) self.sock.connect((self.host, self.port)) self.sock.send(s) fp = self.sock.makefile("rb", 0) line, headers, response_body = read_http(fp) self.assertline(line, "200", "OK", "HTTP/1.0") self.assertEqual(headers.get("content-length"), "1024") self.assertEqual(response_body, tobytes(body))
def test_no_content_length(self): # wtf happens when there's no content-length to_send = tobytes("GET /no_content_length HTTP/1.0\n" "Connection: Keep-Alive\n" "Content-Length: 0\n" "\n") self.sock.connect((self.host, self.port)) self.sock.send(to_send) fp = self.sock.makefile("rb", 0) line = fp.readline() # status line line, headers, response_body = read_http(fp) content_length = headers.get("content-length") self.assertEqual(content_length, None) self.assertEqual(response_body, tobytes("abcdefghi")) # remote closed connection (despite keepalive header) self.sock.send(to_send) self.assertRaises(ConnectionClosed, read_http, fp)
def test_request_body_too_large_with_no_cl_http11(self): body = 'a' * self.toobig to_send = "GET / HTTP/1.1\n\n" to_send += body to_send = tobytes(to_send) self.sock.connect((self.host, self.port)) self.sock.send(to_send) fp = self.sock.makefile('rb') # server trusts the content-length header (assumed 0) line, headers, response_body = read_http(fp) self.assertline(line, '200', 'OK', 'HTTP/1.1') cl = int(headers['content-length']) self.assertEqual(cl, len(response_body)) # server assumes pipelined requests due to http/1.1, and the first # request was assumed c-l 0 because it had no content-length header, # so entire body looks like the header of the subsequent request # second response is an error response line, headers, response_body = read_http(fp) self.assertline(line, '431', 'Request Header Fields Too Large', 'HTTP/1.0') cl = int(headers['content-length']) self.assertEqual(cl, len(response_body)) # connection has been closed self.sock.send(to_send) self.assertRaises(ConnectionClosed, read_http, fp)
def write(self, data): if not self.complete: raise RuntimeError('start_response was not called before body ' 'written') channel = self.channel if not self.wrote_header: rh = self.build_response_header() channel.write_soon(rh) self.wrote_header = True if data: towrite = data cl = self.content_length if self.chunked_response: # use chunked encoding response towrite = tobytes(hex(len(data))[2:].upper()) + b'\r\n' towrite += data + b'\r\n' elif cl is not None: towrite = data[:cl - self.content_bytes_written] self.content_bytes_written += len(towrite) if towrite != data and not self.logged_write_excess: self.logger.warning( 'application-written content exceeded the number of ' 'bytes specified by Content-Length header (%s)' % cl) self.logged_write_excess = True if towrite: channel.write_soon(towrite)
def test_large_body(self): # 1024 characters. body = 'This string has 32 characters.\r\n' * 32 s = tobytes( "GET / HTTP/1.0\n" "Content-Length: %d\n" "\n" "%s" % (len(body), body) ) self.sock.connect((self.host, self.port)) self.sock.send(s) fp = self.sock.makefile('rb', 0) line, headers, response_body = read_http(fp) self.assertline(line, '200', 'OK', 'HTTP/1.0') self.assertEqual(headers.get('content-length'), '1024') self.assertEqual(response_body, tobytes(body))
def testComplexGET(self): data = ( b"GET /foo/a+%2B%2F%C3%A4%3D%26a%3Aint?d=b+%2B%2F%3D%26b%3Aint&c+%2B%2F%3D%26c%3Aint=6 HTTP/8.4\r\n" b"FirstName: mickey\r\n" b"lastname: Mouse\r\n" b"content-length: 10\r\n" b"\r\n" b"Hello mickey.") parser = self.parser self.feed(data) self.assertEqual(parser.command, "GET") self.assertEqual(parser.version, "8.4") self.assertFalse(parser.empty) self.assertEqual( parser.headers, { "FIRSTNAME": "mickey", "LASTNAME": "Mouse", "CONTENT_LENGTH": "10" }, ) # path should be utf-8 encoded self.assertEqual( tobytes(parser.path).decode("utf-8"), text_(b"/foo/a++/\xc3\xa4=&a:int", "utf-8"), ) self.assertEqual(parser.query, "d=b+%2B%2F%3D%26b%3Aint&c+%2B%2F%3D%26c%3Aint=6") self.assertEqual(parser.get_body_stream().getvalue(), b"Hello mick")
def testComplexGET(self): data = b"""\ GET /foo/a+%2B%2F%C3%A4%3D%26a%3Aint?d=b+%2B%2F%3D%26b%3Aint&c+%2B%2F%3D%26c%3Aint=6 HTTP/8.4 FirstName: mickey lastname: Mouse content-length: 10 Hello mickey. """ parser = self.parser self.feed(data) self.assertEqual(parser.command, 'GET') self.assertEqual(parser.version, '8.4') self.assertFalse(parser.empty) self.assertEqual(parser.headers, {'FIRSTNAME': 'mickey', 'LASTNAME': 'Mouse', 'CONTENT_LENGTH': '10', }) # path should be utf-8 encoded self.assertEqual(tobytes(parser.path).decode('utf-8'), text_(b'/foo/a++/\xc3\xa4=&a:int', 'utf-8')) self.assertEqual(parser.query, 'd=b+%2B%2F%3D%26b%3Aint&c+%2B%2F%3D%26c%3Aint=6') self.assertEqual(parser.get_body_stream().getvalue(), b'Hello mick')
def testComplexGET(self): data = b"""\ GET /foo/a+%2B%2F%C3%A4%3D%26a%3Aint?d=b+%2B%2F%3D%26b%3Aint&c+%2B%2F%3D%26c%3Aint=6 HTTP/8.4 FirstName: mickey lastname: Mouse content-length: 10 Hello mickey. """ parser = self.parser self.feed(data) self.assertEqual(parser.command, 'GET') self.assertEqual(parser.version, '8.4') self.assertFalse(parser.empty) self.assertEqual(parser.headers, { 'FIRSTNAME': 'mickey', 'LASTNAME': 'Mouse', 'CONTENT_LENGTH': '10', }) # path should be utf-8 encoded self.assertEqual( tobytes(parser.path).decode('utf-8'), text_(b'/foo/a++/\xc3\xa4=&a:int', 'utf-8')) self.assertEqual(parser.query, 'd=b+%2B%2F%3D%26b%3Aint&c+%2B%2F%3D%26c%3Aint=6') self.assertEqual(parser.get_body_stream().getvalue(), b'Hello mick')
def test_http10_listlentwo(self): body = string.ascii_letters to_send = "GET /list_lentwo HTTP/1.0\n" "Connection: Keep-Alive\n" "Content-Length: %d\n\n" % len(body) to_send += body to_send = tobytes(to_send) self.sock.connect((self.host, self.port)) self.sock.send(to_send) fp = self.sock.makefile("rb", 0) line, headers, response_body = read_http(fp) self.assertline(line, "200", "OK", "HTTP/1.0") self.assertEqual(headers.get("content-length"), None) self.assertEqual(headers.get("connection"), "close") self.assertEqual(response_body, tobytes(body)) # remote closed connection (despite keepalive header), because # lists of length > 1 cannot have their content length divined self.sock.send(to_send) self.assertRaises(ConnectionClosed, read_http, fp)
def test_http11_list(self): body = string.ascii_letters to_send = "GET /list HTTP/1.1\n" "Content-Length: %d\n\n" % len(body) to_send += body to_send = tobytes(to_send) self.sock.connect((self.host, self.port)) self.sock.send(to_send) fp = self.sock.makefile("rb", 0) line, headers, response_body = read_http(fp) self.assertline(line, "200", "OK", "HTTP/1.1") self.assertEqual(headers["content-length"], str(len(body))) self.assertEqual(response_body, tobytes(body)) # remote keeps connection open because it divined the content length # from a length-1 list self.sock.send(to_send) line, headers, response_body = read_http(fp) self.assertline(line, "200", "OK", "HTTP/1.1")
def test_long_body(self): # check server doesnt close connection when body is too long # for cl header to_send = tobytes("GET /long_body HTTP/1.0\n" "Connection: Keep-Alive\n" "Content-Length: 0\n" "\n") self.sock.connect((self.host, self.port)) self.sock.send(to_send) fp = self.sock.makefile("rb", 0) line, headers, response_body = read_http(fp) content_length = int(headers.get("content-length")) or None self.assertEqual(content_length, 9) self.assertEqual(content_length, len(response_body)) self.assertEqual(response_body, tobytes("abcdefghi")) # remote does not close connection (keepalive header) self.sock.send(to_send) fp = self.sock.makefile("rb", 0) line, headers, response_body = read_http(fp) self.assertline(line, "200", "OK", "HTTP/1.0")
def test_http11_list(self): body = string.ascii_letters to_send = ("GET /list HTTP/1.1\n" "Content-Length: %d\n\n" % len(body)) to_send += body to_send = tobytes(to_send) self.sock.connect((self.host, self.port)) self.sock.send(to_send) fp = self.sock.makefile('rb', 0) line, headers, response_body = read_http(fp) self.assertline(line, '200', 'OK', 'HTTP/1.1') self.assertEqual(headers['content-length'], str(len(body))) self.assertEqual(response_body, tobytes(body)) # remote keeps connection open because it divined the content length # from a length-1 list self.sock.send(to_send) line, headers, response_body = read_http(fp) self.assertline(line, '200', 'OK', 'HTTP/1.1')
def test_no_content_length(self): # wtf happens when there's no content-length to_send = tobytes("GET /no_content_length HTTP/1.0\n" "Connection: Keep-Alive\n" "Content-Length: 0\n" "\n") self.sock.connect((self.host, self.port)) self.sock.send(to_send) fp = self.sock.makefile('rb', 0) line = fp.readline() # status line line, headers, response_body = read_http(fp) content_length = headers.get('content-length') self.assertEqual(content_length, None) self.assertEqual(response_body, tobytes('abcdefghi')) # remote closed connection (despite keepalive header) self.sock.send(to_send) self.assertRaises(ConnectionClosed, read_http, fp)
def test_http11_listlentwo(self): body = string.ascii_letters to_send = "GET /list_lentwo HTTP/1.1\n" "Content-Length: %s\n\n" % len(body) to_send += body to_send = tobytes(to_send) self.sock.connect((self.host, self.port)) self.sock.send(to_send) fp = self.sock.makefile("rb") line, headers, response_body = read_http(fp) self.assertline(line, "200", "OK", "HTTP/1.1") expected = b"" for chunk in (body[0], body[1:]): expected += tobytes("%s\r\n%s\r\n" % (str(hex(len(chunk))[2:].upper()), chunk)) expected += b"0\r\n\r\n" self.assertEqual(response_body, expected) # connection is always closed at the end of a chunked response self.sock.send(to_send) self.assertRaises(ConnectionClosed, read_http, fp)
def test_chunking_request_without_content(self): header = tobytes("GET / HTTP/1.1\n" "Transfer-Encoding: chunked\n\n") self.sock.connect((self.host, self.port)) self.sock.send(header) self.sock.send(b"0\r\n\r\n") fp = self.sock.makefile('rb', 0) line, headers, response_body = read_http(fp) self.assertline(line, '200', 'OK', 'HTTP/1.1') self.assertEqual(response_body, b'')
def test_chunking_request_without_content(self): header = tobytes("GET / HTTP/1.1\n" "Transfer-Encoding: chunked\n\n") self.sock.connect((self.host, self.port)) self.sock.send(header) self.sock.send(b"0\r\n\r\n") fp = self.sock.makefile("rb", 0) line, headers, response_body = read_http(fp) self.assertline(line, "200", "OK", "HTTP/1.1") self.assertEqual(response_body, b"")
def test_short_body(self): # check to see if server closes connection when body is too short # for cl header to_send = tobytes("GET /short_body HTTP/1.0\n" "Connection: Keep-Alive\n" "Content-Length: 0\n" "\n") self.sock.connect((self.host, self.port)) self.sock.send(to_send) fp = self.sock.makefile("rb", 0) line, headers, response_body = read_http(fp) # server trusts the content-length header (5) self.assertline(line, "200", "OK", "HTTP/1.0") cl = int(headers["content-length"]) self.assertEqual(cl, 9) self.assertNotEqual(cl, len(response_body)) self.assertEqual(len(response_body), cl - 1) self.assertEqual(response_body, tobytes("abcdefgh")) # remote closed connection (despite keepalive header) self.sock.send(to_send) self.assertRaises(ConnectionClosed, read_http, fp)
def test_http10_generator(self): body = string.ascii_letters to_send = ("GET / HTTP/1.0\n" "Connection: Keep-Alive\n" "Content-Length: %d\n\n" % len(body)) to_send += body to_send = tobytes(to_send) self.sock.connect((self.host, self.port)) self.sock.send(to_send) fp = self.sock.makefile('rb', 0) line, headers, response_body = read_http(fp) self.assertline(line, '200', 'OK', 'HTTP/1.0') self.assertEqual(headers.get('content-length'), None) self.assertEqual(headers.get('connection'), 'close') self.assertEqual(response_body, tobytes(body)) # remote closed connection (despite keepalive header), because # generators cannot have a content-length divined self.sock.send(to_send) self.assertRaises(ConnectionClosed, read_http, fp)
def test_keepalive_http11_explicit(self): # Explicitly set keep-alive data = "Default: Keep me alive" s = tobytes("GET / HTTP/1.1\n" "Connection: keep-alive\n" "Content-Length: %d\n" "\n" "%s" % (len(data), data)) self.sock.connect((self.host, self.port)) self.sock.send(s) response = httplib.HTTPResponse(self.sock) response.begin() self.assertEqual(int(response.status), 200) self.assertTrue(response.getheader("connection") != "close")
def test_keepalive_http11_connclose(self): # specifying Connection: close explicitly data = "Don't keep me alive" s = tobytes("GET / HTTP/1.1\n" "Connection: close\n" "Content-Length: %d\n" "\n" "%s" % (len(data), data)) self.sock.connect((self.host, self.port)) self.sock.send(s) response = httplib.HTTPResponse(self.sock) response.begin() self.assertEqual(int(response.status), 200) self.assertEqual(response.getheader("connection"), "close")
def test_date_and_server(self): to_send = "GET / HTTP/1.0\n" "Content-Length: 0\n\n" to_send = tobytes(to_send) self.sock.connect((self.host, self.port)) self.sock.send(to_send) fp = self.sock.makefile("rb", 0) line, headers, response_body = read_http(fp) self.assertline(line, "200", "OK", "HTTP/1.0") self.assertEqual(headers.get("server"), "waitress") self.assertTrue(headers.get("date"))
def test_send_empty_body(self): to_send = ("GET / HTTP/1.0\n" "Content-Length: 0\n\n") to_send = tobytes(to_send) self.sock.connect((self.host, self.port)) self.sock.send(to_send) fp = self.sock.makefile('rb', 0) line, headers, response_body = read_http(fp) self.assertline(line, '200', 'OK', 'HTTP/1.0') self.assertEqual(headers.get('content-length'), '0') self.assertEqual(response_body, b'')
def test_send_empty_body(self): to_send = "GET / HTTP/1.0\n" "Content-Length: 0\n\n" to_send = tobytes(to_send) self.sock.connect((self.host, self.port)) self.sock.send(to_send) fp = self.sock.makefile("rb", 0) line, headers, response_body = read_http(fp) self.assertline(line, "200", "OK", "HTTP/1.0") self.assertEqual(headers.get("content-length"), "0") self.assertEqual(response_body, b"")
def test_date_and_server(self): to_send = ("GET / HTTP/1.0\n" "Content-Length: 0\n\n") to_send = tobytes(to_send) self.sock.connect((self.host, self.port)) self.sock.send(to_send) fp = self.sock.makefile('rb', 0) line, headers, response_body = read_http(fp) self.assertline(line, '200', 'OK', 'HTTP/1.0') self.assertEqual(headers.get('server'), 'waitress') self.assertTrue(headers.get('date'))
def test_http11_generator(self): body = string.ascii_letters to_send = ("GET / HTTP/1.1\n" "Content-Length: %s\n\n" % len(body)) to_send += body to_send = tobytes(to_send) self.sock.connect((self.host, self.port)) self.sock.send(to_send) fp = self.sock.makefile('rb') line, headers, response_body = read_http(fp) self.assertline(line, '200', 'OK', 'HTTP/1.1') expected = b'' for chunk in chunks(body, 10): expected += tobytes('%s\r\n%s\r\n' % (str(hex(len(chunk))[2:].upper()), chunk)) expected += b'0\r\n\r\n' self.assertEqual(response_body, expected) # connection is always closed at the end of a chunked response self.sock.send(to_send) self.assertRaises(ConnectionClosed, read_http, fp)
def test_http10_listlentwo(self): body = string.ascii_letters to_send = ("GET /list_lentwo HTTP/1.0\n" "Connection: Keep-Alive\n" "Content-Length: %d\n\n" % len(body)) to_send += body to_send = tobytes(to_send) self.sock.connect((self.host, self.port)) self.sock.send(to_send) fp = self.sock.makefile('rb', 0) line, headers, response_body = read_http(fp) self.assertline(line, '200', 'OK', 'HTTP/1.0') self.assertEqual(headers.get('content-length'), None) self.assertEqual(headers.get('connection'), 'close') self.assertEqual(response_body, tobytes(body)) # remote closed connection (despite keepalive header), because # lists of length > 1 cannot have their content length divined self.sock.send(to_send) self.assertRaises(ConnectionClosed, read_http, fp)
def test_bad_host_header(self): # http://corte.si/posts/code/pathod/pythonservers/index.html to_send = "GET / HTTP/1.0\n" " Host: 0\n\n" to_send = tobytes(to_send) self.sock.connect((self.host, self.port)) self.sock.send(to_send) fp = self.sock.makefile("rb", 0) line, headers, response_body = read_http(fp) self.assertline(line, "400", "Bad Request", "HTTP/1.0") self.assertEqual(headers.get("server"), "waitress") self.assertTrue(headers.get("date"))
def test_long_body(self): # check server doesnt close connection when body is too long # for cl header to_send = tobytes("GET /long_body HTTP/1.0\n" "Connection: Keep-Alive\n" "Content-Length: 0\n" "\n") self.sock.connect((self.host, self.port)) self.sock.send(to_send) fp = self.sock.makefile('rb', 0) line, headers, response_body = read_http(fp) content_length = int(headers.get('content-length')) or None self.assertEqual(content_length, 9) self.assertEqual(content_length, len(response_body)) self.assertEqual(response_body, tobytes('abcdefghi')) # remote does not close connection (keepalive header) self.sock.send(to_send) fp = self.sock.makefile('rb', 0) line, headers, response_body = read_http(fp) self.assertline(line, '200', 'OK', 'HTTP/1.0')
def _callFUT(self, app, **kw): response = DummyResponse() environ = DummyEnviron(**kw) def start_response(status, response_headers): response.status = status response.headers = response_headers response.steps = list(app(environ, start_response)) response.body = b"".join(tobytes(s) for s in response.steps) return response
def test_bad_host_header(self): # http://corte.si/posts/code/pathod/pythonservers/index.html to_send = ("GET / HTTP/1.0\n" " Host: 0\n\n") to_send = tobytes(to_send) self.sock.connect((self.host, self.port)) self.sock.send(to_send) fp = self.sock.makefile('rb', 0) line, headers, response_body = read_http(fp) self.assertline(line, '400', 'Bad Request', 'HTTP/1.0') self.assertEqual(headers.get('server'), 'waitress') self.assertTrue(headers.get('date'))
def test_http10_list(self): body = string.ascii_letters to_send = ("GET /list HTTP/1.0\n" "Connection: Keep-Alive\n" "Content-Length: %d\n\n" % len(body)) to_send += body to_send = tobytes(to_send) self.sock.connect((self.host, self.port)) self.sock.send(to_send) fp = self.sock.makefile('rb', 0) line, headers, response_body = read_http(fp) self.assertline(line, '200', 'OK', 'HTTP/1.0') self.assertEqual(headers['content-length'], str(len(body))) self.assertEqual(headers.get('connection'), 'Keep-Alive') self.assertEqual(response_body, tobytes(body)) # remote keeps connection open because it divined the content length # from a length-1 list self.sock.send(to_send) line, headers, response_body = read_http(fp) self.assertline(line, '200', 'OK', 'HTTP/1.0')
def test_after_write_cb(self): to_send = "GET /after_write_cb HTTP/1.1\n\n" to_send = tobytes(to_send) self.sock.connect((self.host, self.port)) self.sock.send(to_send) fp = self.sock.makefile("rb", 0) line, headers, response_body = read_http(fp) self.assertline(line, "200", "OK", "HTTP/1.1") self.assertEqual(response_body, b"") # connection has been closed self.sock.send(to_send) self.assertRaises(ConnectionClosed, read_http, fp)
def test_short_body(self): # check to see if server closes connection when body is too short # for cl header to_send = tobytes("GET /short_body HTTP/1.0\n" "Connection: Keep-Alive\n" "Content-Length: 0\n" "\n") self.sock.connect((self.host, self.port)) self.sock.send(to_send) fp = self.sock.makefile('rb', 0) line, headers, response_body = read_http(fp) # server trusts the content-length header (5) self.assertline(line, '200', 'OK', 'HTTP/1.0') cl = int(headers['content-length']) self.assertEqual(cl, 9) self.assertNotEqual(cl, len(response_body)) self.assertEqual(len(response_body), cl - 1) self.assertEqual(response_body, tobytes('abcdefgh')) # remote closed connection (despite keepalive header) self.sock.send(to_send) self.assertRaises(ConnectionClosed, read_http, fp)
def test_in_generator(self): to_send = "GET /in_generator HTTP/1.1\n\n" to_send = tobytes(to_send) self.sock.connect((self.host, self.port)) self.sock.send(to_send) fp = self.sock.makefile('rb', 0) line, headers, response_body = read_http(fp) self.assertline(line, '200', 'OK', 'HTTP/1.1') self.assertEqual(response_body, b'') # connection has been closed self.sock.send(to_send) self.assertRaises(ConnectionClosed, read_http, fp)
def test_http11_generator(self): body = string.ascii_letters to_send = ("GET / HTTP/1.1\n" "Content-Length: %s\n\n" % len(body)) to_send += body to_send = tobytes(to_send) self.sock.connect((self.host, self.port)) self.sock.send(to_send) fp = self.sock.makefile('rb') line, headers, response_body = read_http(fp) self.assertline(line, '200', 'OK', 'HTTP/1.1') expected = b'' for chunk in chunks(body, 10): expected += tobytes( '%s\r\n%s\r\n' % (str(hex(len(chunk))[2:].upper()), chunk) ) expected += b'0\r\n\r\n' self.assertEqual(response_body, expected) # connection is always closed at the end of a chunked response self.sock.send(to_send) self.assertRaises(ConnectionClosed, read_http, fp)
def execute(self): e = self.request.error body = '%s\r\n\r\n%s' % (e.reason, e.body) tag = '\r\n\r\n(generated by waitress)' body = body + tag self.status = '%s %s' % (e.code, e.reason) cl = len(body) self.content_length = cl self.response_headers.append(('Content-Length', str(cl))) self.response_headers.append(('Content-Type', 'text/plain')) self.response_headers.append(('Connection', 'close')) self.close_on_finish = True self.write(tobytes(body))
def test_keepalive_http11_explicit(self): # Explicitly set keep-alive data = "Default: Keep me alive" s = tobytes("GET / HTTP/1.1\n" "Connection: keep-alive\n" "Content-Length: %d\n" "\n" "%s" % (len(data), data)) self.sock.connect((self.host, self.port)) self.sock.send(s) response = httplib.HTTPResponse(self.sock) response.begin() self.assertEqual(int(response.status), 200) self.assertTrue(response.getheader('connection') != 'close')
def test_keepalive_http11_connclose(self): # specifying Connection: close explicitly data = "Don't keep me alive" s = tobytes("GET / HTTP/1.1\n" "Connection: close\n" "Content-Length: %d\n" "\n" "%s" % (len(data), data)) self.sock.connect((self.host, self.port)) self.sock.send(s) response = httplib.HTTPResponse(self.sock) response.begin() self.assertEqual(int(response.status), 200) self.assertEqual(response.getheader('connection'), 'close')
def test_short_body(self): # check to see if server closes connection when body is too short # for cl header to_send = tobytes("GET /short_body HTTP/1.0\n" "Connection: Keep-Alive\n" "Content-Length: 0\n" "\n") self.sock.connect((self.host, self.port)) self.sock.send(to_send) fp = self.sock.makefile('rb', 0) line = fp.readline() # status line version, status, reason = (x.strip() for x in line.split(None, 2)) headers = parse_headers(fp) content_length = int(headers.get('content-length')) response_body = fp.read(content_length) self.assertEqual(int(status), 200) self.assertNotEqual(content_length, len(response_body)) self.assertEqual(len(response_body), content_length - 1) self.assertEqual(response_body, tobytes('abcdefghi')) # remote closed connection (despite keepalive header); not sure why # first send succeeds self.sock.send(to_send) self.assertRaises(ConnectionClosed, read_http, fp)
def test_after_start_response(self): to_send = "GET /after_start_response HTTP/1.1\n\n" to_send = tobytes(to_send) self.sock.connect((self.host, self.port)) self.sock.send(to_send) fp = self.sock.makefile('rb', 0) line, headers, response_body = read_http(fp) self.assertline(line, '500', 'Internal Server Error', 'HTTP/1.0') cl = int(headers['content-length']) self.assertEqual(cl, len(response_body)) self.assertTrue(response_body.startswith(b'Internal Server Error')) # connection has been closed self.sock.send(to_send) self.assertRaises(ConnectionClosed, read_http, fp)
def test_chunking_request_with_content(self): control_line = b"20;\r\n" # 20 hex = 32 dec s = b'This string has 32 characters.\r\n' expected = s * 12 header = tobytes("GET / HTTP/1.1\n" "Transfer-Encoding: chunked\n\n") self.sock.connect((self.host, self.port)) self.sock.send(header) fp = self.sock.makefile('rb', 0) for n in range(12): self.sock.send(control_line) self.sock.send(s) self.sock.send(b"0\r\n\r\n") line, headers, response_body = read_http(fp) self.assertline(line, '200', 'OK', 'HTTP/1.1') self.assertEqual(response_body, expected)
def test_keepalive_http_11(self): # Handling of Keep-Alive within HTTP 1.1 # All connections are kept alive, unless stated otherwise data = "Default: Keep me alive" s = tobytes("GET / HTTP/1.1\n" "Content-Length: %d\n" "\n" "%s" % (len(data), data)) self.sock.connect((self.host, self.port)) self.sock.send(s) response = httplib.HTTPResponse(self.sock) response.begin() self.assertEqual(int(response.status), 200) self.assertTrue(response.getheader('connection') != 'close')
def test_request_body_too_large_with_no_cl_http10(self): body = 'a' * self.toobig to_send = "GET / HTTP/1.0\n\n" to_send += body to_send = tobytes(to_send) self.sock.connect((self.host, self.port)) self.sock.send(to_send) fp = self.sock.makefile('rb', 0) line, headers, response_body = read_http(fp) self.assertline(line, '200', 'OK', 'HTTP/1.0') cl = int(headers['content-length']) self.assertEqual(cl, len(response_body)) # extra bytes are thrown away (no pipelining), connection closed self.sock.send(to_send) self.assertRaises(ConnectionClosed, read_http, fp)
def test_notfilelike_nocl_http10(self): to_send = "GET /notfilelike_nocl HTTP/1.0\n\n" to_send = tobytes(to_send) self.sock.connect((self.host, self.port)) self.sock.send(to_send) fp = self.sock.makefile('rb', 0) line, headers, response_body = read_http(fp) self.assertline(line, '200', 'OK', 'HTTP/1.0') ct = headers['content-type'] self.assertEqual(ct, 'image/jpeg') self.assertTrue(b'\377\330\377' in response_body) # connection has been closed (no content-length) self.sock.send(to_send) self.assertRaises(ConnectionClosed, read_http, fp)
def test_filelike_longcl_http11(self): to_send = "GET /filelike_longcl HTTP/1.1\n\n" to_send = tobytes(to_send) self.sock.connect((self.host, self.port)) for t in range(0, 2): self.sock.send(to_send) fp = self.sock.makefile('rb', 0) line, headers, response_body = read_http(fp) self.assertline(line, '200', 'OK', 'HTTP/1.1') cl = int(headers['content-length']) self.assertEqual(cl, len(response_body)) ct = headers['content-type'] self.assertEqual(ct, 'image/jpeg') self.assertTrue(b'\377\330\377' in response_body)
def test_keepalive_http_10(self): # Handling of Keep-Alive within HTTP 1.0 data = "Default: Don't keep me alive" s = tobytes("GET / HTTP/1.0\n" "Content-Length: %d\n" "\n" "%s" % (len(data), data)) self.sock.connect((self.host, self.port)) self.sock.send(s) response = httplib.HTTPResponse(self.sock) response.begin() self.assertEqual(int(response.status), 200) connection = response.getheader('Connection', '') # We sent no Connection: Keep-Alive header # Connection: close (or no header) is default. self.assertTrue(connection != 'Keep-Alive')
def test_request_body_too_large_with_no_cl_http11_connclose(self): body = 'a' * self.toobig to_send = "GET / HTTP/1.1\nConnection: close\n\n" to_send += body to_send = tobytes(to_send) self.sock.connect((self.host, self.port)) self.sock.send(to_send) fp = self.sock.makefile('rb', 0) line, headers, response_body = read_http(fp) # server trusts the content-length header (assumed 0) self.assertline(line, '200', 'OK', 'HTTP/1.1') cl = int(headers['content-length']) self.assertEqual(cl, len(response_body)) # connection has been closed self.sock.send(to_send) self.assertRaises(ConnectionClosed, read_http, fp)
def test_keepalive_http10_explicit(self): # If header Connection: Keep-Alive is explicitly sent, # we want to keept the connection open, we also need to return # the corresponding header data = "Keep me alive" s = tobytes("GET / HTTP/1.0\n" "Connection: Keep-Alive\n" "Content-Length: %d\n" "\n" "%s" % (len(data), data)) self.sock.connect((self.host, self.port)) self.sock.send(s) response = httplib.HTTPResponse(self.sock) response.begin() self.assertEqual(int(response.status), 200) connection = response.getheader('Connection', '') self.assertEqual(connection, 'Keep-Alive')
def test_request_body_too_large_with_wrong_cl_http10(self): body = 'a' * self.toobig to_send = ("GET / HTTP/1.0\n" "Content-Length: 5\n\n") to_send += body to_send = tobytes(to_send) self.sock.connect((self.host, self.port)) self.sock.send(to_send) fp = self.sock.makefile('rb') # first request succeeds (content-length 5) line, headers, response_body = read_http(fp) self.assertline(line, '200', 'OK', 'HTTP/1.0') cl = int(headers['content-length']) self.assertEqual(cl, len(response_body)) # server trusts the content-length header; no pipelining, # so request fulfilled, extra bytes are thrown away # connection has been closed self.sock.send(to_send) self.assertRaises(ConnectionClosed, read_http, fp)