def test_render(self): """ When rendering a request, L{WebSocketsResource} uses the C{Sec-WebSocket-Key} header to generate a C{Sec-WebSocket-Accept} value. It creates a L{WebSocketsProtocol} instance connected to the protocol provided by the user factory. """ request = DummyRequest("/") request.requestHeaders = Headers() transport = StringTransportWithDisconnection() transport.protocol = Protocol() request.transport = transport request.headers.update({ "upgrade": "Websocket", "connection": "Upgrade", "sec-websocket-key": "secure", "sec-websocket-version": "13"}) result = self.resource.render(request) self.assertEqual(NOT_DONE_YET, result) self.assertEqual( {"connection": "Upgrade", "upgrade": "WebSocket", "sec-websocket-accept": "oYBv54i42V5dw6KnZqOFroecUTc="}, request.outgoingHeaders) self.assertEqual([""], request.written) self.assertEqual(101, request.responseCode) self.assertIdentical(None, request.transport) self.assertIsInstance(transport.protocol._receiver, SavingEchoReceiver)
def test_render(self): """ When rendering a request, L{WebSocketsResource} uses the C{Sec-WebSocket-Key} header to generate a C{Sec-WebSocket-Accept} value. It creates a L{WebSocketsProtocol} instance connected to the protocol provided by the user factory. """ request = DummyRequest("/") request.requestHeaders = Headers() transport = StringTransportWithDisconnection() transport.protocol = Protocol() request.transport = transport request.headers.update({ "upgrade": "Websocket", "connection": "Upgrade", "sec-websocket-key": "secure", "sec-websocket-version": "13" }) result = self.resource.render(request) self.assertEqual(NOT_DONE_YET, result) self.assertEqual( { "connection": "Upgrade", "upgrade": "WebSocket", "sec-websocket-accept": "oYBv54i42V5dw6KnZqOFroecUTc=" }, request.outgoingHeaders) self.assertEqual([""], request.written) self.assertEqual(101, request.responseCode) self.assertIdentical(None, request.transport) self.assertIsInstance(transport.protocol._receiver, SavingEchoReceiver)
def test_renderSecureRequest(self): """ When the rendered request is over HTTPS, L{WebSocketsResource} wraps the protocol of the C{TLSMemoryBIOProtocol} instance. """ request = DummyRequest("/") request.requestHeaders = Headers() transport = StringTransportWithDisconnection() secureProtocol = TLSMemoryBIOProtocol(Factory(), Protocol()) transport.protocol = secureProtocol request.transport = transport request.headers.update({ "upgrade": "Websocket", "connection": "Upgrade", "sec-websocket-key": "secure", "sec-websocket-version": "13" }) result = self.resource.render(request) self.assertEqual(NOT_DONE_YET, result) self.assertEqual( { "connection": "Upgrade", "upgrade": "WebSocket", "sec-websocket-accept": "oYBv54i42V5dw6KnZqOFroecUTc=" }, request.outgoingHeaders) self.assertEqual([""], request.written) self.assertEqual(101, request.responseCode) self.assertIdentical(None, request.transport) self.assertIsInstance(transport.protocol.wrappedProtocol, WebSocketsProtocol) self.assertIsInstance(transport.protocol.wrappedProtocol._receiver, SavingEchoReceiver)
def test_renderIProtocol(self): """ If the protocol returned by C{lookupProtocol} isn't a C{WebSocketsProtocol}, L{WebSocketsResource} wraps it automatically with L{WebSocketsProtocolWrapper}. """ def lookupProtocol(names, otherRequest): return AccumulatingProtocol(), None self.resource = WebSocketsResource(lookupProtocol) request = DummyRequest("/") request.requestHeaders = Headers() transport = StringTransportWithDisconnection() transport.protocol = Protocol() request.transport = transport request.headers.update({ "upgrade": "Websocket", "connection": "Upgrade", "sec-websocket-key": "secure", "sec-websocket-version": "13"}) result = self.resource.render(request) self.assertEqual(NOT_DONE_YET, result) self.assertIsInstance(transport.protocol, WebSocketsProtocolWrapper) self.assertIsInstance(transport.protocol.wrappedProtocol, AccumulatingProtocol)
def test_render_GET_logs_node_event_with_original_path_ip(self): path = factory.make_name('path') ip = factory.make_ip_address() request = DummyRequest([path.encode('utf-8')]) request.requestHeaders = Headers({ 'X-Server-Addr': ['192.168.1.1'], 'X-Server-Port': ['5248'], 'X-Forwarded-For': [ip], 'X-Forwarded-Port': ['%s' % factory.pick_port()], }) log_info = self.patch(http.log, 'info') mock_deferLater = self.patch(http, 'deferLater') mock_deferLater.side_effect = always_succeed_with(None) self.tftp.backend.get_reader.return_value = fail(AccessViolation()) resource = http.HTTPBootResource() yield self.render_GET(resource, request) self.assertThat( log_info, MockCalledOnceWith("{path} requested by {remoteHost}", path=path, remoteHost=ip)) self.assertThat( mock_deferLater, MockCalledOnceWith(ANY, 0, http.send_node_event_ip_address, event_type=EVENT_TYPES.NODE_HTTP_REQUEST, ip_address=ip, description=path))
def test_render_GET_500_server_error(self): path = factory.make_name("path") ip = factory.make_ip_address() request = DummyRequest([path.encode("utf-8")]) request.requestHeaders = Headers( { "X-Server-Addr": ["192.168.1.1"], "X-Server-Port": ["5248"], "X-Forwarded-For": [ip], "X-Forwarded-Port": ["%s" % factory.pick_port()], } ) self.patch(http.log, "info") mock_deferLater = self.patch(http, "deferLater") mock_deferLater.side_effect = always_succeed_with(None) exc = factory.make_exception("internal error") self.tftp.backend.get_reader.return_value = fail(exc) resource = http.HTTPBootResource() yield self.render_GET(resource, request) self.assertEquals(500, request.responseCode) self.assertEquals(str(exc).encode("utf-8"), b"".join(request.written))
def test_render_GET_503_when_no_tftp_service(self): # Remove the fake 'tftp' service. self.tftp.disownServiceParent() self.tftp = None path = factory.make_name("path") ip = factory.make_ip_address() request = DummyRequest([path.encode("utf-8")]) request.requestHeaders = Headers({ "X-Server-Addr": ["192.168.1.1"], "X-Server-Port": ["5248"], "X-Forwarded-For": [ip], "X-Forwarded-Port": ["%s" % factory.pick_port()], }) self.patch(http.log, "info") mock_deferLater = self.patch(http, "deferLater") mock_deferLater.side_effect = always_succeed_with(None) resource = http.HTTPBootResource() yield self.render_GET(resource, request) self.assertEqual(503, request.responseCode) self.assertEqual(b"HTTP boot service not ready.", b"".join(request.written))
def test_render_GET_produces_from_reader(self): path = factory.make_name('path') ip = factory.make_ip_address() request = DummyRequest([path.encode('utf-8')]) request.requestHeaders = Headers({ 'X-Server-Addr': ['192.168.1.1'], 'X-Server-Port': ['5248'], 'X-Forwarded-For': [ip], 'X-Forwarded-Port': ['%s' % factory.pick_port()], }) self.patch(http.log, 'info') mock_deferLater = self.patch(http, 'deferLater') mock_deferLater.side_effect = always_succeed_with(None) content = factory.make_string(size=100).encode('utf-8') reader = BytesReader(content) self.tftp.backend.get_reader.return_value = succeed(reader) resource = http.HTTPBootResource() yield self.render_GET(resource, request) self.assertEquals( [100], request.responseHeaders.getRawHeaders(b'Content-Length')) self.assertEquals(content, b''.join(request.written))
def test_render_GET_produces_from_reader(self): path = factory.make_name("path") ip = factory.make_ip_address() request = DummyRequest([path.encode("utf-8")]) request.requestHeaders = Headers({ "X-Server-Addr": ["192.168.1.1"], "X-Server-Port": ["5248"], "X-Forwarded-For": [ip], "X-Forwarded-Port": ["%s" % factory.pick_port()], }) self.patch(http.log, "info") mock_deferLater = self.patch(http, "deferLater") mock_deferLater.side_effect = always_succeed_with(None) content = factory.make_string(size=100).encode("utf-8") reader = BytesReader(content) self.tftp.backend.get_reader.return_value = succeed(reader) resource = http.HTTPBootResource() yield self.render_GET(resource, request) self.assertEqual( [100], request.responseHeaders.getRawHeaders(b"Content-Length")) self.assertEqual(content, b"".join(request.written))
def test_render_GET_503_when_no_tftp_service(self): # Remove the fake 'tftp' service. self.tftp.disownServiceParent() self.tftp = None path = factory.make_name('path') ip = factory.make_ip_address() request = DummyRequest([path.encode('utf-8')]) request.requestHeaders = Headers({ 'X-Server-Addr': ['192.168.1.1'], 'X-Server-Port': ['5248'], 'X-Forwarded-For': [ip], 'X-Forwarded-Port': ['%s' % factory.pick_port()], }) self.patch(http.log, 'info') mock_deferLater = self.patch(http, 'deferLater') mock_deferLater.side_effect = always_succeed_with(None) resource = http.HTTPBootResource() yield self.render_GET(resource, request) self.assertEquals(503, request.responseCode) self.assertEquals(b'HTTP boot service not ready.', b''.join(request.written))
def test_renderIProtocol(self): """ If the protocol returned by C{lookupProtocol} isn't a C{WebSocketsProtocol}, L{WebSocketsResource} wraps it automatically with L{WebSocketsProtocolWrapper}. """ def lookupProtocol(names, otherRequest): return AccumulatingProtocol(), None self.resource = WebSocketsResource(lookupProtocol) request = DummyRequest("/") request.requestHeaders = Headers() transport = StringTransportWithDisconnection() transport.protocol = Protocol() request.transport = transport request.headers.update({ "upgrade": "Websocket", "connection": "Upgrade", "sec-websocket-key": "secure", "sec-websocket-version": "13" }) result = self.resource.render(request) self.assertEqual(NOT_DONE_YET, result) self.assertIsInstance(transport.protocol, WebSocketsProtocolWrapper) self.assertIsInstance(transport.protocol.wrappedProtocol, AccumulatingProtocol)
def test_renderSecureRequest(self): """ When the rendered request is over HTTPS, L{WebSocketsResource} wraps the protocol of the C{TLSMemoryBIOProtocol} instance. """ request = DummyRequest("/") request.requestHeaders = Headers() transport = StringTransportWithDisconnection() secureProtocol = TLSMemoryBIOProtocol(Factory(), Protocol()) transport.protocol = secureProtocol request.transport = transport request.headers.update({ "upgrade": "Websocket", "connection": "Upgrade", "sec-websocket-key": "secure", "sec-websocket-version": "13"}) result = self.resource.render(request) self.assertEqual(NOT_DONE_YET, result) self.assertEqual( {"connection": "Upgrade", "upgrade": "WebSocket", "sec-websocket-accept": "oYBv54i42V5dw6KnZqOFroecUTc="}, request.outgoingHeaders) self.assertEqual([""], request.written) self.assertEqual(101, request.responseCode) self.assertIdentical(None, request.transport) self.assertIsInstance( transport.protocol.wrappedProtocol, WebSocketsProtocol) self.assertIsInstance( transport.protocol.wrappedProtocol._receiver, SavingEchoReceiver)
def test_renderProtocol(self): """ If protocols are specified via the C{Sec-WebSocket-Protocol} header, L{WebSocketsResource} passes them to its C{lookupProtocol} argument, which can decide which protocol to return, and which is accepted. """ def lookupProtocol(names, otherRequest): self.assertEqual(["foo", "bar"], names) self.assertIdentical(request, otherRequest) return self.echoProtocol, "bar" self.resource = WebSocketsResource(lookupProtocol) request = DummyRequest("/") request.requestHeaders = Headers( {"sec-websocket-protocol": ["foo", "bar"]}) transport = StringTransportWithDisconnection() transport.protocol = Protocol() request.transport = transport request.headers.update({ "upgrade": "Websocket", "connection": "Upgrade", "sec-websocket-key": "secure", "sec-websocket-version": "13"}) result = self.resource.render(request) self.assertEqual(NOT_DONE_YET, result) self.assertEqual( {"connection": "Upgrade", "upgrade": "WebSocket", "sec-websocket-protocol": "bar", "sec-websocket-accept": "oYBv54i42V5dw6KnZqOFroecUTc="}, request.outgoingHeaders) self.assertEqual([""], request.written) self.assertEqual(101, request.responseCode)
def request_generator(url, method='GET', content=True, headers=True): request = DummyRequest(url) request.method = method if content: request.content = StringIO() if headers: request.requestHeaders = Headers() return request
def test_render_GET_400_when_no_remote_addr(self): path = factory.make_name('path') request = DummyRequest([path.encode('utf-8')]) request.requestHeaders = Headers({ 'X-Server-Addr': ['192.168.1.1'], 'X-Server-Port': ['5248'], }) self.patch(http.log, 'info') mock_deferLater = self.patch(http, 'deferLater') mock_deferLater.side_effect = always_succeed_with(None) resource = http.HTTPBootResource() yield self.render_GET(resource, request) self.assertEquals(400, request.responseCode) self.assertEquals( b'Missing X-Server-Addr and X-Forwarded-For HTTP headers.', b''.join(request.written))
def test_render_GET_400_when_no_remote_addr(self): path = factory.make_name("path") request = DummyRequest([path.encode("utf-8")]) request.requestHeaders = Headers( {"X-Server-Addr": ["192.168.1.1"], "X-Server-Port": ["5248"]} ) self.patch(http.log, "info") mock_deferLater = self.patch(http, "deferLater") mock_deferLater.side_effect = always_succeed_with(None) resource = http.HTTPBootResource() yield self.render_GET(resource, request) self.assertEquals(400, request.responseCode) self.assertEquals( b"Missing X-Server-Addr and X-Forwarded-For HTTP headers.", b"".join(request.written), )
def test_renderNoProtocol(self): """ If the underlying factory doesn't return any protocol, L{WebSocketsResource} returns a failed request with a C{502} code. """ request = DummyRequest("/") request.requestHeaders = Headers() request.transport = StringTransportWithDisconnection() self.echoProtocol = None request.headers.update({ "upgrade": "Websocket", "connection": "Upgrade", "sec-websocket-key": "secure", "sec-websocket-version": "13"}) result = self.resource.render(request) self.assertEqual("", result) self.assertEqual({}, request.outgoingHeaders) self.assertEqual([], request.written) self.assertEqual(502, request.responseCode)
def test_renderNoProtocol(self): """ If the underlying factory doesn't return any protocol, L{WebSocketsResource} returns a failed request with a C{502} code. """ request = DummyRequest("/") request.requestHeaders = Headers() request.transport = StringTransportWithDisconnection() self.echoProtocol = None request.headers.update({ "upgrade": "Websocket", "connection": "Upgrade", "sec-websocket-key": "secure", "sec-websocket-version": "13" }) result = self.resource.render(request) self.assertEqual("", result) self.assertEqual({}, request.outgoingHeaders) self.assertEqual([], request.written) self.assertEqual(502, request.responseCode)
def test_render_GET_404_file_not_found(self): path = factory.make_name('path') ip = factory.make_ip_address() request = DummyRequest([path.encode('utf-8')]) request.requestHeaders = Headers({ 'X-Server-Addr': ['192.168.1.1'], 'X-Server-Port': ['5248'], 'X-Forwarded-For': [ip], 'X-Forwarded-Port': ['%s' % factory.pick_port()], }) self.patch(http.log, 'info') mock_deferLater = self.patch(http, 'deferLater') mock_deferLater.side_effect = always_succeed_with(None) self.tftp.backend.get_reader.return_value = fail(FileNotFound(path)) resource = http.HTTPBootResource() yield self.render_GET(resource, request) self.assertEquals(404, request.responseCode) self.assertEquals(b'', b''.join(request.written))
def test_renderProtocol(self): """ If protocols are specified via the C{Sec-WebSocket-Protocol} header, L{WebSocketsResource} passes them to its C{lookupProtocol} argument, which can decide which protocol to return, and which is accepted. """ def lookupProtocol(names, otherRequest): self.assertEqual(["foo", "bar"], names) self.assertIdentical(request, otherRequest) return self.echoProtocol, "bar" self.resource = WebSocketsResource(lookupProtocol) request = DummyRequest("/") request.requestHeaders = Headers( {"sec-websocket-protocol": ["foo", "bar"]}) transport = StringTransportWithDisconnection() transport.protocol = Protocol() request.transport = transport request.headers.update({ "upgrade": "Websocket", "connection": "Upgrade", "sec-websocket-key": "secure", "sec-websocket-version": "13" }) result = self.resource.render(request) self.assertEqual(NOT_DONE_YET, result) self.assertEqual( { "connection": "Upgrade", "upgrade": "WebSocket", "sec-websocket-protocol": "bar", "sec-websocket-accept": "oYBv54i42V5dw6KnZqOFroecUTc=" }, request.outgoingHeaders) self.assertEqual([""], request.written) self.assertEqual(101, request.responseCode)