def testVariousReads(self): con = httpplus.HTTPConnection('1.2.3.4') con._connect({}) # make sure it trickles in one byte at a time # so that we touch all the cases in readline con.sock.data = [ c.encode('ascii') for c in ('HTTP/1.1 200 OK\r\n' 'Server: BogusServer 1.0\r\n' 'Connection: Close\r\n' '\r\n' '1\n2' '\nabc' 'defg\n4\n5') ] con.sock.close_on_empty = True expected_req = (b'GET / HTTP/1.1\r\n' b'Host: 1.2.3.4\r\n' b'accept-encoding: identity\r\n\r\n') con.request('GET', '/') self.assertEqual((b'1.2.3.4', 80), con.sock.sa) self.assertEqual(expected_req, con.sock.sent) r = con.getresponse() for read_amt, expect in [(1, b'1'), (1, b'\n'), (4, b'2\nab'), ('line', b'cdefg\n'), (None, b'4\n5')]: if read_amt == 'line': self.assertEqual(expect, r.readline()) else: self.assertEqual(expect, r.read(read_amt))
def testSimpleRequest(self): con = httpplus.HTTPConnection('1.2.3.4:80') con._connect({}) con.sock.data = [ b'HTTP/1.1 200 OK\r\n', b'Server: BogusServer 1.0\r\n', b'MultiHeader: Value\r\n' b'MultiHeader: Other Value\r\n' b'MultiHeader: One More!\r\n' b'Content-Length: 10\r\n', b'\r\n' b'1234567890' ] con.request('GET', '/') expected_req = (b'GET / HTTP/1.1\r\n' b'Host: 1.2.3.4\r\n' b'accept-encoding: identity\r\n\r\n') self.assertEqual((b'1.2.3.4', 80), con.sock.sa) self.assertEqual(expected_req, con.sock.sent) resp = con.getresponse() self.assertEqual(b'1234567890', resp.read()) self.assertEqual(['Value', 'Other Value', 'One More!'], resp.headers.getheaders('multiheader')) self.assertEqual(['BogusServer 1.0'], resp.headers.getheaders('server'))
def testReadlineTrickle(self): con = httpplus.HTTPConnection('1.2.3.4') con._connect({}) # make sure it trickles in one byte at a time # so that we touch all the cases in readline con.sock.data = [ c.encode('ascii') for c in ('HTTP/1.1 200 OK\r\n' 'Server: BogusServer 1.0\r\n' 'Connection: Close\r\n' '\r\n' '1\n2\nabcdefg\n4\n5') ] con.sock.close_on_empty = True expected_req = (b'GET / HTTP/1.1\r\n' b'Host: 1.2.3.4\r\n' b'accept-encoding: identity\r\n\r\n') con.request('GET', '/') self.assertEqual((b'1.2.3.4', 80), con.sock.sa) self.assertEqual(expected_req, con.sock.sent) r = con.getresponse() for expected in [b'1\n', b'2\n', b'abcdefg\n', b'4\n', b'5']: actual = r.readline() self.assertEqual(expected, actual, 'Expected %r, got %r' % (expected, actual))
def testSSLRequestNoConnectBody(self): con = httpplus.HTTPConnection('1.2.3.4:443', proxy_hostport=('magicproxy', 4242)) socket.socket = make_preloaded_socket( ['HTTP/1.1 200 OK\r\n', 'Server: BogusServer 1.0\r\n', '\r\n']) con._connect() con.sock.data = ['HTTP/1.1 200 OK\r\n', 'Server: BogusServer 1.0\r\n', 'Content-Length: 10\r\n', '\r\n' '1234567890' ] connect_sent = con.sock.sent con.sock.sent = '' con.request('GET', '/') expected_connect = ('CONNECT 1.2.3.4:443 HTTP/1.0\r\n' 'Host: 1.2.3.4\r\n' 'accept-encoding: identity\r\n' '\r\n') expected_request = ('GET / HTTP/1.1\r\n' 'Host: 1.2.3.4\r\n' 'accept-encoding: identity\r\n\r\n') self.assertEqual(('127.0.0.42', 4242), con.sock.sa) self.assertStringEqual(expected_connect, connect_sent) self.assertStringEqual(expected_request, con.sock.sent) resp = con.getresponse() self.assertEqual(resp.status, 200) self.assertEqual('1234567890', resp.read()) self.assertEqual(['BogusServer 1.0'], resp.headers.getheaders('server'))
def testSimpleRequest(self): con = httpplus.HTTPConnection('1.2.3.4:80', proxy_hostport=('magicproxy', 4242)) con._connect() con.sock.data = ['HTTP/1.1 200 OK\r\n', 'Server: BogusServer 1.0\r\n', 'MultiHeader: Value\r\n' 'MultiHeader: Other Value\r\n' 'MultiHeader: One More!\r\n' 'Content-Length: 10\r\n', '\r\n' '1234567890' ] con.request('GET', '/') expected_req = ('GET http://1.2.3.4/ HTTP/1.1\r\n' 'Host: 1.2.3.4\r\n' 'accept-encoding: identity\r\n\r\n') self.assertEqual(('127.0.0.42', 4242), con.sock.sa) self.assertStringEqual(expected_req, con.sock.sent) resp = con.getresponse() self.assertEqual('1234567890', resp.read()) self.assertEqual(['Value', 'Other Value', 'One More!'], resp.headers.getheaders('multiheader')) self.assertEqual(['BogusServer 1.0'], resp.headers.getheaders('server'))
def test_multiline_header(self): con = httpplus.HTTPConnection('1.2.3.4:80') con._connect({}) con.sock.data = [ b'HTTP/1.1 200 OK\r\n', b'Server: BogusServer 1.0\r\n', b'Multiline: Value\r\n', b' Rest of value\r\n', b'Content-Length: 10\r\n', b'\r\n' b'1234567890' ] con.request('GET', '/') expected_req = (b'GET / HTTP/1.1\r\n' b'Host: 1.2.3.4\r\n' b'accept-encoding: identity\r\n\r\n') self.assertEqual((b'1.2.3.4', 80), con.sock.sa) self.assertEqual(expected_req, con.sock.sent) resp = con.getresponse() self.assertEqual(b'1234567890', resp.read()) if sys.version_info < (3, 0): self.assertEqual(['Value\n Rest of value'], resp.headers.getheaders('multiline')) else: self.assertEqual(['Value\r\n Rest of value'], resp.headers.getheaders('multiline')) # Socket should not be closed self.assertEqual(resp.sock.closed, False) self.assertEqual(con.sock.closed, False)
def testChunkedUpload(self): con = httpplus.HTTPConnection('1.2.3.4:80') con._connect({}) sock = con.sock sock.read_wait_sentinel = b'0\r\n\r\n' sock.data = [ b'HTTP/1.1 200 OK\r\n', b'Server: BogusServer 1.0\r\n', b'Content-Length: 6', b'\r\n\r\n', b"Thanks" ] zz = b'zz\n' con.request('POST', '/', body=io.BytesIO((zz * (0x8010 // 3)) + b'end-of-body')) expected_req = (b'POST / HTTP/1.1\r\n' b'Host: 1.2.3.4\r\n' b'accept-encoding: identity\r\n' b'transfer-encoding: chunked\r\n' b'\r\n') expected_req += chunkedblock(b'zz\n' * (0x8000 // 3) + b'zz') expected_req += chunkedblock(b'\n' + b'zz\n' * ((0x1b - len('end-of-body')) // 3) + b'end-of-body') expected_req += b'0\r\n\r\n' self.assertEqual((b'1.2.3.4', 80), sock.sa) self.assertStringEqual(expected_req, sock.sent) self.assertEqual(b"Thanks", con.getresponse().read()) self.assertEqual(sock.closed, False)
def testDeniedAfterContinueTimeoutExpires(self): con = httpplus.HTTPConnection('1.2.3.4:80') con._connect({}) sock = con.sock sock.data = [ b'HTTP/1.1 403 Forbidden\r\n', b'Server: BogusServer 1.0\r\n', b'Content-Length: 18\r\n', b'Connection: close', b'\r\n\r\n' b"You can't do that." ] sock.read_wait_sentinel = b'Dear server, send response!' sock.close_on_empty = True # send enough data out that we'll chunk it into multiple # blocks and the socket will close before we can send the # whole request. post_body = (b'This is some POST data\n' * 1024 * 32 + b'Dear server, send response!\n' + b'This is some POST data\n' * 1024 * 32) expected_req = self.doPost(con, expect_body=False, body_to_send=post_body) self.assertEqual((b'1.2.3.4', 80), sock.sa) self.assert_(b'POST data\n' in sock.sent) self.assert_(b'Dear server, send response!\n' in sock.sent) # We expect not all of our data was sent. self.assertNotEqual(sock.sent, expected_req) self.assertEqual(b"You can't do that.", con.getresponse().read()) self.assertEqual(sock.closed, True)
def testSslRereadRequired(self): con = httpplus.HTTPConnection('1.2.3.4:443') con._connect({}) # extend the list instead of assign because of how # MockSSLSocket works. con.sock.data = [ b'HTTP/1.1 200 OK\r\n', b'Server: BogusServer 1.0\r\n', b'MultiHeader: Value\r\n' b'MultiHeader: Other Value\r\n' b'MultiHeader: One More!\r\n' b'Content-Length: 10\r\n', b'\r\n' b'1234567890' ] con.request('GET', '/') expected_req = (b'GET / HTTP/1.1\r\n' b'Host: 1.2.3.4\r\n' b'accept-encoding: identity\r\n\r\n') self.assertEqual((b'1.2.3.4', 443), con.sock.sa) self.assertEqual(expected_req, con.sock.sent) resp = con.getresponse() self.assertEqual(b'1234567890', resp.read()) self.assertEqual(['Value', 'Other Value', 'One More!'], resp.headers.getheaders('multiheader')) self.assertEqual(['BogusServer 1.0'], resp.headers.getheaders('server'))
def test_broken_data_obj(self): con = httpplus.HTTPConnection('1.2.3.4:80') con._connect({}) self.assertRaises(httpplus.BadRequestData, con.request, 'POST', '/', body=1)
def _run_simple_test(self, host, server_data, expected_req, expected_data): con = httpplus.HTTPConnection(host) con._connect() con.sock.data = server_data con.request('GET', '/') self.assertEqual(expected_req, con.sock.sent) self.assertEqual(expected_data, con.getresponse().read())
def testSSLProxyFailure(self): con = httpplus.HTTPConnection('1.2.3.4:443', proxy_hostport=('magicproxy', 4242)) socket.socket = make_preloaded_socket( ['HTTP/1.1 407 Proxy Authentication Required\r\n\r\n'], close=True) self.assertRaises(httpplus.HTTPProxyConnectFailedException, con._connect) self.assertRaises(httpplus.HTTPProxyConnectFailedException, con.request, 'GET', '/')
def testCloseAfterNotAllOfHeaders(self): con = httpplus.HTTPConnection('1.2.3.4:80') con._connect({}) con.sock.data = [b'HTTP/1.1 200 OK\r\n', b'Server: NO CARRIER'] con.sock.close_on_empty = True con.request('GET', '/') self.assertRaises(httpplus.HTTPRemoteClosedError, con.getresponse) expected_req = (b'GET / HTTP/1.1\r\n' b'Host: 1.2.3.4\r\n' b'accept-encoding: identity\r\n\r\n') self.assertEqual((b'1.2.3.4', 80), con.sock.sa) self.assertEqual(expected_req, con.sock.sent)
def test_server_closes_before_end_of_body(self): con = httpplus.HTTPConnection('1.2.3.4:80') con._connect({}) s = con.sock s.data = [ b'HTTP/1.1 200 OK\r\n', b'Server: BogusServer 1.0\r\n', b'Connection: Keep-Alive\r\n', b'Content-Length: 16', b'\r\n\r\n', b'You can ' ] # Note: this is shorter than content-length s.close_on_empty = True con.request('GET', '/') r1 = con.getresponse() self.assertRaises(httpplus.HTTPRemoteClosedError, r1.read)
def testTimeout(self): con = httpplus.HTTPConnection('1.2.3.4:80') con._connect({}) con.sock.data = [] self.assertRaises(httpplus.HTTPTimeoutException, con.request, 'GET', '/') expected_req = (b'GET / HTTP/1.1\r\n' b'Host: 1.2.3.4\r\n' b'accept-encoding: identity\r\n\r\n') self.assertEqual((b'1.2.3.4', 80), con.sock.sa) self.assertEqual(expected_req, con.sock.sent)
def testServerWithoutContinue(self): con = httpplus.HTTPConnection('1.2.3.4:80') con._connect({}) sock = con.sock sock.read_wait_sentinel = b'POST data' sock.data = [ b'HTTP/1.1 200 OK\r\n', b'Server: BogusServer 1.0\r\n', b'Content-Length: 16', b'\r\n\r\n', b"You can do that." ] expected_req = self.doPost(con, expect_body=True) self.assertEqual((b'1.2.3.4', 80), sock.sa) self.assertEqual(expected_req, sock.sent) self.assertEqual(b"You can do that.", con.getresponse().read()) self.assertEqual(sock.closed, False)
def testChunkedDownloadPartialChunk(self): con = httpplus.HTTPConnection('1.2.3.4:80') con._connect({}) sock = con.sock sock.data = [ b'HTTP/1.1 200 OK\r\n', b'Server: BogusServer 1.0\r\n', b'transfer-encoding: chunked', b'\r\n\r\n', chunkedblock(b'hi '), ] + tricklebytes(chunkedblock(b'there\n' * 5)) + [chunkedblock(b'')] con.request('GET', '/') self.assertStringEqual(b'hi there\nthere\nthere\nthere\nthere\n', con.getresponse().read())
def testEarlyContinueResponse(self): con = httpplus.HTTPConnection('1.2.3.4:80') con._connect({}) sock = con.sock sock.data = [ b'HTTP/1.1 403 Forbidden\r\n', b'Content-Length: 18\r\n', b'Server: BogusServer 1.0\r\n', b'\r\n' b"You can't do that." ] expected_req = self.doPost(con, expect_body=False) self.assertEqual((b'1.2.3.4', 80), sock.sa) self.assertStringEqual(expected_req, sock.sent) self.assertEqual(b"You can't do that.", con.getresponse().read()) self.assertEqual(sock.closed, True)
def testChunkedDownloadBadEOL(self): con = httpplus.HTTPConnection('1.2.3.4:80') con._connect({}) sock = con.sock sock.data = [ b'HTTP/1.1 200 OK\n', b'Server: BogusServer 1.0\n', b'transfer-encoding: chunked', b'\n\n', chunkedblock(b'hi ', eol=b'\n'), chunkedblock(b'there', eol=b'\n'), chunkedblock(b'', eol=b'\n'), ] con.request('GET', '/') self.assertStringEqual(b'hi there', con.getresponse().read())
def testChunkedDownload(self): con = httpplus.HTTPConnection('1.2.3.4:80') con._connect() sock = con.sock sock.data = [ 'HTTP/1.1 200 OK\r\n', 'Server: BogusServer 1.0\r\n', 'transfer-encoding: chunked', '\r\n\r\n', chunkedblock('hi '), ] + list(chunkedblock('there')) + [ chunkedblock(''), ] con.request('GET', '/') self.assertStringEqual('hi there', con.getresponse().read())
def testChunkedDownloadEarlyHangup(self): con = httpplus.HTTPConnection('1.2.3.4:80') con._connect({}) sock = con.sock broken = chunkedblock(b'hi' * 20)[:-1] sock.data = [ b'HTTP/1.1 200 OK\r\n', b'Server: BogusServer 1.0\r\n', b'transfer-encoding: chunked', b'\r\n\r\n', broken, ] sock.close_on_empty = True con.request('GET', '/') resp = con.getresponse() self.assertRaises(httpplus.HTTPRemoteClosedError, resp.read)
def testPostData(self): con = httpplus.HTTPConnection('1.2.3.4:80') con._connect() sock = con.sock sock.read_wait_sentinel = 'POST data' sock.early_data = ['HTTP/1.1 100 Co', 'ntinue\r\n\r\n'] sock.data = ['HTTP/1.1 200 OK\r\n', 'Server: BogusServer 1.0\r\n', 'Content-Length: 16', '\r\n\r\n', "You can do that."] expected_req = self.doPost(con, expect_body=True) self.assertEqual(('1.2.3.4', 80), sock.sa) self.assertEqual(expected_req, sock.sent) self.assertEqual("You can do that.", con.getresponse().read()) self.assertEqual(sock.closed, False)
def testHeaderlessResponse(self): con = httpplus.HTTPConnection('1.2.3.4', use_ssl=False) con._connect({}) con.sock.data = [b'HTTP/1.1 200 OK\r\n', b'\r\n' b'1234567890'] con.sock.close_on_empty = True con.request('GET', '/') expected_req = (b'GET / HTTP/1.1\r\n' b'Host: 1.2.3.4\r\n' b'accept-encoding: identity\r\n\r\n') self.assertEqual((b'1.2.3.4', 80), con.sock.sa) self.assertEqual(expected_req, con.sock.sent) resp = con.getresponse() self.assertEqual(b'1234567890', resp.read()) self.assertEqual({}, dict(resp.headers)) self.assertEqual(resp.status, 200)
def testChunkedDownloadOddReadBoundaries(self): con = httpplus.HTTPConnection('1.2.3.4:80') con._connect({}) sock = con.sock sock.data = [ b'HTTP/1.1 200 OK\r\n', b'Server: BogusServer 1.0\r\n', b'transfer-encoding: chunked', b'\r\n\r\n', chunkedblock(b'hi '), ] + tricklebytes(chunkedblock(b'there')) + [ chunkedblock(b''), ] con.request('GET', '/') resp = con.getresponse() for amt, expect in [(1, b'h'), (5, b'i the'), (100, b're')]: self.assertEqual(expect, resp.read(amt))
def bogusEOL(self, eol): con = httpplus.HTTPConnection('1.2.3.4:80') con._connect({}) con.sock.data = [ b'HTTP/1.1 200 OK%s' % eol, b'Server: BogusServer 1.0%s' % eol, b'Content-Length: 10', eol * 2, b'1234567890' ] con.request('GET', '/') expected_req = (b'GET / HTTP/1.1\r\n' b'Host: 1.2.3.4\r\n' b'accept-encoding: identity\r\n\r\n') self.assertEqual((b'1.2.3.4', 80), con.sock.sa) self.assertEqual(expected_req, con.sock.sent) self.assertEqual(b'1234567890', con.getresponse().read())
def test_no_keepalive_http_1_0(self): expected_request_one = b"""GET /remote/.hg/requires HTTP/1.1 Host: localhost:9999 accept: application/mercurial-0.1 accept-encoding: identity range: bytes=0- user-agent: mercurial/proto-1.0 """.replace(b'\n', b'\r\n') expected_response_headers = b"""HTTP/1.0 200 OK Server: SimpleHTTP/0.6 Python/2.6.1 Date: Sun, 01 May 2011 13:56:57 GMT Content-type: application/octet-stream Content-Length: 33 Last-Modified: Sun, 01 May 2011 13:56:56 GMT """.replace(b'\n', b'\r\n') expected_response_body = b"""revlogv1 store fncache dotencode """ con = httpplus.HTTPConnection('localhost:9999') con._connect({}) con.sock.data = [expected_response_headers, expected_response_body] s = con.sock con.request('GET', '/remote/.hg/requires', headers={ 'accept-encoding': 'identity', 'range': 'bytes=0-', 'accept': 'application/mercurial-0.1', 'user-agent': 'mercurial/proto-1.0', }) self.assertStringEqual(expected_request_one, s.sent) self.assertEqual(s.closed, False) self.assertNotEqual(s.data, []) self.assert_(con.busy()) resp = con.getresponse() self.assertStringEqual(resp.read(), expected_response_body) self.failIf(con.busy()) self.assertEqual(con.sock, None) self.assertEqual(resp.sock.data, []) self.assert_(resp.sock.closed)
def testSlowConnection(self): con = httpplus.HTTPConnection('1.2.3.4:80') con._connect() # simulate one byte arriving at a time, to check for various # corner cases con.sock.data = list('HTTP/1.1 200 OK\r\n' 'Server: BogusServer 1.0\r\n' 'Content-Length: 10' '\r\n\r\n' '1234567890') con.request('GET', '/') expected_req = ('GET / HTTP/1.1\r\n' 'Host: 1.2.3.4\r\n' 'accept-encoding: identity\r\n\r\n') self.assertEqual(('1.2.3.4', 80), con.sock.sa) self.assertEqual(expected_req, con.sock.sent) self.assertEqual('1234567890', con.getresponse().read())
def testZeroLengthBody(self): con = httpplus.HTTPConnection('1.2.3.4') con._connect() # make sure it trickles in one byte at a time # so that we touch all the cases in readline con.sock.data = list(''.join( ['HTTP/1.1 200 OK\r\n', 'Server: BogusServer 1.0\r\n', 'Content-length: 0\r\n', '\r\n'])) expected_req = ('GET / HTTP/1.1\r\n' 'Host: 1.2.3.4\r\n' 'accept-encoding: identity\r\n\r\n') con.request('GET', '/') self.assertEqual(('1.2.3.4', 80), con.sock.sa) self.assertEqual(expected_req, con.sock.sent) r = con.getresponse() self.assertEqual('', r.read())
def test_request_response_request_close(self): # The timeout in this client is 15 seconds. In practice, this # test should complete in well under a tenth of a second, so # timeouts should indicate a bug in the test code. con = httpplus.HTTPConnection('localhost:%d' % self.server.port, timeout=15) # Verify we can send a bunch of responses and they all work # with the same client. con.request('GET', '/') resp = con.getresponse() self.assertEqual(resp.read(), "hi") con.request('GET', '/ohai') resp = con.getresponse() self.assertEqual(resp.read(), "hi") con.request('GET', '/wat') resp = con.getresponse() self.assertEqual(resp.read(), "hi") con.request('GET', '/quit') resp = con.getresponse() self.assertEqual(resp.read(), "hi")
def testReadline(self): con = httpplus.HTTPConnection('1.2.3.4') con._connect({}) con.sock.data = [ b'HTTP/1.1 200 OK\r\n', b'Server: BogusServer 1.0\r\n', b'Connection: Close\r\n', b'\r\n' b'1\n2\nabcdefg\n4\n5' ] con.sock.close_on_empty = True expected_req = (b'GET / HTTP/1.1\r\n' b'Host: 1.2.3.4\r\n' b'accept-encoding: identity\r\n\r\n') con.request('GET', '/') self.assertEqual((b'1.2.3.4', 80), con.sock.sa) self.assertEqual(expected_req, con.sock.sent) r = con.getresponse() for expected in [b'1\n', b'2\n', b'abcdefg\n', b'4\n', b'5']: actual = r.readline() self.assertEqual(expected, actual, 'Expected %r, got %r' % (expected, actual))