def testSuspendProtocol(self): with Reactor() as reactor: suspend = Suspend() def handler(**httpvars): yield 'before suspend' yield suspend yield "result = %s" % suspend.getResult() yield 'after suspend' listener = MyMockSocket() port = PortNumberGenerator.next() httpserver = HttpServer(reactor, port, handler, sok=listener) httpserver.listen() reactor.removeReader(listener) # avoid new connections httpserver._acceptor._accept() self.assertEquals(1, len(reactor._fds)) self.assertEquals([READ_INTENT], [v.intent for v in reactor._fds.values()]) reactor.step() self.assertEquals(1, len(reactor._fds)) self.assertEquals([WRITE_INTENT], [v.intent for v in reactor._fds.values()]) reactor.step() reactor.step() self.assertEquals(reactor, suspend._reactor) self.assertEquals(0, len(reactor._fds)) suspend.resume('RESPONSE') self.assertEquals(1, len(reactor._fds)) self.assertEquals([WRITE_INTENT], [v.intent for v in reactor._fds.values()]) reactor.step() reactor.step() reactor.step() self.assertEquals(['before suspend', 'result = RESPONSE', 'after suspend'], listener.data) self.assertEquals(0, len(reactor._fds)) # cleanup (most) fd's listener.close()
def testSuspendProtocolWithThrow(self): with Reactor() as reactor: suspend = Suspend() def handler(**httpvars): yield 'before suspend' yield suspend try: suspend.getResult() self.fail() except ValueError, e: tbstring = format_exc() yield "result = %s" % tbstring yield 'after suspend' listener = MyMockSocket() port = PortNumberGenerator.next() httpserver = HttpServer(reactor, port, handler, sok=listener) httpserver.listen() reactor.removeReader(listener) # avoid new connections httpserver._acceptor._accept() reactor.step() reactor.step() reactor.step() self.assertEquals(reactor, suspend._reactor) self.assertEquals(0, len(reactor._fds)) def raiser(): raise ValueError("BAD VALUE") try: raiser() except ValueError, e: exc_type, exc_value, exc_traceback = exc_info() suspend.throw(exc_type, exc_value, exc_traceback)
def testSuspendProtocol(self): reactor = Reactor(select_func=mockselect) suspend = Suspend() def handler(**httpvars): yield 'before suspend' yield suspend yield "result = %s" % suspend.getResult() yield 'after suspend' listener = MyMockSocket() port = 9 httpserver = HttpServer(reactor, port, handler, sok=listener) httpserver.listen() reactor.removeReader(listener) # avoid new connections httpserver._acceptor._accept() reactor.step() reactor.step() self.assertEquals(1, len(reactor._writers)) reactor.step() self.assertEquals(reactor, suspend._reactor) self.assertEquals(0, len(reactor._writers)) suspend.resume('RESPONSE') reactor.step() reactor.step() reactor.step() self.assertEquals(['before suspend', 'result = RESPONSE', 'after suspend'], listener.data)
def testWindowsPostMultipartForm(self): httpRequest = open(inmydir('data/multipart-data-02')).read() self.requestData = {} def handler(**kwargs): self.requestData = kwargs return yield with stdout_replaced(): with Reactor() as reactor: server = HttpServer(reactor, self.port, handler) server.listen() sok = socket() sok.connect(('localhost', self.port)) sok.send(httpRequest) reactor.addTimer(2, lambda: self.fail("Test Stuck")) while self.requestData.get('Form', None) == None: reactor.step() form = self.requestData['Form'] self.assertEquals(4, len(form)) self.assertEquals(['SOME ID'], form['id']) self.assertEquals(1, len(form['somename'])) filename, mimetype, data = form['somename'][0] self.assertEquals('Bank Gothic Medium BT.ttf', filename) self.assertEquals('application/octet-stream', mimetype) # cleanup sok.close() server.shutdown()
def testPostMethodTimesOutOnBadBody(self): self.requestData = None def handler(**kwargs): self.requestData = kwargs done = [] def onDone(): fromServer = sok.recv(1024) self.assertTrue('HTTP/1.0 400 Bad Request' in fromServer) done.append(True) reactor = Reactor() server = HttpServer(reactor, self.port, handler, timeout=0.01) server.listen() reactor.addTimer(0.02, onDone) sok = socket() sok.connect(('localhost', self.port)) sok.send( 'POST / HTTP/1.0\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: 8\r\n\r\n' ) while not done: reactor.step()
def testReadMultipartFormEndBoundary(self): httpRequest = open(inmydir('data/multipart-data-04')).read() self.requestData = {} def handler(**kwargs): self.requestData = kwargs return yield with stdout_replaced(): with Reactor() as reactor: server = HttpServer(reactor, self.port, handler) server.listen() sok = socket() sok.connect(('localhost', self.port)) sok.send(httpRequest) reactor.addTimer(2, lambda: self.fail("Test Stuck")) while self.requestData.get('Form', None) == None: reactor.step() form = self.requestData['Form'] self.assertEquals(1, len(form)) self.assertEquals(3521*'X', form['id'][0]) # cleanup sok.close() server.shutdown()
def testReadChunkedAndCompressedPost(self): postData = 'AhjBeehCeehAhjBeehCeehAhjBeehCeehAhjBeehCeeh' postDataCompressed = compress(postData) self.assertEquals(20, len(postDataCompressed)) self.assertEquals(15, len(postDataCompressed[:15])) self.assertEquals(5, len(postDataCompressed[15:])) self.requestData = {} def handler(**kwargs): self.requestData = kwargs reactor = Reactor() server = HttpServer(reactor, self.port, handler, timeout=0.01, recvSize=3) server.listen() sok = socket() sok.connect(('localhost', self.port)) postString = 'POST / HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nTransfer-Encoding: chunked\r\nContent-Encoding: deflate\r\n\r\nf\r\n%s\r\n5\r\n%s\r\n0\r\n' % ( postDataCompressed[:15], postDataCompressed[15:]) sok.send(postString) reactor.addTimer(0.2, lambda: self.fail("Test Stuck")) while self.requestData.get('Body', None) != postData: reactor.step()
def testTextFileSeenAsFile(self): httpRequest = open(inmydir('data/multipart-data-03')).read() self.requestData = {} def handler(**kwargs): self.requestData = kwargs return yield with stdout_replaced(): with Reactor() as reactor: server = HttpServer(reactor, self.port, handler) server.listen() sok = socket() sok.connect(('localhost', self.port)) sok.send(httpRequest) reactor.addTimer(2, lambda: self.fail("Test Stuck")) while self.requestData.get('Form', None) == None: reactor.step() form = self.requestData['Form'] self.assertEquals(4, len(form)) self.assertEquals(['SOME ID'], form['id']) self.assertEquals(1, len(form['somename'])) filename, mimetype, data = form['somename'][0] self.assertEquals('hello.bas', filename) self.assertEquals('text/plain', mimetype) # cleanup sok.close() server.shutdown()
def testPostMethodDeCompressesDeflatedBody_deflate(self): self.requestData = None def handler(**kwargs): self.requestData = kwargs reactor = Reactor() server = HttpServer(reactor, self.port, handler, timeout=0.01) server.listen() sok = socket() sok.connect(('localhost', self.port)) bodyData = 'bodydatabodydata' bodyDataCompressed = compress(bodyData) contentLengthCompressed = len(bodyDataCompressed) sok.send(('POST / HTTP/1.0\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: %d\r\nContent-Encoding: deflate\r\n\r\n' % contentLengthCompressed) + bodyDataCompressed) while not self.requestData: reactor.step() self.assertEquals(dict, type(self.requestData)) self.assertTrue('Headers' in self.requestData) headers = self.requestData['Headers'] self.assertEquals('POST', self.requestData['Method']) self.assertEquals('application/x-www-form-urlencoded', headers['Content-Type']) self.assertEquals(contentLengthCompressed, int(headers['Content-Length'])) # TS: is this correct?, maybe decompressed length? self.assertTrue('Body' in self.requestData) self.assertEquals('bodydatabodydata', self.requestData['Body'])
def testInvalidPOSTRequestStartsOnlyOneTimer(self): # problem in found in OAS, timers not removed properly when whole body hasnt been read yet _httpserver.RECVSIZE = 1 reactor = Reactor() timers = [] orgAddTimer = reactor.addTimer def addTimerInterceptor(*timer): timers.append(timer) return orgAddTimer(*timer) reactor.addTimer = addTimerInterceptor server = HttpServer(reactor, self.port, lambda **kwargs: (x for x in []), timeout=0.01) server.listen() sok = socket() sok.connect(('localhost', self.port)) sok.send('POST / HTTP/1.0\r\nContent-Length: 10\r\n\r\n') reactor.step() sok.send(".") sleep(0.1) reactor.step() sok.send(".") reactor.step() sleep(0.1) while select([sok],[], [], 0) != ([sok], [], []): reactor.step() self.assertEquals(2, len(timers))
def testPostMethodReadsBody(self): self.requestData = None def handler(**kwargs): self.requestData = kwargs reactor = Reactor() server = HttpServer(reactor, self.port, handler, timeout=0.01) server.listen() sok = socket() sok.connect(('localhost', self.port)) sok.send( 'POST / HTTP/1.0\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: 8\r\n\r\nbodydata' ) while not self.requestData: reactor.step() self.assertEquals(dict, type(self.requestData)) self.assertTrue('Headers' in self.requestData) headers = self.requestData['Headers'] self.assertEquals('POST', self.requestData['Method']) self.assertEquals('application/x-www-form-urlencoded', headers['Content-Type']) self.assertEquals(8, int(headers['Content-Length'])) self.assertTrue('Body' in self.requestData) self.assertEquals('bodydata', self.requestData['Body'])
def testSmallFragmentsWhileSendingResponse(self): def response(**kwargs): yield 'some text that is longer than ' yield 'the lenght of fragments sent' reactor = Reactor() server = HttpServer(reactor, self.port, response, recvSize=3) server.listen() sok = socket() sok.connect(('localhost', self.port)) sok.send( 'GET /path/here HTTP/1.0\r\nConnection: close\r\nApe-Nut: Mies\r\n\r\n' ) while not reactor._writers: reactor.step() serverSok, handler = reactor._writers.items()[0] originalSend = serverSok.send def sendOnlyManagesToActuallySendThreeBytesPerSendCall(data, *options): originalSend(data[:3], *options) return 3 serverSok.send = sendOnlyManagesToActuallySendThreeBytesPerSendCall for i in range(21): reactor.step() fragment = sok.recv(4096) self.assertEquals( 'some text that is longer than the lenght of fragments sent', fragment)
def testPutMethodReadsBody(self): self.requestData = None def handler(**kwargs): self.requestData = kwargs return yield with stdout_replaced(): with Reactor() as reactor: server = HttpServer(reactor, self.port, handler, timeout=0.01) server.listen() sok = socket() sok.connect(('localhost', self.port)) sok.send('PUT / HTTP/1.0\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: 8\r\n\r\nbodydata') while not self.requestData: reactor.step() self.assertEquals(dict, type(self.requestData)) self.assertTrue('Headers' in self.requestData) headers = self.requestData['Headers'] self.assertEquals('PUT', self.requestData['Method']) self.assertEquals('application/x-www-form-urlencoded', headers['Content-Type']) self.assertEquals(8, int(headers['Content-Length'])) self.assertTrue('Body' in self.requestData) self.assertEquals('bodydata', self.requestData['Body']) # cleanup sok.close() server.shutdown()
def sendRequestAndReceiveResponse(self, request, response='The Response', recvSize=4096, compressResponse=False, extraStepsAfterCompress=1, stepWatcher=None): self.responseCalled = False @compose def responseGenFunc(**kwargs): yield response yield '' self.responseCalled = True server = HttpServer(self.reactor, self.port, responseGenFunc, recvSize=recvSize, compressResponse=compressResponse) server.listen() sok = socket() sok.connect(('localhost', self.port)) sok.send(request) sok.setblocking(0) clientResponse = '' def clientRecv(): clientResponse = '' while True: try: r = sok.recv(4096) except SocketError, (errno, msg): if errno == EAGAIN: break raise if not r: break clientResponse += r return clientResponse
def testSmallFragmentsWhileSendingResponse(self): def response(**kwargs): yield '' # Socket poking here - then try to really send stuff yield 'some text that is longer than ' yield 'the lenght of fragments sent' with Reactor() as reactor: server = HttpServer(reactor, self.port, response, recvSize=3) server.listen() sok = socket() sok.connect(('localhost', self.port)) sok.send('GET /path/here HTTP/1.0\r\nConnection: close\r\nApe-Nut: Mies\r\n\r\n') writerFile = lambda: [context.fileOrFd for context in reactor._fds.values() if context.intent == WRITE_INTENT] while not writerFile(): reactor.step() serverSok = writerFile()[0] originalSend = serverSok.send def sendOnlyManagesToActuallySendThreeBytesPerSendCall(data, *options): originalSend(data[:3], *options) return 3 serverSok.send = sendOnlyManagesToActuallySendThreeBytesPerSendCall for i in range(22): reactor.step() fragment = sok.recv(4096) self.assertEquals('some text that is longer than the lenght of fragments sent', fragment) # cleanup sok.close() server.shutdown()
def testHttpServerEncodesUnicode(self): unicodeString = u'some t\xe9xt' oneStringLength = len(unicodeString.encode(getdefaultencoding())) self.assertTrue(len(unicodeString) != oneStringLength) def response(**kwargs): yield unicodeString * 6000 with Reactor() as reactor: server = HttpServer(reactor, self.port, response, recvSize=3) server.listen() sok = socket() sok.connect(('localhost', self.port)) sok.send('GET /path/here HTTP/1.0\r\nConnection: close\r\nApe-Nut: Mies\r\n\r\n') writers = lambda: [c for c in reactor._fds.values() if c.intent == WRITE_INTENT] while not writers(): reactor.step() reactor.step() reactor.step() fragment = sok.recv(100000) # will read about 49152 chars self.assertEquals(oneStringLength * 6000, len(fragment)) self.assertTrue("some t\xc3\xa9xt" in fragment, fragment) # cleanup sok.close() server.shutdown()
def testPostMethodDeCompressesDeflatedBody_deflate(self): self.requestData = None def handler(**kwargs): self.requestData = kwargs reactor = Reactor() server = HttpServer(reactor, self.port, handler, timeout=0.01) server.listen() sok = socket() sok.connect(('localhost', self.port)) bodyData = 'bodydatabodydata' bodyDataCompressed = compress(bodyData) contentLengthCompressed = len(bodyDataCompressed) sok.send(( 'POST / HTTP/1.0\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: %d\r\nContent-Encoding: deflate\r\n\r\n' % contentLengthCompressed) + bodyDataCompressed) while not self.requestData: reactor.step() self.assertEquals(dict, type(self.requestData)) self.assertTrue('Headers' in self.requestData) headers = self.requestData['Headers'] self.assertEquals('POST', self.requestData['Method']) self.assertEquals('application/x-www-form-urlencoded', headers['Content-Type']) self.assertEquals(contentLengthCompressed, int(headers['Content-Length']) ) # TS: is this correct?, maybe decompressed length? self.assertTrue('Body' in self.requestData) self.assertEquals('bodydatabodydata', self.requestData['Body'])
def testPostMethodDeCompressesDeflatedBody_unrecognizedEncoding(self): self.requestData = None def handler(**kwargs): self.requestData = kwargs return yield reactor = Reactor() server = HttpServer(reactor, self.port, handler, timeout=0.01) server.listen() sok = socket() sok.connect(('localhost', self.port)) bodyData = 'bodydatabodydata' bodyDataCompressed = compress(bodyData) contentLengthCompressed = len(bodyDataCompressed) sok.send(( 'POST / HTTP/1.0\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: %d\r\nContent-Encoding: unknown\r\n\r\n' % contentLengthCompressed) + bodyDataCompressed) while select([sok], [], [], 0) != ([sok], [], []): reactor.step() self.assertTrue(sok.recv(4096).startswith('HTTP/1.0 400 Bad Request')) self.assertEquals(None, self.requestData)
def sendRequestAndReceiveResponse(self, request, response='The Response', recvSize=4096, compressResponse=False, extraStepAfterCompress=True): self.responseCalled = False @compose def responseGenFunc(**kwargs): yield response yield '' self.responseCalled = True server = HttpServer(self.reactor, self.port, responseGenFunc, recvSize=recvSize, compressResponse=compressResponse) server.listen() sok = socket() sok.connect(('localhost', self.port)) sok.send(request) mockStdout = None with self.stdout_replaced() as mockStdout: while not self.responseCalled: self.reactor.step() if compressResponse and extraStepAfterCompress: #not everythingSent???: self.reactor.step() stdoutValue = mockStdout.getvalue() if stdoutValue: print stdoutValue server.shutdown() r = sok.recv(4096) sok.close() return r
def testPostMethodDeCompressesDeflatedBody_unrecognizedEncoding(self): self.requestData = None def handler(**kwargs): self.requestData = kwargs return yield with Reactor() as reactor: server = HttpServer(reactor, self.port, handler, timeout=0.01) server.listen() sok = socket() sok.connect(('localhost', self.port)) bodyData = 'bodydatabodydata' bodyDataCompressed = compress(bodyData) contentLengthCompressed = len(bodyDataCompressed) sok.send(('POST / HTTP/1.0\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: %d\r\nContent-Encoding: unknown\r\n\r\n' % contentLengthCompressed) + bodyDataCompressed) while select([sok],[], [], 0) != ([sok], [], []): reactor.step() self.assertTrue(sok.recv(4096).startswith('HTTP/1.0 400 Bad Request')) self.assertEquals(None, self.requestData) # cleanup sok.close() server.shutdown()
def testYieldInHttpServer(self): bucket = [] def handler(RequestURI, **kwargs): yield 'A' while 'continue' not in bucket: yield Yield yield 'B' with stdout_replaced(): with Reactor() as reactor: server = HttpServer(reactor, self.port, handler) server.listen() sok = socket() sok.connect(('localhost', self.port)) sok.send('GET /path/here HTTP/1.0\r\n\r\n') for i in xrange(500): reactor.step() self.assertEquals('A', sok.recv(100)) bucket.append('continue') reactor.step() self.assertEquals('B', sok.recv(100)) # cleanup sok.close() server.shutdown()
def testPostMethodTimesOutOnBadBody(self): self.requestData = None def handler(**kwargs): self.requestData = kwargs return yield done = [] def onDone(): fromServer = sok.recv(1024) self.assertTrue('HTTP/1.0 400 Bad Request' in fromServer) done.append(True) with Reactor() as reactor: server = HttpServer(reactor, self.port, handler, timeout=0.01) server.listen() reactor.addTimer(0.02, onDone) sok = socket() sok.connect(('localhost', self.port)) sok.send('POST / HTTP/1.0\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: 8\r\n\r\n') while not done: reactor.step() # cleanup sok.close() server.shutdown()
def testSendHeader(self): self.kwargs = None def response(**kwargs): self.kwargs = kwargs yield 'nosense' reactor = Reactor() server = HttpServer(reactor, self.port, response) server.listen() sok = socket() sok.connect(('localhost', self.port)) sok.send( 'GET /path/here HTTP/1.0\r\nConnection: close\r\nApe-Nut: Mies\r\n\r\n' ) while not self.kwargs: reactor.step() self.assertEquals( { 'Body': '', 'RequestURI': '/path/here', 'HTTPVersion': '1.0', 'Method': 'GET', 'Headers': { 'Connection': 'close', 'Ape-Nut': 'Mies' }, 'Client': ('127.0.0.1', MATCHALL) }, self.kwargs)
def testReadChunkedAndCompressedPost(self): postData = 'AhjBeehCeehAhjBeehCeehAhjBeehCeehAhjBeehCeeh' postDataCompressed = compress(postData) self.assertEquals(20, len(postDataCompressed)) self.assertEquals(15, len(postDataCompressed[:15])) self.assertEquals(5, len(postDataCompressed[15:])) self.requestData = {} def handler(**kwargs): self.requestData = kwargs return yield with stdout_replaced(): with Reactor() as reactor: server = HttpServer(reactor, self.port, handler, timeout=0.01, recvSize=3) server.listen() sok = socket() sok.connect(('localhost', self.port)) postString = 'POST / HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nTransfer-Encoding: chunked\r\nContent-Encoding: deflate\r\n\r\nf\r\n%s\r\n5\r\n%s\r\n0\r\n' % (postDataCompressed[:15], postDataCompressed[15:]) sok.send(postString) reactor.addTimer(0.2, lambda: self.fail("Test Stuck")) while self.requestData.get('Body', None) != postData: reactor.step() # cleanup sok.close() server.shutdown()
def testPostMethodDeCompressesDeflatedBody_gzip(self): self.requestData = None def handler(**kwargs): self.requestData = kwargs reactor = Reactor() server = HttpServer(reactor, self.port, handler, timeout=0.01) server.listen() sok = socket() sok.connect(('localhost', self.port)) bodyData = 'bodydatabodydata' _sio = StringIO() _gzFileObj = GzipFile(filename=None, mode='wb', compresslevel=6, fileobj=_sio) _gzFileObj.write(bodyData); _gzFileObj.close() compressedBodyData = _sio.getvalue() bodyDataCompressed = compress(bodyData) contentLengthCompressed = len(bodyDataCompressed) sok.send(('POST / HTTP/1.0\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: %d\r\nContent-Encoding: gzip\r\n\r\n' % contentLengthCompressed) + bodyDataCompressed) while not self.requestData: reactor.step() self.assertEquals(dict, type(self.requestData)) self.assertTrue('Headers' in self.requestData) headers = self.requestData['Headers'] self.assertEquals('POST', self.requestData['Method']) self.assertEquals('application/x-www-form-urlencoded', headers['Content-Type']) self.assertEquals(contentLengthCompressed, int(headers['Content-Length'])) self.assertTrue('Body' in self.requestData) self.assertEquals('bodydatabodydata', self.requestData['Body'])
def XXX_testPostMultipartFormCompressed(self): """Not yet""" httpRequest = open(inmydir('data/multipart-data-01-compressed')).read() self.requestData = {} def handler(**kwargs): self.requestData = kwargs return yield with Reactor() as reactor: server = HttpServer(reactor, self.port, handler) server.listen() sok = socket() sok.connect(('localhost', self.port)) sok.send(httpRequest) reactor.addTimer(2, lambda: self.fail("Test Stuck")) while self.requestData.get('Form', None) == None: reactor.step() form = self.requestData['Form'] self.assertEquals(4, len(form)) self.assertEquals(['SOME ID'], form['id']) # cleanup sok.close() server.shutdown()
def testInvalidPOSTRequestStartsOnlyOneTimer(self): # problem in found in OAS, timers not removed properly when whole body hasnt been read yet _httpserver.RECVSIZE = 1 reactor = Reactor() timers = [] orgAddTimer = reactor.addTimer def addTimerInterceptor(*timer): timers.append(timer) return orgAddTimer(*timer) reactor.addTimer = addTimerInterceptor server = HttpServer(reactor, self.port, lambda **kwargs: (x for x in []), timeout=0.01) server.listen() sok = socket() sok.connect(('localhost', self.port)) sok.send('POST / HTTP/1.0\r\nContent-Length: 10\r\n\r\n') reactor.step() sok.send(".") sleep(0.1) reactor.step() sok.send(".") reactor.step() sleep(0.1) while select([sok], [], [], 0) != ([sok], [], []): reactor.step() self.assertEquals(2, len(timers))
def testOnlyHandleAMaximumNrOfRequests(self): codes = [] def handler(**kwargs): yield "OK" def error_handler(**kwargs): codes.append(kwargs['ResponseCode']) yield "FAIL" server = HttpServer(self.reactor, self.port, handler, errorHandler=error_handler, maxConnections=5) server.listen() self.reactor.getOpenConnections = lambda: 10 sock = socket() sock.connect(('localhost', self.port)) self.reactor.step() sock.send("GET / HTTP/1.0\r\n\r\n") self.reactor.step().step().step() server.shutdown() self.assertEquals('FAIL', sock.recv(1024)) self.assertEquals([503], codes) # cleanup sock.close()
class ObservableHttpServer(Observable): def __init__(self, reactor, port, timeout=1, prio=None, sok=None, maxConnections=None, compressResponse=True, bindAddress=None): Observable.__init__(self) self._port = port self._reactor = reactor self._timeout = timeout self._started = False self._prio = prio self._sok = sok self._maxConnections = maxConnections self._compressResponse = compressResponse self._bindAddress = bindAddress def startServer(self): """Starts server, When running a http server on port 80, this method should be called by the root user. In other cases it will be started when initializing all observers, see observer_init() """ self._httpserver = HttpServer( self._reactor, self._port, self._connect, timeout=self._timeout, prio=self._prio, sok=self._sok, maxConnections=self._maxConnections, errorHandler=self._error, compressResponse=self._compressResponse, bindAddress=self._bindAddress ) self._httpserver.listen() self._started = True def observer_init(self): if not self._started: self.startServer() def _connect(self, **kwargs): return compose(self.handleRequest(port=self._port, **kwargs)) def _error(self, **kwargs): yield serverUnavailableHtml +\ '<html><head></head><body><h1>Service Unavailable</h1></body></html>' self.do.logHttpError(**kwargs) def handleRequest(self, RequestURI=None, **kwargs): scheme, netloc, path, query, fragments = urlsplit(RequestURI) arguments = parse_qs(query, keep_blank_values=True) requestArguments = { 'scheme': scheme, 'netloc': netloc, 'path': path, 'query': query, 'fragments': fragments, 'arguments': arguments, 'RequestURI': RequestURI} requestArguments.update(kwargs) yield self.all.handleRequest(**requestArguments) def setMaxConnections(self, m): self._httpserver.setMaxConnections(m)
def testConnectBindAddress(self): reactor = CallTrace() server = HttpServer(reactor, self.port, lambda **kwargs: None, bindAddress='127.0.0.1') server.listen() self.assertEquals(('127.0.0.1', self.port), server._acceptor._sok.getsockname()) # cleanup server.shutdown()
def testSuspendThrowBackwardsCompatibleWithInstanceOnlyThrow_YouWillMissTracebackHistory( self): with Reactor() as reactor: suspend = Suspend() def handler(**httpvars): yield 'before suspend' yield suspend try: suspend.getResult() self.fail() except ValueError, e: tbstring = format_exc() yield "result = %s" % tbstring yield 'after suspend' listener = MyMockSocket() port = PortNumberGenerator.next() httpserver = HttpServer(reactor, port, handler, sok=listener) httpserver.listen() reactor.removeReader(listener) # avoid new connections httpserver._acceptor._accept() self.assertEquals(1, len(reactor._fds)) reactor.step() reactor.step() reactor.step() self.assertEquals(reactor, suspend._reactor) self.assertEquals(0, len(reactor._fds)) def raiser(): raise ValueError("BAD VALUE") try: raiser() except: exc_value = exc_info()[1] suspend.throw(exc_value) self.assertEquals(1, len(reactor._fds)) reactor.step() reactor.step() reactor.step() expectedTraceback = ignoreLineNumbers( """Traceback (most recent call last): File "%(__file__)s", line 201, in handler suspend.getResult() File "%(suspend.py)s", line 62, in getResult raise self._exception[0], self._exception[1], self._exception[2] ValueError: BAD VALUE """ % fileDict) self.assertEquals(3, len(listener.data)) self.assertEquals('before suspend', listener.data[0]) self.assertEqualsWS("result = %s" % expectedTraceback, ignoreLineNumbers(listener.data[1])) self.assertEquals('after suspend', listener.data[2]) self.assertEquals(0, len(reactor._fds)) # cleanup (most) fd's listener.close()
def testConnectBindAddress(self): reactor = CallTrace() server = HttpServer(reactor, self.port, lambda **kwargs: None, bindAddress='127.0.0.1') server.listen() self.assertEquals(('127.0.0.1', self.port), server._acceptor._sok.getsockname())
class AsyncReaderTest(WeightlessTestCase): def dispatch(self, *args, **kwargs): return compose(self.handler(*args, **kwargs)) def setUp(self): WeightlessTestCase.setUp(self) self.reactor = Reactor() self.port = randint(2**10, 2**16) self.httpserver = HttpServer(self.reactor, self.port, self.dispatch) self.httpserver.listen() def tearDown(self): self.httpserver.shutdown() self.reactor.shutdown() WeightlessTestCase.tearDown(self) def testHttpRequest(self): self.assertEquals('GET / HTTP/1.0\r\n', _httpRequest('GET', '/')) self.assertEquals('POST / HTTP/1.0\r\n', _httpRequest('POST', '/')) def testPassRequestThruToBackOfficeServer(self): done = [False] backofficeport = self.port + 1 def passthruhandler(*args, **kwargs): request = kwargs['RequestURI'] response = yield httpget('localhost', backofficeport, request) yield response done[0] = True self.handler = passthruhandler expectedrequest = "GET /depot?arg=1&arg=2 HTTP/1.0\r\n\r\n" responses = (i for i in ['hel', 'lo!']) backofficeserver = testserver(backofficeport, responses, expectedrequest) client = clientget('localhost', self.port, '/depot?arg=1&arg=2') while not done[0]: self.reactor.step() response = client.recv(99) self.assertEquals('hello!', response) def testConnectFails(self): exceptions = [] def failingserver(*args, **kwarg): try: response = yield httpget(*target) except Exception, e: exceptions.append(exc_info()) self.handler = failingserver clientget('localhost', self.port, '/') target = ('localhost', 'port', '/') # non-numeric port try: with self.stderr_replaced(): with self.loopingReactor(): while not exceptions: pass except Exception, e: pass
def testValidRequestResetsTimer(self): reactor = Reactor() server = HttpServer(reactor, self.port, lambda **kwargs: ('a' for a in range(3)), timeout=0.01, recvSize=3) server.listen() sok = socket() sok.connect(('localhost', self.port)) sok.send('GET / HTTP/1.0\r\n\r\n') sleep(0.02) for i in range(11): reactor.step() response = sok.recv(4096) self.assertEquals('aaa', response)
def testSuspendThrowBackwardsCompatibleWithInstanceOnlyThrow_YouWillMissTracebackHistory(self): with Reactor() as reactor: suspend = Suspend() def handler(**httpvars): yield 'before suspend' yield suspend try: suspend.getResult() self.fail() except ValueError, e: tbstring = format_exc() yield "result = %s" % tbstring yield 'after suspend' listener = MyMockSocket() port = PortNumberGenerator.next() httpserver = HttpServer(reactor, port, handler, sok=listener) httpserver.listen() reactor.removeReader(listener) # avoid new connections httpserver._acceptor._accept() self.assertEquals(1, len(reactor._fds)) reactor.step() reactor.step() reactor.step() self.assertEquals(reactor, suspend._reactor) self.assertEquals(0, len(reactor._fds)) def raiser(): raise ValueError("BAD VALUE") try: raiser() except: exc_value = exc_info()[1] suspend.throw(exc_value) self.assertEquals(1, len(reactor._fds)) reactor.step() reactor.step() reactor.step() expectedTraceback = ignoreLineNumbers("""Traceback (most recent call last): File "%(__file__)s", line 201, in handler suspend.getResult() File "%(suspend.py)s", line 62, in getResult raise self._exception[0], self._exception[1], self._exception[2] ValueError: BAD VALUE """ % fileDict) self.assertEquals(3, len(listener.data)) self.assertEquals('before suspend', listener.data[0]) self.assertEqualsWS("result = %s" % expectedTraceback, ignoreLineNumbers(listener.data[1])) self.assertEquals('after suspend', listener.data[2]) self.assertEquals(0, len(reactor._fds)) # cleanup (most) fd's listener.close()
def testSendHeader(self): self.kwargs = None def response(**kwargs): self.kwargs = kwargs yield 'nosense' reactor = Reactor() server = HttpServer(reactor, self.port, response) server.listen() sok = socket() sok.connect(('localhost', self.port)) sok.send('GET /path/here HTTP/1.0\r\nConnection: close\r\nApe-Nut: Mies\r\n\r\n') while not self.kwargs: reactor.step() self.assertEquals({'Body': '', 'RequestURI': '/path/here', 'HTTPVersion': '1.0', 'Method': 'GET', 'Headers': {'Connection': 'close', 'Ape-Nut': 'Mies'}, 'Client': ('127.0.0.1', MATCHALL)}, self.kwargs)
def testInvalidRequestWithHalfHeader(self): reactor = Reactor() server = HttpServer(reactor, self.port, None, timeout=0.1) server.listen() sok = socket() sok.connect(('localhost', self.port)) sok.send('POST / HTTP/1.0\r\n') sok.send('Expect: something\r\n') sok.send('Content-Length: 5\r\n') sok.send('\r\n1234') sok.close() with self.stderr_replaced() as s: for i in range(4): reactor.step() self.assertEquals(1, len(reactor._readers))
def testReadChunkedPost(self): self.requestData = {} def handler(**kwargs): self.requestData = kwargs reactor = Reactor() server = HttpServer(reactor, self.port, handler, timeout=0.01, recvSize=3) server.listen() sok = socket() sok.connect(('localhost', self.port)) sok.send('POST / HTTP/1.0\r\nContent-Type: application/x-www-form-urlencoded\r\nTransfer-Encoding: chunked\r\n\r\n5\r\nabcde\r\n5\r\nfghij\r\n0\r\n') reactor.addTimer(0.2, lambda: self.fail("Test Stuck")) while self.requestData.get('Body', None) != 'abcdefghij': reactor.step()
def testConnect(self): self.req = False def onRequest(**kwargs): self.req = True yield 'nosens' reactor = Reactor() server = HttpServer(reactor, self.port, onRequest) server.listen() sok = socket() sok.connect(('localhost', self.port)) sok.send('GET / HTTP/1.0\r\n\r\n') reactor.step() # connect/accept reactor.step() # read GET request reactor.step() # call onRequest for response data self.assertEquals(True, self.req)
def testDefaultErrorHandler(self): def handler(**kwargs): yield "OK" server = HttpServer(self.reactor, self.port, handler, maxConnections=5) server.listen() self.reactor.getOpenConnections = lambda: 10 sock = socket() sock.connect(('localhost', self.port)) self.reactor.step() sock.send("GET / HTTP/1.0\r\n\r\n") self.reactor.step().step().step() self.assertEquals('HTTP/1.0 503 Service Unavailable\r\n\r\n<html><head></head><body><h1>Service Unavailable</h1></body></html>', sock.recv(1024)) server.shutdown()
def startServer(self): """Starts server, When running a http server on port 80, this method should be called by the root user. In other cases it will be started when initializing all observers, see observer_init() """ self._httpserver = HttpServer(self._reactor, self._port, self._connect, timeout=self._timeout, prio=self._prio, sok=self._sok, maxConnections=self._maxConnections, errorHandler=self._error, compressResponse=self._compressResponse, bindAddress=self._bindAddress) self._httpserver.listen() self._started = True
def testReadMultipartFormEndBoundary(self): httpRequest = open(inmydir('data/multipart-data-04')).read() self.requestData = {} def handler(**kwargs): self.requestData = kwargs reactor = Reactor() server = HttpServer(reactor, self.port, handler) server.listen() sok = socket() sok.connect(('localhost', self.port)) sok.send(httpRequest) reactor.addTimer(2, lambda: self.fail("Test Stuck")) while self.requestData.get('Form', None) == None: reactor.step() form = self.requestData['Form'] self.assertEquals(1, len(form)) self.assertEquals(3521 * 'X', form['id'][0])
def testSuspendProtocol(self): with Reactor() as reactor: suspend = Suspend() def handler(**httpvars): yield 'before suspend' yield suspend yield "result = %s" % suspend.getResult() yield 'after suspend' listener = MyMockSocket() port = PortNumberGenerator.next() httpserver = HttpServer(reactor, port, handler, sok=listener) httpserver.listen() reactor.removeReader(listener) # avoid new connections httpserver._acceptor._accept() self.assertEquals(1, len(reactor._fds)) self.assertEquals([READ_INTENT], [v.intent for v in reactor._fds.values()]) reactor.step() self.assertEquals(1, len(reactor._fds)) self.assertEquals([WRITE_INTENT], [v.intent for v in reactor._fds.values()]) reactor.step() reactor.step() self.assertEquals(reactor, suspend._reactor) self.assertEquals(0, len(reactor._fds)) suspend.resume('RESPONSE') self.assertEquals(1, len(reactor._fds)) self.assertEquals([WRITE_INTENT], [v.intent for v in reactor._fds.values()]) reactor.step() reactor.step() reactor.step() self.assertEquals( ['before suspend', 'result = RESPONSE', 'after suspend'], listener.data) self.assertEquals(0, len(reactor._fds)) # cleanup (most) fd's listener.close()
def XXX_testPostMultipartFormCompressed(self): """Not yet""" httpRequest = open(inmydir('data/multipart-data-01-compressed')).read() self.requestData = {} def handler(**kwargs): self.requestData = kwargs reactor = Reactor() server = HttpServer(reactor, self.port, handler) server.listen() sok = socket() sok.connect(('localhost', self.port)) sok.send(httpRequest) reactor.addTimer(2, lambda: self.fail("Test Stuck")) while self.requestData.get('Form', None) == None: reactor.step() form = self.requestData['Form'] self.assertEquals(4, len(form)) self.assertEquals(['SOME ID'], form['id'])
def testYieldInHttpServer(self): bucket = [] def handler(RequestURI, **kwargs): yield 'A' while 'continue' not in bucket: yield Yield yield 'B' reactor = Reactor() server = HttpServer(reactor, self.port, handler) server.listen() sok = socket() sok.connect(('localhost', self.port)) sok.send('GET /path/here HTTP/1.0\r\n\r\n') for i in xrange(500): reactor.step() self.assertEquals('A', sok.recv(100)) bucket.append('continue') reactor.step() self.assertEquals('B', sok.recv(100))
def testInvalidGETRequestStartsOnlyOneTimer(self): _httpserver.RECVSIZE = 3 reactor = Reactor() timers = [] orgAddTimer = reactor.addTimer def addTimerInterceptor(*timer): timers.append(timer) return orgAddTimer(*timer) reactor.addTimer = addTimerInterceptor server = HttpServer(reactor, self.port, None, timeout=0.01) server.listen() sok = socket() sok.connect(('localhost', self.port)) sok.send('GET HTTP/1.0\r\n\r\n') # no path while select([sok], [], [], 0) != ([sok], [], []): reactor.step() response = sok.recv(4096) self.assertEquals('HTTP/1.0 400 Bad Request\r\n\r\n', response) self.assertEquals(1, len(timers))
def testOnlyHandleAMaximumNrOfRequests(self): codes = [] def handler(**kwargs): yield "OK" def error_handler(**kwargs): codes.append(kwargs['ResponseCode']) yield "FAIL" server = HttpServer(self.reactor, self.port, handler, errorHandler=error_handler, maxConnections=5) server.listen() self.reactor.getOpenConnections = lambda: 10 sock = socket() sock.connect(('localhost', self.port)) self.reactor.step() sock.send("GET / HTTP/1.0\r\n\r\n") self.reactor.step().step().step() server.shutdown() self.assertEquals('FAIL', sock.recv(1024)) self.assertEquals([503], codes)
def testPostMethodDeCompressesDeflatedBody_gzip(self): self.requestData = None def handler(**kwargs): self.requestData = kwargs reactor = Reactor() server = HttpServer(reactor, self.port, handler, timeout=0.01) server.listen() sok = socket() sok.connect(('localhost', self.port)) bodyData = 'bodydatabodydata' _sio = StringIO() _gzFileObj = GzipFile(filename=None, mode='wb', compresslevel=6, fileobj=_sio) _gzFileObj.write(bodyData) _gzFileObj.close() compressedBodyData = _sio.getvalue() bodyDataCompressed = compress(bodyData) contentLengthCompressed = len(bodyDataCompressed) sok.send(( 'POST / HTTP/1.0\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: %d\r\nContent-Encoding: gzip\r\n\r\n' % contentLengthCompressed) + bodyDataCompressed) while not self.requestData: reactor.step() self.assertEquals(dict, type(self.requestData)) self.assertTrue('Headers' in self.requestData) headers = self.requestData['Headers'] self.assertEquals('POST', self.requestData['Method']) self.assertEquals('application/x-www-form-urlencoded', headers['Content-Type']) self.assertEquals(contentLengthCompressed, int(headers['Content-Length'])) self.assertTrue('Body' in self.requestData) self.assertEquals('bodydatabodydata', self.requestData['Body'])
def testReadChunkedPost(self): self.requestData = {} def handler(**kwargs): self.requestData = kwargs reactor = Reactor() server = HttpServer(reactor, self.port, handler, timeout=0.01, recvSize=3) server.listen() sok = socket() sok.connect(('localhost', self.port)) sok.send( 'POST / HTTP/1.0\r\nContent-Type: application/x-www-form-urlencoded\r\nTransfer-Encoding: chunked\r\n\r\n5\r\nabcde\r\n5\r\nfghij\r\n0\r\n' ) reactor.addTimer(0.2, lambda: self.fail("Test Stuck")) while self.requestData.get('Body', None) != 'abcdefghij': reactor.step()
def testWindowsPostMultipartForm(self): httpRequest = open(inmydir('data/multipart-data-02')).read() self.requestData = {} def handler(**kwargs): self.requestData = kwargs reactor = Reactor() server = HttpServer(reactor, self.port, handler) server.listen() sok = socket() sok.connect(('localhost', self.port)) sok.send(httpRequest) reactor.addTimer(2, lambda: self.fail("Test Stuck")) while self.requestData.get('Form', None) == None: reactor.step() form = self.requestData['Form'] self.assertEquals(4, len(form)) self.assertEquals(['SOME ID'], form['id']) self.assertEquals(1, len(form['somename'])) filename, mimetype, data = form['somename'][0] self.assertEquals('Bank Gothic Medium BT.ttf', filename) self.assertEquals('application/octet-stream', mimetype)
def testTextFileSeenAsFile(self): httpRequest = open(inmydir('data/multipart-data-03')).read() self.requestData = {} def handler(**kwargs): self.requestData = kwargs reactor = Reactor() server = HttpServer(reactor, self.port, handler) server.listen() sok = socket() sok.connect(('localhost', self.port)) sok.send(httpRequest) reactor.addTimer(2, lambda: self.fail("Test Stuck")) while self.requestData.get('Form', None) == None: reactor.step() form = self.requestData['Form'] self.assertEquals(4, len(form)) self.assertEquals(['SOME ID'], form['id']) self.assertEquals(1, len(form['somename'])) filename, mimetype, data = form['somename'][0] self.assertEquals('hello.bas', filename) self.assertEquals('text/plain', mimetype)
def testHttpServerEncodesUnicode(self): unicodeString = u'some t\xe9xt' oneStringLength = len(unicodeString.encode(getdefaultencoding())) self.assertTrue(len(unicodeString) != oneStringLength) def response(**kwargs): yield unicodeString * 6000 reactor = Reactor() server = HttpServer(reactor, self.port, response, recvSize=3) server.listen() sok = socket() sok.connect(('localhost', self.port)) sok.send( 'GET /path/here HTTP/1.0\r\nConnection: close\r\nApe-Nut: Mies\r\n\r\n' ) while not reactor._writers: reactor.step() reactor.step() fragment = sok.recv(100000) # will read about 49152 chars reactor.step() fragment += sok.recv(100000) self.assertEquals(oneStringLength * 6000, len(fragment)) self.assertTrue("some t\xc3\xa9xt" in fragment, fragment)
def testDefaultErrorHandler(self): def handler(**kwargs): yield "OK" server = HttpServer(self.reactor, self.port, handler, maxConnections=5) server.listen() self.reactor.getOpenConnections = lambda: 10 sock = socket() sock.connect(('localhost', self.port)) self.reactor.step() sock.send("GET / HTTP/1.0\r\n\r\n") self.reactor.step().step().step() self.assertEquals( 'HTTP/1.0 503 Service Unavailable\r\n\r\n<html><head></head><body><h1>Service Unavailable</h1></body></html>', sock.recv(1024)) server.shutdown()
def testOnlyHandleAMaximumNrOfRequestsBelowBoundary(self): def handler(**kwargs): yield "OK" def error_handler(**kwargs): yield "FAIL" server = HttpServer(self.reactor, self.port, handler, errorHandler=error_handler, maxConnections=10) server.listen() self.reactor.getOpenConnections = lambda: 5 sock = socket() sock.connect(('localhost', self.port)) self.reactor.step() sock.send("GET / HTTP/1.0\r\n\r\n") self.reactor.step().step().step() server.shutdown() self.assertEquals('OK', sock.recv(1024))