codekingpro/portable-devtools
115k
1#cython: language_level=3
2
3from __future__ import print_function
4from cpython.mem cimport PyMem_Malloc, PyMem_Free
5from cpython cimport PyObject_GetBuffer, PyBuffer_Release, PyBUF_SIMPLE, \
6 Py_buffer
7
8from .errors import HttpParserInvalidURLError
9
10cimport cython
11from . cimport url_cparser as uparser
12
13__all__ = ('parse_url',)
14
15@cython.freelist(250)
16cdef class URL:
17 cdef readonly bytes schema
18 cdef readonly bytes host
19 cdef readonly object port
20 cdef readonly bytes path
21 cdef readonly bytes query
22 cdef readonly bytes fragment
23 cdef readonly bytes userinfo
24
25 def __cinit__(self, bytes schema, bytes host, object port, bytes path,
26 bytes query, bytes fragment, bytes userinfo):
27
28 self.schema = schema
29 self.host = host
30 self.port = port
31 self.path = path
32 self.query = query
33 self.fragment = fragment
34 self.userinfo = userinfo
35
36 def __repr__(self):
37 return ('<URL schema: {!r}, host: {!r}, port: {!r}, path: {!r}, '
38 'query: {!r}, fragment: {!r}, userinfo: {!r}>'
39 .format(self.schema, self.host, self.port, self.path,
40 self.query, self.fragment, self.userinfo))
41
42
43def parse_url(url):
44 cdef:
45 Py_buffer py_buf
46 char* buf_data
47 uparser.http_parser_url* parsed
48 int res
49 bytes schema = None
50 bytes host = None
51 object port = None
52 bytes path = None
53 bytes query = None
54 bytes fragment = None
55 bytes userinfo = None
56 object result = None
57 int off
58 int ln
59
60 parsed = <uparser.http_parser_url*> \
61 PyMem_Malloc(sizeof(uparser.http_parser_url))
62 uparser.http_parser_url_init(parsed)
63
64 PyObject_GetBuffer(url, &py_buf, PyBUF_SIMPLE)
65 try:
66 buf_data = <char*>py_buf.buf
67 res = uparser.http_parser_parse_url(buf_data, py_buf.len, 0, parsed)
68
69 if res == 0:
70 if parsed.field_set & (1 << uparser.UF_SCHEMA):
71 off = parsed.field_data[<int>uparser.UF_SCHEMA].off
72 ln = parsed.field_data[<int>uparser.UF_SCHEMA].len
73 schema = buf_data[off:off+ln]
74
75 if parsed.field_set & (1 << uparser.UF_HOST):
76 off = parsed.field_data[<int>uparser.UF_HOST].off
77 ln = parsed.field_data[<int>uparser.UF_HOST].len
78 host = buf_data[off:off+ln]
79
80 if parsed.field_set & (1 << uparser.UF_PORT):
81 port = parsed.port
82
83 if parsed.field_set & (1 << uparser.UF_PATH):
84 off = parsed.field_data[<int>uparser.UF_PATH].off
85 ln = parsed.field_data[<int>uparser.UF_PATH].len
86 path = buf_data[off:off+ln]
87
88 if parsed.field_set & (1 << uparser.UF_QUERY):
89 off = parsed.field_data[<int>uparser.UF_QUERY].off
90 ln = parsed.field_data[<int>uparser.UF_QUERY].len
91 query = buf_data[off:off+ln]
92
93 if parsed.field_set & (1 << uparser.UF_FRAGMENT):
94 off = parsed.field_data[<int>uparser.UF_FRAGMENT].off
95 ln = parsed.field_data[<int>uparser.UF_FRAGMENT].len
96 fragment = buf_data[off:off+ln]
97
98 if parsed.field_set & (1 << uparser.UF_USERINFO):
99 off = parsed.field_data[<int>uparser.UF_USERINFO].off
100 ln = parsed.field_data[<int>uparser.UF_USERINFO].len
101 userinfo = buf_data[off:off+ln]
102
103 return URL(schema, host, port, path, query, fragment, userinfo)
104 else:
105 raise HttpParserInvalidURLError("invalid url {!r}".format(url))
106 finally:
107 PyBuffer_Release(&py_buf)
108 PyMem_Free(parsed)
109 