Skip to content

Commit fed9b38

Browse files
committed
Refactor parse_url to use the buffer protocol; add tests
1 parent 539227b commit fed9b38

File tree

2 files changed

+23
-9
lines changed

2 files changed

+23
-9
lines changed

httptools/parser/parser.pyx

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -310,9 +310,10 @@ cdef class URL:
310310
self.query, self.fragment, self.userinfo))
311311

312312

313-
def parse_url(const char* url):
313+
def parse_url(url):
314314
cdef:
315-
size_t url_len = len(url)
315+
Py_buffer py_buf
316+
char* buf_data
316317
cparser.http_parser_url* parsed
317318
int res
318319
bytes schema = None
@@ -330,44 +331,48 @@ def parse_url(const char* url):
330331
PyMem_Malloc(sizeof(cparser.http_parser_url))
331332
cparser.http_parser_url_init(parsed)
332333

334+
PyObject_GetBuffer(url, &py_buf, PyBUF_SIMPLE)
333335
try:
334-
res = cparser.http_parser_parse_url(url, url_len, 0, parsed)
336+
buf_data = <char*>py_buf.buf
337+
res = cparser.http_parser_parse_url(buf_data, py_buf.len, 0, parsed)
338+
335339
if res == 0:
336340
if parsed.field_set & (1 << cparser.UF_SCHEMA):
337341
off = parsed.field_data[<int>cparser.UF_SCHEMA].off
338342
ln = parsed.field_data[<int>cparser.UF_SCHEMA].len
339-
schema = url[off:off+ln]
343+
schema = buf_data[off:off+ln]
340344

341345
if parsed.field_set & (1 << cparser.UF_HOST):
342346
off = parsed.field_data[<int>cparser.UF_HOST].off
343347
ln = parsed.field_data[<int>cparser.UF_HOST].len
344-
host = url[off:off+ln]
348+
host = buf_data[off:off+ln]
345349

346350
if parsed.field_set & (1 << cparser.UF_PORT):
347351
port = parsed.port
348352

349353
if parsed.field_set & (1 << cparser.UF_PATH):
350354
off = parsed.field_data[<int>cparser.UF_PATH].off
351355
ln = parsed.field_data[<int>cparser.UF_PATH].len
352-
path = url[off:off+ln]
356+
path = buf_data[off:off+ln]
353357

354358
if parsed.field_set & (1 << cparser.UF_QUERY):
355359
off = parsed.field_data[<int>cparser.UF_QUERY].off
356360
ln = parsed.field_data[<int>cparser.UF_QUERY].len
357-
query = url[off:off+ln]
361+
query = buf_data[off:off+ln]
358362

359363
if parsed.field_set & (1 << cparser.UF_FRAGMENT):
360364
off = parsed.field_data[<int>cparser.UF_FRAGMENT].off
361365
ln = parsed.field_data[<int>cparser.UF_FRAGMENT].len
362-
fragment = url[off:off+ln]
366+
fragment = buf_data[off:off+ln]
363367

364368
if parsed.field_set & (1 << cparser.UF_USERINFO):
365369
off = parsed.field_data[<int>cparser.UF_USERINFO].off
366370
ln = parsed.field_data[<int>cparser.UF_USERINFO].len
367-
userinfo = url[off:off+ln]
371+
userinfo = buf_data[off:off+ln]
368372

369373
return URL(schema, host, port, path, query, fragment, userinfo)
370374
else:
371375
raise HttpParserInvalidURLError("invalid url {!r}".format(url))
372376
finally:
377+
PyBuffer_Release(&py_buf)
373378
PyMem_Free(parsed)

tests/test_parser.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,3 +316,12 @@ def test_parser_url_7(self):
316316
def test_parser_url_8(self):
317317
with self.assertRaises(TypeError):
318318
httptools.parse_url(None)
319+
320+
def test_parser_url_9(self):
321+
with self.assertRaisesRegex(httptools.HttpParserInvalidURLError,
322+
r'a\\x00aa'):
323+
self.parse(b'dsf://a\x00aa')
324+
325+
def test_parser_url_10(self):
326+
with self.assertRaisesRegex(TypeError, 'a bytes-like object'):
327+
self.parse('dsf://aaa')

0 commit comments

Comments
 (0)