12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182 |
- # -*- coding: utf-8 -*-
- """
- hyper/http11/parser
- ~~~~~~~~~~~~~~~~~~~
- This module contains hyper's pure-Python HTTP/1.1 parser. This module defines
- an abstraction layer for HTTP/1.1 parsing that allows for dropping in other
- modules if needed, in order to obtain speedups on your chosen platform.
- """
- from collections import namedtuple
- Response = namedtuple(
- 'Response', ['status', 'msg', 'minor_version', 'headers', 'consumed']
- )
- class ParseError(Exception):
- """
- An invalid HTTP message was passed to the parser.
- """
- pass
- class Parser(object):
- """
- A single HTTP parser object.
- This object is not thread-safe, and it does maintain state that is shared
- across parsing requests. For this reason, make sure that access to this
- object is synchronized if you use it across multiple threads.
- """
- def __init__(self):
- pass
- def parse_response(self, buffer):
- """
- Parses a single HTTP response from a buffer.
- :param buffer: A ``memoryview`` object wrapping a buffer containing a
- HTTP response.
- :returns: A :class:`Response <hyper.http11.parser.Response>` object, or
- ``None`` if there is not enough data in the buffer.
- """
- # Begin by copying the data out of the buffer. This is necessary
- # because as much as possible we want to use the built-in bytestring
- # methods, rather than looping over the data in Python.
- temp_buffer = buffer.tobytes()
- index = temp_buffer.find(b'\n')
- if index == -1:
- return None
- version, status, reason = temp_buffer[0:index].split(None, 2)
- if not version.startswith(b'HTTP/1.'):
- raise ParseError("Not HTTP/1.X!")
- minor_version = int(version[7:])
- status = int(status)
- reason = memoryview(reason.strip())
- # Chomp the newline.
- index += 1
- # Now, parse the headers out.
- end_index = index
- headers = []
- while True:
- end_index = temp_buffer.find(b'\n', index)
- if end_index == -1:
- return None
- elif (end_index - index) <= 1:
- # Chomp the newline
- end_index += 1
- break
- name, value = temp_buffer[index:end_index].split(b':', 1)
- value = value.strip()
- headers.append((memoryview(name), memoryview(value)))
- index = end_index + 1
- resp = Response(status, reason, minor_version, headers, end_index)
- return resp
|