From: Michael Wallner Date: Fri, 25 Sep 2015 12:37:15 +0000 (+0200) Subject: Merge R_2_5 X-Git-Tag: RELEASE_3_0_0_RC1~21 X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-http;a=commitdiff_plain;h=4bf1b4570329514fa00dc68c6e02f581c3792d73;hp=3e3f308c565cea1b153717f213d61731aef2fcf4 Merge R_2_5 --- diff --git a/php_http_client_curl.c b/php_http_client_curl.c index a4e84ce..85f12b7 100644 --- a/php_http_client_curl.c +++ b/php_http_client_curl.c @@ -1228,6 +1228,11 @@ static void php_http_curle_options_init(php_http_options_t *registry) { php_http_option_t *opt; + /* url options */ +#if PHP_HTTP_CURL_VERSION(7,42,0) + php_http_option_register(registry, ZEND_STRL("path_as_is"), CURLOPT_PATH_AS_IS, IS_BOOL); +#endif + /* proxy */ if ((opt = php_http_option_register(registry, ZEND_STRL("proxyhost"), CURLOPT_PROXY, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; @@ -1528,6 +1533,7 @@ static void php_http_curle_options_init(php_http_options_t *registry) } #endif #if PHP_HTTP_CURL_VERSION(7,39,0) + /* FIXME: see http://curl.haxx.se/libcurl/c/CURLOPT_PINNEDPUBLICKEY.html#AVAILABILITY */ if ((opt = php_http_option_register(registry, ZEND_STRL("pinned_publickey"), CURLOPT_PINNEDPUBLICKEY, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; @@ -2027,9 +2033,14 @@ static ZEND_RESULT_CODE php_http_client_curl_handler_prepare(php_http_client_cur * See also https://tools.ietf.org/html/rfc7231#section-5.1.1 */ if (PHP_HTTP_INFO(msg).request.method) { - if (!strcasecmp("PUT", PHP_HTTP_INFO(msg).request.method)) { + switch(php_http_select_str(PHP_HTTP_INFO(msg).request.method, 2, "HEAD", "PUT")) { + case 0: + curl_easy_setopt(curl->handle, CURLOPT_NOBODY, 1L); + break; + case 1: curl_easy_setopt(curl->handle, CURLOPT_UPLOAD, 1L); - } else { + break; + default: curl_easy_setopt(curl->handle, CURLOPT_CUSTOMREQUEST, PHP_HTTP_INFO(msg).request.method); } } else { diff --git a/php_http_info.c b/php_http_info.c index f389be9..6eef822 100644 --- a/php_http_info.c +++ b/php_http_info.c @@ -139,6 +139,10 @@ php_http_info_t *php_http_info_parse(php_http_info_t *info, const char *pre_head } else { PHP_HTTP_INFO(info).request.url = php_http_url_parse_authority(url, http - url, ~0); } + if (!PHP_HTTP_INFO(info).request.url) { + PTR_SET(PHP_HTTP_INFO(info).request.method, NULL); + return NULL; + } } else { PTR_SET(PHP_HTTP_INFO(info).request.method, NULL); return NULL; diff --git a/php_http_message.c b/php_http_message.c index f06065a..e6cdbc8 100644 --- a/php_http_message.c +++ b/php_http_message.c @@ -1575,10 +1575,10 @@ static PHP_METHOD(HttpMessage, setRequestUrl) url = php_http_url_from_zval(zurl, ~0); zend_restore_error_handling(&zeh); - if (php_http_url_is_empty(url)) { + if (url && php_http_url_is_empty(url)) { php_http_url_free(&url); php_http_throw(invalid_arg, "Cannot set http\\Message's request url to an empty string", NULL); - } else { + } else if (url) { PTR_SET(obj->message->http.info.request.url, url); } diff --git a/php_http_url.c b/php_http_url.c index afe39bf..c5c19a5 100644 --- a/php_http_url.c +++ b/php_http_url.c @@ -1026,44 +1026,55 @@ static ZEND_RESULT_CODE parse_widn(struct parse_state *state) } #endif -static ZEND_RESULT_CODE parse_hostinfo(struct parse_state *state, const char *ptr) +#ifdef HAVE_INET_PTON +static const char *parse_ip6(struct parse_state *state, const char *ptr) { size_t mb, len; - const char *end = state->ptr, *tmp = ptr, *port = NULL; - -#ifdef HAVE_INET_PTON - if (*ptr == '[') { - char *error = NULL, *tmp = memchr(ptr, ']', end - ptr); - - if (tmp) { - size_t addrlen = tmp - ptr + 1; - char buf[16], *addr = estrndup(ptr + 1, addrlen - 2); - int rv = inet_pton(AF_INET6, addr, buf); - - efree(addr); - if (rv == 1) { - state->buffer[state->offset] = '['; - state->url.host = &state->buffer[state->offset]; - inet_ntop(AF_INET6, buf, state->url.host + 1, state->maxlen - state->offset); - state->offset += strlen(state->url.host); - state->buffer[state->offset++] = ']'; - state->buffer[state->offset++] = 0; - ptr = tmp + 1; - } else if (rv == -1) { - error = strerror(errno); - } else { - error = "unexpected '['"; - } + const char *error = NULL, *end = state->ptr, *tmp = memchr(ptr, ']', end - ptr); + + if (tmp) { + size_t addrlen = tmp - ptr + 1; + char buf[16], *addr = estrndup(ptr + 1, addrlen - 2); + int rv = inet_pton(AF_INET6, addr, buf); + + if (rv == 1) { + state->buffer[state->offset] = '['; + state->url.host = &state->buffer[state->offset]; + inet_ntop(AF_INET6, buf, state->url.host + 1, state->maxlen - state->offset); + state->offset += strlen(state->url.host); + state->buffer[state->offset++] = ']'; + state->buffer[state->offset++] = 0; + ptr = tmp + 1; + } else if (rv == -1) { + error = strerror(errno); } else { - error = "expected ']'"; + error = "unexpected '['"; } + efree(addr); + } else { + error = "expected ']'"; + } - if (error) { - php_error_docref(NULL, E_WARNING, "Failed to parse hostinfo; %s", error); - return FAILURE; - } + if (error) { + php_error_docref(NULL, E_WARNING, "Failed to parse hostinfo; %s", error); + return NULL; } + + return ptr; +} #endif + +static ZEND_RESULT_CODE parse_hostinfo(struct parse_state *state, const char *ptr) +{ + size_t mb, len; + const char *end = state->ptr, *tmp = ptr, *port = NULL, *label = NULL; + +#ifdef HAVE_INET_PTON + if (*ptr == '[' && !(ptr = parse_ip6(state, ptr))) { + return FAILURE; + } +#endif + if (ptr != end) do { switch (*ptr) { case ':': @@ -1091,6 +1102,20 @@ static ZEND_RESULT_CODE parse_hostinfo(struct parse_state *state, const char *pt case '!': case '$': case '&': case '\'': case '(': case ')': case '*': case '+': case ',': case ';': case '=': /* sub-delims */ case '-': case '.': case '_': case '~': /* unreserved */ + if (port || !label) { + /* sort of a compromise, just ensure we don't end up + * with a dot at the beginning or two consecutive dots + */ + php_error_docref(NULL, E_WARNING, + "Failed to parse %s; unexpected '%c' at pos %u in '%s'", + port ? "port" : "host", + (unsigned char) *ptr, (unsigned) (ptr - tmp), tmp); + return FAILURE; + } + state->buffer[state->offset++] = *ptr; + label = NULL; + break; + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': @@ -1113,6 +1138,7 @@ static ZEND_RESULT_CODE parse_hostinfo(struct parse_state *state, const char *pt state->url.port *= 10; state->url.port += *ptr - '0'; } else { + label = ptr; state->buffer[state->offset++] = *ptr; } break; @@ -1128,6 +1154,7 @@ static ZEND_RESULT_CODE parse_hostinfo(struct parse_state *state, const char *pt } else if (!(mb = parse_mb(state, PARSE_HOSTINFO, ptr, end, tmp, 0))) { return FAILURE; } + label = ptr; ptr += mb - 1; } } while (++ptr != end); diff --git a/tests/bug66388.phpt b/tests/bug66388.phpt index e4cbf2a..77d50c7 100644 --- a/tests/bug66388.phpt +++ b/tests/bug66388.phpt @@ -11,23 +11,27 @@ skip_online_test(); use http\Client, http\Client\Request; +include "helper/server.inc"; + echo "Test\n"; -$client = new Client(); -$request = new Request( - 'POST', - 'https://api.twitter.com/oauth/request_token', - array( - 'Content-Length' => 0 - ) -); -$client->enqueue($request); -echo $client->send()->getResponse()->getResponseCode(); +server("proxy.inc", function($port) { + $client = new Client(); + $request = new Request( + 'POST', + "http://localhost:$port/", + array( + 'Content-Length' => 0 + ) + ); + $client->enqueue($request); + echo $client->send()->getResponse()->getResponseCode(); +}); ?> ===DONE=== --EXPECTF-- Test -40%d +200 ===DONE=== diff --git a/tests/client003.phpt b/tests/client003.phpt index bca3302..63e0ef3 100644 --- a/tests/client003.phpt +++ b/tests/client003.phpt @@ -14,7 +14,7 @@ include "helper/server.inc"; echo "Test\n"; server("proxy.inc", function($port) { - $request = new http\Client\Request("GET", "http://www.example.org/"); + $request = new http\Client\Request("GET", "http://localhost:$port/"); foreach (http\Client::getAvailableDrivers() as $driver) { $client = new http\Client($driver); diff --git a/tests/gh-issue12.phpt b/tests/gh-issue12.phpt new file mode 100644 index 0000000..0721586 --- /dev/null +++ b/tests/gh-issue12.phpt @@ -0,0 +1,31 @@ +--TEST-- +crash with bad url passed to http\Message::setRequestUrl() +--SKIPIF-- + +--FILE-- +setRequestUrl($url); + printf("OK: %s\n", $url); + } catch (Exception $e) { + printf("%s\n", $e->getMessage()); + } +} + +?> +===DONE=== +--EXPECT-- +Test +http\Message::setRequestUrl(): Failed to parse host; unexpected '.' at pos 0 in '.foo.bar' +http\Message::setRequestUrl(): Failed to parse host; unexpected '.' at pos 4 in 'foo..bar' +OK: http://foo.bar. +===DONE===