def parse_body(self): if self.content_length is None and self.request.method in NO_SEMANTICS: self.on_body(self.request) return 0 elif self.content_length == 0: self.request.body = b"" self.on_body(self.request) return 0 elif self.content_length is not None: if self.content_length > len(self.buffer): return -2 self.request.body = bytes(self.buffer[:self.content_length]) self.on_body(self.request) self.buffer = self.buffer[self.content_length:] result = self.content_length return result elif self.transfer == 'identity': return -2 elif self.transfer == 'chunked': if not self.chunked_decoder: self.chunked_decoder = ffi.new('struct phr_chunked_decoder*') self.chunked_decoder.consume_trailer = b'\x01' self.chunked_offset = ffi.new('size_t*') chunked_offset_start = self.chunked_offset[0] self.chunked_offset[0] = len(self.buffer) - self.chunked_offset[0] result = lib.phr_decode_chunked( self.chunked_decoder, ffi.from_buffer(self.buffer) + chunked_offset_start, self.chunked_offset) self.chunked_offset[0] = self.chunked_offset[0] + chunked_offset_start if result == -2: self.buffer = self.buffer[:self.chunked_offset[0]] return result elif result == -1: self.on_error('malformed_body') self._reset_state() self.buffer = bytearray() return result self.request.body = bytes(self.buffer[:self.chunked_offset[0]]) self.on_body(self.request) self.buffer = self.buffer[ self.chunked_offset[0]:self.chunked_offset[0] + result] return result
def parse_headers(self, data): c_method = ffi.new('char **') method_len = ffi.new('size_t *') c_path = ffi.new('char **') path_len = ffi.new('size_t *') minor_version = ffi.new('int *') c_headers = ffi.new('struct phr_header[10]') num_headers = ffi.new('size_t *') num_headers[0] = 10 result = lib.phr_parse_request(self.buffer, self.buffer_len, c_method, method_len, c_path, path_len, minor_version, c_headers, num_headers, 0) print('parse_headers:result: {}'.format( result)) # parse_headers:result: 679 if result == -2: if self.buffer == data: self.buffer = ffi.new('char[8192]') self.buffer_owned = True ffi.memmove(self.buffer, data, len(data)) return result if result == -1: self.on_error() self._reset() return result self.buffer_consumed += result method = ffi.string(c_method[0], method_len[0]).decode('ascii') path = ffi.string(c_path[0], path_len[0]).decode('ascii') version = "1." + str(minor_version[0]) headers = {} for idx in range(num_headers[0]): header = c_headers[idx] name = ffi.string(header.name, header.name_len).decode('ascii') value = ffi.string(header.value, header.value_len).decode('latin1') headers[name] = value self.request = HttpRequest(method, path, version, headers) self.on_headers(self.request) return result
def __init__(self, on_headers, on_body, on_error): self.on_headers = on_headers self.on_body = on_body self.on_error = on_error self.c_method = ffi.new('char **') self.method_len = ffi.new('size_t *') self.c_path = ffi.new('char **') self.path_len = ffi.new('size_t *') self.minor_version = ffi.new('int *') self.c_headers = ffi.new('struct phr_header[10]') self.num_headers = ffi.new('size_t *') self.chunked_offset = ffi.new('size_t*') self.buffer = bytearray() self._reset_state()