def testParsedAndRaw(self): def parse(raw): return parsedvalue(raw) def generate(parsed): return parsed.raw rawvalue = ("value1", "value2") rawvalue2 = ("value3", "value4") handler = HeaderHandler(parsers={'test': (parse,)}, generators={'test': (generate,)}) h = http_headers.Headers(handler=handler) h.setRawHeaders("test", rawvalue) self.assertEquals(h.getHeader("test"), parsedvalue(rawvalue)) h.setHeader("test", parsedvalue(rawvalue2)) self.assertEquals(h.getRawHeaders("test"), rawvalue2) # Check the initializers h = http_headers.Headers(rawHeaders={"test": rawvalue}, handler=handler) self.assertEquals(h.getHeader("test"), parsedvalue(rawvalue)) h = http_headers.Headers({"test": parsedvalue(rawvalue2)}, handler=handler) self.assertEquals(h.getRawHeaders("test"), rawvalue2)
def __init__(self, code=None, headers=None, stream=None): """ @param code: The HTTP status code for this Response @type code: C{int} @param headers: Headers to be sent to the client. @type headers: C{dict}, L{txweb2.http_headers.Headers}, or C{None} @param stream: Content body to send to the HTTP client @type stream: L{txweb2.stream.IByteStream} """ if code is not None: self.code = int(code) if headers is not None: if isinstance(headers, dict): headers = http_headers.Headers(headers) self.headers = headers else: self.headers = http_headers.Headers() if stream is not None: self.stream = IByteStream(stream)
def testIfMatch(self): request = http.Request(None, "GET", "/", "HTTP/1.1", 0, http_headers.Headers()) out_headers = http_headers.Headers() response = http.Response(responsecode.OK, out_headers, None) # Behavior with no ETag set, should be same as with an ETag request.headers.setRawHeaders("If-Match", ('*', )) self.checkPreconditions(request, response, True, responsecode.OK) self.checkPreconditions(request, response, False, responsecode.PRECONDITION_FAILED, entityExists=False) # Ask for tag, but no etag set. request.headers.setRawHeaders("If-Match", ('"frob"', )) self.checkPreconditions(request, response, False, responsecode.PRECONDITION_FAILED) # Actually set the ETag header out_headers.setHeader("ETag", http_headers.ETag('foo')) out_headers.setHeader("Last-Modified", 946771200) # Sun, 02 Jan 2000 00:00:00 GMT # behavior of entityExists request.headers.setRawHeaders("If-Match", ('*', )) self.checkPreconditions(request, response, True, responsecode.OK) self.checkPreconditions(request, response, False, responsecode.PRECONDITION_FAILED, entityExists=False) # tag matches request.headers.setRawHeaders("If-Match", ('"frob", "foo"', )) self.checkPreconditions(request, response, True, responsecode.OK) # none match request.headers.setRawHeaders("If-Match", ('"baz", "bob"', )) self.checkPreconditions(request, response, False, responsecode.PRECONDITION_FAILED) # But if we have an error code already, ignore this header response.code = responsecode.INTERNAL_SERVER_ERROR self.checkPreconditions(request, response, True, responsecode.INTERNAL_SERVER_ERROR) response.code = responsecode.OK # Must only compare strong tags out_headers.setHeader("ETag", http_headers.ETag('foo', weak=True)) request.headers.setRawHeaders("If-Match", ('W/"foo"', )) self.checkPreconditions(request, response, False, responsecode.PRECONDITION_FAILED)
def testIfModifiedSince(self): if time.time() < 946771200: self.fail( RuntimeError("Your computer's clock is way wrong, " "this test will be invalid.")) request = http.Request(None, "GET", "/", "HTTP/1.1", 0, http_headers.Headers()) out_headers = http_headers.Headers() response = http.Response(responsecode.OK, out_headers, None) # No Last-Modified => always succeed request.headers.setRawHeaders("If-Modified-Since", ('Mon, 03 Jan 2000 00:00:00 GMT', )) self.checkPreconditions(request, response, True, responsecode.OK) # Set output headers out_headers.setHeader("ETag", http_headers.ETag('foo')) out_headers.setHeader("Last-Modified", 946771200) # Sun, 02 Jan 2000 00:00:00 GMT request.headers.setRawHeaders("If-Modified-Since", ('Mon, 03 Jan 2000 00:00:00 GMT', )) self.checkPreconditions(request, response, False, responsecode.NOT_MODIFIED) # With a non-GET method request.method = "PUT" self.checkPreconditions(request, response, False, responsecode.NOT_MODIFIED) request.method = "GET" request.headers.setRawHeaders("If-Modified-Since", ('Sat, 01 Jan 2000 00:00:00 GMT', )) self.checkPreconditions(request, response, True, responsecode.OK) # But if we have an error code already, ignore this header response.code = responsecode.INTERNAL_SERVER_ERROR self.checkPreconditions(request, response, True, responsecode.INTERNAL_SERVER_ERROR) response.code = responsecode.OK # invalid date => header ignored request.headers.setRawHeaders("If-Modified-Since", ('alalalalalalalalalala', )) self.checkPreconditions(request, response, True, responsecode.OK) # date in the future => assume modified request.headers.setHeader("If-Modified-Since", time.time() + 500) self.checkPreconditions(request, response, True, responsecode.OK)
def test_maxFields(self): """ Check that the C{maxSize} parameter makes the parsing raise an exception if the data contains too many fields. """ ctype = http_headers.MimeType('multipart', 'form-data', (('boundary', '---xyz'),)) content = """-----xyz\r Content-Disposition: form-data; name="foo"\r \r Foo Bar\r -----xyz\r Content-Disposition: form-data; name="foo"\r \r Baz\r -----xyz\r Content-Disposition: form-data; name="file"; filename="filename"\r Content-Type: text/html\r \r blah\r -----xyz\r Content-Disposition: form-data; name="file"; filename="filename"\r Content-Type: text/plain\r \r bleh\r -----xyz--\r """ root = resource.Resource() request = SimpleRequest(server.Site(root), "GET", "/", http_headers.Headers({'content-type': ctype}), content) def cb(res): self.assertEquals(res.response.description, "Maximum number of fields 3 exceeded") return self.assertFailure(server.parsePOSTData(request, maxFields=3), http.HTTPError).addCallback(cb)
def test_multipart(self): """ Test parsing data in multipart format: it should fill the C{files} attribute. """ ctype = http_headers.MimeType('multipart', 'form-data', (('boundary', '---weeboundary'),)) content = """-----weeboundary\r Content-Disposition: form-data; name="FileNameOne"; filename="myfilename"\r Content-Type: text/html\r \r my great content wooo\r -----weeboundary--\r """ root = resource.Resource() request = SimpleRequest( server.Site(root), "GET", "/", http_headers.Headers({'content-type': ctype}), content) def cb(ign): self.assertEquals(request.args, {}) self.assertEquals(request.files.keys(), ['FileNameOne']) self.assertEquals( request.files.values()[0][0][:2], ('myfilename', http_headers.MimeType('text', 'html', {}))) f = request.files.values()[0][0][2] self.assertEquals(f.read(), "my great content wooo") return server.parsePOSTData(request).addCallback(cb)
def test_multipartMaxSize(self): """ Check that the C{maxSize} parameter makes the parsing raise an exception if the data is too big. """ ctype = http_headers.MimeType('multipart', 'form-data', (('boundary', '---weeboundary'),)) content = """-----weeboundary\r Content-Disposition: form-data; name="FileNameOne"; filename="myfilename"\r Content-Type: text/html\r \r my great content wooo and even more and more\r -----weeboundary--\r """ root = resource.Resource() request = SimpleRequest( server.Site(root), "GET", "/", http_headers.Headers({'content-type': ctype}), content) def cb(res): self.assertEquals( res.response.description, "Maximum length of 10 bytes exceeded.") return self.assertFailure( server.parsePOSTData(request, maxSize=10), http.HTTPError).addCallback(cb)
def test_receive_fake_conduit_no_action(self): """ Cross-pod request fails when conduit does not support the action. """ store = self.storeUnderTest() self.patch(store, "conduit", self.FakeConduit(store)) request = SimpleRequest(self.site, "POST", "/conduit", headers=http_headers.Headers( rawHeaders={ "Content-Type": ("application/json", ), self.thisServer.secretHeader()[0]: self.thisServer.secretHeader()[1], }), content=""" { "action":"bogus", "echo":"bravo" } """.replace("\n", "\r\n")) response = (yield self.send(request)) self.assertEqual(response.code, responsecode.BAD_REQUEST)
def test_receive_ping(self): """ Cross-pod request works with the "ping" action. """ request = SimpleRequest(self.site, "POST", "/conduit", headers=http_headers.Headers( rawHeaders={ "Content-Type": ("application/json", ), self.thisServer.secretHeader()[0]: self.thisServer.secretHeader()[1], }), content=""" { "action":"ping" } """.replace("\n", "\r\n")) response = (yield self.send(request)) self.assertEqual(response.code, responsecode.OK) data = (yield allDataFromStream(response.stream)) j = json.loads(data) self.assertTrue("result" in j) self.assertEqual(j["result"], "ok")
def test_badCredentials(self): """ Test the behavior of locateChild when SACLS are enabled, and incorrect credentials are given. should return a 401 UnauthorizedResponse """ self.actualRoot.useSacls = True request = SimpleStoreRequest( self, "GET", "/principals/", headers=http_headers.Headers( { "Authorization": [ "basic", "%s" % ("dreid:dreid".encode("base64"),) ] } ) ) try: _ignore_resrc, _ignore_segments = (yield maybeDeferred( self.actualRoot.locateChild, request, ["principals"] )) raise AssertionError( "RootResource.locateChild did not return an error" ) except HTTPError, e: self.assertEquals(e.response.code, 401)
def getResponseFor(self, root, uri, headers={}, method=None, version=None, prepath='', content=None, length=_unset): if not isinstance(headers, http_headers.Headers): headers = http_headers.Headers(headers) if length is _unset: if content is not None: length = len(content) else: length = 0 if method is None: method = self.method if version is None: version = self.version cr = self.chanrequest(root, uri, length, headers, method, version, prepath, content) cr.request.process() return cr.deferredFinish
def test_receive_fake_conduit(self): """ Cross-pod request works when conduit does support the action. """ store = self.storeUnderTest() self.patch(store, "conduit", self.FakeConduit(store)) request = SimpleRequest(self.site, "POST", "/conduit", headers=http_headers.Headers( rawHeaders={ "Content-Type": ("application/json", ), self.thisServer.secretHeader()[0]: self.thisServer.secretHeader()[1], }), content=""" { "action":"fake", "echo":"bravo" } """.replace("\n", "\r\n")) response = (yield self.send(request)) self.assertEqual(response.code, responsecode.OK) data = (yield allDataFromStream(response.stream)) j = json.loads(data) self.assertTrue("result" in j) self.assertEqual(j["result"], "ok") self.assertTrue("back2u" in j) self.assertEqual(j["back2u"], "bravo") self.assertTrue("more" in j) self.assertEqual(j["more"], "bits")
def test_logging(self): """ Test permissions when creating accounting """ class FakeRequest(object): def handleContentChunk(self, data): pass def handleContentComplete(self): pass # Make log root a file channelRequest = HTTPLoggingChannelRequest(HTTPChannel(), queued=1) channelRequest.request = FakeRequest() channelRequest.gotInitialLine("GET / HTTP/1.1") channelRequest.lineReceived("Host:localhost") channelRequest.lineReceived("Content-Length:5") channelRequest.handleContentChunk("Bogus") channelRequest.handleContentComplete() channelRequest.writeHeaders( 200, http_headers.Headers({ "Content-Type": http_headers.MimeType('text', 'plain'), "Content-Length": "4" })) channelRequest.transport.write("Data") channelRequest.finish()
def testImmutable(self): h = http_headers.Headers(handler=HeaderHandler(parsers={}, generators={})) h.makeImmutable() self.assertRaises(AttributeError, h.setRawHeaders, "test", [1]) self.assertRaises(AttributeError, h.setHeader, "test", 1) self.assertRaises(AttributeError, h.removeHeader, "test")
def __init__(self, site, method, prepath, uri, length=None, headers=None, version=(1, 1), content=None): self.producer = None self.site = site self.method = method self.prepath = prepath self.uri = uri if headers is None: headers = http_headers.Headers() self.headers = headers self.http_version = version # Anything below here we do not pass as arguments self.request = server.Request(self, self.method, self.uri, self.http_version, length, self.headers, site=self.site, prepathuri=self.prepath) if content is not None: self.request.handleContentChunk(content) self.request.handleContentComplete() self.code = None self.responseHeaders = None self.data = '' self.deferredFinish = defer.Deferred()
def test_PROPFIND(self): self.actualRoot.useSacls = True body = """<?xml version="1.0" encoding="utf-8" ?> <D:propfind xmlns:D="DAV:"> <D:prop> <D:getetag/> <D:displayname/> </D:prop> </D:propfind> """ principal = yield self.actualRoot.findPrincipalForAuthID("dreid") request = SimpleStoreRequest( self, "PROPFIND", "/principals/users/dreid/", headers=http_headers.Headers({ 'Depth': '1', }), authPrincipal=principal, content=body ) response = yield self.send(request) response = IResponse(response) if response.code != responsecode.MULTI_STATUS: self.fail("Incorrect response for PROPFIND /principals/: %s" % (response.code,)) request = SimpleStoreRequest( self, "PROPFIND", "/principals/users/dreid/", headers=http_headers.Headers({ 'Depth': '1', }), authPrincipal=principal, content=body ) response = yield self.send(request) response = IResponse(response) if response.code != responsecode.MULTI_STATUS: self.fail("Incorrect response for PROPFIND /principals/: %s" % (response.code,)) self.assertEqual(self.actualRoot.responseCache.cacheHitCount, 1)
def testWithoutHeaders(self): request = http.Request(None, "GET", "/", "HTTP/1.1", 0, http_headers.Headers()) out_headers = http_headers.Headers() response = http.Response(responsecode.OK, out_headers, None) self.checkPreconditions(request, response, True, responsecode.OK) out_headers.setHeader("ETag", http_headers.ETag('foo')) self.checkPreconditions(request, response, True, responsecode.OK) out_headers.removeHeader("ETag") out_headers.setHeader("Last-Modified", 946771200) # Sun, 02 Jan 2000 00:00:00 GMT self.checkPreconditions(request, response, True, responsecode.OK) out_headers.setHeader("ETag", http_headers.ETag('foo')) self.checkPreconditions(request, response, True, responsecode.OK)
def testParsed(self): parsed = parsedvalue(("value1", "value2")) h = http_headers.Headers(handler=HeaderHandler(parsers={}, generators={})) h.setHeader("test", parsed) self.assertEquals(h.hasHeader("test"), True) self.assertEquals(h.getHeader("test"), parsed) self.assertEquals(h.getHeader("foobar"), None) h.removeHeader("test") self.assertEquals(h.getHeader("test"), None)
def test_receive_reject_local_originator(self): """ Make calendar """ request = SimpleRequest( self.site, "POST", "/ischedule", headers=http_headers.Headers( rawHeaders={ "Originator": ("mailto:[email protected]", ), "Recipient": ("mailto:[email protected]", ), "Content-Type": ("text/calendar", ) }), content="""BEGIN:VCALENDAR CALSCALE:GREGORIAN PRODID:-//Example Inc.//Example Calendar//EN VERSION:2.0 METHOD:REQUEST BEGIN:VEVENT DTSTAMP:20051222T205953Z CREATED:20060101T150000Z DTSTART:20060101T100000Z DURATION:PT1H SUMMARY:event 1 UID:deadlocked ORGANIZER:mailto:[email protected] ATTENDEE;PARTSTAT=ACCEPTED:mailto:[email protected] ATTENDEE;RSVP=TRUE;PARTSTAT=NEEDS-ACTION:mailto:[email protected] END:VEVENT END:VCALENDAR """.replace("\n", "\r\n")) response = (yield self.send(request)) self.assertEqual(response.code, responsecode.FORBIDDEN) calendar = (yield self.calendarUnderTest(name="calendar_1", home="user01")) count = (yield calendar.listCalendarObjects()) self.assertEqual(len(count), 0) inbox = (yield self.calendarUnderTest(name="inbox", home="user01")) count = (yield inbox.listCalendarObjects()) self.assertEqual(len(count), 0) calendar = (yield self.calendarUnderTest(name="calendar_1", home="user02")) count = (yield calendar.listCalendarObjects()) self.assertEqual(len(count), 0) inbox = (yield self.calendarUnderTest(name="inbox", home="user02")) count = (yield inbox.listCalendarObjects()) self.assertEqual(len(count), 0)
def testRaw(self): rawvalue = ("value1", "value2") h = http_headers.Headers(handler=HeaderHandler(parsers={}, generators={})) h.setRawHeaders("test", rawvalue) self.assertEquals(h.hasHeader("test"), True) self.assertEquals(h.getRawHeaders("test"), rawvalue) self.assertEquals(list(h.getAllRawHeaders()), [('Test', rawvalue)]) self.assertEquals(h.getRawHeaders("foobar"), None) h.removeHeader("test") self.assertEquals(h.getRawHeaders("test"), None)
def test_wrongContentType(self): """ Check that a content-type not handled raise a C{http.HTTPError}. """ ctype = http_headers.MimeType('application', 'foobar') content = "key=value&multiple=two+words&multiple=more%20words" root = resource.Resource() request = SimpleRequest( server.Site(root), "GET", "/", http_headers.Headers({'content-type': ctype}), content) return self.assertFailure(server.parsePOSTData(request), http.HTTPError)
def _abortWithError(self, errorcode, text=''): """Handle low level protocol errors.""" headers = http_headers.Headers() headers.setHeader('content-length', len(text) + 1) self.abortConnection(closeWrite=False) self.writeHeaders(errorcode, headers) self.write(text) self.write("\n") self.finish() log.warn("Aborted request (%d) %s" % (errorcode, text)) raise AbortedException
def test_MOVE(self): def do_test(response): response = IResponse(response) if response.code != responsecode.FORBIDDEN: self.fail("Incorrect response for MOVE /: %s" % (response.code, )) request = SimpleStoreRequest(self, "MOVE", "/", headers=http_headers.Headers( {"Destination": "/copy/"})) return self.send(request, do_test)
def testIfRange(self): request = http.Request(None, "GET", "/", "HTTP/1.1", 0, http_headers.Headers()) response = TestResponse() self.assertEquals(http.checkIfRange(request, response), True) request.headers.setRawHeaders("If-Range", ('"foo"', )) self.assertEquals(http.checkIfRange(request, response), False) response.headers.setHeader("ETag", http_headers.ETag('foo')) self.assertEquals(http.checkIfRange(request, response), True) request.headers.setRawHeaders("If-Range", ('"bar"', )) response.headers.setHeader("ETag", http_headers.ETag('foo')) self.assertEquals(http.checkIfRange(request, response), False) request.headers.setRawHeaders("If-Range", ('W/"foo"', )) response.headers.setHeader("ETag", http_headers.ETag('foo', weak=True)) self.assertEquals(http.checkIfRange(request, response), False) request.headers.setRawHeaders("If-Range", ('"foo"', )) response.headers.removeHeader("ETag") self.assertEquals(http.checkIfRange(request, response), False) request.headers.setRawHeaders("If-Range", ('Sun, 02 Jan 2000 00:00:00 GMT', )) response.headers.setHeader("Last-Modified", 946771200) # Sun, 02 Jan 2000 00:00:00 GMT self.assertEquals(http.checkIfRange(request, response), True) request.headers.setRawHeaders("If-Range", ('Sun, 02 Jan 2000 00:00:01 GMT', )) response.headers.setHeader("Last-Modified", 946771200) # Sun, 02 Jan 2000 00:00:00 GMT self.assertEquals(http.checkIfRange(request, response), False) request.headers.setRawHeaders("If-Range", ('Sun, 01 Jan 2000 23:59:59 GMT', )) response.headers.setHeader("Last-Modified", 946771200) # Sun, 02 Jan 2000 00:00:00 GMT self.assertEquals(http.checkIfRange(request, response), False) request.headers.setRawHeaders("If-Range", ('Sun, 01 Jan 2000 23:59:59 GMT', )) response.headers.removeHeader("Last-Modified") self.assertEquals(http.checkIfRange(request, response), False) request.headers.setRawHeaders("If-Range", ('jwerlqjL#$Y*KJAN', )) self.assertEquals(http.checkIfRange(request, response), False)
def test_urlencoded(self): """ Test parsing data in urlencoded format: it should end in the C{args} attribute. """ ctype = http_headers.MimeType('application', 'x-www-form-urlencoded') content = "key=value&multiple=two+words&multiple=more%20words" root = resource.Resource() request = SimpleRequest(server.Site(root), "GET", "/", http_headers.Headers({'content-type': ctype}), content) def cb(ign): self.assertEquals(request.files, {}) self.assertEquals(request.args, {'multiple': ['two words', 'more words'], 'key': ['value']}) return server.parsePOSTData(request).addCallback(cb)
def testIfUnmodifiedSince(self): request = http.Request(None, "GET", "/", "HTTP/1.1", 0, http_headers.Headers()) out_headers = http_headers.Headers() response = http.Response(responsecode.OK, out_headers, None) # No Last-Modified => always fail. request.headers.setRawHeaders("If-Unmodified-Since", ('Mon, 03 Jan 2000 00:00:00 GMT', )) self.checkPreconditions(request, response, False, responsecode.PRECONDITION_FAILED) # Set output headers out_headers.setHeader("ETag", http_headers.ETag('foo')) out_headers.setHeader("Last-Modified", 946771200) # Sun, 02 Jan 2000 00:00:00 GMT request.headers.setRawHeaders("If-Unmodified-Since", ('Mon, 03 Jan 2000 00:00:00 GMT', )) self.checkPreconditions(request, response, True, responsecode.OK) request.headers.setRawHeaders("If-Unmodified-Since", ('Sat, 01 Jan 2000 00:00:00 GMT', )) self.checkPreconditions(request, response, False, responsecode.PRECONDITION_FAILED) # But if we have an error code already, ignore this header response.code = responsecode.INTERNAL_SERVER_ERROR self.checkPreconditions(request, response, True, responsecode.INTERNAL_SERVER_ERROR) response.code = responsecode.OK # invalid date => header ignored request.headers.setRawHeaders("If-Unmodified-Since", ('alalalalalalalalalala', )) self.checkPreconditions(request, response, True, responsecode.OK)
def test_receive_no_secret(self): """ Cross-pod request fails when there is no shared secret header present. """ request = SimpleRequest( self.site, "POST", "/conduit", headers=http_headers.Headers( rawHeaders={"Content-Type": ("text/plain", )}), content="""Hello, World! """.replace("\n", "\r\n")) response = (yield self.send(request)) self.assertEqual(response.code, responsecode.FORBIDDEN)
def NotModifiedResponse(oldResponse=None): if oldResponse is not None: headers = http_headers.Headers() for header in ( # Required from sec 10.3.5: 'date', 'etag', 'content-location', 'expires', 'cache-control', 'vary', # Others: 'server', 'proxy-authenticate', 'www-authenticate', 'warning' ): value = oldResponse.headers.getRawHeaders(header) if value is not None: headers.setRawHeaders(header, value) else: headers = None return Response(code=responsecode.NOT_MODIFIED, headers=headers)
def __init__(self, site, method, uri, headers=None, content=None): if not headers: headers = http_headers.Headers(headers) super(SimpleRequest, self).__init__(site=site, chanRequest=None, command=method, path=uri, version=self.clientproto, contentLength=len(content or ''), headers=headers) self.stream = stream.MemoryStream(content or '') self.remoteAddr = address.IPv4Address('TCP', '127.0.0.1', 0) self._parseURL() self.host = 'localhost' self.port = 8080
def test_otherErrors(self): """ Test that errors durign parsing other than C{MimeFormatError} are propagated. """ ctype = http_headers.MimeType('multipart', 'form-data', (('boundary', '---weeboundary'),)) # XXX: maybe this is not a good example # parseContentDispositionFormData could handle this problem content = """-----weeboundary\r Content-Disposition: form-data; name="FileNameOne"; filename="myfilename and invalid data \r -----weeboundary--\r """ root = resource.Resource() request = SimpleRequest( server.Site(root), "GET", "/", http_headers.Headers({'content-type': ctype}), content) return self.assertFailure(server.parsePOSTData(request), ValueError)