second commit
This commit is contained in:
5
env/lib/python3.11/site-packages/httptools/parser/__init__.py
vendored
Normal file
5
env/lib/python3.11/site-packages/httptools/parser/__init__.py
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
from .parser import * # NoQA
|
||||
from .errors import * # NoQA
|
||||
from .url_parser import * # NoQA
|
||||
|
||||
__all__ = parser.__all__ + errors.__all__ + url_parser.__all__ # NoQA
|
BIN
env/lib/python3.11/site-packages/httptools/parser/__pycache__/__init__.cpython-311.pyc
vendored
Normal file
BIN
env/lib/python3.11/site-packages/httptools/parser/__pycache__/__init__.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
env/lib/python3.11/site-packages/httptools/parser/__pycache__/errors.cpython-311.pyc
vendored
Normal file
BIN
env/lib/python3.11/site-packages/httptools/parser/__pycache__/errors.cpython-311.pyc
vendored
Normal file
Binary file not shown.
167
env/lib/python3.11/site-packages/httptools/parser/cparser.pxd
vendored
Normal file
167
env/lib/python3.11/site-packages/httptools/parser/cparser.pxd
vendored
Normal file
@ -0,0 +1,167 @@
|
||||
from libc.stdint cimport int32_t, uint8_t, uint16_t, uint64_t
|
||||
|
||||
|
||||
cdef extern from "llhttp.h":
|
||||
struct llhttp__internal_s:
|
||||
int32_t _index
|
||||
void *_span_pos0
|
||||
void *_span_cb0
|
||||
int32_t error
|
||||
const char *reason
|
||||
const char *error_pos
|
||||
void *data
|
||||
void *_current
|
||||
uint64_t content_length
|
||||
uint8_t type
|
||||
uint8_t method
|
||||
uint8_t http_major
|
||||
uint8_t http_minor
|
||||
uint8_t header_state
|
||||
uint16_t flags
|
||||
uint8_t upgrade
|
||||
uint16_t status_code
|
||||
uint8_t finish
|
||||
void *settings
|
||||
ctypedef llhttp__internal_s llhttp__internal_t
|
||||
ctypedef llhttp__internal_t llhttp_t
|
||||
|
||||
ctypedef int (*llhttp_data_cb) (llhttp_t*,
|
||||
const char *at,
|
||||
size_t length) except -1
|
||||
|
||||
ctypedef int (*llhttp_cb) (llhttp_t*) except -1
|
||||
|
||||
struct llhttp_settings_s:
|
||||
llhttp_cb on_message_begin
|
||||
llhttp_data_cb on_url
|
||||
llhttp_data_cb on_status
|
||||
llhttp_data_cb on_header_field
|
||||
llhttp_data_cb on_header_value
|
||||
llhttp_cb on_headers_complete
|
||||
llhttp_data_cb on_body
|
||||
llhttp_cb on_message_complete
|
||||
llhttp_cb on_chunk_header
|
||||
llhttp_cb on_chunk_complete
|
||||
ctypedef llhttp_settings_s llhttp_settings_t
|
||||
|
||||
enum llhttp_type:
|
||||
HTTP_BOTH,
|
||||
HTTP_REQUEST,
|
||||
HTTP_RESPONSE
|
||||
ctypedef llhttp_type llhttp_type_t
|
||||
|
||||
enum llhttp_errno:
|
||||
HPE_OK,
|
||||
HPE_INTERNAL,
|
||||
HPE_STRICT,
|
||||
HPE_LF_EXPECTED,
|
||||
HPE_UNEXPECTED_CONTENT_LENGTH,
|
||||
HPE_CLOSED_CONNECTION,
|
||||
HPE_INVALID_METHOD,
|
||||
HPE_INVALID_URL,
|
||||
HPE_INVALID_CONSTANT,
|
||||
HPE_INVALID_VERSION,
|
||||
HPE_INVALID_HEADER_TOKEN,
|
||||
HPE_INVALID_CONTENT_LENGTH,
|
||||
HPE_INVALID_CHUNK_SIZE,
|
||||
HPE_INVALID_STATUS,
|
||||
HPE_INVALID_EOF_STATE,
|
||||
HPE_INVALID_TRANSFER_ENCODING,
|
||||
HPE_CB_MESSAGE_BEGIN,
|
||||
HPE_CB_HEADERS_COMPLETE,
|
||||
HPE_CB_MESSAGE_COMPLETE,
|
||||
HPE_CB_CHUNK_HEADER,
|
||||
HPE_CB_CHUNK_COMPLETE,
|
||||
HPE_PAUSED,
|
||||
HPE_PAUSED_UPGRADE,
|
||||
HPE_USER
|
||||
ctypedef llhttp_errno llhttp_errno_t
|
||||
|
||||
enum llhttp_flags:
|
||||
F_CONNECTION_KEEP_ALIVE,
|
||||
F_CONNECTION_CLOSE,
|
||||
F_CONNECTION_UPGRADE,
|
||||
F_CHUNKED,
|
||||
F_UPGRADE,
|
||||
F_CONTENT_LENGTH,
|
||||
F_SKIPBODY,
|
||||
F_TRAILING,
|
||||
F_LENIENT,
|
||||
F_TRANSFER_ENCODING
|
||||
ctypedef llhttp_flags llhttp_flags_t
|
||||
|
||||
enum llhttp_method:
|
||||
HTTP_DELETE,
|
||||
HTTP_GET,
|
||||
HTTP_HEAD,
|
||||
HTTP_POST,
|
||||
HTTP_PUT,
|
||||
HTTP_CONNECT,
|
||||
HTTP_OPTIONS,
|
||||
HTTP_TRACE,
|
||||
HTTP_COPY,
|
||||
HTTP_LOCK,
|
||||
HTTP_MKCOL,
|
||||
HTTP_MOVE,
|
||||
HTTP_PROPFIND,
|
||||
HTTP_PROPPATCH,
|
||||
HTTP_SEARCH,
|
||||
HTTP_UNLOCK,
|
||||
HTTP_BIND,
|
||||
HTTP_REBIND,
|
||||
HTTP_UNBIND,
|
||||
HTTP_ACL,
|
||||
HTTP_REPORT,
|
||||
HTTP_MKACTIVITY,
|
||||
HTTP_CHECKOUT,
|
||||
HTTP_MERGE,
|
||||
HTTP_MSEARCH,
|
||||
HTTP_NOTIFY,
|
||||
HTTP_SUBSCRIBE,
|
||||
HTTP_UNSUBSCRIBE,
|
||||
HTTP_PATCH,
|
||||
HTTP_PURGE,
|
||||
HTTP_MKCALENDAR,
|
||||
HTTP_LINK,
|
||||
HTTP_UNLINK,
|
||||
HTTP_SOURCE,
|
||||
HTTP_PRI,
|
||||
HTTP_DESCRIBE,
|
||||
HTTP_ANNOUNCE,
|
||||
HTTP_SETUP,
|
||||
HTTP_PLAY,
|
||||
HTTP_PAUSE,
|
||||
HTTP_TEARDOWN,
|
||||
HTTP_GET_PARAMETER,
|
||||
HTTP_SET_PARAMETER,
|
||||
HTTP_REDIRECT,
|
||||
HTTP_RECORD,
|
||||
HTTP_FLUSH
|
||||
ctypedef llhttp_method llhttp_method_t
|
||||
|
||||
void llhttp_init(llhttp_t* parser, llhttp_type_t type, const llhttp_settings_t* settings)
|
||||
|
||||
void llhttp_settings_init(llhttp_settings_t* settings)
|
||||
|
||||
llhttp_errno_t llhttp_execute(llhttp_t* parser, const char* data, size_t len)
|
||||
|
||||
void llhttp_resume_after_upgrade(llhttp_t* parser)
|
||||
|
||||
int llhttp_should_keep_alive(const llhttp_t* parser)
|
||||
|
||||
const char* llhttp_get_error_pos(const llhttp_t* parser)
|
||||
const char* llhttp_get_error_reason(const llhttp_t* parser)
|
||||
const char* llhttp_method_name(llhttp_method_t method)
|
||||
|
||||
void llhttp_set_error_reason(llhttp_t* parser, const char* reason);
|
||||
|
||||
void llhttp_set_lenient_headers(llhttp_t* parser, bint enabled);
|
||||
void llhttp_set_lenient_chunked_length(llhttp_t* parser, bint enabled);
|
||||
void llhttp_set_lenient_keep_alive(llhttp_t* parser, bint enabled);
|
||||
void llhttp_set_lenient_transfer_encoding(llhttp_t* parser, bint enabled);
|
||||
void llhttp_set_lenient_version(llhttp_t* parser, bint enabled);
|
||||
void llhttp_set_lenient_data_after_close(llhttp_t* parser, bint enabled);
|
||||
void llhttp_set_lenient_optional_lf_after_cr(llhttp_t* parser, bint enabled);
|
||||
void llhttp_set_lenient_optional_cr_before_lf(llhttp_t* parser, bint enabled);
|
||||
void llhttp_set_lenient_optional_crlf_after_chunk(llhttp_t* parser, bint enabled);
|
||||
void llhttp_set_lenient_spaces_after_chunk_size(llhttp_t* parser, bint enabled);
|
30
env/lib/python3.11/site-packages/httptools/parser/errors.py
vendored
Normal file
30
env/lib/python3.11/site-packages/httptools/parser/errors.py
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
__all__ = ('HttpParserError',
|
||||
'HttpParserCallbackError',
|
||||
'HttpParserInvalidStatusError',
|
||||
'HttpParserInvalidMethodError',
|
||||
'HttpParserInvalidURLError',
|
||||
'HttpParserUpgrade')
|
||||
|
||||
|
||||
class HttpParserError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class HttpParserCallbackError(HttpParserError):
|
||||
pass
|
||||
|
||||
|
||||
class HttpParserInvalidStatusError(HttpParserError):
|
||||
pass
|
||||
|
||||
|
||||
class HttpParserInvalidMethodError(HttpParserError):
|
||||
pass
|
||||
|
||||
|
||||
class HttpParserInvalidURLError(HttpParserError):
|
||||
pass
|
||||
|
||||
|
||||
class HttpParserUpgrade(Exception):
|
||||
pass
|
BIN
env/lib/python3.11/site-packages/httptools/parser/parser.cpython-311-darwin.so
vendored
Executable file
BIN
env/lib/python3.11/site-packages/httptools/parser/parser.cpython-311-darwin.so
vendored
Executable file
Binary file not shown.
436
env/lib/python3.11/site-packages/httptools/parser/parser.pyx
vendored
Normal file
436
env/lib/python3.11/site-packages/httptools/parser/parser.pyx
vendored
Normal file
@ -0,0 +1,436 @@
|
||||
#cython: language_level=3
|
||||
|
||||
from __future__ import print_function
|
||||
from typing import Optional
|
||||
|
||||
from cpython.mem cimport PyMem_Malloc, PyMem_Free
|
||||
from cpython cimport PyObject_GetBuffer, PyBuffer_Release, PyBUF_SIMPLE, \
|
||||
Py_buffer, PyBytes_AsString
|
||||
|
||||
from .python cimport PyMemoryView_Check, PyMemoryView_GET_BUFFER
|
||||
|
||||
|
||||
from .errors import (HttpParserError,
|
||||
HttpParserCallbackError,
|
||||
HttpParserInvalidStatusError,
|
||||
HttpParserInvalidMethodError,
|
||||
HttpParserInvalidURLError,
|
||||
HttpParserUpgrade)
|
||||
|
||||
cimport cython
|
||||
from . cimport cparser
|
||||
|
||||
|
||||
__all__ = ('HttpRequestParser', 'HttpResponseParser')
|
||||
|
||||
|
||||
@cython.internal
|
||||
cdef class HttpParser:
|
||||
|
||||
cdef:
|
||||
cparser.llhttp_t* _cparser
|
||||
cparser.llhttp_settings_t* _csettings
|
||||
|
||||
bytes _current_header_name
|
||||
bytes _current_header_value
|
||||
|
||||
_proto_on_url, _proto_on_status, _proto_on_body, \
|
||||
_proto_on_header, _proto_on_headers_complete, \
|
||||
_proto_on_message_complete, _proto_on_chunk_header, \
|
||||
_proto_on_chunk_complete, _proto_on_message_begin
|
||||
|
||||
object _last_error
|
||||
|
||||
Py_buffer py_buf
|
||||
|
||||
def __cinit__(self):
|
||||
self._cparser = <cparser.llhttp_t*> \
|
||||
PyMem_Malloc(sizeof(cparser.llhttp_t))
|
||||
if self._cparser is NULL:
|
||||
raise MemoryError()
|
||||
|
||||
self._csettings = <cparser.llhttp_settings_t*> \
|
||||
PyMem_Malloc(sizeof(cparser.llhttp_settings_t))
|
||||
if self._csettings is NULL:
|
||||
raise MemoryError()
|
||||
|
||||
def __dealloc__(self):
|
||||
PyMem_Free(self._cparser)
|
||||
PyMem_Free(self._csettings)
|
||||
|
||||
cdef _init(self, protocol, cparser.llhttp_type_t mode):
|
||||
cparser.llhttp_settings_init(self._csettings)
|
||||
|
||||
cparser.llhttp_init(self._cparser, mode, self._csettings)
|
||||
self._cparser.data = <void*>self
|
||||
|
||||
self._current_header_name = None
|
||||
self._current_header_value = None
|
||||
|
||||
self._proto_on_header = getattr(protocol, 'on_header', None)
|
||||
if self._proto_on_header is not None:
|
||||
self._csettings.on_header_field = cb_on_header_field
|
||||
self._csettings.on_header_value = cb_on_header_value
|
||||
self._proto_on_headers_complete = getattr(
|
||||
protocol, 'on_headers_complete', None)
|
||||
self._csettings.on_headers_complete = cb_on_headers_complete
|
||||
|
||||
self._proto_on_body = getattr(protocol, 'on_body', None)
|
||||
if self._proto_on_body is not None:
|
||||
self._csettings.on_body = cb_on_body
|
||||
|
||||
self._proto_on_message_begin = getattr(
|
||||
protocol, 'on_message_begin', None)
|
||||
if self._proto_on_message_begin is not None:
|
||||
self._csettings.on_message_begin = cb_on_message_begin
|
||||
|
||||
self._proto_on_message_complete = getattr(
|
||||
protocol, 'on_message_complete', None)
|
||||
if self._proto_on_message_complete is not None:
|
||||
self._csettings.on_message_complete = cb_on_message_complete
|
||||
|
||||
self._proto_on_chunk_header = getattr(
|
||||
protocol, 'on_chunk_header', None)
|
||||
self._csettings.on_chunk_header = cb_on_chunk_header
|
||||
|
||||
self._proto_on_chunk_complete = getattr(
|
||||
protocol, 'on_chunk_complete', None)
|
||||
self._csettings.on_chunk_complete = cb_on_chunk_complete
|
||||
|
||||
self._last_error = None
|
||||
|
||||
cdef _maybe_call_on_header(self):
|
||||
if self._current_header_value is not None:
|
||||
current_header_name = self._current_header_name
|
||||
current_header_value = self._current_header_value
|
||||
|
||||
self._current_header_name = self._current_header_value = None
|
||||
|
||||
if self._proto_on_header is not None:
|
||||
self._proto_on_header(current_header_name,
|
||||
current_header_value)
|
||||
|
||||
cdef _on_header_field(self, bytes field):
|
||||
self._maybe_call_on_header()
|
||||
if self._current_header_name is None:
|
||||
self._current_header_name = field
|
||||
else:
|
||||
self._current_header_name += field
|
||||
|
||||
cdef _on_header_value(self, bytes val):
|
||||
if self._current_header_value is None:
|
||||
self._current_header_value = val
|
||||
else:
|
||||
# This is unlikely, as mostly HTTP headers are one-line
|
||||
self._current_header_value += val
|
||||
|
||||
cdef _on_headers_complete(self):
|
||||
self._maybe_call_on_header()
|
||||
|
||||
if self._proto_on_headers_complete is not None:
|
||||
self._proto_on_headers_complete()
|
||||
|
||||
cdef _on_chunk_header(self):
|
||||
if (self._current_header_value is not None or
|
||||
self._current_header_name is not None):
|
||||
raise HttpParserError('invalid headers state')
|
||||
|
||||
if self._proto_on_chunk_header is not None:
|
||||
self._proto_on_chunk_header()
|
||||
|
||||
cdef _on_chunk_complete(self):
|
||||
self._maybe_call_on_header()
|
||||
|
||||
if self._proto_on_chunk_complete is not None:
|
||||
self._proto_on_chunk_complete()
|
||||
|
||||
### Public API ###
|
||||
|
||||
def set_dangerous_leniencies(
|
||||
self,
|
||||
lenient_headers: Optional[bool] = None,
|
||||
lenient_chunked_length: Optional[bool] = None,
|
||||
lenient_keep_alive: Optional[bool] = None,
|
||||
lenient_transfer_encoding: Optional[bool] = None,
|
||||
lenient_version: Optional[bool] = None,
|
||||
lenient_data_after_close: Optional[bool] = None,
|
||||
lenient_optional_lf_after_cr: Optional[bool] = None,
|
||||
lenient_optional_cr_before_lf: Optional[bool] = None,
|
||||
lenient_optional_crlf_after_chunk: Optional[bool] = None,
|
||||
lenient_spaces_after_chunk_size: Optional[bool] = None,
|
||||
):
|
||||
cdef cparser.llhttp_t* parser = self._cparser
|
||||
if lenient_headers is not None:
|
||||
cparser.llhttp_set_lenient_headers(
|
||||
parser, lenient_headers)
|
||||
if lenient_chunked_length is not None:
|
||||
cparser.llhttp_set_lenient_chunked_length(
|
||||
parser, lenient_chunked_length)
|
||||
if lenient_keep_alive is not None:
|
||||
cparser.llhttp_set_lenient_keep_alive(
|
||||
parser, lenient_keep_alive)
|
||||
if lenient_transfer_encoding is not None:
|
||||
cparser.llhttp_set_lenient_transfer_encoding(
|
||||
parser, lenient_transfer_encoding)
|
||||
if lenient_version is not None:
|
||||
cparser.llhttp_set_lenient_version(
|
||||
parser, lenient_version)
|
||||
if lenient_data_after_close is not None:
|
||||
cparser.llhttp_set_lenient_data_after_close(
|
||||
parser, lenient_data_after_close)
|
||||
if lenient_optional_lf_after_cr is not None:
|
||||
cparser.llhttp_set_lenient_optional_lf_after_cr(
|
||||
parser, lenient_optional_lf_after_cr)
|
||||
if lenient_optional_cr_before_lf is not None:
|
||||
cparser.llhttp_set_lenient_optional_cr_before_lf(
|
||||
parser, lenient_optional_cr_before_lf)
|
||||
if lenient_optional_crlf_after_chunk is not None:
|
||||
cparser.llhttp_set_lenient_optional_crlf_after_chunk(
|
||||
parser, lenient_optional_crlf_after_chunk)
|
||||
if lenient_spaces_after_chunk_size is not None:
|
||||
cparser.llhttp_set_lenient_spaces_after_chunk_size(
|
||||
parser, lenient_spaces_after_chunk_size)
|
||||
|
||||
def get_http_version(self):
|
||||
cdef cparser.llhttp_t* parser = self._cparser
|
||||
return '{}.{}'.format(parser.http_major, parser.http_minor)
|
||||
|
||||
def should_keep_alive(self):
|
||||
return bool(cparser.llhttp_should_keep_alive(self._cparser))
|
||||
|
||||
def should_upgrade(self):
|
||||
cdef cparser.llhttp_t* parser = self._cparser
|
||||
return bool(parser.upgrade)
|
||||
|
||||
def feed_data(self, data):
|
||||
cdef:
|
||||
size_t data_len
|
||||
cparser.llhttp_errno_t err
|
||||
Py_buffer *buf
|
||||
bint owning_buf = False
|
||||
const char* err_pos
|
||||
|
||||
if PyMemoryView_Check(data):
|
||||
buf = PyMemoryView_GET_BUFFER(data)
|
||||
data_len = <size_t>buf.len
|
||||
err = cparser.llhttp_execute(
|
||||
self._cparser,
|
||||
<char*>buf.buf,
|
||||
data_len)
|
||||
|
||||
else:
|
||||
buf = &self.py_buf
|
||||
PyObject_GetBuffer(data, buf, PyBUF_SIMPLE)
|
||||
owning_buf = True
|
||||
data_len = <size_t>buf.len
|
||||
|
||||
err = cparser.llhttp_execute(
|
||||
self._cparser,
|
||||
<char*>buf.buf,
|
||||
data_len)
|
||||
|
||||
try:
|
||||
if self._cparser.upgrade == 1 and err == cparser.HPE_PAUSED_UPGRADE:
|
||||
err_pos = cparser.llhttp_get_error_pos(self._cparser)
|
||||
|
||||
# Immediately free the parser from "error" state, simulating
|
||||
# http-parser behavior here because 1) we never had the API to
|
||||
# allow users manually "resume after upgrade", and 2) the use
|
||||
# case for resuming parsing is very rare.
|
||||
cparser.llhttp_resume_after_upgrade(self._cparser)
|
||||
|
||||
# The err_pos here is specific for the input buf. So if we ever
|
||||
# switch to the llhttp behavior (re-raise HttpParserUpgrade for
|
||||
# successive calls to feed_data() until resume_after_upgrade is
|
||||
# called), we have to store the result and keep our own state.
|
||||
raise HttpParserUpgrade(err_pos - <char*>buf.buf)
|
||||
finally:
|
||||
if owning_buf:
|
||||
PyBuffer_Release(buf)
|
||||
|
||||
if err != cparser.HPE_OK:
|
||||
ex = parser_error_from_errno(
|
||||
self._cparser,
|
||||
<cparser.llhttp_errno_t> self._cparser.error)
|
||||
if isinstance(ex, HttpParserCallbackError):
|
||||
if self._last_error is not None:
|
||||
ex.__context__ = self._last_error
|
||||
self._last_error = None
|
||||
raise ex
|
||||
|
||||
|
||||
cdef class HttpRequestParser(HttpParser):
|
||||
|
||||
def __init__(self, protocol):
|
||||
self._init(protocol, cparser.HTTP_REQUEST)
|
||||
|
||||
self._proto_on_url = getattr(protocol, 'on_url', None)
|
||||
if self._proto_on_url is not None:
|
||||
self._csettings.on_url = cb_on_url
|
||||
|
||||
def get_method(self):
|
||||
cdef cparser.llhttp_t* parser = self._cparser
|
||||
return cparser.llhttp_method_name(<cparser.llhttp_method_t> parser.method)
|
||||
|
||||
|
||||
cdef class HttpResponseParser(HttpParser):
|
||||
|
||||
def __init__(self, protocol):
|
||||
self._init(protocol, cparser.HTTP_RESPONSE)
|
||||
|
||||
self._proto_on_status = getattr(protocol, 'on_status', None)
|
||||
if self._proto_on_status is not None:
|
||||
self._csettings.on_status = cb_on_status
|
||||
|
||||
def get_status_code(self):
|
||||
cdef cparser.llhttp_t* parser = self._cparser
|
||||
return parser.status_code
|
||||
|
||||
|
||||
cdef int cb_on_message_begin(cparser.llhttp_t* parser) except -1:
|
||||
cdef HttpParser pyparser = <HttpParser>parser.data
|
||||
try:
|
||||
pyparser._proto_on_message_begin()
|
||||
except BaseException as ex:
|
||||
pyparser._last_error = ex
|
||||
return -1
|
||||
else:
|
||||
return 0
|
||||
|
||||
|
||||
cdef int cb_on_url(cparser.llhttp_t* parser,
|
||||
const char *at, size_t length) except -1:
|
||||
cdef HttpParser pyparser = <HttpParser>parser.data
|
||||
try:
|
||||
pyparser._proto_on_url(at[:length])
|
||||
except BaseException as ex:
|
||||
cparser.llhttp_set_error_reason(parser, "`on_url` callback error")
|
||||
pyparser._last_error = ex
|
||||
return cparser.HPE_USER
|
||||
else:
|
||||
return 0
|
||||
|
||||
|
||||
cdef int cb_on_status(cparser.llhttp_t* parser,
|
||||
const char *at, size_t length) except -1:
|
||||
cdef HttpParser pyparser = <HttpParser>parser.data
|
||||
try:
|
||||
pyparser._proto_on_status(at[:length])
|
||||
except BaseException as ex:
|
||||
cparser.llhttp_set_error_reason(parser, "`on_status` callback error")
|
||||
pyparser._last_error = ex
|
||||
return cparser.HPE_USER
|
||||
else:
|
||||
return 0
|
||||
|
||||
|
||||
cdef int cb_on_header_field(cparser.llhttp_t* parser,
|
||||
const char *at, size_t length) except -1:
|
||||
cdef HttpParser pyparser = <HttpParser>parser.data
|
||||
try:
|
||||
pyparser._on_header_field(at[:length])
|
||||
except BaseException as ex:
|
||||
cparser.llhttp_set_error_reason(parser, "`on_header_field` callback error")
|
||||
pyparser._last_error = ex
|
||||
return cparser.HPE_USER
|
||||
else:
|
||||
return 0
|
||||
|
||||
|
||||
cdef int cb_on_header_value(cparser.llhttp_t* parser,
|
||||
const char *at, size_t length) except -1:
|
||||
cdef HttpParser pyparser = <HttpParser>parser.data
|
||||
try:
|
||||
pyparser._on_header_value(at[:length])
|
||||
except BaseException as ex:
|
||||
cparser.llhttp_set_error_reason(parser, "`on_header_value` callback error")
|
||||
pyparser._last_error = ex
|
||||
return cparser.HPE_USER
|
||||
else:
|
||||
return 0
|
||||
|
||||
|
||||
cdef int cb_on_headers_complete(cparser.llhttp_t* parser) except -1:
|
||||
cdef HttpParser pyparser = <HttpParser>parser.data
|
||||
try:
|
||||
pyparser._on_headers_complete()
|
||||
except BaseException as ex:
|
||||
pyparser._last_error = ex
|
||||
return -1
|
||||
else:
|
||||
if pyparser._cparser.upgrade:
|
||||
return 1
|
||||
else:
|
||||
return 0
|
||||
|
||||
|
||||
cdef int cb_on_body(cparser.llhttp_t* parser,
|
||||
const char *at, size_t length) except -1:
|
||||
cdef HttpParser pyparser = <HttpParser>parser.data
|
||||
try:
|
||||
pyparser._proto_on_body(at[:length])
|
||||
except BaseException as ex:
|
||||
cparser.llhttp_set_error_reason(parser, "`on_body` callback error")
|
||||
pyparser._last_error = ex
|
||||
return cparser.HPE_USER
|
||||
else:
|
||||
return 0
|
||||
|
||||
|
||||
cdef int cb_on_message_complete(cparser.llhttp_t* parser) except -1:
|
||||
cdef HttpParser pyparser = <HttpParser>parser.data
|
||||
try:
|
||||
pyparser._proto_on_message_complete()
|
||||
except BaseException as ex:
|
||||
pyparser._last_error = ex
|
||||
return -1
|
||||
else:
|
||||
return 0
|
||||
|
||||
|
||||
cdef int cb_on_chunk_header(cparser.llhttp_t* parser) except -1:
|
||||
cdef HttpParser pyparser = <HttpParser>parser.data
|
||||
try:
|
||||
pyparser._on_chunk_header()
|
||||
except BaseException as ex:
|
||||
pyparser._last_error = ex
|
||||
return -1
|
||||
else:
|
||||
return 0
|
||||
|
||||
|
||||
cdef int cb_on_chunk_complete(cparser.llhttp_t* parser) except -1:
|
||||
cdef HttpParser pyparser = <HttpParser>parser.data
|
||||
try:
|
||||
pyparser._on_chunk_complete()
|
||||
except BaseException as ex:
|
||||
pyparser._last_error = ex
|
||||
return -1
|
||||
else:
|
||||
return 0
|
||||
|
||||
|
||||
cdef parser_error_from_errno(cparser.llhttp_t* parser, cparser.llhttp_errno_t errno):
|
||||
cdef bytes reason = cparser.llhttp_get_error_reason(parser)
|
||||
|
||||
if errno in (cparser.HPE_CB_MESSAGE_BEGIN,
|
||||
cparser.HPE_CB_HEADERS_COMPLETE,
|
||||
cparser.HPE_CB_MESSAGE_COMPLETE,
|
||||
cparser.HPE_CB_CHUNK_HEADER,
|
||||
cparser.HPE_CB_CHUNK_COMPLETE,
|
||||
cparser.HPE_USER):
|
||||
cls = HttpParserCallbackError
|
||||
|
||||
elif errno == cparser.HPE_INVALID_STATUS:
|
||||
cls = HttpParserInvalidStatusError
|
||||
|
||||
elif errno == cparser.HPE_INVALID_METHOD:
|
||||
cls = HttpParserInvalidMethodError
|
||||
|
||||
elif errno == cparser.HPE_INVALID_URL:
|
||||
cls = HttpParserInvalidURLError
|
||||
|
||||
else:
|
||||
cls = HttpParserError
|
||||
|
||||
return cls(reason.decode('latin-1'))
|
6
env/lib/python3.11/site-packages/httptools/parser/python.pxd
vendored
Normal file
6
env/lib/python3.11/site-packages/httptools/parser/python.pxd
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
cimport cpython
|
||||
|
||||
|
||||
cdef extern from "Python.h":
|
||||
cpython.Py_buffer* PyMemoryView_GET_BUFFER(object)
|
||||
bint PyMemoryView_Check(object)
|
31
env/lib/python3.11/site-packages/httptools/parser/url_cparser.pxd
vendored
Normal file
31
env/lib/python3.11/site-packages/httptools/parser/url_cparser.pxd
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
from libc.stdint cimport uint16_t
|
||||
|
||||
|
||||
cdef extern from "http_parser.h":
|
||||
# URL Parser
|
||||
|
||||
enum http_parser_url_fields:
|
||||
UF_SCHEMA = 0,
|
||||
UF_HOST = 1,
|
||||
UF_PORT = 2,
|
||||
UF_PATH = 3,
|
||||
UF_QUERY = 4,
|
||||
UF_FRAGMENT = 5,
|
||||
UF_USERINFO = 6,
|
||||
UF_MAX = 7
|
||||
|
||||
struct http_parser_url_field_data:
|
||||
uint16_t off
|
||||
uint16_t len
|
||||
|
||||
struct http_parser_url:
|
||||
uint16_t field_set
|
||||
uint16_t port
|
||||
http_parser_url_field_data[<int>UF_MAX] field_data
|
||||
|
||||
void http_parser_url_init(http_parser_url *u)
|
||||
|
||||
int http_parser_parse_url(const char *buf,
|
||||
size_t buflen,
|
||||
int is_connect,
|
||||
http_parser_url *u)
|
BIN
env/lib/python3.11/site-packages/httptools/parser/url_parser.cpython-311-darwin.so
vendored
Executable file
BIN
env/lib/python3.11/site-packages/httptools/parser/url_parser.cpython-311-darwin.so
vendored
Executable file
Binary file not shown.
108
env/lib/python3.11/site-packages/httptools/parser/url_parser.pyx
vendored
Normal file
108
env/lib/python3.11/site-packages/httptools/parser/url_parser.pyx
vendored
Normal file
@ -0,0 +1,108 @@
|
||||
#cython: language_level=3
|
||||
|
||||
from __future__ import print_function
|
||||
from cpython.mem cimport PyMem_Malloc, PyMem_Free
|
||||
from cpython cimport PyObject_GetBuffer, PyBuffer_Release, PyBUF_SIMPLE, \
|
||||
Py_buffer
|
||||
|
||||
from .errors import HttpParserInvalidURLError
|
||||
|
||||
cimport cython
|
||||
from . cimport url_cparser as uparser
|
||||
|
||||
__all__ = ('parse_url',)
|
||||
|
||||
@cython.freelist(250)
|
||||
cdef class URL:
|
||||
cdef readonly bytes schema
|
||||
cdef readonly bytes host
|
||||
cdef readonly object port
|
||||
cdef readonly bytes path
|
||||
cdef readonly bytes query
|
||||
cdef readonly bytes fragment
|
||||
cdef readonly bytes userinfo
|
||||
|
||||
def __cinit__(self, bytes schema, bytes host, object port, bytes path,
|
||||
bytes query, bytes fragment, bytes userinfo):
|
||||
|
||||
self.schema = schema
|
||||
self.host = host
|
||||
self.port = port
|
||||
self.path = path
|
||||
self.query = query
|
||||
self.fragment = fragment
|
||||
self.userinfo = userinfo
|
||||
|
||||
def __repr__(self):
|
||||
return ('<URL schema: {!r}, host: {!r}, port: {!r}, path: {!r}, '
|
||||
'query: {!r}, fragment: {!r}, userinfo: {!r}>'
|
||||
.format(self.schema, self.host, self.port, self.path,
|
||||
self.query, self.fragment, self.userinfo))
|
||||
|
||||
|
||||
def parse_url(url):
|
||||
cdef:
|
||||
Py_buffer py_buf
|
||||
char* buf_data
|
||||
uparser.http_parser_url* parsed
|
||||
int res
|
||||
bytes schema = None
|
||||
bytes host = None
|
||||
object port = None
|
||||
bytes path = None
|
||||
bytes query = None
|
||||
bytes fragment = None
|
||||
bytes userinfo = None
|
||||
object result = None
|
||||
int off
|
||||
int ln
|
||||
|
||||
parsed = <uparser.http_parser_url*> \
|
||||
PyMem_Malloc(sizeof(uparser.http_parser_url))
|
||||
uparser.http_parser_url_init(parsed)
|
||||
|
||||
PyObject_GetBuffer(url, &py_buf, PyBUF_SIMPLE)
|
||||
try:
|
||||
buf_data = <char*>py_buf.buf
|
||||
res = uparser.http_parser_parse_url(buf_data, py_buf.len, 0, parsed)
|
||||
|
||||
if res == 0:
|
||||
if parsed.field_set & (1 << uparser.UF_SCHEMA):
|
||||
off = parsed.field_data[<int>uparser.UF_SCHEMA].off
|
||||
ln = parsed.field_data[<int>uparser.UF_SCHEMA].len
|
||||
schema = buf_data[off:off+ln]
|
||||
|
||||
if parsed.field_set & (1 << uparser.UF_HOST):
|
||||
off = parsed.field_data[<int>uparser.UF_HOST].off
|
||||
ln = parsed.field_data[<int>uparser.UF_HOST].len
|
||||
host = buf_data[off:off+ln]
|
||||
|
||||
if parsed.field_set & (1 << uparser.UF_PORT):
|
||||
port = parsed.port
|
||||
|
||||
if parsed.field_set & (1 << uparser.UF_PATH):
|
||||
off = parsed.field_data[<int>uparser.UF_PATH].off
|
||||
ln = parsed.field_data[<int>uparser.UF_PATH].len
|
||||
path = buf_data[off:off+ln]
|
||||
|
||||
if parsed.field_set & (1 << uparser.UF_QUERY):
|
||||
off = parsed.field_data[<int>uparser.UF_QUERY].off
|
||||
ln = parsed.field_data[<int>uparser.UF_QUERY].len
|
||||
query = buf_data[off:off+ln]
|
||||
|
||||
if parsed.field_set & (1 << uparser.UF_FRAGMENT):
|
||||
off = parsed.field_data[<int>uparser.UF_FRAGMENT].off
|
||||
ln = parsed.field_data[<int>uparser.UF_FRAGMENT].len
|
||||
fragment = buf_data[off:off+ln]
|
||||
|
||||
if parsed.field_set & (1 << uparser.UF_USERINFO):
|
||||
off = parsed.field_data[<int>uparser.UF_USERINFO].off
|
||||
ln = parsed.field_data[<int>uparser.UF_USERINFO].len
|
||||
userinfo = buf_data[off:off+ln]
|
||||
|
||||
return URL(schema, host, port, path, query, fragment, userinfo)
|
||||
else:
|
||||
raise HttpParserInvalidURLError("invalid url {!r}".format(url))
|
||||
finally:
|
||||
PyBuffer_Release(&py_buf)
|
||||
PyMem_Free(parsed)
|
Reference in New Issue
Block a user