mirror of
https://github.com/danog/ext-uv.git
synced 2024-11-30 04:29:01 +01:00
improve http parser:
* support multiple line header field and value. * support http upgrade mechanism (you have to parse websocket protocol manually)
This commit is contained in:
parent
fe317d62c0
commit
951622a3aa
53
php_uv.c
53
php_uv.c
@ -2316,6 +2316,12 @@ static int on_message_complete(http_parser *p)
|
|||||||
php_http_parser_context *result = p->data;
|
php_http_parser_context *result = p->data;
|
||||||
result->finished = 1;
|
result->finished = 1;
|
||||||
|
|
||||||
|
if (result->tmp != NULL) {
|
||||||
|
efree(result->tmp);
|
||||||
|
result->tmp = NULL;
|
||||||
|
result->tmp_len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2332,7 +2338,6 @@ static int on_url_cb(http_parser *p, const char *at, size_t len)
|
|||||||
zval *data = result->data;
|
zval *data = result->data;
|
||||||
|
|
||||||
http_parser_parse_url(at, len, 0, &result->handle);
|
http_parser_parse_url(at, len, 0, &result->handle);
|
||||||
|
|
||||||
add_assoc_stringl(data, "QUERY_STRING", (char*)at, len, 1);
|
add_assoc_stringl(data, "QUERY_STRING", (char*)at, len, 1);
|
||||||
|
|
||||||
PHP_HTTP_PARSER_PARSE_URL(UF_SCHEMA, SCHEME);
|
PHP_HTTP_PARSER_PARSE_URL(UF_SCHEMA, SCHEME);
|
||||||
@ -2369,10 +2374,24 @@ char *php_uv_strtoupper(char *s, size_t len)
|
|||||||
static int header_field_cb(http_parser *p, const char *at, size_t len)
|
static int header_field_cb(http_parser *p, const char *at, size_t len)
|
||||||
{
|
{
|
||||||
php_http_parser_context *result = p->data;
|
php_http_parser_context *result = p->data;
|
||||||
/* TODO: */
|
|
||||||
result->tmp = estrndup(at, len);
|
|
||||||
php_uv_strtoupper(result->tmp, len);
|
|
||||||
|
|
||||||
|
if (result->was_header_value) {
|
||||||
|
if (result->tmp != NULL) {
|
||||||
|
efree(result->tmp);
|
||||||
|
result->tmp = NULL;
|
||||||
|
result->tmp_len = 0;
|
||||||
|
}
|
||||||
|
result->tmp = estrndup(at, len);
|
||||||
|
php_uv_strtoupper(result->tmp, len);
|
||||||
|
result->tmp_len = len;
|
||||||
|
} else {
|
||||||
|
result->tmp = erealloc(result->tmp, len + result->tmp_len + 1);
|
||||||
|
memcpy(result->tmp + result->tmp_len, at, len);
|
||||||
|
result->tmp[result->tmp_len + len] = '\0';
|
||||||
|
result->tmp_len = result->tmp_len + len;
|
||||||
|
}
|
||||||
|
|
||||||
|
result->was_header_value = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2381,10 +2400,21 @@ static int header_value_cb(http_parser *p, const char *at, size_t len)
|
|||||||
php_http_parser_context *result = p->data;
|
php_http_parser_context *result = p->data;
|
||||||
zval *data = result->headers;
|
zval *data = result->headers;
|
||||||
|
|
||||||
add_assoc_stringl(data, result->tmp, (char*)at, len, 1);
|
if (result->was_header_value) {
|
||||||
/* TODO: */
|
zval **element;
|
||||||
efree(result->tmp);
|
|
||||||
result->tmp = NULL;
|
if (zend_hash_find(Z_ARRVAL_P(data), result->tmp, result->tmp_len+1, (void **)&element) == SUCCESS) {
|
||||||
|
Z_STRVAL_PP(element) = erealloc(Z_STRVAL_PP(element), Z_STRLEN_PP(element) + len + 1);
|
||||||
|
memcpy(Z_STRVAL_PP(element) + Z_STRLEN_PP(element), at, len);
|
||||||
|
|
||||||
|
Z_STRVAL_PP(element)[Z_STRLEN_PP(element)+len] = '\0';
|
||||||
|
Z_STRLEN_PP(element) = Z_STRLEN_PP(element) + len;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
add_assoc_stringl(data, result->tmp, (char*)at, len, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
result->was_header_value = 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6317,6 +6347,9 @@ PHP_FUNCTION(uv_http_parser_init)
|
|||||||
ctx->data = result;
|
ctx->data = result;
|
||||||
ctx->headers = header;
|
ctx->headers = header;
|
||||||
ctx->finished = 0;
|
ctx->finished = 0;
|
||||||
|
ctx->was_header_value = 1;
|
||||||
|
ctx->tmp = NULL;
|
||||||
|
ctx->tmp_len = 0;
|
||||||
|
|
||||||
if (target == HTTP_RESPONSE) {
|
if (target == HTTP_RESPONSE) {
|
||||||
ctx->is_response = 1;
|
ctx->is_response = 1;
|
||||||
@ -6369,8 +6402,8 @@ PHP_FUNCTION(uv_http_parser_execute)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (nparsed != body_len) {
|
if (nparsed != body_len) {
|
||||||
php_error_docref(NULL TSRMLS_CC, E_NOTICE, "parse failed.");
|
zend_throw_exception_ex(zend_exception_get_default(TSRMLS_C), 0 TSRMLS_CC, "parse failed");
|
||||||
RETURN_FALSE;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ZVAL_ZVAL(result, context->data, 1, 0);
|
ZVAL_ZVAL(result, context->data, 1, 0);
|
||||||
|
1
php_uv.h
1
php_uv.h
@ -197,6 +197,7 @@ typedef struct {
|
|||||||
zval *data;
|
zval *data;
|
||||||
zval *headers;
|
zval *headers;
|
||||||
char *tmp;
|
char *tmp;
|
||||||
|
size_t tmp_len;
|
||||||
} php_http_parser_context;
|
} php_http_parser_context;
|
||||||
|
|
||||||
#define PHP_UV_HTTPPARSER_RESOURCE_NAME "uv_httpparser"
|
#define PHP_UV_HTTPPARSER_RESOURCE_NAME "uv_httpparser"
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
--TEST--
|
--TEST--
|
||||||
Check for uv_cwd
|
Check for uv_http_parser
|
||||||
--FILE--
|
--FILE--
|
||||||
<?php
|
<?php
|
||||||
$parser = uv_http_parser_init();
|
$parser = uv_http_parser_init();
|
||||||
@ -33,7 +33,22 @@ Cache-Control: max-age=0
|
|||||||
echo $result['PATH'] . PHP_EOL;
|
echo $result['PATH'] . PHP_EOL;
|
||||||
echo $result['QUERY'] . PHP_EOL;
|
echo $result['QUERY'] . PHP_EOL;
|
||||||
echo $result['FRAGMENT'] . PHP_EOL;
|
echo $result['FRAGMENT'] . PHP_EOL;
|
||||||
|
echo $result['UPGRADE'] . PHP_EOL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$buffer = "GET /demo HTTP/1.1
|
||||||
|
Upgrade: WebSocket
|
||||||
|
Connection: Upgrade
|
||||||
|
Host: example.com
|
||||||
|
Origin: http://example.com
|
||||||
|
WebSocket-Protocol: sample
|
||||||
|
|
||||||
|
";
|
||||||
|
|
||||||
|
$parser = uv_http_parser_init();
|
||||||
|
$result = array();
|
||||||
|
uv_http_parser_execute($parser, $buffer, $result);
|
||||||
|
var_dump($result);
|
||||||
--EXPECT--
|
--EXPECT--
|
||||||
# Headers count
|
# Headers count
|
||||||
9
|
9
|
||||||
@ -52,3 +67,27 @@ max-age=0
|
|||||||
/img/http-parser.png
|
/img/http-parser.png
|
||||||
key=value
|
key=value
|
||||||
frag
|
frag
|
||||||
|
0
|
||||||
|
array(5) {
|
||||||
|
["QUERY_STRING"]=>
|
||||||
|
string(5) "/demo"
|
||||||
|
["PATH"]=>
|
||||||
|
string(5) "/demo"
|
||||||
|
["REQUEST_METHOD"]=>
|
||||||
|
string(3) "GET"
|
||||||
|
["UPGRADE"]=>
|
||||||
|
int(1)
|
||||||
|
["HEADERS"]=>
|
||||||
|
array(5) {
|
||||||
|
["UPGRADE"]=>
|
||||||
|
string(9) "WebSocket"
|
||||||
|
["CONNECTION"]=>
|
||||||
|
string(7) "Upgrade"
|
||||||
|
["HOST"]=>
|
||||||
|
string(11) "example.com"
|
||||||
|
["ORIGIN"]=>
|
||||||
|
string(18) "http://example.com"
|
||||||
|
["WEBSOCKET_PROTOCOL"]=>
|
||||||
|
string(6) "sample"
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user