def parse_request_line(self, buf, event, first=False): # {{{ line = self.readline(buf) if line is None: return self.request_line = line.rstrip() if line == b'\r\n': # Ignore a single leading empty line, as per RFC 2616 sec 4.1 if first: return self.set_state(READ, self.parse_request_line, Accumulator()) return self.simple_response(http.client.BAD_REQUEST, 'Multiple leading empty lines not allowed') try: method, uri, req_protocol = line.strip().split(b' ', 2) rp = int(req_protocol[5]), int(req_protocol[7]) self.method = method.decode('ascii').upper() except Exception: return self.simple_response(http.client.BAD_REQUEST, "Malformed Request-Line") if self.method not in HTTP_METHODS: return self.simple_response(http.client.BAD_REQUEST, "Unknown HTTP method") try: self.request_protocol = protocol_map[rp] except KeyError: return self.simple_response(http.client.HTTP_VERSION_NOT_SUPPORTED) self.response_protocol = protocol_map[min((1, 1), rp)] try: self.scheme, self.path, self.query = parse_uri(uri) except HTTPSimpleResponse as e: return self.simple_response(e.http_code, e.message, close_after_response=False) self.header_line_too_long_error_code = http.client.REQUEST_ENTITY_TOO_LARGE self.set_state(READ, self.parse_header_line, HTTPHeaderParser(), Accumulator())
def read_chunk_length(self, inheaders, line_buf, buf, bytes_read, event): line = self.readline(line_buf) if line is None: return bytes_read[0] += len(line) try: chunk_size = int(line.strip(), 16) except Exception: return self.simple_response( http_client.BAD_REQUEST, '%s is not a valid chunk size' % reprlib.repr(line.strip())) if bytes_read[0] + chunk_size + 2 > self.max_request_body_size: return self.simple_response( http_client.REQUEST_ENTITY_TOO_LARGE, 'Chunked request is larger than %d bytes' % self.max_request_body_size) if chunk_size == 0: self.set_state(READ, self.read_chunk_separator, inheaders, Accumulator(), buf, bytes_read, last=True) else: self.set_state(READ, self.read_chunk, inheaders, buf, chunk_size, buf.tell() + chunk_size, bytes_read)
def read_request_body(self, inheaders, request_content_length, chunked_read): buf = SpooledTemporaryFile(prefix='rq-body-', max_size=DEFAULT_BUFFER_SIZE, dir=self.tdir) if chunked_read: self.set_state(READ, self.read_chunk_length, inheaders, Accumulator(), buf, [0]) else: if request_content_length > 0: self.set_state(READ, self.sized_read, inheaders, buf, request_content_length) else: self.prepare_response(inheaders, BytesIO())
def connection_ready(self): 'Become ready to read an HTTP request' self.method = self.request_line = None self.response_protocol = self.request_protocol = HTTP1 self.path = self.query = None self.close_after_response = False self.header_line_too_long_error_code = http.client.REQUEST_URI_TOO_LONG self.response_started = False self.set_state(READ, self.parse_request_line, Accumulator(), first=True)
def read_chunk_separator(self, inheaders, line_buf, buf, bytes_read, event, last=False): line = self.readline(line_buf) if line is None: return if line != b'\r\n': return self.simple_response(http.client.BAD_REQUEST, 'Chunk does not have trailing CRLF') bytes_read[0] += len(line) if bytes_read[0] > self.max_request_body_size: return self.simple_response(http.client.REQUEST_ENTITY_TOO_LARGE, 'Chunked request is larger than %d bytes' % self.max_request_body_size) if last: self.prepare_response(inheaders, buf) else: self.set_state(READ, self.read_chunk_length, inheaders, Accumulator(), buf, bytes_read)
def read_chunk(self, inheaders, buf, chunk_size, end, bytes_read, event): if not self.read(buf, end): return bytes_read[0] += chunk_size self.set_state(READ, self.read_chunk_separator, inheaders, Accumulator(), buf, bytes_read)
def parse_request_line(self, buf, event, first=False): # {{{ line = self.readline(buf) if line is None: return if line == b'\r\n': # Ignore a single leading empty line, as per RFC 2616 sec 4.1 if first: return self.set_state(READ, self.parse_request_line, Accumulator()) return self.simple_response( httplib.BAD_REQUEST, 'Multiple leading empty lines not allowed') try: method, uri, req_protocol = line.strip().split(b' ', 2) rp = int(req_protocol[5]), int(req_protocol[7]) self.method = method.decode('ascii').upper() except Exception: return self.simple_response(httplib.BAD_REQUEST, "Malformed Request-Line") if self.method not in HTTP_METHODS: return self.simple_response(httplib.BAD_REQUEST, "Unknown HTTP method") try: self.request_protocol = protocol_map[rp] except KeyError: return self.simple_response(httplib.HTTP_VERSION_NOT_SUPPORTED) self.response_protocol = protocol_map[min((1, 1), rp)] scheme, authority, path = parse_request_uri(uri) if b'#' in path: return self.simple_response(httplib.BAD_REQUEST, "Illegal #fragment in Request-URI.") if scheme: try: self.scheme = scheme.decode('ascii') except ValueError: return self.simple_response(httplib.BAD_REQUEST, 'Un-decodeable scheme') qs = b'' if b'?' in path: path, qs = path.split(b'?', 1) try: self.query = MultiDict.create_from_query_string(qs) except Exception: return self.simple_response(httplib.BAD_REQUEST, 'Unparseable query string') try: path = '%2F'.join( unquote(x).decode('utf-8') for x in quoted_slash.split(path)) except ValueError as e: return self.simple_response(httplib.BAD_REQUEST, as_unicode(e)) self.path = tuple( filter(None, (x.replace('%2F', '/') for x in path.split('/')))) self.header_line_too_long_error_code = httplib.REQUEST_ENTITY_TOO_LARGE self.request_line = line.rstrip() self.set_state(READ, self.parse_header_line, HTTPHeaderParser(), Accumulator())