class HeadersTests(GeneratorTestCase): def setUp(self): super().setUp() self.reader = StreamReader() def parse_headers(self): return parse_headers(self.reader.read_line) def test_parse_invalid_name(self): self.reader.feed_data(b"foo bar: baz qux\r\n\r\n") with self.assertRaises(ValueError): next(self.parse_headers()) def test_parse_invalid_value(self): self.reader.feed_data(b"foo: \x00\x00\x0f\r\n\r\n") with self.assertRaises(ValueError): next(self.parse_headers()) def test_parse_too_long_value(self): self.reader.feed_data(b"foo: bar\r\n" * 257 + b"\r\n") with self.assertRaises(SecurityError): next(self.parse_headers()) def test_parse_too_long_line(self): # Header line contains 5 + 4104 + 2 = 4111 bytes. self.reader.feed_data(b"foo: " + b"a" * 4104 + b"\r\n\r\n") with self.assertRaises(SecurityError): next(self.parse_headers()) def test_parse_invalid_line_ending(self): self.reader.feed_data(b"foo: bar\n\n") with self.assertRaises(EOFError): next(self.parse_headers())
def parse(self, data, mask, max_size=None, extensions=None): """ Parse a frame from a bytestring. """ reader = StreamReader() reader.feed_data(data) reader.feed_eof() parser = Frame.parse(reader.read_exact, mask=mask, max_size=max_size, extensions=extensions) return self.assertGeneratorReturns(parser)
class RequestTests(GeneratorTestCase): def setUp(self): super().setUp() self.reader = StreamReader() def parse(self): return Request.parse(self.reader.read_line) def test_parse(self): # Example from the protocol overview in RFC 6455 self.reader.feed_data( b"GET /chat HTTP/1.1\r\n" b"Host: server.example.com\r\n" b"Upgrade: websocket\r\n" b"Connection: Upgrade\r\n" b"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" b"Origin: http://example.com\r\n" b"Sec-WebSocket-Protocol: chat, superchat\r\n" b"Sec-WebSocket-Version: 13\r\n" b"\r\n" ) request = self.assertGeneratorReturns(self.parse()) self.assertEqual(request.path, "/chat") self.assertEqual(request.headers["Upgrade"], "websocket") def test_parse_empty(self): self.reader.feed_eof() with self.assertRaises(EOFError) as raised: next(self.parse()) self.assertEqual( str(raised.exception), "connection closed while reading HTTP request line", ) def test_parse_invalid_request_line(self): self.reader.feed_data(b"GET /\r\n\r\n") with self.assertRaises(ValueError) as raised: next(self.parse()) self.assertEqual( str(raised.exception), "invalid HTTP request line: GET /", ) def test_parse_unsupported_method(self): self.reader.feed_data(b"OPTIONS * HTTP/1.1\r\n\r\n") with self.assertRaises(ValueError) as raised: next(self.parse()) self.assertEqual( str(raised.exception), "unsupported HTTP method: OPTIONS", ) def test_parse_unsupported_version(self): self.reader.feed_data(b"GET /chat HTTP/1.0\r\n\r\n") with self.assertRaises(ValueError) as raised: next(self.parse()) self.assertEqual( str(raised.exception), "unsupported HTTP version: HTTP/1.0", ) def test_parse_invalid_header(self): self.reader.feed_data(b"GET /chat HTTP/1.1\r\nOops\r\n") with self.assertRaises(ValueError) as raised: next(self.parse()) self.assertEqual( str(raised.exception), "invalid HTTP header line: Oops", ) def test_serialize(self): # Example from the protocol overview in RFC 6455 request = Request( "/chat", Headers( [ ("Host", "server.example.com"), ("Upgrade", "websocket"), ("Connection", "Upgrade"), ("Sec-WebSocket-Key", "dGhlIHNhbXBsZSBub25jZQ=="), ("Origin", "http://example.com"), ("Sec-WebSocket-Protocol", "chat, superchat"), ("Sec-WebSocket-Version", "13"), ] ), ) self.assertEqual( request.serialize(), b"GET /chat HTTP/1.1\r\n" b"Host: server.example.com\r\n" b"Upgrade: websocket\r\n" b"Connection: Upgrade\r\n" b"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" b"Origin: http://example.com\r\n" b"Sec-WebSocket-Protocol: chat, superchat\r\n" b"Sec-WebSocket-Version: 13\r\n" b"\r\n", )
def setUp(self): super().setUp() self.reader = StreamReader()
class ResponseTests(GeneratorTestCase): def setUp(self): super().setUp() self.reader = StreamReader() def parse(self): return Response.parse( self.reader.read_line, self.reader.read_exact, self.reader.read_to_eof ) def test_parse(self): # Example from the protocol overview in RFC 6455 self.reader.feed_data( b"HTTP/1.1 101 Switching Protocols\r\n" b"Upgrade: websocket\r\n" b"Connection: Upgrade\r\n" b"Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" b"Sec-WebSocket-Protocol: chat\r\n" b"\r\n" ) response = self.assertGeneratorReturns(self.parse()) self.assertEqual(response.status_code, 101) self.assertEqual(response.reason_phrase, "Switching Protocols") self.assertEqual(response.headers["Upgrade"], "websocket") self.assertIsNone(response.body) def test_parse_empty(self): self.reader.feed_eof() with self.assertRaises(EOFError) as raised: next(self.parse()) self.assertEqual( str(raised.exception), "connection closed while reading HTTP status line" ) def test_parse_invalid_status_line(self): self.reader.feed_data(b"Hello!\r\n") with self.assertRaises(ValueError) as raised: next(self.parse()) self.assertEqual( str(raised.exception), "invalid HTTP status line: Hello!", ) def test_parse_unsupported_version(self): self.reader.feed_data(b"HTTP/1.0 400 Bad Request\r\n\r\n") with self.assertRaises(ValueError) as raised: next(self.parse()) self.assertEqual( str(raised.exception), "unsupported HTTP version: HTTP/1.0", ) def test_parse_invalid_status(self): self.reader.feed_data(b"HTTP/1.1 OMG WTF\r\n\r\n") with self.assertRaises(ValueError) as raised: next(self.parse()) self.assertEqual( str(raised.exception), "invalid HTTP status code: OMG", ) def test_parse_unsupported_status(self): self.reader.feed_data(b"HTTP/1.1 007 My name is Bond\r\n\r\n") with self.assertRaises(ValueError) as raised: next(self.parse()) self.assertEqual( str(raised.exception), "unsupported HTTP status code: 007", ) def test_parse_invalid_reason(self): self.reader.feed_data(b"HTTP/1.1 200 \x7f\r\n\r\n") with self.assertRaises(ValueError) as raised: next(self.parse()) self.assertEqual( str(raised.exception), "invalid HTTP reason phrase: \x7f", ) def test_parse_invalid_header(self): self.reader.feed_data(b"HTTP/1.1 500 Internal Server Error\r\nOops\r\n") with self.assertRaises(ValueError) as raised: next(self.parse()) self.assertEqual( str(raised.exception), "invalid HTTP header line: Oops", ) def test_parse_body_with_content_length(self): self.reader.feed_data( b"HTTP/1.1 200 OK\r\nContent-Length: 13\r\n\r\nHello world!\n" ) response = self.assertGeneratorReturns(self.parse()) self.assertEqual(response.body, b"Hello world!\n") def test_parse_body_without_content_length(self): self.reader.feed_data(b"HTTP/1.1 200 OK\r\n\r\nHello world!\n") gen = self.parse() self.assertGeneratorRunning(gen) self.reader.feed_eof() response = self.assertGeneratorReturns(gen) self.assertEqual(response.body, b"Hello world!\n") def test_parse_body_with_transfer_encoding(self): self.reader.feed_data(b"HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n") with self.assertRaises(NotImplementedError) as raised: next(self.parse()) self.assertEqual( str(raised.exception), "transfer codings aren't supported", ) def test_parse_body_no_content(self): self.reader.feed_data(b"HTTP/1.1 204 No Content\r\n\r\n") response = self.assertGeneratorReturns(self.parse()) self.assertIsNone(response.body) def test_parse_body_not_modified(self): self.reader.feed_data(b"HTTP/1.1 304 Not Modified\r\n\r\n") response = self.assertGeneratorReturns(self.parse()) self.assertIsNone(response.body) def test_serialize(self): # Example from the protocol overview in RFC 6455 response = Response( 101, "Switching Protocols", Headers( [ ("Upgrade", "websocket"), ("Connection", "Upgrade"), ("Sec-WebSocket-Accept", "s3pPLMBiTxaQ9kYGzzhZRbK+xOo="), ("Sec-WebSocket-Protocol", "chat"), ] ), ) self.assertEqual( response.serialize(), b"HTTP/1.1 101 Switching Protocols\r\n" b"Upgrade: websocket\r\n" b"Connection: Upgrade\r\n" b"Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" b"Sec-WebSocket-Protocol: chat\r\n" b"\r\n", ) def test_serialize_with_body(self): response = Response( 200, "OK", Headers([("Content-Length", "13"), ("Content-Type", "text/plain")]), b"Hello world!\n", ) self.assertEqual( response.serialize(), b"HTTP/1.1 200 OK\r\n" b"Content-Length: 13\r\n" b"Content-Type: text/plain\r\n" b"\r\n" b"Hello world!\n", )
def setUp(self): self.reader = StreamReader()
class StreamReaderTests(GeneratorTestCase): def setUp(self): self.reader = StreamReader() def test_read_line(self): self.reader.feed_data(b"spam\neggs\n") gen = self.reader.read_line() line = self.assertGeneratorReturns(gen) self.assertEqual(line, b"spam\n") gen = self.reader.read_line() line = self.assertGeneratorReturns(gen) self.assertEqual(line, b"eggs\n") def test_read_line_need_more_data(self): self.reader.feed_data(b"spa") gen = self.reader.read_line() self.assertGeneratorRunning(gen) self.reader.feed_data(b"m\neg") line = self.assertGeneratorReturns(gen) self.assertEqual(line, b"spam\n") gen = self.reader.read_line() self.assertGeneratorRunning(gen) self.reader.feed_data(b"gs\n") line = self.assertGeneratorReturns(gen) self.assertEqual(line, b"eggs\n") def test_read_line_not_enough_data(self): self.reader.feed_data(b"spa") self.reader.feed_eof() gen = self.reader.read_line() with self.assertRaises(EOFError) as raised: next(gen) self.assertEqual( str(raised.exception), "stream ends after 3 bytes, before end of line" ) def test_read_exact(self): self.reader.feed_data(b"spameggs") gen = self.reader.read_exact(4) data = self.assertGeneratorReturns(gen) self.assertEqual(data, b"spam") gen = self.reader.read_exact(4) data = self.assertGeneratorReturns(gen) self.assertEqual(data, b"eggs") def test_read_exact_need_more_data(self): self.reader.feed_data(b"spa") gen = self.reader.read_exact(4) self.assertGeneratorRunning(gen) self.reader.feed_data(b"meg") data = self.assertGeneratorReturns(gen) self.assertEqual(data, b"spam") gen = self.reader.read_exact(4) self.assertGeneratorRunning(gen) self.reader.feed_data(b"gs") data = self.assertGeneratorReturns(gen) self.assertEqual(data, b"eggs") def test_read_exact_not_enough_data(self): self.reader.feed_data(b"spa") self.reader.feed_eof() gen = self.reader.read_exact(4) with self.assertRaises(EOFError) as raised: next(gen) self.assertEqual( str(raised.exception), "stream ends after 3 bytes, expected 4 bytes" ) def test_read_to_eof(self): gen = self.reader.read_to_eof() self.reader.feed_data(b"spam") self.assertGeneratorRunning(gen) self.reader.feed_eof() data = self.assertGeneratorReturns(gen) self.assertEqual(data, b"spam") def test_read_to_eof_at_eof(self): self.reader.feed_eof() gen = self.reader.read_to_eof() data = self.assertGeneratorReturns(gen) self.assertEqual(data, b"") def test_at_eof_after_feed_data(self): gen = self.reader.at_eof() self.assertGeneratorRunning(gen) self.reader.feed_data(b"spam") eof = self.assertGeneratorReturns(gen) self.assertFalse(eof) def test_at_eof_after_feed_eof(self): gen = self.reader.at_eof() self.assertGeneratorRunning(gen) self.reader.feed_eof() eof = self.assertGeneratorReturns(gen) self.assertTrue(eof) def test_feed_data_after_feed_data(self): self.reader.feed_data(b"spam") self.reader.feed_data(b"eggs") gen = self.reader.read_exact(8) data = self.assertGeneratorReturns(gen) self.assertEqual(data, b"spameggs") gen = self.reader.at_eof() self.assertGeneratorRunning(gen) def test_feed_eof_after_feed_data(self): self.reader.feed_data(b"spam") self.reader.feed_eof() gen = self.reader.read_exact(4) data = self.assertGeneratorReturns(gen) self.assertEqual(data, b"spam") gen = self.reader.at_eof() eof = self.assertGeneratorReturns(gen) self.assertTrue(eof) def test_feed_data_after_feed_eof(self): self.reader.feed_eof() with self.assertRaises(EOFError) as raised: self.reader.feed_data(b"spam") self.assertEqual(str(raised.exception), "stream ended") def test_feed_eof_after_feed_eof(self): self.reader.feed_eof() with self.assertRaises(EOFError) as raised: self.reader.feed_eof() self.assertEqual(str(raised.exception), "stream ended") def test_discard(self): gen = self.reader.read_to_eof() self.reader.feed_data(b"spam") self.reader.discard() self.assertGeneratorRunning(gen) self.reader.feed_eof() data = self.assertGeneratorReturns(gen) self.assertEqual(data, b"")