Beispiel #1
0
    def test_status_written(self):
        writer = HttpWriter(None, None, None, None)
        self.assertFalse(writer._headers_sent)

        writer._status_written = self._headers_sent = True

        writer.restore()

        self.assertFalse(writer._headers_sent)
Beispiel #2
0
class BaseHttpProtocol(asyncio.StreamReaderProtocol):
    handler_factory = BaseHandler
    def __init__(self, *, keep_alive=None, loop=None):
        if keep_alive is None:
            keep_alive = _DEFAULT_KEEP_ALIVE
        self._reader = asyncio.StreamReader(loop=loop)
        self._keep_alive = keep_alive
        super().__init__(self._reader, None, loop)
        self.h_timeout = None

    def connection_made(self, transport):
        self._transport = transport
        self._reader.set_transport(transport)

        self._writer = HttpWriter(transport, self,
                            self._reader,
                            self._loop)

        self._handler = self._build_handler()

        self._task = asyncio.async(self._handle_client())
        self._task.add_done_callback(self._maybe_log_exception)

        self._reset_timeout()

    def connection_lost(self, exc):
        self._task.cancel()
        self._task = None
        handler = self._handler
        self._writer = None
        self._handler = None
        self._stop_timeout()
        try:
            handler.connection_lost(exc)
        finally:
            super().connection_lost(exc)

    def data_received(self, data):
        self._reset_timeout()
        super().data_received(data)

    @asyncio.coroutine
    def _handle_client(self):
        while True:
            try:
                req = yield from HttpParser.parse(self._reader)
            except BadRequestException as e:
                self._bad_request(self._writer, e)
                self._writer.close()
                break
            # connection has been closed
            if req is None:
                break

            try:
                yield from self._handler.handle_request(req)
            finally:
                if self._should_close_conn_immediately(req):
                    self._writer.close()
                else:
                    yield from req.body.read()
                    if self._writer is not None:
                        self._writer.restore()

    def _reset_timeout(self):
        self._stop_timeout()

        self.h_timeout = self._loop.call_later(
            self._keep_alive, self._handle_timeout)

    def _stop_timeout(self):
        if self.h_timeout is not None:
            self.h_timeout.cancel()
            self.h_timeout = None

    def _handle_timeout(self):
        if self._handler.on_timeout():
            self._reset_timeout()

    def _build_handler(self):
        return self.handler_factory(self._transport, self,
                            self._reader,
                            self._writer,
                            **self.get_handler_kwargs())

    def get_handler_kwargs(self):
        return {}

    def _should_close_conn_immediately(self, req):
        if self._keep_alive < 1:
            return True

        should_close = False
        if req.version.lower() == 'http/1.0':
            should_close = True
        conn_header = req['connection']
        if not conn_header:
            return should_close
        if conn_header == 'keep-alive':
            should_close = False
        elif conn_header == 'close':
            should_close = True
        return should_close

    def _maybe_log_exception(self, task):
        try:
            if not task.cancelled():
                task.result()
        except:
            logger.exception("An exception ocurred while serving request")
            if self._writer is not None:
                self._writer.close()