Merge branch 'master' into phpng
authorMichael Wallner <mike@php.net>
Fri, 7 Aug 2015 09:36:04 +0000 (11:36 +0200)
committerMichael Wallner <mike@php.net>
Fri, 7 Aug 2015 09:36:04 +0000 (11:36 +0200)
Conflicts:
php_http_client.c
php_http_client_curl.c
php_http_env_request.c
php_http_env_response.c
php_http_header_parser.c

17 files changed:
.gitmodules [new file with mode: 0644]
.travis.yml
README.md [new file with mode: 0644]
config9.m4
gen_travis_yml.php [new file with mode: 0755]
php_http_client_curl.c
php_http_env_request.c
php_http_header_parser.c
php_http_querystring.c
php_http_url.c
tests/client019.phpt
tests/gh-issue6.phpt [new file with mode: 0644]
tests/gh-issue7.phpt [new file with mode: 0644]
tests/helper/pipeline.inc
tests/helper/server.inc
tests/message002.phpt
travis/pecl [new submodule]

diff --git a/.gitmodules b/.gitmodules
new file mode 100644 (file)
index 0000000..e53f88c
--- /dev/null
@@ -0,0 +1,4 @@
+[submodule "travis-pecl"]
+       path = travis/pecl
+       url = https://github.com/m6w6/travis-pecl.git
+       branch = master
index 7dc1227b83ed44b004342080d5e9206b3991629c..9ac277751061e2ef6816314267616081ccb6b6bb 100644 (file)
@@ -1,10 +1,52 @@
-language: php
+# autogenerated file; do not edit
+language: c
 
-php:
-  - 5.3
-  - 5.4
+addons:
+ apt:
+  packages:
+   - php5-cli
+   - php-pear
+   - libcurl4-openssl-dev
+   - zlib1g-dev
+   - libidn11-dev
+   - libevent-dev
 
-before_script: phpize
+env:
+ - PHP=5.4 enable_debug=no enable_maintainer_zts=no enable_json=no enable_hash=yes enable_iconv=yes
+ - PHP=5.5 enable_debug=no enable_maintainer_zts=no enable_json=no enable_hash=yes enable_iconv=yes
+ - PHP=5.6 enable_debug=no enable_maintainer_zts=no enable_json=no enable_hash=yes enable_iconv=yes
+ - PHP=5.4 enable_debug=yes enable_maintainer_zts=no enable_json=no enable_hash=yes enable_iconv=yes
+ - PHP=5.5 enable_debug=yes enable_maintainer_zts=no enable_json=no enable_hash=yes enable_iconv=yes
+ - PHP=5.6 enable_debug=yes enable_maintainer_zts=no enable_json=no enable_hash=yes enable_iconv=yes
+ - PHP=5.4 enable_debug=no enable_maintainer_zts=yes enable_json=no enable_hash=yes enable_iconv=yes
+ - PHP=5.5 enable_debug=no enable_maintainer_zts=yes enable_json=no enable_hash=yes enable_iconv=yes
+ - PHP=5.6 enable_debug=no enable_maintainer_zts=yes enable_json=no enable_hash=yes enable_iconv=yes
+ - PHP=5.4 enable_debug=yes enable_maintainer_zts=yes enable_json=no enable_hash=yes enable_iconv=yes
+ - PHP=5.5 enable_debug=yes enable_maintainer_zts=yes enable_json=no enable_hash=yes enable_iconv=yes
+ - PHP=5.6 enable_debug=yes enable_maintainer_zts=yes enable_json=no enable_hash=yes enable_iconv=yes
+ - PHP=5.4 enable_debug=no enable_maintainer_zts=no enable_json=yes enable_hash=yes enable_iconv=yes
+ - PHP=5.5 enable_debug=no enable_maintainer_zts=no enable_json=yes enable_hash=yes enable_iconv=yes
+ - PHP=5.6 enable_debug=no enable_maintainer_zts=no enable_json=yes enable_hash=yes enable_iconv=yes
+ - PHP=5.4 enable_debug=yes enable_maintainer_zts=no enable_json=yes enable_hash=yes enable_iconv=yes
+ - PHP=5.5 enable_debug=yes enable_maintainer_zts=no enable_json=yes enable_hash=yes enable_iconv=yes
+ - PHP=5.6 enable_debug=yes enable_maintainer_zts=no enable_json=yes enable_hash=yes enable_iconv=yes
+ - PHP=5.4 enable_debug=no enable_maintainer_zts=yes enable_json=yes enable_hash=yes enable_iconv=yes
+ - PHP=5.5 enable_debug=no enable_maintainer_zts=yes enable_json=yes enable_hash=yes enable_iconv=yes
+ - PHP=5.6 enable_debug=no enable_maintainer_zts=yes enable_json=yes enable_hash=yes enable_iconv=yes
+ - PHP=5.4 enable_debug=yes enable_maintainer_zts=yes enable_json=yes enable_hash=yes enable_iconv=yes
+ - PHP=5.5 enable_debug=yes enable_maintainer_zts=yes enable_json=yes enable_hash=yes enable_iconv=yes
+ - PHP=5.6 enable_debug=yes enable_maintainer_zts=yes enable_json=yes enable_hash=yes enable_iconv=yes
 
-script: ./configure && make && NO_INTERACTION=1 REPORT_EXIT_STATUS=1 TEST_PHP_DETAILED=1 make test
+before_script:
+ - make -f travis/pecl/Makefile php
+ - make -f travis/pecl/Makefile pecl PECL=raphf
+ - make -f travis/pecl/Makefile pecl PECL=propro
 
+script:
+ - make -f travis/pecl/Makefile ext PECL=http
+ - make -f travis/pecl/Makefile test
+
+after_script:
+ - test -e tests/helper/server.log && cat tests/helper/server.log
+
+sudo: false
diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..09dcd90
--- /dev/null
+++ b/README.md
@@ -0,0 +1,121 @@
+# pecl/http v2
+
+[![Build Status](https://travis-ci.org/m6w6/ext-http.svg?branch=master)](https://travis-ci.org/m6w6/ext-http)
+
+## About:
+
+Extended HTTP support. Again. 
+
+* Introduces the http namespace.
+* PHP stream based message bodies.
+* Encapsulated env request/response.
+* Modular client support.
+
+## Installation:
+
+This extension is hosted at [PECL](http://pecl.php.net) and can be installed with [PEAR](http://pear.php.net)'s pecl command:
+
+    # pecl install pecl_http
+
+## Dependencies:
+
+pecl/http depends on a number of system libraries and PHP extensions for special features.
+
+#### Required system libraries:
+
+The following system libraries are required to build this extension:
+
+##### zlib
+Provides gzip/zlib/deflate encoding.  
+Minimum version: 1.2.0.4  
+Install on Debian: `apt-get install zlib1g-dev`
+
+
+#### Optional system libraries:
+
+The following system libraries are optional and provide additional features:
+
+##### libidn
+Provides IDNA support in URLs.  
+Minimum version: none  
+Install on Debian: `apt-get install libidn11-dev`
+
+##### libidn2
+Provides IDNA support in URLs (fallback if libidn is not available).  
+Minimum version: none  
+Install on Debian: `apt-get install libidn2-0-dev`
+
+##### libicu
+Provides IDNA support in URLs (fallback if libidn is not available).  
+Minimum version: none  
+Install on Debian: `apt-get install libicu-dev`
+
+##### libcurl
+Provides HTTP request functionality.  
+Minimum version: 7.18.2  
+Install on Debian: `apt-get install libcurl4-openssl-dev`  
+Note: There are usually different styles of SSL support for libcurl available, so you can replace 'openssl' in the above command f.e. with 'nss' or 'gnutls'.
+
+##### libevent
+Eventloop support for the HTTP client.  
+Minimum version: none  
+Install on Debian: `apt-get install libevent-dev`
+
+### PHP extensions:
+
+This extension unconditionally depends on the pre-loaded presence of the following PHP extensions:
+
+* [raphf](https://github.com/m6w6/ext-raphf)
+* [propro](https://github.com/m6w6/ext-propro)
+* spl
+
+
+If configured ```--with-http-shared-deps``` (default) it depends on the pre-loaded presence of the following extensions, as long as they were available at build time:
+
+* hash
+* iconv
+* json (only until < 2.4.0)
+
+Please ensure that all extension on which pecl/http depends, are loaded before it, e.g in your `php.ini`:
+
+       ; obligatory deps
+       extension = raphf.so
+       extension = propro.so
+       
+       ; if shared deps were enabled
+       extension = hash.so
+       extension = iconv.so
+       extension = json.so
+       
+       ; finally load pecl/http
+       extension = http.so
+
+## Conflicts:
+
+pecl/http-v2 conflicts with the following extensions:
+
+* http-v1
+* event (only until <= 2.0.3)
+
+## INI Directives:
+
+* http.etag.mode = "crc32b"  
+  Default hash method for dynamic response payloads to generate an ETag.
+
+## Stream Filters:
+
+The http extension registers the ```http.*``` namespace for its stream filters. Provided stream filters are:
+
+* http.chunked_decode  
+  Decode a stream encoded with chunked transfer encoding.
+* http.chunked_encode  
+  Encode a stream with chunked transfer encoding.
+* http.inflate  
+  Decode a stream encoded with deflate/zlib/gzip encoding.
+* http.deflate  
+  Encode a stream with deflate/zlib/gzip encoding.
+
+
+## Documentation:
+
+Documentation is available at https://mdref.m6w6.name/http
index b82a3a77a316234bf1767175314ab392ba71288a..c38107c01bc17f23b1b88a4989b1644b49c5fcd6 100644 (file)
@@ -93,6 +93,34 @@ if test "$PHP_HTTP" != "no"; then
                fi
        ])
        
+       dnl
+       dnl HTTP_CURL_SSL_LIB_CHECK(ssllib[, code-if-yes[, code-if-not])
+       dnl
+       AC_DEFUN([HTTP_CURL_SSL_LIB_CHECK], [
+               AC_MSG_CHECKING([for $1 support in libcurl])
+               AC_TRY_RUN([
+                       #include <curl/curl.h>
+                       int main(int argc, char *argv[]) {
+                               curl_version_info_data *data = curl_version_info(CURLVERSION_NOW);
+                               if (data && data->ssl_version && *data->ssl_version) {
+                                       const char *ptr = data->ssl_version;
+                                       while(*ptr == ' ') ++ptr;
+                                       return strncasecmp(ptr, "$1", sizeof("$1")-1);
+                               }
+                               return 1;
+                       }
+               ], [
+                       AC_MSG_RESULT([yes])
+                       $2
+               ], [
+                       AC_MSG_RESULT([no])
+                       $3
+               ], [
+                       AC_MSG_RESULT([no])
+                       $3
+               ])
+       ])
+       
 
 dnl ----
 dnl STDC
@@ -288,58 +316,33 @@ dnl ----
                                AC_MSG_RESULT([yes])
                                AC_DEFINE([PHP_HTTP_HAVE_SSL], [1], [ ])
                        
-                               AC_MSG_CHECKING([for openssl support in libcurl])
-                               AC_TRY_RUN([
-                                       #include <curl/curl.h>
-                                       int main(int argc, char *argv[]) {
-                                               curl_version_info_data *data = curl_version_info(CURLVERSION_NOW);
-                                               if (data && data->ssl_version && *data->ssl_version) {
-                                                       const char *ptr = data->ssl_version;
-                                                       while(*ptr == ' ') ++ptr;
-                                                       return strncasecmp(ptr, "OpenSSL", sizeof("OpenSSL")-1);
-                                               }
-                                               return 1;
-                                       }
-                               ], [
-                                       AC_MSG_RESULT([yes])
+                               HTTP_CURL_SSL_LIB_CHECK(OpenSSL, [
                                        AC_CHECK_HEADER([openssl/ssl.h], [
                                                AC_CHECK_HEADER([openssl/crypto.h], [
                                                        AC_DEFINE([PHP_HTTP_HAVE_OPENSSL], [1], [ ])
                                                        CURL_SSL_LIBS="ssl crypto"
                                                ])
                                        ])
-                               ], [
-                                       AC_MSG_RESULT([no])
-                               ], [
-                                       AC_MSG_RESULT([no])
                                ])
-                       
-                               AC_MSG_CHECKING([for gnutls support in libcurl])
-                               AC_TRY_RUN([
-                                       #include <curl/curl.h>
-                                       int main(int argc, char *argv[]) {
-                                               curl_version_info_data *data = curl_version_info(CURLVERSION_NOW);
-                                               if (data && data->ssl_version && *data->ssl_version) {
-                                                       const char *ptr = data->ssl_version;
-                                                       while(*ptr == ' ') ++ptr;
-                                                       return strncasecmp(ptr, "GnuTLS", sizeof("GnuTLS")-1);
-                                               }
-                                               return 1;
-                                       }
-                               ], [
-                                       AC_MSG_RESULT([yes])
+                               HTTP_CURL_SSL_LIB_CHECK(GnuTLS, [
                                        AC_CHECK_HEADER([gnutls.h], [
                                                AC_CHECK_HEADER([gcrypt.h], [
                                                        AC_DEFINE([PHP_HTTP_HAVE_GNUTLS], [1], [ ])
                                                        CURL_SSL_LIBS="gnutls gcrypt"
                                                ])
                                        ])
-                               ], [
-                                       AC_MSG_RESULT([no])
-                               ], [
-                                       AC_MSG_RESULT([no])
+                               ])
+                               HTTP_CURL_SSL_LIB_CHECK(NSS, [
+                                       AC_DEFINE([PHP_HTTP_HAVE_NSS], [1], [ ])
+                               ])
+                               HTTP_CURL_SSL_LIB_CHECK(SecureTransport, [
+                                       AC_DEFINE([PHP_HTTP_HAVE_DARWINSSL], [1], [ ])
+                               ])
+                               HTTP_CURL_SSL_LIB_CHECK(GSKit, [
+                                       AC_DEFINE([PHP_HTTP_HAVE_GSKIT], [1], [ ])
                                ])
                        else
+                               dnl no CURL_SSL
                                AC_MSG_RESULT([no])
                        fi
                        
diff --git a/gen_travis_yml.php b/gen_travis_yml.php
new file mode 100755 (executable)
index 0000000..89ab0b2
--- /dev/null
@@ -0,0 +1,45 @@
+#!/usr/bin/env php
+# autogenerated file; do not edit
+language: c
+
+addons:
+ apt:
+  packages:
+   - php5-cli
+   - php-pear
+   - libcurl4-openssl-dev
+   - zlib1g-dev
+   - libidn11-dev
+   - libevent-dev
+
+env:
+<?php
+
+$gen = include "./travis/pecl/gen-matrix.php";
+$env = $gen([
+       "PHP" => ["5.4", "5.5", "5.6"],
+       "enable_debug",
+       "enable_maintainer_zts",
+       "enable_json",
+       "enable_hash" => ["yes"],
+       "enable_iconv" => ["yes"]
+]);
+foreach ($env as $e) {
+       printf(" - %s\n", $e);
+}
+
+?>
+
+before_script:
+ - make -f travis/pecl/Makefile php
+ - make -f travis/pecl/Makefile pecl PECL=raphf
+ - make -f travis/pecl/Makefile pecl PECL=propro
+
+script:
+ - make -f travis/pecl/Makefile ext PECL=http
+ - make -f travis/pecl/Makefile test
+
+after_script:
+ - test -e tests/helper/server.log && cat tests/helper/server.log
+
+sudo: false
index cb530649b1e87a4a72318a8815373ed88d1f3b01..a4e84ced00cec07c97a0e44fdeecbff04d16914e 100644 (file)
@@ -528,10 +528,11 @@ static ZEND_RESULT_CODE php_http_curle_get_info(CURL *ch, HashTable *info)
                        case CURLSSLBACKEND_QSOSSL:
                                backend = "qsossl";
                                break;
-#endif
+#else
                        case CURLSSLBACKEND_GSKIT:
                                backend = "gskit";
                                break;
+#endif
                        case CURLSSLBACKEND_POLARSSL:
                                backend = "polarssl";
                                break;
@@ -554,7 +555,7 @@ static ZEND_RESULT_CODE php_http_curle_get_info(CURL *ch, HashTable *info)
        }
 #endif
 
-#if PHP_HTTP_CURL_VERSION(7,19,1) && defined(PHP_HTTP_HAVE_OPENSSL)
+#if (PHP_HTTP_CURL_VERSION(7,19,1) && defined(PHP_HTTP_HAVE_OPENSSL)) || (PHP_HTTP_CURL_VERSION(7,34,0) && defined(PHP_HTTP_HAVE_NSS)) || (PHP_HTTP_CURL_VERSION(7,42,0) && defined(PHP_HTTP_HAVE_GNUTLS)) || (PHP_HTTP_CURL_VERSION(7,39,0) && defined(PHP_HTTP_HAVE_GSKIT))
        {
                int i;
                zval ci_array, subarray;
@@ -1249,6 +1250,11 @@ static void php_http_curle_options_init(php_http_options_t *registry)
                opt->setter = php_http_curle_option_set_proxyheader;
        }
 #endif
+#if PHP_HTTP_CURL_VERSION(7,43,0)
+       if ((opt = php_http_option_register(registry, ZEND_STRL("proxy_service_name"), CURLOPT_PROXY_SERVICE_NAME, IS_STRING))) {
+               opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
+       }
+#endif
 
 #if PHP_HTTP_CURL_VERSION(7,40,0)
        if ((opt = php_http_option_register(registry, ZEND_STRL("unix_socket_path"), CURLOPT_UNIX_SOCKET_PATH, IS_STRING))) {
@@ -1325,6 +1331,11 @@ static void php_http_curle_options_init(php_http_options_t *registry)
        if ((opt = php_http_option_register(registry, ZEND_STRL("httpauthtype"), CURLOPT_HTTPAUTH, IS_LONG))) {
                Z_LVAL(opt->defval) = CURLAUTH_ANYSAFE;
        }
+#if PHP_HTTP_CURL_VERSION(7,43,0)
+       if ((opt = php_http_option_register(registry, ZEND_STRL("service_name"), CURLOPT_SERVICE_NAME, IS_STRING))) {
+               opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
+       }
+#endif
 
        /* redirects */
        if ((opt = php_http_option_register(registry, ZEND_STRL("redirect"), CURLOPT_FOLLOWLOCATION, IS_LONG))) {
@@ -1503,8 +1514,10 @@ static void php_http_curle_options_init(php_http_options_t *registry)
                }
 #      endif
 #endif
-#if PHP_HTTP_CURL_VERSION(7,19,1) && defined(PHP_HTTP_HAVE_OPENSSL)
-               php_http_option_register(registry, ZEND_STRL("certinfo"), CURLOPT_CERTINFO, _IS_BOOL);
+#if (PHP_HTTP_CURL_VERSION(7,19,1) && defined(PHP_HTTP_HAVE_OPENSSL)) || (PHP_HTTP_CURL_VERSION(7,34,0) && defined(PHP_HTTP_HAVE_NSS)) || (PHP_HTTP_CURL_VERSION(7,42,0) && defined(PHP_HTTP_HAVE_GNUTLS)) || (PHP_HTTP_CURL_VERSION(7,39,0) && defined(PHP_HTTP_HAVE_GSKIT))
+               if ((opt = php_http_option_register(registry, ZEND_STRL("certinfo"), CURLOPT_CERTINFO, _IS_BOOL))) {
+                       ZVAL_FALSE(&opt->defval);
+               }
 #endif
 #if PHP_HTTP_CURL_VERSION(7,36,0)
                if ((opt = php_http_option_register(registry, ZEND_STRL("enable_npn"), CURLOPT_SSL_ENABLE_NPN, _IS_BOOL))) {
@@ -1530,6 +1543,9 @@ static void php_http_curle_options_init(php_http_options_t *registry)
                if ((opt = php_http_option_register(registry, ZEND_STRL("tlsauthpass"), CURLOPT_TLSAUTH_PASSWORD, IS_STRING))) {
                        opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
                }
+#endif
+#if PHP_HTTP_CURL_VERSION(7,42,0) && (defined(PHP_HTTP_HAVE_NSS) || defined(PHP_HTTP_HAVE_DARWINSSL))
+               php_http_option_register(registry, ZEND_STRL("falsestart"), CURLOPT_SSL_FALSESTART, _IS_BOOL);
 #endif
        }
 }
index 5f1d130dfb0081290fc42897480f3c116bd747df..0ee68f464ade730199dc260857d70c221072bc61 100644 (file)
@@ -166,6 +166,7 @@ static PHP_METHOD(HttpEnvRequest, __construct)
                zval *this_ptr = getThis(); \
                zval qs_tmp, *qs = zend_read_property(Z_OBJCE_P(this_ptr), this_ptr, ZEND_STRL(prop), 0, &qs_tmp); \
                 \
+               ZVAL_NULL(&rv); \
                array_init(&mn); \
                Z_TRY_ADDREF_P(qs); \
                add_next_index_zval(&mn, qs); \
index e1ebe12cf503cc284e11e0ae9bd5315c14517887..5dfaeddfe8c9067c2a6393d82ed1a0d20b535d28 100644 (file)
@@ -141,11 +141,14 @@ php_http_header_parser_state_t php_http_header_parser_parse(php_http_header_pars
                                const char *colon, *eol_str = NULL;
                                int eol_len = 0;
 
+                               /* fix buffer here, so eol_str pointer doesn't become obsolete afterwards */
+                               php_http_buffer_fix(buffer);
+
                                if (buffer->data == (eol_str = php_http_locate_bin_eol(buffer->data, buffer->used, &eol_len))) {
                                        /* end of headers */
                                        php_http_buffer_cut(buffer, 0, eol_len);
                                        php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_DONE);
-                               } else if (php_http_info_parse(&parser->info, php_http_buffer_fix(buffer)->data)) {
+                               } else if (php_http_info_parse(&parser->info, buffer->data)) {
                                        /* new message starting with request/response line */
                                        if (callback_func) {
                                                callback_func(callback_arg, &headers, &parser->info);
@@ -171,7 +174,6 @@ php_http_header_parser_state_t php_http_header_parser_parse(php_http_header_pars
                                        php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_VALUE);
                                } else if (eol_str || (flags & PHP_HTTP_HEADER_PARSER_CLEANUP)) {
                                        /* neither reqeust/response line nor 'header:' string, or injected new line or NUL etc. */
-                                       php_http_buffer_fix(buffer);
                                        php_http_header_parser_error(strspn(buffer->data, PHP_HTTP_HEADER_NAME_CHARS), buffer->data, buffer->used, eol_str);
                                        return php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_FAILURE);
                                } else {
index 589b01506bd3e58db1d907584a2f834ef244c6e6..5f4eff81a9a101414d4ffed647fcc9ae6c9a4f12 100644 (file)
@@ -16,6 +16,9 @@
 #include <ext/spl/spl_array.h>
 
 #ifdef PHP_HTTP_HAVE_ICONV
+#      ifndef HAVE_ICONV
+#              define HAVE_ICONV 1
+#      endif
 #      undef PHP_ATOM_INC
 #      include <ext/iconv/php_iconv.h>
 #endif
index 2c5d3f48f86ae719a387335c319776ec59d83803..afe39bfe4511711cb5db2cff518c31e0f4e8952c 100644 (file)
@@ -1290,8 +1290,11 @@ static const char *parse_query(struct parse_state *state)
                        state->buffer[state->offset++] = *state->ptr;
                        break;
 
-               case ']':
-               case '[':
+               /* RFC1738 unsafe */
+               case '{': case '}':
+               case '<': case '>':
+               case '[': case ']':
+               case '|': case '\\': case '^': case '`': case '"': case ' ':
                        if (state->flags & PHP_HTTP_URL_PARSE_TOPCT) {
                                state->buffer[state->offset++] = '%';
                                state->buffer[state->offset++] = parse_xdigits[((unsigned char) *state->ptr) >> 4];
@@ -1362,6 +1365,19 @@ static const char *parse_fragment(struct parse_state *state)
                        state->buffer[state->offset++] = *state->ptr;
                        break;
 
+               /* RFC1738 unsafe */
+               case '{': case '}':
+               case '<': case '>':
+               case '[': case ']':
+               case '|': case '\\': case '^': case '`': case '"': case ' ':
+                       if (state->flags & PHP_HTTP_URL_PARSE_TOPCT) {
+                               state->buffer[state->offset++] = '%';
+                               state->buffer[state->offset++] = parse_xdigits[((unsigned char) *state->ptr) >> 4];
+                               state->buffer[state->offset++] = parse_xdigits[((unsigned char) *state->ptr) & 0xf];
+                               break;
+                       }
+                       /* no break */
+
                case '?': case '/':
                case '!': case '$': case '&': case '\'': case '(': case ')': case '*':
                case '+': case ',': case ';': case '=': /* sub-delims */
index 9666b976a618a6f297df56448ac70df54ae18c58..eea116a2082eba3dc5372b21daa9d4c4e959ebf0 100644 (file)
@@ -6,7 +6,7 @@ include "skipif.inc";
 skip_client_test();
 $client = new http\Client("curl");
 array_key_exists("proxyheader", $client->getAvailableOptions())
-       or die("skip need libcurl with CUTLOPT_PROXYHEADER support\n");
+       or die("skip need libcurl with CURLOPT_PROXYHEADER support\n");
 ?>
 --FILE--
 <?php
diff --git a/tests/gh-issue6.phpt b/tests/gh-issue6.phpt
new file mode 100644 (file)
index 0000000..3de34bd
--- /dev/null
@@ -0,0 +1,21 @@
+--TEST--
+url - unsafe characters
+--SKIPIF--
+<?php include "skipif.inc"; ?>
+--FILE--
+<?php 
+
+echo "Test\n";
+
+echo (new http\Url("?__utma=1152894289.1017686999.9107388726.1439222726.1494721726.1&__utmb=115739289.1.10.1437388726&__utmc=115883619&__utmx=-&__utmz=115111289.14310476.1.1.utmcsr=google|utmccn=(organic)|utmcmd=organic|utmctr=(not%20provided)&__utmv=-&__utmk=112678937"))->query;
+echo "\n";
+echo (new http\Url("?id={\$id}"))->query;
+echo "\n";
+
+?>
+===DONE===
+--EXPECT--
+Test
+__utma=1152894289.1017686999.9107388726.1439222726.1494721726.1&__utmb=115739289.1.10.1437388726&__utmc=115883619&__utmx=-&__utmz=115111289.14310476.1.1.utmcsr=google|utmccn=(organic)|utmcmd=organic|utmctr=(not%20provided)&__utmv=-&__utmk=112678937
+id={$id}
+===DONE===
diff --git a/tests/gh-issue7.phpt b/tests/gh-issue7.phpt
new file mode 100644 (file)
index 0000000..38e597c
--- /dev/null
@@ -0,0 +1,32 @@
+--TEST--
+crash with querystring and exception from error handler
+--SKIPIF--
+<?php include "skipif.inc"; ?>
+--GET--
+q[]=1&r[]=2
+--FILE--
+<?php 
+echo "Test\n";
+
+set_error_handler(function($c,$e) { throw new Exception($e); });
+
+try {
+       $q = http\QueryString::getGlobalInstance();
+       var_dump($q->get("q","s"));
+} catch (\Exception $e) {
+       echo $e->getMessage(),"\n";
+}
+try {
+       $r = new http\Env\Request;
+       var_dump($r->getQuery("r", "s"));
+} catch (\Exception $e) {
+       echo $e->getMessage(),"\n";
+}
+
+?>
+===DONE===
+--EXPECT--
+Test
+Array to string conversion
+Array to string conversion
+===DONE===
index b7175c109fac1b24d4f4a31e000e08cda288ae4d..a6b16999c373b3835396edd44f17e5e4428e554f 100644 (file)
@@ -10,17 +10,24 @@ function respond($client, $msg) {
 }
 
 serve(function($client) {
+       $R = array(STDIN); $W = $E = array();
+       if (!stream_select($R, $W, $E, 10, 0)) {
+               logger("Client %d timed out", (int) $client);
+               return;
+       }
        $count = trim(fgets(STDIN));
-       
+       logger("Expecting %d messages from client %d", $count, (int) $client);
        /* the peek message */
        respond($client, new http\Message($client, false));
-       
+       logger("Handled the peek request of client %d", (int) $client);
        /* pipelined messages */
        $req = array();
        for ($i=0; $i < $count; ++ $i) {
                $req[] = new http\Message($client, false);
+               logger("Read request no. %d from client %d", $i+1, (int) $client);
        }
-       foreach ($req as $msg) {
+       foreach ($req as $i => $msg) {
                respond($client, $msg);
+               logger("Sent response no. %d to client %d", $i+1, (int) $client);
        }
 });
index a13dc12027d89204d1d49192b0ea77bde57f4d23..091ff5cd483834d5c88d7e6304b42270bad9fe91 100644 (file)
@@ -1,5 +1,19 @@
 <?php
 
+ini_set("log_errors", true);
+ini_set("error_log", __DIR__."/server.log");
+
+function logger() {
+       if (!ini_get("date.timezone")) {
+               date_default_timezone_set(@date_default_timezone_get());
+       }
+       error_log(sprintf("%s(%s): %s", 
+               basename(getenv("SCRIPT_FILENAME"), ".php"), 
+               basename(current(get_included_files()), ".inc"), 
+               call_user_func_array("sprintf", func_get_args())
+       ));
+}
+
 $php = getenv('TEST_PHP_EXECUTABLE');
 if ($php) {
        define('PHP_BIN', $php);
@@ -28,20 +42,26 @@ function serve($cb) {
         */
        $offset = rand(0,2000);
        foreach (range(8000+$offset, 9000+$offset) as $port) {
+               logger("serve: Trying port %d", $port);
                if (($server = @stream_socket_server("tcp://localhost:$port"))) {
                        fprintf(STDERR, "%s\n", $port);
+                       logger("serve: Using port %d", $port);
                        do {
                                $R = array($server); $W = array(); $E = array();
-                               $select = stream_select($R, $E, $E, 0, 10000);
+                               $select = stream_select($R, $E, $E, 10, 0);
                                if ($select && ($client = stream_socket_accept($server, 1))) {
+                                       logger("serve: Accept client %d", (int) $client);
                                        if (getenv("PHP_HTTP_TEST_SSL")) {
                                                stream_socket_enable_crypto($client, true, STREAM_CRYPTO_METHOD_SSLv23_SERVER);
                                        }
                                        try {
                                                while (!feof($client)) {
+                                                       logger("serve: Handle client %d", (int) $client);
                                                        $cb($client);
                                                }
+                                               logger("serve: EOF on client %d", (int) $client);
                                        } catch (Exception $ex) {
+                                               logger("serve: Exception on client %d: %s", (int) $client, $ex->getMessage());
                                                /* ignore disconnect */
                                                if ($ex->getMessage() !== "Empty message received from stream") {
                                                        fprintf(STDERR, "%s\n", $ex);
@@ -49,7 +69,7 @@ function serve($cb) {
                                                break;
                                        }
                                }
-                       } while ($select !== false);
+                       } while ($select);
                        return;
                }
        }
@@ -123,4 +143,4 @@ function proc($bin, $args, $cb) {
                fpassthru($stderr);
                fpassthru($stdout);
        }
-}
\ No newline at end of file
+}
index e16f8dc97359741c01b5b2a07d4e4331acdc892e..573fdbd8a9ded3106f72c0a1f0f4ffdff8f038b1 100644 (file)
@@ -19,6 +19,11 @@ use http\env\Request as HttpEnvRequest;
 
 $m = new HttpEnvRequest();
 
+// travis' env headers have another order, wtf?
+$h = $m->getHeaders();
+ksort($h);
+$m->setHeaders($h);
+
 var_dump($m);
 
 echo "Message->toString\n";
@@ -50,14 +55,14 @@ object(%s)#%d (13) {
   string(3) "1.1"
   ["headers":protected]=>
   array(4) {
-    ["X-Test"]=>
-    string(4) "test"
     ["Content-Length"]=>
     string(1) "3"
     ["Content-Type"]=>
     string(14) "test/something"
     ["Cookie"]=>
     string(7) "foo=bar"
+    ["X-Test"]=>
+    string(4) "test"
   }
   ["parentMessage":protected]=>
   NULL
@@ -87,10 +92,10 @@ object(%s)#%d (13) {
 }
 Message->toString
 POST / HTTP/1.1%a
-X-Test: test%a
 Content-Length: 3%a
 Content-Type: test/something%a
 Cookie: foo=bar%a
+X-Test: test%a
 %a
 b=c
 Body->toString
diff --git a/travis/pecl b/travis/pecl
new file mode 160000 (submodule)
index 0000000..0815aa6
--- /dev/null
@@ -0,0 +1 @@
+Subproject commit 0815aa6d8727870e6bf8409700925abfaaf2b723