async def parse(self): """Parse http request Returns: Request object, or None if no data received Raises: BadRequest: request headers invalid or incomplete RequestHeaderFieldsTooLarge: request headers too large RequestTimeout: read request headers timeout RequestEntityTooLarge: request content-length too large """ # browsers may preconnect but didn't send request immediately # keep-alive connection has similar behaviors first_chunk = b'' async with timeout_after(self.keep_alive_timeout): first_chunk = await self._recv() if not first_chunk: return None # read request headers try: self._feed(first_chunk) async with timeout_after(self.header_timeout) as is_timeout: while not self._headers_completed: if self._readed_size > self.max_header_size: raise RequestHeaderFieldsTooLarge() chunk = await self._recv() self._feed(chunk) if not chunk: break except httptools.HttpParserError as ex: msg = 'Invalid request headers from %s' LOG.debug(msg, self._address, exc_info=True) raise BadRequest('Invalid request headers') from ex if is_timeout: raise RequestTimeout() if not self._headers_completed: LOG.debug('Incomplete request headers from %s', self._address) raise BadRequest('Incomplete request headers') # check content-length if self.method in ['POST', 'PUT', 'PATCH']: content_length = self._get_content_length() if content_length > self.max_body_size: raise RequestEntityTooLarge() return RawRequest( method=self.method, url=self.url, version=self.version, headers=self.headers, body=self._body_stream(), remote_ip=self.remote_ip, protocol=self.protocol, keep_alive=self.keep_alive, )
async def test_sleep_timeout(): begin = time.monotonic() async with timeout_after(0.1) as is_timeout: await sleep(10) assert is_timeout cost = time.monotonic() - begin assert cost >= 0.1 and cost < 0.15
async def parse(self): if not self._has_timeout(): await self._read_header() else: async with timeout_after(self.timeout) as is_timeout: await self._read_header() if is_timeout: raise ReadTimeoutError() if not self.headers_completed: raise ProtocolError('incomplete response headers') body_stream = self.body_stream() decoder = self._get_decoder() if decoder: body_stream = _decompress(body_stream, decoder) def stream(chunk_size=DEFAULT_BUFFER_SIZE): self._set_current_buffer_size(chunk_size) return body_stream environ = dict( version=self.version, status=self.status, reason=self.reason, keep_alive=self.keep_alive, headers=self.headers, stream=stream, ) return Response(**environ)
async def _body_stream(self): """ Read request body Raises: BadRequest: request body invalid or incomplete RequestTimeout: read request body timeout """ self._buffer_size = self.body_buffer_size if self._body_chunks: yield self._take_body_chunks() if self._completed: return async with timeout_after(self.body_timeout) as is_timeout: try: while not self._completed: chunk = await self._recv() self._feed(chunk) if self._body_chunks: yield self._take_body_chunks() if not chunk: break except httptools.HttpParserError as ex: msg = 'Invalid request body from %s' LOG.debug(msg, self._address, exc_info=True) raise BadRequest('Invalid request body') from ex if is_timeout: raise RequestTimeout() if not self._completed: LOG.debug('Incomplete request body from %s', self._address) raise BadRequest('Incomplete request body')
async def test_task_timeout(): task = await spawn(sleep(10)) begin = time.monotonic() async with timeout_after(0.1) as is_timeout: await task.join() assert is_timeout cost = time.monotonic() - begin assert cost >= 0.1 and cost < 0.15
async def body_stream(self): if not self._has_timeout(): async for chunk in self._body_stream_impl(): yield chunk else: async with timeout_after(self.timeout) as is_timeout: async for chunk in self._body_stream_impl(): yield chunk if is_timeout: raise ReadTimeoutError()
async def server(address): sock = socket(AF_INET, SOCK_DGRAM) sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, True) sock.bind(address) results.append('recvfrom wait') async with timeout_after(0.1) as is_timeout: await sock.recvfrom(8192) results.append('not here') if is_timeout: results.append('recvfrom timeout') await sock.close()
async def server(address): sock = socket(AF_INET, SOCK_STREAM) sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, True) sock.bind(address) sock.listen(1) results.append('accept wait') async with timeout_after(0.1) as is_timeout: client, addr = await sock.accept() results.append('not here') if is_timeout: results.append('accept timeout') await sock.close()
async def test_timeout(): begin = time.monotonic() task = await nio.spawn(nio.sleep(1)) async with nio.timeout_after(0.1) as is_timeout: await task.join() if is_timeout: print('is_timeout') await task.cancel() else: print('not is_timeout') await task.join() cost = time.monotonic() - begin assert cost >= 0.1 and cost < 0.15