From: Michael Wallner Date: Thu, 21 May 2015 07:55:15 +0000 (+0200) Subject: fix http\Params::__toString() with RFC5988 payload; fix tests X-Git-Tag: RELEASE_2_5_0_RC1~2 X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-http;a=commitdiff_plain;h=0a5bb2d697afe41949b22afa679d7a5aa4e11f13 fix http\Params::__toString() with RFC5988 payload; fix tests --- diff --git a/php_http_params.c b/php_http_params.c index b91314d..5adeb91 100644 --- a/php_http_params.c +++ b/php_http_params.c @@ -63,27 +63,32 @@ static inline void sanitize_escaped(zval *zv TSRMLS_DC) php_stripcslashes(Z_STRVAL_P(zv), &Z_STRLEN_P(zv)); } -static inline void prepare_escaped(zval *zv TSRMLS_DC) +static inline void quote_string(zval *zv, zend_bool force TSRMLS_DC) { - if (Z_TYPE_P(zv) == IS_STRING) { - int len = Z_STRLEN_P(zv); + int len = Z_STRLEN_P(zv); - Z_STRVAL_P(zv) = php_addcslashes(Z_STRVAL_P(zv), Z_STRLEN_P(zv), &Z_STRLEN_P(zv), 1, - ZEND_STRL("\0..\37\173\\\"") TSRMLS_CC); + Z_STRVAL_P(zv) = php_addcslashes(Z_STRVAL_P(zv), Z_STRLEN_P(zv), &Z_STRLEN_P(zv), 1, + ZEND_STRL("\0..\37\173\\\"") TSRMLS_CC); - if (len != Z_STRLEN_P(zv) || strpbrk(Z_STRVAL_P(zv), "()<>@,;:\"[]?={} ")) { - zval tmp = *zv; - int len = Z_STRLEN_P(zv) + 2; - char *str = emalloc(len + 1); + if (force || len != Z_STRLEN_P(zv) || strpbrk(Z_STRVAL_P(zv), "()<>@,;:\"[]?={} ")) { + zval tmp = *zv; + int len = Z_STRLEN_P(zv) + 2; + char *str = emalloc(len + 1); - str[0] = '"'; - memcpy(&str[1], Z_STRVAL_P(zv), Z_STRLEN_P(zv)); - str[len-1] = '"'; - str[len] = '\0'; + str[0] = '"'; + memcpy(&str[1], Z_STRVAL_P(zv), Z_STRLEN_P(zv)); + str[len-1] = '"'; + str[len] = '\0'; - zval_dtor(&tmp); - ZVAL_STRINGL(zv, str, len, 0); - } + zval_dtor(&tmp); + ZVAL_STRINGL(zv, str, len, 0); + } +} + +static inline void prepare_escaped(zval *zv TSRMLS_DC) +{ + if (Z_TYPE_P(zv) == IS_STRING) { + quote_string(zv, 0 TSRMLS_CC); } else { zval_dtor(zv); ZVAL_EMPTY_STRING(zv); @@ -297,6 +302,14 @@ static inline void sanitize_rfc5988(char *str, size_t len, zval *zv TSRMLS_DC) php_trim(str, len, " ><", 3, zv, 3 TSRMLS_CC); } +static inline void prepare_rfc5988(zval *zv TSRMLS_DC) +{ + if (Z_TYPE_P(zv) != IS_STRING) { + zval_dtor(zv); + ZVAL_EMPTY_STRING(zv); + } +} + static void utf8encode(zval *zv) { size_t pos, len = 0; @@ -369,7 +382,11 @@ static inline void prepare_key(unsigned flags, char *old_key, size_t old_len, ch } if (flags & PHP_HTTP_PARAMS_ESCAPED) { - prepare_escaped(&zv TSRMLS_CC); + if (flags & PHP_HTTP_PARAMS_RFC5988) { + prepare_rfc5988(&zv TSRMLS_CC); + } else { + prepare_escaped(&zv TSRMLS_CC); + } } *new_key = Z_STRVAL(zv); @@ -762,6 +779,17 @@ static inline void shift_rfc5988(php_http_buffer_t *buf, char *key_str, size_t k efree(str); } +static inline void shift_rfc5988_val(php_http_buffer_t *buf, zval *zv, const char *vss, size_t vsl, unsigned flags TSRMLS_DC) +{ + zval *tmp = php_http_zsep(1, IS_STRING, zv); + + quote_string(tmp, 1 TSRMLS_CC); + php_http_buffer_append(buf, vss, vsl); + php_http_buffer_append(buf, Z_STRVAL_P(tmp), Z_STRLEN_P(tmp)); + + zval_ptr_dtor(&tmp); +} + static inline void shift_val(php_http_buffer_t *buf, zval *zvalue, const char *vss, size_t vsl, unsigned flags TSRMLS_DC) { if (Z_TYPE_P(zvalue) != IS_BOOL) { @@ -802,6 +830,21 @@ static void shift_arg(php_http_buffer_t *buf, char *key_str, size_t key_len, zva } } else { shift_key(buf, key_str, key_len, ass, asl, flags TSRMLS_CC); + + if (flags & PHP_HTTP_PARAMS_RFC5988) { + switch (key_len) { + case lenof("rel"): + case lenof("title"): + case lenof("anchor"): + /* some args must be quoted */ + if (0 <= php_http_select_str(key_str, 3, "rel", "title", "anchor")) { + shift_rfc5988_val(buf, zvalue, vss, vsl, flags TSRMLS_CC); + return; + } + break; + } + } + shift_val(buf, zvalue, vss, vsl, flags TSRMLS_CC); } } diff --git a/tests/bug69313.phpt b/tests/bug69313.phpt index d2bea4f..c1d56ef 100644 --- a/tests/bug69313.phpt +++ b/tests/bug69313.phpt @@ -8,7 +8,7 @@ skip_client_test(); --FILE-- enqueue($request); $client->send(); - echo $client->getResponse(); + dump_message(null, $client->getResponse()); }); ?> @@ -30,16 +30,16 @@ Done Test HTTP/1.1 200 OK Accept-Ranges: bytes +Content-Length: %d Etag: "%s" X-Original-Transfer-Encoding: chunked -Content-Length: %d GET / HTTP/1.1 -User-Agent: %s -Host: localhost:%d Accept: */* -Content-Type: text/plain Content-Length: 3 +Content-Type: text/plain +Host: localhost:%d +User-Agent: %s X-Original-Content-Length: 3 foo diff --git a/tests/client019.phpt b/tests/client019.phpt index c41a260..9666b97 100644 --- a/tests/client019.phpt +++ b/tests/client019.phpt @@ -41,8 +41,9 @@ server("proxy.inc", function($port, $stdin, $stdout, $stderr) { Test Server on port %d CONNECT www.example.com:80 HTTP/1.1 +Hello: there! Host: www.example.com:80 -User-Agent: PECL_HTTP/%s PHP/%s libcurl/%s Proxy-Connection: Keep-Alive -Hello: there! +User-Agent: PECL_HTTP/%s PHP/%s libcurl/%s + ===DONE=== diff --git a/tests/client020.phpt b/tests/client020.phpt index 7ea5d60..ed86f4a 100644 --- a/tests/client020.phpt +++ b/tests/client020.phpt @@ -35,7 +35,8 @@ server("proxy.inc", function($port, $stdin, $stdout, $stderr) { Test Server on port %d GET / HTTP/1.1 -User-Agent: PECL_HTTP/%s PHP/%s libcurl/%s -Host: localhost:%d Accept: */* +Host: localhost:%d +User-Agent: PECL_HTTP/%s PHP/%s libcurl/%s + ===DONE=== diff --git a/tests/client025.phpt b/tests/client025.phpt index 3c4793e..3f90cbd 100644 --- a/tests/client025.phpt +++ b/tests/client025.phpt @@ -7,6 +7,7 @@ include "skipif.inc"; --FILE-- setOptions(array("resume" => 1, "expect_100_timeout" => 0)); $request->getBody()->append("123"); - echo $client->enqueue($request)->send()->getResponse(); + dump_message(null, $client->enqueue($request)->send()->getResponse()); }); // Content-length is 2 instead of 3 in older libcurls ?> @@ -25,17 +26,17 @@ server("proxy.inc", function($port) { Test HTTP/1.1 200 OK Accept-Ranges: bytes +Content-Length: %d Etag: "%x" X-Original-Transfer-Encoding: chunked -Content-Length: %d PUT / HTTP/1.1 -Content-Range: bytes 1-2/3 -User-Agent: %s -Host: localhost:%d Accept: */* Content-Length: %d +Content-Range: bytes 1-2/3 Expect: 100-continue +Host: localhost:%d +User-Agent: %s X-Original-Content-Length: %d 23===DONE=== diff --git a/tests/helper/dump.inc b/tests/helper/dump.inc new file mode 100644 index 0000000..5f5f367 --- /dev/null +++ b/tests/helper/dump.inc @@ -0,0 +1,21 @@ +getInfo()); + $headers = $msg->getHeaders(); + ksort($headers); + foreach ($headers as $key => $val) { + fprintf($stream, "%s: %s\n", $key, $val); + } + fprintf($stream, "\n"); + $msg->getBody()->toStream($stream); + + if ($parent && ($msg = $msg->getParentMessage())) { + dump_message($stream, $msg, true); + } +} + +?> \ No newline at end of file diff --git a/tests/helper/proxy.inc b/tests/helper/proxy.inc index 80a0073..f99dd97 100644 --- a/tests/helper/proxy.inc +++ b/tests/helper/proxy.inc @@ -1,5 +1,6 @@ getBody()->append($request); */ - $request->toStream($response->getBody()->getResource()); + dump_message($response->getBody()->getResource(), $request); $response->send($client); }); diff --git a/tests/helper/upload.inc b/tests/helper/upload.inc index 9502d2b..ddc06a8 100644 --- a/tests/helper/upload.inc +++ b/tests/helper/upload.inc @@ -1,5 +1,6 @@ getBody()->append($request); */ - $request->toStream($response->getBody()->getResource()); + dump_message($response->getBody()->getResource(), $request); $response->send($client); }); diff --git a/tests/params016.phpt b/tests/params016.phpt new file mode 100644 index 0000000..e5fbd97 --- /dev/null +++ b/tests/params016.phpt @@ -0,0 +1,46 @@ +--TEST-- +header params rfc5988 +--SKIPIF-- + +--FILE-- +; rel="next", ; rel="last" +EOF; + +$p = new http\Params($link, ",", ";", "=", + http\Params::PARSE_RFC5988 | http\Params::PARSE_ESCAPED); +var_dump($p->params); +var_dump((string)$p); +?> +===DONE=== +--EXPECT-- +Test +array(2) { + ["https://api.github.com/search/code?q=addClass+user%3Amozilla&page=2"]=> + array(2) { + ["value"]=> + bool(true) + ["arguments"]=> + array(1) { + ["rel"]=> + string(4) "next" + } + } + ["https://api.github.com/search/code?q=addClass+user%3Amozilla&page=34"]=> + array(2) { + ["value"]=> + bool(true) + ["arguments"]=> + array(1) { + ["rel"]=> + string(4) "last" + } + } +} +string(162) ";rel="next",;rel="last"" +===DONE=== diff --git a/tests/params017.phpt b/tests/params017.phpt new file mode 100644 index 0000000..b3587e5 --- /dev/null +++ b/tests/params017.phpt @@ -0,0 +1,69 @@ +--TEST-- +header params rfc5988 +--SKIPIF-- + +--FILE-- +; + rel="previous"; title*=UTF-8'de'letztes%20Kapitel, + ; + rel="next"; title*=UTF-8'de'n%c3%a4chstes%20Kapitel +EOF; + +$p = current(http\Header::parse($link, "http\\Header"))->getParams( + http\Params::DEF_PARAM_SEP, + http\Params::DEF_ARG_SEP, + http\Params::DEF_VAL_SEP, + http\Params::PARSE_RFC5988 | http\Params::PARSE_ESCAPED +); +var_dump($p->params); +var_dump((string)$p); +?> +===DONE=== +--EXPECTF-- +Test +array(2) { + ["/TheBook/chapter2"]=> + array(2) { + ["value"]=> + bool(true) + ["arguments"]=> + array(2) { + ["rel"]=> + string(8) "previous" + ["*rfc5987*"]=> + array(1) { + ["title"]=> + array(1) { + ["de"]=> + string(15) "letztes Kapitel" + } + } + } + } + ["/TheBook/chapter4"]=> + array(2) { + ["value"]=> + bool(true) + ["arguments"]=> + array(2) { + ["rel"]=> + string(4) "next" + ["*rfc5987*"]=> + array(1) { + ["title"]=> + array(1) { + ["de"]=> + string(17) "nächstes Kapitel" + } + } + } + } +} +string(139) ";rel="previous";title*=utf-8'de'letztes%20Kapitel,;rel="next";title*=utf-8'de'n%C3%A4chstes%20Kapitel" +===DONE===