def test_02_handler(self): """ L{HTTP.__init__} is called with a function as its argument. This function is called by L{HTTP.requestReceived} with the request parameters, and its response is passed to L{HTTP._writeResponse}. In other words, this function determines how the HTTP server processes and handles requests. """ def handler(method, path, headers, body): self.assertEqual(method, "WOO") self.assertEqual(path, "/path") self.assertEqual(headers, {"Key": "value"}) return Response(300, "hello", {"k": "v"}) protocol = HTTP(handler, reactor=task.Clock()) response = [] protocol._writeResponse = lambda r: response.append(r) # Handler is stored as an attribute of the protocol: self.assertIdentical(protocol._handler, handler) # requestReceived calls handler, and then takes the results and passes # it to _writeResponse: protocol.requestReceived("WOO", "/path", {"Key": "value"}, "") self.assertResponsesEqual(response[0], Response(300, "hello", {"k": "v"}))
def test_14_handlerReturnsDeferredWithFailure(self): """ If the handler returns a Deferred that fires with a failure, L{HTTP.requestReceived} writes a 500 response code using L{HTTP._writeResponse} and logs the exception. """ # Handler that returns eventual result: result = defer.Deferred() def handler(method, path, headers, body): return result protocol = HTTP(handler, reactor=task.Clock()) response = [] protocol._writeResponse = lambda r: response.append(r) protocol.requestReceived("GET", "/", [], "") # Deferred hasn't fired yet, so no response is sent yet: self.assertEqual(len(response), 0) # Now we fire the Deferred with an exception: result.errback(ZeroDivisionError()) # 500 response code: self.assertEqual(len(response), 1) self.assertEqual(response[0].code, 500) # The error was logged using twisted.python.log.err(): excs = self.flushLoggedErrors(ZeroDivisionError) self.assertEqual(len(excs), 1)
def test_11_handlerException(self): """ If the handler throws an exception, L{HTTP.requestReceived} writes a response with error code 500 (internal server error), and the exception is logged. """ def handler(method, path, headers, body): raise RuntimeError("I am a buggy handler!") protocol = HTTP(handler, reactor=task.Clock()) response = [] protocol._writeResponse = lambda r: response.append(r) protocol.requestReceived("GET", "/", [], "") # We don't assert anything on the body of the response; if you're # feeling ambitious you can include the text of the traceback in your # response: self.assertEqual(len(response), 1) self.assertEqual(response[0].code, 500) # You should log the error using twisted.python.log.err(). This makes # sure the logged error doesn't cause the test to fail: excs = self.flushLoggedErrors(RuntimeError) # And this asserts that you logged it, i.e. that there was one # RuntimeError logged: self.assertEqual(len(excs), 1)
def test_19_requestBodyToHandler(self): """ If the HTTP request includes a body, it is passed to the handler function. """ result = [] def handler(method, path, headers, body): result.append(body) return Response(200, "hello", {}) protocol = HTTP(handler, reactor=task.Clock()) response = [] protocol._writeResponse = lambda r: response.append(r) protocol.requestReceived("GET", "/", {}, "the body") self.assertEqual(result, ["the body"])
def test_03_receiveRequest(self): """ When L{HTTP.dataReceived} receives the bytes for a HTTP request, L{HTTP.requestRecieved} is called with the method and path. """ protocol = HTTP(None, reactor=task.Clock()) received = [] protocol.requestReceived = lambda *args: received.append(args) # Hook up a fake in-memory transport: protocol.makeConnection(AbortableTransport()) protocol.dataReceived("GET /foo/bar HTTP/1.1\r\n\r\n") self.assertEqual(received, [("GET", "/foo/bar", {}, "")])
def test_12_handlerReturnsDeferred(self): """ If the handler returns a Deferred that fires with (code, body, headers), L{HTTP.requestReceived} writes it as a response using L{HTTP._writeResponse}. """ # Handler that returns eventual result: result = defer.Deferred() def handler(method, path, headers, body): return result protocol = HTTP(handler, reactor=task.Clock()) response = [] protocol._writeResponse = lambda r: response.append(r) protocol.requestReceived("GET", "/", [], "") # Deferred hasn't fired yet, so no response is sent yet: self.assertEqual(len(response), 0) # Now we fire the Deferred, and response should be written: result.callback(Response(200, "response", {"key": "value"})) self.assertResponsesEqual(response[0], Response(200, "response", {"key": "value"}))
def test_04_receiveHeaders(self): """ When L{HTTP.dataReceived} receives the bytes for a HTTP request, L{HTTP.requestRecieved} is called with a dictionary of headers. """ protocol = HTTP(None, reactor=task.Clock()) received = [] protocol.requestReceived = lambda *args: received.append(args) protocol.makeConnection(AbortableTransport()) protocol.dataReceived("GET /foo/bar HTTP/1.1\r\n" "Key: val ue\r\n" "Another: thing\r\n" "\r\n") self.assertEqual( received, [("GET", "/foo/bar", {"Key": "val ue", "Another": "thing"}, "")])
def test_18_contentLength(self): """ If the HTTP request includes a 'content-length' header, the value indicates the number of bytes of the request body, which will get passed as the fourth argument to the requestReceived. """ protocol = HTTP(None, reactor=task.Clock()) received = [] protocol.requestReceived = lambda *args: received.append(args) protocol.makeConnection(AbortableTransport()) protocol.dataReceived("GET /foo/bar HTTP/1.1\r\n") protocol.dataReceived("Content-Length: 10\r\n") protocol.dataReceived("\r\n") protocol.dataReceived("abcde") self.assertEqual(received, []) protocol.dataReceived("fghij") self.assertEqual( received, [("GET", "/foo/bar", {"Content-Length": "10"}, "abcdefghij")])
def test_05_receiveAfterFinalNewline(self): """ L{HTTP.requestReceived} is only called after C{dataReceived} gets the final line with just '\r\n'. (Network connections may not deliver the full request in a single dataReceived() call, so the protocol will need to implement a state machine tracking where it is in the process of parsing the HTTP request.) """ protocol = HTTP(None, reactor=task.Clock()) received = [] protocol.requestReceived = lambda *args: received.append(args) protocol.makeConnection(AbortableTransport()) protocol.dataReceived("HEAD /?x=y HTTP/") protocol.dataReceived("1.1\r\n") self.assertEqual(received, []) protocol.dataReceived("\r\n") self.assertEqual(received, [("HEAD", "/?x=y", {}, "")])