Merge pull request #74 from gbarosio/readme
authorMichael Wallner <mike@php.net>
Mon, 4 Feb 2019 13:37:10 +0000 (14:37 +0100)
committerGitHub <noreply@github.com>
Mon, 4 Feb 2019 13:37:10 +0000 (14:37 +0100)
Added the correct git url to the README.md fileE [ci skip]

71 files changed:
.gitignore
.travis.yml
autoconf/pecl/libbrotli.m4 [new file with mode: 0644]
autoconf/pecl/libevent.m4
autoconf/pecl/pecl.m4
config9.m4
package.xml
php_http.h
scripts/coverity.sh
scripts/gen_curlinfo.php
scripts/gen_if_utf8.php [new file with mode: 0755]
scripts/gen_stubs.php
scripts/gen_switch_utf8.php [new file with mode: 0755]
scripts/gen_travis_yml.php
scripts/gen_utf8.php
src/php_http.c
src/php_http_api.h
src/php_http_buffer.c
src/php_http_buffer.h
src/php_http_client.c
src/php_http_client_curl.c
src/php_http_client_curl_user.c
src/php_http_client_request.c
src/php_http_encoding.c
src/php_http_encoding.h
src/php_http_encoding_brotli.c [new file with mode: 0644]
src/php_http_encoding_brotli.h [new file with mode: 0644]
src/php_http_encoding_zlib.c [new file with mode: 0644]
src/php_http_encoding_zlib.h [new file with mode: 0644]
src/php_http_env_request.c
src/php_http_env_response.c
src/php_http_exception.h
src/php_http_filter.c
src/php_http_header.c
src/php_http_header_parser.c
src/php_http_header_parser.h
src/php_http_info.c
src/php_http_message.c
src/php_http_message_body.c
src/php_http_message_parser.c
src/php_http_message_parser.h
src/php_http_misc.c
src/php_http_misc.h
src/php_http_object.c
src/php_http_options.c
src/php_http_params.c
src/php_http_querystring.c
src/php_http_url.c
src/php_http_utf8.h
tests/bug66388.phpt
tests/client002.phpt
tests/client012.phpt
tests/client013.phpt
tests/client028.phpt
tests/encstream015.phpt [new file with mode: 0644]
tests/encstream016.phpt [new file with mode: 0644]
tests/encstream017.phpt [new file with mode: 0644]
tests/encstream018.phpt [new file with mode: 0644]
tests/encstream019.phpt [new file with mode: 0644]
tests/envresponse003.phpt
tests/filterbrotli.phpt [new file with mode: 0644]
tests/helper/server.inc
tests/propertyproxy001.phpt
tests/skipif.inc
tests/urlparser004.phpt
tests/urlparser006.phpt
tests/urlparser010.phpt
tests/urlparser012.phpt
tests/urlparser013.phpt
travis/brotli.sh [new file with mode: 0755]
travis/pecl

index 15cb267257c54706212926e479507a906c1161c2..95f72a28281acbb05db5529e90af406dc42cd6d3 100644 (file)
@@ -41,6 +41,7 @@ lcov_data
 *~
 *.phar
 !travis/*.phar
+bench/
 vendor/
 /php_http_api.h
 /php_http_buffer.h
@@ -53,6 +54,8 @@ vendor/
 /php_http_cookie.h
 /php_http_curl.h
 /php_http_encoding.h
+/php_http_encoding_zlib.h
+/php_http_encoding_brotli.h
 /php_http_env.h
 /php_http_env_request.h
 /php_http_env_response.h
@@ -76,4 +79,5 @@ vendor/
 /php_http_utf8.h
 /php_http_version.h
 /tests/helper/server.log
-*.gcov
+*gcov
+*lcov
index 5524d3027534d27be1ce35d58ea569534004cb6d..b1ef3281864fa1ceca44c0031b7f51d9912fdd32 100644 (file)
@@ -1,6 +1,6 @@
 # autogenerated file; do not edit
 language: c
-sudo: required
+sudo: false
 dist: trusty
 
 addons:
@@ -14,68 +14,48 @@ addons:
    - libicu-dev
    - libevent-dev
 
+compiler:
+ - gcc
+ - clang
+
+cache:
+ directories:
+  - $HOME/cache
+before_cache:
+ - find $HOME/cache -name '*.gcda' -o -name '*.gcno' -delete
+
 env:
- - PHP=7.0 enable_debug=no enable_maintainer_zts=no enable_json=no enable_hash=yes enable_iconv=yes with_http_libicu_dir=no
- - PHP=7.1 enable_debug=no enable_maintainer_zts=no enable_json=no enable_hash=yes enable_iconv=yes with_http_libicu_dir=no
- - PHP=master enable_debug=no enable_maintainer_zts=no enable_json=no enable_hash=yes enable_iconv=yes with_http_libicu_dir=no
- - PHP=7.0 enable_debug=yes enable_maintainer_zts=no enable_json=no enable_hash=yes enable_iconv=yes with_http_libicu_dir=no
- - PHP=7.1 enable_debug=yes enable_maintainer_zts=no enable_json=no enable_hash=yes enable_iconv=yes with_http_libicu_dir=no
- - PHP=master enable_debug=yes enable_maintainer_zts=no enable_json=no enable_hash=yes enable_iconv=yes with_http_libicu_dir=no
- - PHP=7.0 enable_debug=no enable_maintainer_zts=yes enable_json=no enable_hash=yes enable_iconv=yes with_http_libicu_dir=no
- - PHP=7.1 enable_debug=no enable_maintainer_zts=yes enable_json=no enable_hash=yes enable_iconv=yes with_http_libicu_dir=no
- - PHP=master enable_debug=no enable_maintainer_zts=yes enable_json=no enable_hash=yes enable_iconv=yes with_http_libicu_dir=no
- - PHP=7.0 enable_debug=yes enable_maintainer_zts=yes enable_json=no enable_hash=yes enable_iconv=yes with_http_libicu_dir=no
- - PHP=7.1 enable_debug=yes enable_maintainer_zts=yes enable_json=no enable_hash=yes enable_iconv=yes with_http_libicu_dir=no
- - PHP=master enable_debug=yes enable_maintainer_zts=yes enable_json=no enable_hash=yes enable_iconv=yes with_http_libicu_dir=no
- - PHP=7.0 enable_debug=no enable_maintainer_zts=no enable_json=yes enable_hash=yes enable_iconv=yes with_http_libicu_dir=no
- - PHP=7.1 enable_debug=no enable_maintainer_zts=no enable_json=yes enable_hash=yes enable_iconv=yes with_http_libicu_dir=no
- - PHP=master enable_debug=no enable_maintainer_zts=no enable_json=yes enable_hash=yes enable_iconv=yes with_http_libicu_dir=no
- - PHP=7.0 enable_debug=yes enable_maintainer_zts=no enable_json=yes enable_hash=yes enable_iconv=yes with_http_libicu_dir=no
- - PHP=7.1 enable_debug=yes enable_maintainer_zts=no enable_json=yes enable_hash=yes enable_iconv=yes with_http_libicu_dir=no
- - PHP=master enable_debug=yes enable_maintainer_zts=no enable_json=yes enable_hash=yes enable_iconv=yes with_http_libicu_dir=no
- - PHP=7.0 enable_debug=no enable_maintainer_zts=yes enable_json=yes enable_hash=yes enable_iconv=yes with_http_libicu_dir=no
- - PHP=7.1 enable_debug=no enable_maintainer_zts=yes enable_json=yes enable_hash=yes enable_iconv=yes with_http_libicu_dir=no
- - PHP=master enable_debug=no enable_maintainer_zts=yes enable_json=yes enable_hash=yes enable_iconv=yes with_http_libicu_dir=no
- - PHP=7.0 enable_debug=yes enable_maintainer_zts=yes enable_json=yes enable_hash=yes enable_iconv=yes with_http_libicu_dir=no
- - PHP=7.1 enable_debug=yes enable_maintainer_zts=yes enable_json=yes enable_hash=yes enable_iconv=yes with_http_libicu_dir=no
- - PHP=master enable_debug=yes enable_maintainer_zts=yes enable_json=yes enable_hash=yes enable_iconv=yes with_http_libicu_dir=no
- - PHP=7.0 enable_debug=no enable_maintainer_zts=no enable_json=no enable_hash=yes enable_iconv=yes with_http_libicu_dir=yes
- - PHP=7.1 enable_debug=no enable_maintainer_zts=no enable_json=no enable_hash=yes enable_iconv=yes with_http_libicu_dir=yes
- - PHP=master enable_debug=no enable_maintainer_zts=no enable_json=no enable_hash=yes enable_iconv=yes with_http_libicu_dir=yes
- - PHP=7.0 enable_debug=yes enable_maintainer_zts=no enable_json=no enable_hash=yes enable_iconv=yes with_http_libicu_dir=yes
- - PHP=7.1 enable_debug=yes enable_maintainer_zts=no enable_json=no enable_hash=yes enable_iconv=yes with_http_libicu_dir=yes
- - PHP=master enable_debug=yes enable_maintainer_zts=no enable_json=no enable_hash=yes enable_iconv=yes with_http_libicu_dir=yes
- - PHP=7.0 enable_debug=no enable_maintainer_zts=yes enable_json=no enable_hash=yes enable_iconv=yes with_http_libicu_dir=yes
- - PHP=7.1 enable_debug=no enable_maintainer_zts=yes enable_json=no enable_hash=yes enable_iconv=yes with_http_libicu_dir=yes
- - PHP=master enable_debug=no enable_maintainer_zts=yes enable_json=no enable_hash=yes enable_iconv=yes with_http_libicu_dir=yes
- - PHP=7.0 enable_debug=yes enable_maintainer_zts=yes enable_json=no enable_hash=yes enable_iconv=yes with_http_libicu_dir=yes
- - PHP=7.1 enable_debug=yes enable_maintainer_zts=yes enable_json=no enable_hash=yes enable_iconv=yes with_http_libicu_dir=yes
- - PHP=master enable_debug=yes enable_maintainer_zts=yes enable_json=no enable_hash=yes enable_iconv=yes with_http_libicu_dir=yes
- - PHP=7.0 enable_debug=no enable_maintainer_zts=no enable_json=yes enable_hash=yes enable_iconv=yes with_http_libicu_dir=yes
- - PHP=7.1 enable_debug=no enable_maintainer_zts=no enable_json=yes enable_hash=yes enable_iconv=yes with_http_libicu_dir=yes
- - PHP=master enable_debug=no enable_maintainer_zts=no enable_json=yes enable_hash=yes enable_iconv=yes with_http_libicu_dir=yes
- - PHP=7.0 enable_debug=yes enable_maintainer_zts=no enable_json=yes enable_hash=yes enable_iconv=yes with_http_libicu_dir=yes
- - PHP=7.1 enable_debug=yes enable_maintainer_zts=no enable_json=yes enable_hash=yes enable_iconv=yes with_http_libicu_dir=yes
- - PHP=master enable_debug=yes enable_maintainer_zts=no enable_json=yes enable_hash=yes enable_iconv=yes with_http_libicu_dir=yes
- - PHP=7.0 enable_debug=no enable_maintainer_zts=yes enable_json=yes enable_hash=yes enable_iconv=yes with_http_libicu_dir=yes
- - PHP=7.1 enable_debug=no enable_maintainer_zts=yes enable_json=yes enable_hash=yes enable_iconv=yes with_http_libicu_dir=yes
- - PHP=master enable_debug=no enable_maintainer_zts=yes enable_json=yes enable_hash=yes enable_iconv=yes with_http_libicu_dir=yes
- - PHP=7.0 enable_debug=yes enable_maintainer_zts=yes enable_json=yes enable_hash=yes enable_iconv=yes with_http_libicu_dir=yes
- - PHP=7.1 enable_debug=yes enable_maintainer_zts=yes enable_json=yes enable_hash=yes enable_iconv=yes with_http_libicu_dir=yes
- - PHP=master enable_debug=yes enable_maintainer_zts=yes enable_json=yes enable_hash=yes enable_iconv=yes with_http_libicu_dir=yes
-# once with gcov
- - CFLAGS="-O0 -g --coverage" CXXFLAGS="-O0 -g --coverage" PHP=master enable_json=yes enable_hash=yes enable_iconv=yes 
+ - PHP=7.0 enable_debug=yes enable_maintainer_zts=yes enable_json=yes enable_hash=yes enable_iconv=yes with_http_libbrotli_dir=/home/travis/brotli
+ - PHP=7.1 enable_debug=yes enable_maintainer_zts=yes enable_json=yes enable_hash=yes enable_iconv=yes with_http_libbrotli_dir=/home/travis/brotli
+ - PHP=7.3 enable_debug=yes enable_maintainer_zts=yes enable_json=yes enable_hash=yes enable_iconv=yes with_http_libbrotli_dir=/home/travis/brotli
+ - PHP=master enable_debug=yes enable_maintainer_zts=yes enable_json=yes enable_hash=yes enable_iconv=yes with_http_libbrotli_dir=/home/travis/brotli
+ - PHP=7.2 with_http_libicu_dir=no with_http_libidn_dir=no with_http_libidn2_dir=no with_http_libcurl_dir=no with_http_libevent_dir=no
+ - PHP=7.2 enable_debug=no enable_maintainer_zts=no enable_json=yes enable_hash=yes enable_iconv=yes with_http_libbrotli_dir=/home/travis/brotli
+ - PHP=7.2 enable_debug=yes enable_maintainer_zts=no enable_json=yes enable_hash=yes enable_iconv=yes with_http_libbrotli_dir=/home/travis/brotli
+ - PHP=7.2 enable_debug=no enable_maintainer_zts=yes enable_json=yes enable_hash=yes enable_iconv=yes with_http_libbrotli_dir=/home/travis/brotli
+ - PHP=7.2 enable_debug=yes enable_maintainer_zts=yes enable_json=yes enable_hash=yes enable_iconv=yes with_http_libbrotli_dir=/home/travis/brotli
+ - CFLAGS='-O0 -g --coverage' CXXFLAGS='-O0 -g --coverage' PHP=7.2 enable_json=yes enable_hash=yes enable_iconv=yes with_http_libbrotli_dir=/home/travis/brotli with_http_libicu_dir=yes with_http_libidn_dir=no with_http_libidn2_dir=no 
+ - CFLAGS='-O0 -g --coverage' CXXFLAGS='-O0 -g --coverage' PHP=7.2 enable_json=yes enable_hash=yes enable_iconv=yes with_http_libbrotli_dir=/home/travis/brotli with_http_libidn_dir=yes with_http_libicu_dir=no with_http_libidn2_dir=no 
+ - CFLAGS='-O0 -g --coverage' CXXFLAGS='-O0 -g --coverage' PHP=7.2 enable_json=yes enable_hash=yes enable_iconv=yes with_http_libbrotli_dir=/home/travis/brotli with_http_libidn2_dir=yes with_http_libicu_dir=no with_http_libidn_dir=no 
 
-before_script:
- - make -f travis/pecl/Makefile php
- - make -f travis/pecl/Makefile pecl PECL=raphf:raphf:2.0.0
- - make -f travis/pecl/Makefile pecl PECL=propro:propro:2.0.1
- - make -f travis/pecl/Makefile ext PECL=http
+install:
+ - ./travis/brotli.sh v1.0.2
+ - |
+   if test "$PHP" = master; then \
+     make -f travis/pecl/Makefile reconf; \
+     make -f travis/pecl/Makefile pecl-rm pecl-clean PECL=ext-raphf.git:raphf:master; \
+     make -f travis/pecl/Makefile pecl-rm pecl-clean PECL=ext-propro.git:propro:master; \
+   fi
+ - make -f travis/pecl/Makefile php || make -f travis/pecl/Makefile clean php
+ - make -f travis/pecl/Makefile pecl PECL=ext-raphf.git:raphf:master
+ - make -f travis/pecl/Makefile pecl PECL=ext-propro.git:propro:master
 
 script:
+ - make -f travis/pecl/Makefile ext PECL=http
  - make -f travis/pecl/Makefile test
- - make -f travis/pecl/Makefile cppcheck
 
+after_script:
+ - make -f travis/pecl/Makefile cppcheck
 after_failure:
  - test -e tests/helper/server.log && cat tests/helper/server.log
 after_success:
diff --git a/autoconf/pecl/libbrotli.m4 b/autoconf/pecl/libbrotli.m4
new file mode 100644 (file)
index 0000000..f8916e2
--- /dev/null
@@ -0,0 +1,47 @@
+
+AC_DEFUN([PECL_CHECK_LIBBROTLI], [
+       PECL_CHECK_LIBBROTLI_COMMON([$1], [$2])
+       PECL_CHECK_DONE(libbrotlicommon, [$PECL_VAR([HAVE_LIBBROTLI_COMMON])])
+       PECL_CHECK_LIBBROTLI_DEC([$1], [$2])
+       PECL_CHECK_DONE(libbrotlidec, [$PECL_VAR([HAVE_LIBBROTLI_DEC])])
+       PECL_CHECK_LIBBROTLI_ENC([$1], [$2])
+       PECL_CHECK_DONE(libbrotlienc, [$PECL_VAR([HAVE_LIBBROTLI_ENC])])
+       
+       if $PECL_VAR([HAVE_LIBBROTLI_COMMON]) \
+       && $PECL_VAR([HAVE_LIBBROTLI_DEC]) \
+       && $PECL_VAR([HAVE_LIBBROTLI_ENC]); then
+               PECL_VAR([HAVE_LIBBROTLI])=true
+       else
+               PECL_VAR([HAVE_LIBBROTLI])=false
+       fi
+])
+
+AC_DEFUN([PECL_CHECK_LIBBROTLI_COMMON], [
+       PECL_CHECK_PKGCONFIG(libbrotlicommon, [$1])
+       
+       PECL_HAVE_VERSION(libbrotlicommon, ifelse($2,,1.0,$2), [
+               PECL_VAR([HAVE_LIBBROTLI_COMMON])=true
+       ], [
+               PECL_VAR([HAVE_LIBBROTLI_COMMON])=false
+       ])
+])
+
+AC_DEFUN([PECL_CHECK_LIBBROTLI_DEC], [
+       PECL_CHECK_PKGCONFIG(libbrotlidec, [$1])
+       
+       PECL_HAVE_VERSION(libbrotlidec, ifelse($2,,1.0,$2), [
+               PECL_VAR([HAVE_LIBBROTLI_DEC])=true
+       ], [
+               PECL_VAR([HAVE_LIBBROTLI_DEC])=false
+       ])
+])
+
+AC_DEFUN([PECL_CHECK_LIBBROTLI_ENC], [
+       PECL_CHECK_PKGCONFIG(libbrotlienc, [$1])
+       
+       PECL_HAVE_VERSION(libbrotlienc, ifelse($2,,1.0,$2), [
+               PECL_VAR([HAVE_LIBBROTLI_ENC])=true
+       ], [
+               PECL_VAR([HAVE_LIBBROTLI_ENC])=false
+       ])
+])
index bd04296576380763faa179f7d66fe9995fd9b886..88d082dacfa662e40e5a68f5a47bf67fc1a441d2 100644 (file)
@@ -1,17 +1,19 @@
 
 AC_DEFUN([PECL_CHECK_LIBEVENT], [
        PECL_CHECK_PKGCONFIG(libevent, [$1])
-       PECL_HAVE_VERSION(libevent, 2.0, [
-               PECL_DEFINE([HAVE_LIBEVENT2])
-       ])
-       ifelse([$2],,,[PECL_HAVE_VERSION(libevent, [$2])])
-       AC_CHECK_FUNC(event_base_new,,[
-               AC_DEFINE([event_base_new], [event_init], [missing event_base_new() in libevent1])
-       ])
-       AC_CHECK_FUNC(event_assign,,[
-               AC_DEFINE([event_assign(e, b, s, a, cb, d)], [do {\
-                       event_set(e, s, a, cb, d); \
-                       event_base_set(b, e);\
-               } while(0)], [missing event_assign() in libevent1])
-       ])
+       if test -n "$PECL_CHECKED_VERSION(libevent)"; then
+               PECL_HAVE_VERSION(libevent, 2.0, [
+                       PECL_DEFINE([HAVE_LIBEVENT2])
+               ], [ ])
+               ifelse([$2],,,[PECL_HAVE_VERSION(libevent, [$2])])
+               AC_CHECK_FUNC(event_base_new,,[
+                       AC_DEFINE([event_base_new], [event_init], [missing event_base_new() in libevent1])
+               ])
+               AC_CHECK_FUNC(event_assign,,[
+                       AC_DEFINE([event_assign(e, b, s, a, cb, d)], [do {\
+                               event_set(e, s, a, cb, d); \
+                               event_base_set(b, e);\
+                       } while(0)], [missing event_assign() in libevent1])
+               ])
+       fi
 ])
\ No newline at end of file
index 6721e1c1455f68bf2d01c0bb0c173792aaa72f7e..1763d5d8d36f738eed00a9de5598e1631f9a8707 100644 (file)
@@ -221,7 +221,7 @@ AC_DEFUN([PECL_HAVE_VERSION], [
        aversion=_PECL_TR_VERSION([$PECL_CHECKED_VERSION([$1])])
        mversion=_PECL_TR_VERSION([$2])
        AC_MSG_CHECKING([whether $1 version $PECL_CHECKED_VERSION([$1]) >= $2])
-       if test "$aversion" -lt "$mversion"; then
+       if test -z "$aversion" || test "$aversion" -lt "$mversion"; then
                ifelse($4,,AC_MSG_ERROR([no]), [
                        AC_MSG_RESULT([no])
                        $4
@@ -332,8 +332,16 @@ dnl PECL_CHECK_PKGCONFIG(pkg[, additional-pkg-config-path])
 dnl
 AC_DEFUN([PECL_CHECK_PKGCONFIG], [dnl
        AC_REQUIRE([PECL_PROG_PKGCONFIG])dnl
-       ifelse($2,,,PKG_CONFIG_PATH="$2/lib/pkgconfig:$PKG_CONFIG_PATH")
+       ifelse($2,,, [
+               PECL_SAVE_VAR(pkgconfig_path)="$PKG_CONFIG_PATH"
+               if test -d "$2"; then
+                       export PKG_CONFIG_PATH="$2/lib/pkgconfig:$PKG_CONFIG_PATH"
+               fi
+       ])
        PECL_CHECK_CONFIG([$1], [$PKG_CONFIG $1], [--modversion], [--cflags-only-I], [--libs-only-L], [--libs-only-l])
+       ifelse($2,,, [
+               PKG_CONFIG_PATH="$PECL_SAVE_VAR(pkgconfig_path)"
+       ])
 ])
 dnl
 dnl PECL_CHECK_DONE(name, success[, incline, libline])
index dda5b015fe8bc0138a2ba0f3781628be373dd500..897b92ff94ef016e551a45fe8dabe1e2ec283500 100644 (file)
@@ -2,6 +2,7 @@
 m4_foreach(dir, [., ext/http], [
        sinclude(dir/autoconf/pecl/pecl.m4)
        sinclude(dir/autoconf/pecl/zlib.m4)
+       sinclude(dir/autoconf/pecl/libbrotli.m4)
        sinclude(dir/autoconf/pecl/libcurl.m4)
        sinclude(dir/autoconf/pecl/libevent.m4)
 ])
@@ -29,6 +30,12 @@ if test "$PHP_HTTP" != "no"; then
        [  --with-http-zlib-dir[=DIR]         HTTP: where to find zlib], $PHP_HTTP, no)
        PECL_CHECK_ZLIB([$PHP_HTTP_ZLIB_DIR], [1.2.0.4])
        PECL_CHECK_DONE(zlib, $PECL_VAR([HAVE_ZLIB]))
+       
+       dnl BROTLI
+       PHP_ARG_WITH([http-libbrotli-dir], [whether/where to check for libbrotli],
+       [  --with-http-libbrotli-dir[=DIR]    HTTP: where to find libbrotli], $PHP_HTTP, no)
+       PECL_CHECK_LIBBROTLI([$PHP_HTTP_LIBBROTLI_DIR], [1.0])
+       PECL_CHECK_DONE(libbrotli, $PECL_VAR([HAVE_LIBBROTLI]))
 
        dnl CURL
        PHP_ARG_WITH([http-libcurl-dir], [whether/where to check for libcurl],
index 0f109076fd1e2c9da690c2154b42bee3c6248ebc..046c82b679eeb7a49c101a94eaf34994a500b1d0 100644 (file)
@@ -31,10 +31,10 @@ https://mdref.m6w6.name/http
   <email>mike@php.net</email>
   <active>yes</active>
  </lead>
- <date>2017-04-04</date>
+ <date>2018-07-19</date>
  <version>
-  <release>3.1.1dev</release>
-  <api>3.1.0</api>
+  <release>3.2.1dev</release>
+  <api>3.2.0</api>
  </version>
  <stability>
   <release>stable</release>
@@ -42,7 +42,7 @@ https://mdref.m6w6.name/http
  </stability>
  <license uri="http://copyfree.org/content/standard/licenses/2bsd/license.txt">BSD-2-Clause</license>
  <notes><![CDATA[
-* Fix gh-issue #65: http\Client::enqueue(): Could not enqueue request: The easy handle is already added to a multi handle (@rcanavan, Mike)
+*
 ]]></notes>
  <contents>
   <dir name="/">
@@ -64,6 +64,7 @@ https://mdref.m6w6.name/http
    <dir name="autoconf">
     <dir name="pecl">
         <file role="src" name="pecl.m4"/>
+        <file role="src" name="libbrotli.m4"/>
         <file role="src" name="libcurl.m4"/>
         <file role="src" name="libevent.m4"/>
         <file role="src" name="zlib.m4"/>
@@ -92,6 +93,10 @@ https://mdref.m6w6.name/http
     <file role="src" name="php_http_curl.h"/>
     <file role="src" name="php_http_encoding.c"/>
     <file role="src" name="php_http_encoding.h"/>
+    <file role="src" name="php_http_encoding_zlib.c"/>
+    <file role="src" name="php_http_encoding_zlib.h"/>
+    <file role="src" name="php_http_encoding_brotli.c"/>
+    <file role="src" name="php_http_encoding_brotli.h"/>
     <file role="src" name="php_http_env.c"/>
     <file role="src" name="php_http_env.h"/>
     <file role="src" name="php_http_env_request.c"/>
@@ -228,6 +233,11 @@ https://mdref.m6w6.name/http
      <file role="test" name="encstream007.phpt"/>
      <file role="test" name="encstream008.phpt"/>
      <file role="test" name="encstream009.phpt"/>
+     <file role="test" name="encstream015.phpt"/>
+     <file role="test" name="encstream016.phpt"/>
+     <file role="test" name="encstream017.phpt"/>
+     <file role="test" name="encstream018.phpt"/>
+     <file role="test" name="encstream019.phpt"/>
      <file role="test" name="envrequestbody001.phpt"/>
      <file role="test" name="envrequestcookie001.phpt"/>
      <file role="test" name="envrequestfiles001.phpt"/>
@@ -260,6 +270,7 @@ https://mdref.m6w6.name/http
      <file role="test" name="envresponseheader001.phpt"/>
      <file role="test" name="envresponseranges001.phpt"/>
      <file role="test" name="etag001.phpt"/>
+     <file role="test" name="filterbrotli.phpt"/>
      <file role="test" name="filterchunked.phpt"/>
      <file role="test" name="filterzlib.phpt"/>
      <file role="test" name="gh-issue6.phpt"/>
@@ -269,6 +280,7 @@ https://mdref.m6w6.name/http
      <file role="test" name="gh-issue47.phpt"/>
      <file role="test" name="gh-issue48.phpt"/>
      <file role="test" name="gh-issue50.phpt"/>
+     <file role="test" name="gh-issue63.phpt"/>
      <file role="test" name="header001.phpt"/>
      <file role="test" name="header002.phpt"/>
      <file role="test" name="header003.phpt"/>
@@ -332,6 +344,7 @@ https://mdref.m6w6.name/http
      <file role="test" name="phpinfo.phpt"/>
      <file role="test" name="propertyproxy001.phpt"/>
      <file role="test" name="querystring001.phpt"/>
+     <file role="test" name="querystring001_a.phpt"/>
      <file role="test" name="querystring002.phpt"/>
      <file role="test" name="querystring003.phpt"/>
      <file role="test" name="serialize001.phpt"/>
index 2cf0de72a3f4851aaeaa80c8a3914131bd8f3b33..f698f6410457b78a2770cd66d9454707a5b852de 100644 (file)
@@ -13,7 +13,7 @@
 #ifndef PHP_EXT_HTTP_H
 #define PHP_EXT_HTTP_H
 
-#define PHP_PECL_HTTP_VERSION "3.1.1dev"
+#define PHP_PECL_HTTP_VERSION "3.2.1dev"
 
 extern zend_module_entry http_module_entry;
 #define phpext_http_ptr &http_module_entry
index 08a04f1fbacccc32b78a6cae72eb42cef6080893..883fd26599c70fed3be7c31b9cd2c8127a74254e 100755 (executable)
@@ -17,9 +17,18 @@ phpize
 ./configure
 make clean
 
+
 $COVERITY_BIN --dir $COVERITY_BUILD_DIR/cov-int make -j8
 
+echo >&2
+echo -n "Submit results to scan.coverity.com? (y/N) " >&2
+read submit
+echo >&2
+
+if test "$submit" != "y"; then
+       exit
+fi
+
 pushd $COVERITY_BUILD_DIR
 tar -czf cov-int{.tgz,}
 popd
index 376a7e5e460e7674f13ea08a8a833befe8d3a6b8..9fae4cb8d78c6baee7873b89a7a491e1a3c1d22e 100755 (executable)
@@ -10,9 +10,9 @@ function failure() {
 
 function file_re($file, $pattern, $all = true) {
        static $path;
-       
+
        $path or $path = isset($_SERVER['argv'][1]) ? $_SERVER['argv'][1].'/include/curl/' : "/usr/local/include/curl/";
-       
+
        if ($content = file_get_contents($path . $file)) {
                if ($all) {
                        if (preg_match_all($pattern, $content, $matches, PREG_SET_ORDER)) {
@@ -35,7 +35,10 @@ $ifdefs = array(
     'PRIMARY_PORT' => 'PHP_HTTP_CURL_VERSION(7,21,0)',
     'LOCAL_PORT' => 'PHP_HTTP_CURL_VERSION(7,21,0)',
     'LOCAL_IP' => 'PHP_HTTP_CURL_VERSION(7,21,0)',
-       'HTTP_VERSION' => 'PHP_HTTP_CURL_VERSION(7,50,0)'
+       'HTTP_VERSION' => 'PHP_HTTP_CURL_VERSION(7,50,0)',
+       'PROXY_SSL_VERIFYRESULT' => 'PHP_HTTP_CURL_VERSION(7,52,0)',
+       'PROTOCOL' => 'PHP_HTTP_CURL_VERSION(7,52,0)',
+       'SCHEME' => 'PHP_HTTP_CURL_VERSION(7,52,0)',
 );
 $exclude = array(
        'ACTIVESOCKET',
@@ -58,19 +61,19 @@ $translate = array(
 );
 
 $templates = array(
-'STRING' => 
+'STRING' =>
 '      if (CURLE_OK == curl_easy_getinfo(ch, %s, &c)) {
                ZVAL_STRING(&tmp, STR_PTR(c));
                zend_hash_str_update(info, "%s", lenof("%2$s"), &tmp);
        }
 ',
-'DOUBLE' => 
+'DOUBLE' =>
 '      if (CURLE_OK == curl_easy_getinfo(ch, %s, &d)) {
                ZVAL_DOUBLE(&tmp, d);
                zend_hash_str_update(info, "%s", lenof("%2$s"), &tmp);
        }
 ',
-'LONG' => 
+'LONG' =>
 '      if (CURLE_OK == curl_easy_getinfo(ch, %s, &l)) {
                ZVAL_LONG(&tmp, l);
                zend_hash_str_update(info, "%s", lenof("%2$s"), &tmp);
@@ -101,7 +104,7 @@ foreach ($infos as $info) {
        if (isset($ifdefs[$short])) printf("#endif\n");
 }
 
-file_put_contents("src/php_http_client_curl.c", 
+file_put_contents("src/php_http_client_curl.c",
        preg_replace('/(\/\* BEGIN::CURLINFO \*\/\n).*(\n\s*\/\* END::CURLINFO \*\/)/s', '$1'. ob_get_contents() .'$2',
                file_get_contents("src/php_http_client_curl.c")));
 
diff --git a/scripts/gen_if_utf8.php b/scripts/gen_if_utf8.php
new file mode 100755 (executable)
index 0000000..720a5a9
--- /dev/null
@@ -0,0 +1,92 @@
+#!/usr/bin/env php
+<?php
+
+error_reporting(E_ALL);
+set_error_handler(function($c, $e, $f, $l) {
+       throw new Exception("$e in $f on line $l");
+});
+
+$i18n = $argc >= 2 ? $argv[1] : "/usr/share/i18n/locales/i18n";
+
+$f = fopen($i18n, "r");
+$c = false;
+$a = false;
+
+ob_start(null, 0xfffff);
+
+while (!feof($f)) {
+       $line = fgets($f);
+       if (!$c && $line !== "LC_CTYPE\n") {
+               continue;
+       }
+       $c = true;
+       if ($line === "END LC_CTYPE\n") {
+               break;
+       }
+       switch($line{0}) {
+       case "%":
+               break;
+       case "\n":
+               if ($a) {
+                       break 2;
+               }
+               break;
+       case " ":
+               if ($a) {
+                       foreach (explode(";", trim($line, "\n/ ;")) as $ranges) {
+                               $range = explode("..", $ranges);
+                               $step = 0;
+                               $end = 0;
+                               switch (count($range)) {
+                               case 3:
+                                       list($sstart, $sstep, $send) = $range;
+                                       sscanf($sstart, "<U%X>", $start);
+                                       sscanf($sstep, "(%d)", $step);
+                                       sscanf($send, "<U%X>", $end);
+
+                                       break;
+                               case 2:
+                                       list($sstart, $send) = $range;
+                                       $step = 1;
+                                       sscanf($sstart, "<U%X>", $start);
+                                       sscanf($send, "<U%X>", $end);
+                                       break;
+                               case 1:
+                                       list($sstart) = $range;
+                                       sscanf($sstart, "<U%X>", $start);
+                                       break;
+                               }
+                               $r[]=[$start,$end,$step];
+                       }
+               }
+               break;
+       default:
+               if ($a) {
+                       break 2;
+               } elseif ($line === "alpha /\n") {
+                       $a = true;
+               }
+               break;
+       }
+}
+function sp($sp, $ch = " ") { return str_repeat($ch, $sp); }
+$sp = 1;
+foreach ($r as list($start, $end, $step)) {
+       if ($end) {
+               if ($step > 1) {
+                       die("\nUNEXPECTED: step>1\n");
+                       printf("\tfor (i=0x%08X; i <= 0x%08X; i+= %d) { if (i == ch) return 1; }\n", $start, $end, $step);
+               } else {
+                       //printf(" if (ch >= 0x%08X && ch <= 0x%08X) return 1;\n", $start, $end);
+                       printf("%sif (ch >= 0x%08X) {\n", sp($sp), $start);
+                       printf("%sif (ch <= 0x%08X) return 1;\n", sp(++$sp), $end);
+               }
+       } else {
+               printf("%sif (ch == 0x%08X) return 1;\n", sp($sp), $start);
+       }
+}
+printf("  %s\n", sp($sp-1, "}"));
+
+file_put_contents("php_http_utf8.h",
+       preg_replace('/(\/\* BEGIN::UTF8SWITCH \*\/\n).*(\n\s*\/\* END::UTF8SWITCH \*\/)/s', '$1'. ob_get_contents() .'$2',
+               file_get_contents("php_http_utf8.h")));
index 20a1f0fdd853b35d459090e1a43f33a3e4d6cbf2..5f28545aec073d20b2a8668ffe3db95e1967134c 100755 (executable)
@@ -1,8 +1,11 @@
 #!/usr/bin/env php
 <?php
 
-function m($m) {
+function m($m, $c = null) {
        $n = "";
+       if ($c && $c->isInterface()) {
+               $m ^= ReflectionMethod::IS_ABSTRACT;
+       }
        foreach (Reflection::getModifierNames($m) as $mn) {
                $n .= $mn . " ";
        }
@@ -169,7 +172,7 @@ foreach ($namespaces as $ns) {
 
             foreach ($c->getMethods() as $m) {
                 if ($m->getDeclaringClass()->getName() == $c->getName()) {
-                    fprintf($out, "\t\t%sfunction %s(", m($m->getModifiers()), 
+                    fprintf($out, "\t\t%sfunction %s(", m($m->getModifiers(), $c), 
                             $m->getName());
                     $ps = array();
                     foreach ($m->getParameters() as $p) {
diff --git a/scripts/gen_switch_utf8.php b/scripts/gen_switch_utf8.php
new file mode 100755 (executable)
index 0000000..66a97c8
--- /dev/null
@@ -0,0 +1,152 @@
+#!/usr/bin/env php
+<?php
+
+error_reporting(E_ALL);
+set_error_handler(function($c, $e, $f, $l) {
+       throw new Exception("$e in $f on line $l");
+});
+
+$i18n = $argc >= 2 ? $argv[1] : "/usr/share/i18n/locales/i18n";
+
+$b = 10;
+$m = 0xfffff000 >> $b;
+$b2 = 8;
+$x = $m >> $b2;
+
+$f = fopen($i18n, "r");
+$c = false;
+$a = false;
+
+$ranges = $lables = $gotos = [];
+
+ob_start(null, 0xfffff);
+
+while (!feof($f)) {
+       $line = fgets($f);
+       if (!$c && $line !== "LC_CTYPE\n") {
+               continue;
+       }
+       $c = true;
+       if ($line === "END LC_CTYPE\n") {
+               break;
+       }
+       switch($line{0}) {
+       case "%":
+               break;
+       case "\n":
+               if ($a) {
+                       break 2;
+               }
+               break;
+       case " ":
+               if ($a) {
+                       foreach (explode(";", trim($line, "\n/ ;")) as $list) {
+                               $range = explode("..", $list);
+                               $step = 0;
+                               $end = 0;
+                               switch (count($range)) {
+                               case 3:
+                                       list($sstart, $sstep, $send) = $range;
+                                       sscanf($sstart, "<U%X>", $start);
+                                       sscanf($sstep, "(%d)", $step);
+                                       sscanf($send, "<U%X>", $end);
+
+                                       break;
+                               case 2:
+                                       list($sstart, $send) = $range;
+                                       $step = 1;
+                                       sscanf($sstart, "<U%X>", $start);
+                                       sscanf($send, "<U%X>", $end);
+                                       break;
+                               case 1:
+                                       list($sstart) = $range;
+                                       sscanf($sstart, "<U%X>", $start);
+                                       break;
+                               }
+                               $sw = $start >> $b;
+                               $sw2 = ($start & $m) >> $b2;
+                               if (isset($ranges[$sw][$sw2])) {
+                                       //$ranges[$sw][$sw2] = array_filter($ranges[$sw][$sw2]);
+                               }
+                               $ranges[$sw][$sw2][]=[$start,$end,$step];
+                               if ($end) {
+                                       $goto = $start;
+                               }
+                               while (($start += $step) <= $end) {
+                                       $ssw = $start >> $b;
+                                       $ssw2 = ($start & $m) >> $b2;
+                                       if (!isset($ranges[$ssw][$ssw2]) || null !== end($ranges[$ssw][$ssw2])) {
+                                               $ranges[$ssw][$ssw2][]=null;
+                                       }
+                                       if ($ssw != $sw || $ssw2 != $sw2) {
+                                               $gotos[$ssw][$ssw2] = $goto;
+                                               $labels[$sw][$sw2] = $goto;
+                                       }
+                               }
+                       }
+               }
+               break;
+       default:
+               if ($a) {
+                       break 2;
+               } elseif ($line === "alpha /\n") {
+                       $a = true;
+               }
+               break;
+       }
+}
+
+function sp($sp, $ch = " ") { return str_repeat($ch, $sp); }
+
+printf("switch (ch >> %d) {\n", $b);
+foreach ($ranges as $sw => $sws) {
+       printf("case 0x%08X:\n", $sw);
+       printf(" switch((ch & 0x%08X) >> %d) {\n", $m, $b2);
+       foreach ($sws as $sw2 => $specs) {
+               printf(" case 0x%08X:\n", $sw2);
+               $sp = 2;
+               $start = null;
+               foreach ($specs as $index => $spec) {
+                       if ($spec) {
+                               list($start, $end, $step) = $spec;
+                               if (isset($labels[$sw][$sw2])) {
+                                       $label = $labels[$sw][$sw2];
+                                       if ((!$end && $label == $start) || ($end && $label >= $start && $label <= $end)) {
+                                               printf("%sc_%08X:;\n", sp($sp), $label);
+                                       }
+                               }
+                               if ($end) {
+                                       if ($step > 1) {
+                                               die("\nUNEXPECTED: step>1\n");
+                                               printf("\tfor (i=0x%08X; i <= 0x%08X; i+= %d) { if (i == ch) return 1; }\n", $start, $end, $step);
+                                       } else {
+                                               printf("%sif (ch >= 0x%08X) {\n", sp($sp), $start);
+                                               printf("%sif (ch <= 0x%08X) return 1;\n", sp(++$sp), $end);
+                                       }
+                               } else {
+                                       printf("%sif (ch == 0x%08X) return 1;\n", sp($sp), $start);
+                               }                       
+                       } else {
+                               if (isset($gotos[$sw][$sw2]) && !$start) {
+                                       if (isset($specs[$index + 1])) {
+                                               list($next) = $specs[$index + 1];
+                                               printf("%sif (ch < 0x%08X)\n ", sp($sp), $next);
+                                       }
+                                       $goto = $gotos[$sw][$sw2];
+                                       printf("%sgoto c_%08X;\n", sp($sp), $goto);
+                                       $start = $goto;
+                               }
+                       }
+               }
+               if ($sp > 2) {
+                       printf("  %s\n", sp($sp-2, "}"));
+               }
+               printf("  break;\n");
+       }
+       printf(" }\n break;\n");
+}
+printf("}\n");
+
+file_put_contents("php_http_utf8.h",
+       preg_replace('/(\/\* BEGIN::UTF8SWITCH \*\/\n).*(\n\s*\/\* END::UTF8SWITCH \*\/)/s', '$1'. ob_get_contents() .'$2',
+               file_get_contents("php_http_utf8.h")));
index ff43cf063b88ed4f827130ec89c79df5b97e6acf..94713074a3d08d72158a227c0c5ecce3ce2df76e 100755 (executable)
@@ -1,7 +1,7 @@
 #!/usr/bin/env php
 # autogenerated file; do not edit
 language: c
-sudo: required
+sudo: false
 dist: trusty
 
 addons:
@@ -15,37 +15,88 @@ addons:
    - libicu-dev
    - libevent-dev
 
+compiler:
+ - gcc
+ - clang
+
+cache:
+ directories:
+  - $HOME/cache
+before_cache:
+ - find $HOME/cache -name '*.gcda' -o -name '*.gcno' -delete
+
 env:
 <?php
 
 $gen = include "./travis/pecl/gen-matrix.php";
+$cur = "7.2";
 $env = $gen([
-       "PHP" => ["7.0", "7.1", "master"],
+// most useful for all additional versions except current
+       "PHP" => ["7.0", "7.1", "7.3", "master"],
+       "enable_debug" => "yes",
+       "enable_maintainer_zts" => "yes",
+       "enable_json" => "yes",
+       "enable_hash" => "yes",
+       "enable_iconv" => "yes",
+       "with_http_libbrotli_dir" => "/home/travis/brotli"
+], [
+// everything disabled for current
+       "PHP" => $cur,
+       "with_http_libicu_dir" => "no",
+       "with_http_libidn_dir" => "no",
+       "with_http_libidn2_dir" => "no",
+       "with_http_libcurl_dir" => "no",
+       "with_http_libevent_dir" => "no",
+], [
+// everything enabled for current, switching on debug/zts
+       "PHP" => $cur,
        "enable_debug",
        "enable_maintainer_zts",
-       "enable_json",
-       "enable_hash" => ["yes"],
-       "enable_iconv" => ["yes"],
-       "with_http_libicu_dir",
+       "enable_json" => "yes",
+       "enable_hash" => "yes",
+       "enable_iconv" => "yes",
+       "with_http_libbrotli_dir" => "/home/travis/brotli",
+], [
+// once everything enabled for current, with coverage
+       "CFLAGS" => "'-O0 -g --coverage'",
+       "CXXFLAGS" => "'-O0 -g --coverage'",
+       "PHP" => $cur,
+       "enable_json" => "yes",
+       "enable_hash" => "yes",
+       "enable_iconv" => "yes",
+       "with_http_libbrotli_dir" => "/home/travis/brotli",
+       [
+               "with_http_libicu_dir",
+               "with_http_libidn_dir",
+               "with_http_libidn2_dir",
+       ],
 ]);
-foreach ($env as $e) {
-       printf(" - %s\n", $e);
+foreach ($env as $grp) {
+       foreach ($grp as $e) {
+               printf(" - %s\n", $e);
+       }
 }
 
 ?>
-# once with gcov
- - CFLAGS="-O0 -g --coverage" CXXFLAGS="-O0 -g --coverage" PHP=master enable_json=yes enable_hash=yes enable_iconv=yes 
 
-before_script:
- - make -f travis/pecl/Makefile php
- - make -f travis/pecl/Makefile pecl PECL=raphf:raphf:2.0.0
- - make -f travis/pecl/Makefile pecl PECL=propro:propro:2.0.1
- - make -f travis/pecl/Makefile ext PECL=http
+install:
+ - ./travis/brotli.sh v1.0.2
+ - |
+   if test "$PHP" = master; then \
+     make -f travis/pecl/Makefile reconf; \
+     make -f travis/pecl/Makefile pecl-rm pecl-clean PECL=ext-raphf.git:raphf:master; \
+     make -f travis/pecl/Makefile pecl-rm pecl-clean PECL=ext-propro.git:propro:master; \
+   fi
+ - make -f travis/pecl/Makefile php || make -f travis/pecl/Makefile clean php
+ - make -f travis/pecl/Makefile pecl PECL=ext-raphf.git:raphf:master
+ - make -f travis/pecl/Makefile pecl PECL=ext-propro.git:propro:master
 
 script:
+ - make -f travis/pecl/Makefile ext PECL=http
  - make -f travis/pecl/Makefile test
- - make -f travis/pecl/Makefile cppcheck
 
+after_script:
+ - make -f travis/pecl/Makefile cppcheck
 after_failure:
  - test -e tests/helper/server.log && cat tests/helper/server.log
 after_success:
index 865a2f5d5f4e92159e925e76bf4becfa783403e7..43b49e382fdc2c64c4dac5e216ec0453b6f2e7c2 100755 (executable)
@@ -11,6 +11,8 @@ $i18n = $argc >= 2 ? $argv[1] : "/usr/share/i18n/locales/i18n";
 $f = fopen($i18n, "r");
 $c = false;
 $a = false;
+$r = [];
+$n = [];
 
 ob_start(null, 0xffff);
 while (!feof($f)) {
@@ -55,23 +57,14 @@ while (!feof($f)) {
                                        sscanf($sstart, "<U%X>", $start);
                                        break;
                                }
-                               print "\t{";
-                               if ($start >= 0xffff) {
-                                       printf("0x%08X, ", $start);
-                                       if ($end) {
-                                               printf("0x%08X, ", $end);
-                                       } else {
-                                               print("         0, ");
+                               if ($end) {
+                                       if ($step != 1) {
+                                               die("UNEXPECTED step=$step\n");
                                        }
+                                       $r[] = [$start, $end];
                                } else {
-                                       printf("    0x%04X, ", $start);
-                                       if ($end) {
-                                               printf("    0x%04X, ", $end);
-                                       } else {
-                                               print("         0, ");
-                                       }
+                                       $n[] = $start;
                                }
-                               printf("%d},\n", $step);
                        }
                }
                break;
@@ -85,6 +78,29 @@ while (!feof($f)) {
        }
 }
 
+$maxstep = 0;
+printf("static const utf8_range_t utf8_ranges[] = {\n\t{");
+foreach ($r as $i => list($start, $end)) {
+       if ($i) if ($i%3) {
+               printf(", {");
+       } else {
+               printf(",\n\t{");
+       }
+               
+       printf("0x%08X, 0x%08X}", $start, $end);
+}
+printf("\n};\n\n");
+printf("static const unsigned utf8_chars[] = {\n\t");
+foreach ($n as $i => $u) {
+       if ($i) if (($i%6)) {
+               printf(", ");
+       } else {
+               printf(",\n\t");
+       }
+       printf("0x%08X", $u);
+}
+printf("\n};\n");
+
 file_put_contents("php_http_utf8.h",
        preg_replace('/(\/\* BEGIN::UTF8TABLE \*\/\n).*(\n\s*\/\* END::UTF8TABLE \*\/)/s', '$1'. ob_get_contents() .'$2',
                file_get_contents("php_http_utf8.h")));
index 207c248ae0f04a6831d50fc8c34bc732b94d9a7c..498a224be018b59e3282d7d5a2685309711940c4 100644 (file)
 #if PHP_HTTP_HAVE_LIBICU
 #      include <unicode/uversion.h>
 #endif
-#if PHP_HTTP_HAVE_LIBIDN2
-#      include <idn2.h>
-#endif
 #if PHP_HTTP_HAVE_LIBIDN
 #      include <idna.h>
 #endif
+#if PHP_HTTP_HAVE_LIBIDN2
+#      include <idn2.h>
+#endif
 #if PHP_HTTP_HAVE_LIBIDNKIT2 || PHP_HTTP_HAVE_LIBIDNKIT
 #include "idn/version.h"
 #endif
@@ -137,6 +137,10 @@ PHP_MINIT_FUNCTION(http)
        || SUCCESS != PHP_MINIT_CALL(http_exception)
        || SUCCESS != PHP_MINIT_CALL(http_cookie)
        || SUCCESS != PHP_MINIT_CALL(http_encoding)
+       || SUCCESS != PHP_MINIT_CALL(http_encoding_zlib)
+#if PHP_HTTP_HAVE_LIBBROTLI
+       || SUCCESS != PHP_MINIT_CALL(http_encoding_brotli)
+#endif
        || SUCCESS != PHP_MINIT_CALL(http_filter)
        || SUCCESS != PHP_MINIT_CALL(http_header)
        || SUCCESS != PHP_MINIT_CALL(http_header_parser)
index 4071f0fba949a6e935e3cc967f9425801718b64e..bca57f17141f6cf073fef9ee7e5acf1a21e83c69 100644 (file)
 #ifndef PHP_HTTP_API_H
 #define PHP_HTTP_API_H
 
+#ifdef __COVERITY_GCC_VERSION_AT_LEAST
+# define _Float128 float
+# define _Float64 float
+# define _Float32 float
+# define _Float64x float
+# define _Float32x float
+#endif
+
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
@@ -80,6 +88,8 @@
 #include "php_http.h"
 #include "php_http_cookie.h"
 #include "php_http_encoding.h"
+#include "php_http_encoding_zlib.h"
+#include "php_http_encoding_brotli.h"
 #include "php_http_info.h"
 #include "php_http_message.h"
 #include "php_http_env.h"
index d7cfd56c33b207364083a50036cb910398889b98..5913cfcd60bd0633fe603ad651ff25c8875ce521 100644 (file)
@@ -10,7 +10,7 @@
     +--------------------------------------------------------------------+
 */
 
-#include "php.h"
+#include "php_http_api.h"
 #include "php_http_buffer.h"
 
 PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_init_ex(
@@ -37,7 +37,7 @@ PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_from_string_ex(
 {
        int free_buf = !!buf;
 
-       if ((buf = php_http_buffer_init(buf))) {
+       if (EXPECTED(buf = php_http_buffer_init(buf))) {
                if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_append(buf, str, len)) {
                        if (free_buf) {
                                pefree(buf, buf->pmem);
@@ -59,7 +59,7 @@ PHP_HTTP_BUFFER_API size_t php_http_buffer_resize_ex(
        if (buf->free < len) {
                size_t size = override_size ? override_size : buf->size;
                
-               while ((size + buf->free) < len) {
+               while (UNEXPECTED((size + buf->free) < len)) {
                        size <<= 1;
                }
                
@@ -117,9 +117,11 @@ PHP_HTTP_BUFFER_API size_t php_http_buffer_append(php_http_buffer_t *buf,
        ) {
                return PHP_HTTP_BUFFER_NOMEM;
        }
-       memcpy(buf->data + buf->used, append, append_len);
-       buf->used += append_len;
-       buf->free -= append_len;
+       if (append_len) {
+               memcpy(buf->data + buf->used, append, append_len);
+               buf->used += append_len;
+               buf->free -= append_len;
+       }
        return append_len;
 }
 
@@ -147,7 +149,9 @@ PHP_HTTP_BUFFER_API char *php_http_buffer_data(const php_http_buffer_t *buf,
                char **into, size_t *len)
 {
        char *copy = ecalloc(1, buf->used + 1);
-       memcpy(copy, buf->data, buf->used);
+       if (buf->data) {
+               memcpy(copy, buf->data, buf->used);
+       }
        if (into) {
                *into = copy;
        }
@@ -300,7 +304,7 @@ PHP_HTTP_BUFFER_API size_t php_http_buffer_chunked_input(php_http_buffer_t **s,
        php_http_buffer_t *str;
        size_t passed;
 
-       if (!*s) {
+       if (UNEXPECTED(!*s)) {
                *s = php_http_buffer_init_ex(NULL, chunk_size,
                                chunk_size ? PHP_HTTP_BUFFER_INIT_PREALLOC : 0);
        }
index 818c4430e5ed891e0144f29bae080a8d1cedb3c9..6592ec408ce5ad5e3c02725e93dc2184febb4028 100644 (file)
@@ -24,7 +24,7 @@
 #ifndef PTR_FREE
 #      define PTR_FREE(PTR) \
        { \
-               if (PTR) { \
+               if (EXPECTED(PTR)) { \
                        efree(PTR); \
                } \
        }
index cedc239b68c1f780c2df5ef7b46b5bf74f448992..2f8b4aed62df35b79016a276930f21c4666b27b0 100644 (file)
@@ -689,7 +689,7 @@ static PHP_METHOD(HttpClient, enqueue)
        zend_fcall_info_cache fcc = empty_fcall_info_cache;
        php_http_client_object_t *obj;
        php_http_message_object_t *msg_obj;
-       php_http_client_enqueue_t q;
+       php_http_client_enqueue_t q = {0};
 
        php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O|f", &request, php_http_get_client_request_class_entry(), &fci, &fcc), invalid_arg, return);
 
@@ -701,6 +701,17 @@ static PHP_METHOD(HttpClient, enqueue)
                return;
        }
 
+       /* set early for progress callback */
+       q.opaque = msg_obj;
+
+       if (obj->client->callback.progress.func) {
+               php_http_client_progress_state_t progress = {0};
+
+               progress.info = "prepare";
+               obj->client->callback.progress.func(obj->client->callback.progress.arg, obj->client, &q, &progress);
+       }
+
+       Z_ADDREF_P(request);
        q.request = msg_obj->message;
        q.options = combined_options(getThis(), request);
        q.dtor = msg_queue_dtor;
@@ -711,12 +722,10 @@ static PHP_METHOD(HttpClient, enqueue)
        if (fci.size) {
                Z_TRY_ADDREF(fci.function_name);
                if (fci.object) {
-                       ++GC_REFCOUNT(fci.object);
+                       GC_ADDREF(fci.object);
                }
        }
 
-       Z_ADDREF_P(request);
-
        php_http_expect(SUCCESS == php_http_client_enqueue(obj->client, &q), runtime,
                        msg_queue_dtor(&q);
                        return;
@@ -781,7 +790,7 @@ static PHP_METHOD(HttpClient, requeue)
        if (fci.size) {
                Z_TRY_ADDREF(fci.function_name);
                if (fci.object) {
-                       ++GC_REFCOUNT(fci.object);
+                       GC_ADDREF(fci.object);
                }
        }
 
@@ -1305,7 +1314,7 @@ static PHP_METHOD(HttpClient, setDebug)
 }
 
 static zend_function_entry php_http_client_methods[] = {
-       PHP_ME(HttpClient, __construct,          ai_HttpClient_construct,            ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
+       PHP_ME(HttpClient, __construct,          ai_HttpClient_construct,            ZEND_ACC_PUBLIC)
        PHP_ME(HttpClient, reset,                ai_HttpClient_reset,                ZEND_ACC_PUBLIC)
        PHP_ME(HttpClient, enqueue,              ai_HttpClient_enqueue,              ZEND_ACC_PUBLIC)
        PHP_ME(HttpClient, dequeue,              ai_HttpClient_dequeue,              ZEND_ACC_PUBLIC)
index f07bb8f4abbcefa148b39b7a2d2a2b5ef718192f..1c84e3dde7940d50d62ea544d3016ad66b1129e9 100644 (file)
@@ -218,6 +218,7 @@ static int php_http_curle_raw_callback(CURL *ch, curl_infotype type, char *data,
        switch (type) {
                case CURLINFO_TEXT:
                        if (data[0] == '-') {
+                               goto text;
                        } else if (php_memnstr(data, ZEND_STRL("Adding handle:"), data + length)) {
                                h->progress.info = "setup";
                        } else if (php_memnstr(data, ZEND_STRL("addHandle"), data + length)) {
@@ -234,8 +235,16 @@ static int php_http_curle_raw_callback(CURL *ch, curl_infotype type, char *data,
                                h->progress.info = "connected";
                        } else if (php_memnstr(data, ZEND_STRL("blacklisted"), data + length)) {
                                h->progress.info = "blacklist check";
+                       } else if (php_memnstr(data, ZEND_STRL("TLS"), data + length)) {
+                               h->progress.info = "ssl negotiation";
                        } else if (php_memnstr(data, ZEND_STRL("SSL"), data + length)) {
                                h->progress.info = "ssl negotiation";
+                       } else if (php_memnstr(data, ZEND_STRL("certificate"), data + length)) {
+                               h->progress.info = "ssl negotiation";
+                       } else if (php_memnstr(data, ZEND_STRL("ALPN"), data + length)) {
+                               h->progress.info = "alpn";
+                       } else if (php_memnstr(data, ZEND_STRL("NPN"), data + length)) {
+                               h->progress.info = "npn";
                        } else if (php_memnstr(data, ZEND_STRL("upload"), data + length)) {
                                h->progress.info = "uploaded";
                        } else if (php_memnstr(data, ZEND_STRL("left intact"), data + length)) {
@@ -247,6 +256,7 @@ static int php_http_curle_raw_callback(CURL *ch, curl_infotype type, char *data,
                        } else if (php_memnstr(data, ZEND_STRL("Operation timed out"), data + length)) {
                                h->progress.info = "timeout";
                        } else {
+                               text:;
 #if 0
                                h->progress.info = data;
                                data[length - 1] = '\0';
@@ -480,6 +490,24 @@ static ZEND_RESULT_CODE php_http_curle_get_info(CURL *ch, HashTable *info)
                zend_hash_str_update(info, "http_version", lenof("http_version"), &tmp);
        }
 #endif
+#if PHP_HTTP_CURL_VERSION(7,52,0)
+       if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_PROXY_SSL_VERIFYRESULT, &l)) {
+               ZVAL_LONG(&tmp, l);
+               zend_hash_str_update(info, "proxy_ssl_verifyresult", lenof("proxy_ssl_verifyresult"), &tmp);
+       }
+#endif
+#if PHP_HTTP_CURL_VERSION(7,52,0)
+       if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_PROTOCOL, &l)) {
+               ZVAL_LONG(&tmp, l);
+               zend_hash_str_update(info, "protocol", lenof("protocol"), &tmp);
+       }
+#endif
+#if PHP_HTTP_CURL_VERSION(7,52,0)
+       if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SCHEME, &c)) {
+               ZVAL_STRING(&tmp, STR_PTR(c));
+               zend_hash_str_update(info, "scheme", lenof("scheme"), &tmp);
+       }
+#endif
 
        /* END::CURLINFO */
 
@@ -488,7 +516,11 @@ static ZEND_RESULT_CODE php_http_curle_get_info(CURL *ch, HashTable *info)
                zval ti_array, subarray;
                struct curl_tlssessioninfo *ti;
 
+#if PHP_HTTP_CURL_VERSION(7,48,0)
+               if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_TLS_SSL_PTR, &ti)) {
+#else
                if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_TLS_SESSION, &ti)) {
+#endif
                        char *backend;
 
                        ZVAL_NULL(&subarray);
@@ -502,15 +534,22 @@ static ZEND_RESULT_CODE php_http_curle_get_info(CURL *ch, HashTable *info)
                                backend = "openssl";
 #if PHP_HTTP_HAVE_LIBCURL_OPENSSL
                                {
+#if PHP_HTTP_CURL_VERSION(7,48,0)
+                                       SSL *ssl = ti->internals;
+                                       SSL_CTX *ctx = ssl ? SSL_get_SSL_CTX(ssl) : NULL;
+#else
                                        SSL_CTX *ctx = ti->internals;
+#endif
 
                                        array_init(&subarray);
-                                       add_assoc_long_ex(&subarray, ZEND_STRL("number"), SSL_CTX_sess_number(ctx));
-                                       add_assoc_long_ex(&subarray, ZEND_STRL("connect"), SSL_CTX_sess_connect(ctx));
-                                       add_assoc_long_ex(&subarray, ZEND_STRL("connect_good"), SSL_CTX_sess_connect_good(ctx));
-                                       add_assoc_long_ex(&subarray, ZEND_STRL("connect_renegotiate"), SSL_CTX_sess_connect_renegotiate(ctx));
-                                       add_assoc_long_ex(&subarray, ZEND_STRL("hits"), SSL_CTX_sess_hits(ctx));
-                                       add_assoc_long_ex(&subarray, ZEND_STRL("cache_full"), SSL_CTX_sess_cache_full(ctx));
+                                       if (ctx) {
+                                               add_assoc_long_ex(&subarray, ZEND_STRL("number"), SSL_CTX_sess_number(ctx));
+                                               add_assoc_long_ex(&subarray, ZEND_STRL("connect"), SSL_CTX_sess_connect(ctx));
+                                               add_assoc_long_ex(&subarray, ZEND_STRL("connect_good"), SSL_CTX_sess_connect_good(ctx));
+                                               add_assoc_long_ex(&subarray, ZEND_STRL("connect_renegotiate"), SSL_CTX_sess_connect_renegotiate(ctx));
+                                               add_assoc_long_ex(&subarray, ZEND_STRL("hits"), SSL_CTX_sess_hits(ctx));
+                                               add_assoc_long_ex(&subarray, ZEND_STRL("cache_full"), SSL_CTX_sess_cache_full(ctx));
+                                       }
                                }
 #endif
                                break;
@@ -522,11 +561,13 @@ static ZEND_RESULT_CODE php_http_curle_get_info(CURL *ch, HashTable *info)
                                        char *desc;
 
                                        array_init(&subarray);
-                                       if ((desc = gnutls_session_get_desc(sess))) {
-                                               add_assoc_string_ex(&subarray, ZEND_STRL("desc"), desc);
-                                               gnutls_free(desc);
+                                       if (sess) {
+                                               if ((desc = gnutls_session_get_desc(sess))) {
+                                                       add_assoc_string_ex(&subarray, ZEND_STRL("desc"), desc);
+                                                       gnutls_free(desc);
+                                               }
+                                               add_assoc_bool_ex(&subarray, ZEND_STRL("resumed"), gnutls_session_is_resumed(sess));
                                        }
-                                       add_assoc_bool_ex(&subarray, ZEND_STRL("resumed"), gnutls_session_is_resumed(sess));
                                }
 #endif
                                break;
index d44f3dac815f1512ee9f9c51d66719b0733ffa87..1f69a51cb7203e3d4acb05502f512a703a1f1eb6 100644 (file)
@@ -22,7 +22,7 @@ typedef struct php_http_client_curl_user_ev {
        php_http_client_curl_user_context_t *context;
 } php_http_client_curl_user_ev_t;
 
-static void php_http_client_curl_user_handler(INTERNAL_FUNCTION_PARAMETERS)
+static ZEND_NAMED_FUNCTION(php_http_client_curl_user_handler)
 {
        zval *zstream = NULL, *zclient = NULL;
        php_stream *stream = NULL;
index 71a9129e3f994f6513c64c023c88ae66afcafb26..9055f490f379097411ed6b73fb86b68e0a4c1646 100644 (file)
@@ -273,7 +273,7 @@ static PHP_METHOD(HttpClientRequest, getSslOptions)
 }
 
 static zend_function_entry php_http_client_request_methods[] = {
-       PHP_ME(HttpClientRequest, __construct,    ai_HttpClientRequest___construct,    ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
+       PHP_ME(HttpClientRequest, __construct,    ai_HttpClientRequest___construct,    ZEND_ACC_PUBLIC)
        PHP_ME(HttpClientRequest, setContentType, ai_HttpClientRequest_setContentType, ZEND_ACC_PUBLIC)
        PHP_ME(HttpClientRequest, getContentType, ai_HttpClientRequest_getContentType, ZEND_ACC_PUBLIC)
        PHP_ME(HttpClientRequest, setQuery,       ai_HttpClientRequest_setQuery,       ZEND_ACC_PUBLIC)
index 83d17947790c106abfc8702f3ac975d8aa5b15ba..c3e9a3a5f618a4f119247fcfd0ce0fbdb0608a94 100644 (file)
@@ -12,8 +12,6 @@
 
 #include "php_http_api.h"
 
-#include <zlib.h>
-
 static inline int eol_match(char **line, int *eol_len)
 {
        char *ptr = *line;
@@ -109,129 +107,6 @@ const char *php_http_encoding_dechunk(const char *encoded, size_t encoded_len, c
        return e_ptr;
 }
 
-static inline int php_http_inflate_rounds(z_stream *Z, int flush, char **buf, size_t *len)
-{
-       int status = 0, round = 0;
-       php_http_buffer_t buffer;
-       
-       *buf = NULL;
-       *len = 0;
-       
-       php_http_buffer_init_ex(&buffer, Z->avail_in, PHP_HTTP_BUFFER_INIT_PREALLOC);
-       
-       do {
-               if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_resize_ex(&buffer, buffer.size, 0, 1)) {
-                       status = Z_MEM_ERROR;
-               } else {
-                       Z->avail_out = buffer.free;
-                       Z->next_out = (Bytef *) buffer.data + buffer.used;
-#if 0
-                       fprintf(stderr, "\n%3d: %3d PRIOR: size=%7lu,\tfree=%7lu,\tused=%7lu,\tavail_in=%7lu,\tavail_out=%7lu\n", round, status, buffer.size, buffer.free, buffer.used, Z->avail_in, Z->avail_out);
-#endif
-                       status = inflate(Z, flush);
-                       php_http_buffer_account(&buffer, buffer.free - Z->avail_out);
-#if 0
-                       fprintf(stderr, "%3d: %3d AFTER: size=%7lu,\tfree=%7lu,\tused=%7lu,\tavail_in=%7lu,\tavail_out=%7lu\n", round, status, buffer.size, buffer.free, buffer.used, Z->avail_in, Z->avail_out);
-#endif
-                       PHP_HTTP_INFLATE_BUFFER_SIZE_ALIGN(buffer.size);
-               }
-       } while ((Z_BUF_ERROR == status || (Z_OK == status && Z->avail_in)) && ++round < PHP_HTTP_INFLATE_ROUNDS);
-       
-       if (status == Z_OK || status == Z_STREAM_END) {
-               php_http_buffer_shrink(&buffer);
-               php_http_buffer_fix(&buffer);
-               *buf = buffer.data;
-               *len = buffer.used;
-       } else {
-               php_http_buffer_dtor(&buffer);
-       }
-       
-       return status;
-}
-
-ZEND_RESULT_CODE php_http_encoding_deflate(int flags, const char *data, size_t data_len, char **encoded, size_t *encoded_len)
-{
-       int status, level, wbits, strategy;
-       z_stream Z;
-       
-       PHP_HTTP_DEFLATE_LEVEL_SET(flags, level);
-       PHP_HTTP_DEFLATE_WBITS_SET(flags, wbits);
-       PHP_HTTP_DEFLATE_STRATEGY_SET(flags, strategy);
-       
-       memset(&Z, 0, sizeof(z_stream));
-       *encoded = NULL;
-       *encoded_len = 0;
-       
-       status = deflateInit2(&Z, level, Z_DEFLATED, wbits, MAX_MEM_LEVEL, strategy);
-       if (Z_OK == status) {
-               *encoded_len = PHP_HTTP_DEFLATE_BUFFER_SIZE_GUESS(data_len);
-               *encoded = emalloc(*encoded_len);
-               
-               Z.next_in = (Bytef *) data;
-               Z.next_out = (Bytef *) *encoded;
-               Z.avail_in = data_len;
-               Z.avail_out = *encoded_len;
-               
-               status = deflate(&Z, Z_FINISH);
-               deflateEnd(&Z);
-               
-               if (Z_STREAM_END == status) {
-                       /* size buffer down to actual length */
-                       *encoded = erealloc(*encoded, Z.total_out + 1);
-                       (*encoded)[*encoded_len = Z.total_out] = '\0';
-                       return SUCCESS;
-               } else {
-                       PTR_SET(*encoded, NULL);
-                       *encoded_len = 0;
-               }
-       }
-       
-       php_error_docref(NULL, E_WARNING, "Could not deflate data: %s", zError(status));
-       return FAILURE;
-}
-
-ZEND_RESULT_CODE php_http_encoding_inflate(const char *data, size_t data_len, char **decoded, size_t *decoded_len)
-{
-       z_stream Z;
-       int status, wbits = PHP_HTTP_WINDOW_BITS_ANY;
-       
-       memset(&Z, 0, sizeof(z_stream));
-       
-retry_raw_inflate:
-       status = inflateInit2(&Z, wbits);
-       if (Z_OK == status) {
-               Z.next_in = (Bytef *) data;
-               Z.avail_in = data_len + 1; /* include the terminating NULL, see #61287 */
-               
-               switch (status = php_http_inflate_rounds(&Z, Z_NO_FLUSH, decoded, decoded_len)) {
-                       case Z_STREAM_END:
-                               inflateEnd(&Z);
-                               return SUCCESS;
-
-                       case Z_OK:
-                               status = Z_DATA_ERROR;
-                               break;
-                       
-                       case Z_DATA_ERROR:
-                               /* raw deflated data? */
-                               if (PHP_HTTP_WINDOW_BITS_ANY == wbits) {
-                                       inflateEnd(&Z);
-                                       wbits = PHP_HTTP_WINDOW_BITS_RAW;
-                                       goto retry_raw_inflate;
-                               }
-                               break;
-               }
-               inflateEnd(&Z);
-
-               if (*decoded_len && *decoded) {
-                       efree(*decoded);
-               }
-       }
-       
-       php_error_docref(NULL, E_WARNING, "Could not inflate data: %s", zError(status));
-       return FAILURE;
-}
-
 php_http_encoding_stream_t *php_http_encoding_stream_init(php_http_encoding_stream_t *s, php_http_encoding_stream_ops_t *ops, unsigned flags)
 {
        int freeme;
@@ -243,10 +118,10 @@ php_http_encoding_stream_t *php_http_encoding_stream_init(php_http_encoding_stre
 
        s->flags = flags;
 
-       if ((s->ops = ops)) {
+       if (EXPECTED(s->ops = ops)) {
                php_http_encoding_stream_t *ss = s->ops->init(s);
 
-               if (ss) {
+               if (EXPECTED(ss)) {
                        return ss;
                }
        } else {
@@ -286,10 +161,12 @@ ZEND_RESULT_CODE php_http_encoding_stream_reset(php_http_encoding_stream_t **s)
 {
        php_http_encoding_stream_t *ss;
 
-       if ((*s)->ops->dtor) {
+       if (EXPECTED((*s)->ops->dtor)) {
                (*s)->ops->dtor(*s);
        }
-       if ((ss = (*s)->ops->init(*s))) {
+
+       if (EXPECTED(ss = (*s)->ops->init(*s))) {
+               ss->flags &= ~PHP_HTTP_ENCODING_STREAM_DIRTY;
                *s = ss;
                return SUCCESS;
        }
@@ -298,10 +175,15 @@ ZEND_RESULT_CODE php_http_encoding_stream_reset(php_http_encoding_stream_t **s)
 
 ZEND_RESULT_CODE php_http_encoding_stream_update(php_http_encoding_stream_t *s, const char *in_str, size_t in_len, char **out_str, size_t *out_len)
 {
-       if (!s->ops->update) {
-               return FAILURE;
+       ZEND_RESULT_CODE rc = FAILURE;
+
+       if (EXPECTED(s->ops->update)) {
+               rc = s->ops->update(s, in_str, in_len, out_str, out_len);
        }
-       return s->ops->update(s, in_str, in_len, out_str, out_len);
+
+       s->flags |= PHP_HTTP_ENCODING_STREAM_DIRTY;
+
+       return rc;
 }
 
 ZEND_RESULT_CODE php_http_encoding_stream_flush(php_http_encoding_stream_t *s, char **out_str, size_t *out_len)
@@ -317,7 +199,7 @@ ZEND_RESULT_CODE php_http_encoding_stream_flush(php_http_encoding_stream_t *s, c
 zend_bool php_http_encoding_stream_done(php_http_encoding_stream_t *s)
 {
        if (!s->ops->done) {
-               return 0;
+               return !(s->flags & PHP_HTTP_ENCODING_STREAM_DIRTY);
        }
        return s->ops->done(s);
 }
@@ -327,6 +209,9 @@ ZEND_RESULT_CODE php_http_encoding_stream_finish(php_http_encoding_stream_t *s,
        if (!s->ops->finish) {
                *out_str = NULL;
                *out_len = 0;
+
+               s->flags &= ~PHP_HTTP_ENCODING_STREAM_DIRTY;
+
                return SUCCESS;
        }
        return s->ops->finish(s, out_str, out_len);
@@ -334,15 +219,15 @@ ZEND_RESULT_CODE php_http_encoding_stream_finish(php_http_encoding_stream_t *s,
 
 void php_http_encoding_stream_dtor(php_http_encoding_stream_t *s)
 {
-       if (s->ops->dtor) {
+       if (EXPECTED(s->ops->dtor)) {
                s->ops->dtor(s);
        }
 }
 
 void php_http_encoding_stream_free(php_http_encoding_stream_t **s)
 {
-       if (*s) {
-               if ((*s)->ops->dtor) {
+       if (EXPECTED(*s)) {
+               if (EXPECTED((*s)->ops->dtor)) {
                        (*s)->ops->dtor(*s);
                }
                pefree(*s, ((*s)->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT));
@@ -356,48 +241,6 @@ struct dechunk_ctx {
        unsigned zeroed:1;
 };
 
-static php_http_encoding_stream_t *deflate_init(php_http_encoding_stream_t *s)
-{
-       int status, level, wbits, strategy, p = (s->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT);
-       z_streamp ctx = pecalloc(1, sizeof(z_stream), p);
-       
-       PHP_HTTP_DEFLATE_LEVEL_SET(s->flags, level);
-       PHP_HTTP_DEFLATE_WBITS_SET(s->flags, wbits);
-       PHP_HTTP_DEFLATE_STRATEGY_SET(s->flags, strategy);
-       
-       if (Z_OK == (status = deflateInit2(ctx, level, Z_DEFLATED, wbits, MAX_MEM_LEVEL, strategy))) {
-               if ((ctx->opaque = php_http_buffer_init_ex(NULL, PHP_HTTP_DEFLATE_BUFFER_SIZE, p ? PHP_HTTP_BUFFER_INIT_PERSISTENT : 0))) {
-                       s->ctx = ctx;
-                       return s;
-               }
-               deflateEnd(ctx);
-               status = Z_MEM_ERROR;
-       }
-       pefree(ctx, p);
-       php_error_docref(NULL, E_WARNING, "Failed to initialize deflate encoding stream: %s", zError(status));
-       return NULL;
-}
-
-static php_http_encoding_stream_t *inflate_init(php_http_encoding_stream_t *s)
-{
-       int status, wbits, p = (s->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT);
-       z_streamp ctx = pecalloc(1, sizeof(z_stream), p);
-       
-       PHP_HTTP_INFLATE_WBITS_SET(s->flags, wbits);
-       
-       if (Z_OK == (status = inflateInit2(ctx, wbits))) {
-               if ((ctx->opaque = php_http_buffer_init_ex(NULL, PHP_HTTP_DEFLATE_BUFFER_SIZE, p ? PHP_HTTP_BUFFER_INIT_PERSISTENT : 0))) {
-                       s->ctx = ctx;
-                       return s;
-               }
-               inflateEnd(ctx);
-               status = Z_MEM_ERROR;
-       }
-       pefree(ctx, p);
-       php_error_docref(NULL, E_WARNING, "Failed to initialize inflate stream: %s", zError(status));
-       return NULL;
-}
-
 static php_http_encoding_stream_t *dechunk_init(php_http_encoding_stream_t *s)
 {
        struct dechunk_ctx *ctx = pecalloc(1, sizeof(*ctx), (s->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT));
@@ -413,42 +256,6 @@ static php_http_encoding_stream_t *dechunk_init(php_http_encoding_stream_t *s)
        return s;
 }
 
-static php_http_encoding_stream_t *deflate_copy(php_http_encoding_stream_t *from, php_http_encoding_stream_t *to)
-{
-       int status, p = to->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT;
-       z_streamp from_ctx = from->ctx, to_ctx = pecalloc(1, sizeof(*to_ctx), p);
-
-       if (Z_OK == (status = deflateCopy(to_ctx, from_ctx))) {
-               if ((to_ctx->opaque = php_http_buffer_init_ex(NULL, PHP_HTTP_DEFLATE_BUFFER_SIZE, p ? PHP_HTTP_BUFFER_INIT_PERSISTENT : 0))) {
-                       php_http_buffer_append(to_ctx->opaque, PHP_HTTP_BUFFER(from_ctx->opaque)->data, PHP_HTTP_BUFFER(from_ctx->opaque)->used);
-                       to->ctx = to_ctx;
-                       return to;
-               }
-               deflateEnd(to_ctx);
-               status = Z_MEM_ERROR;
-       }
-       php_error_docref(NULL, E_WARNING, "Failed to copy deflate encoding stream: %s", zError(status));
-       return NULL;
-}
-
-static php_http_encoding_stream_t *inflate_copy(php_http_encoding_stream_t *from, php_http_encoding_stream_t *to)
-{
-       int status, p = from->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT;
-       z_streamp from_ctx = from->ctx, to_ctx = pecalloc(1, sizeof(*to_ctx), p);
-
-       if (Z_OK == (status = inflateCopy(to_ctx, from_ctx))) {
-               if ((to_ctx->opaque = php_http_buffer_init_ex(NULL, PHP_HTTP_DEFLATE_BUFFER_SIZE, p ? PHP_HTTP_BUFFER_INIT_PERSISTENT : 0))) {
-                       php_http_buffer_append(to_ctx->opaque, PHP_HTTP_BUFFER(from_ctx->opaque)->data, PHP_HTTP_BUFFER(from_ctx->opaque)->used);
-                       to->ctx = to_ctx;
-                       return to;
-               }
-               inflateEnd(to_ctx);
-               status = Z_MEM_ERROR;
-       }
-       php_error_docref(NULL, E_WARNING, "Failed to copy inflate encoding stream: %s", zError(status));
-       return NULL;
-}
-
 static php_http_encoding_stream_t *dechunk_copy(php_http_encoding_stream_t *from, php_http_encoding_stream_t *to)
 {
        int p = from->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT;
@@ -466,84 +273,6 @@ static php_http_encoding_stream_t *dechunk_copy(php_http_encoding_stream_t *from
        return NULL;
 }
 
-static ZEND_RESULT_CODE deflate_update(php_http_encoding_stream_t *s, const char *data, size_t data_len, char **encoded, size_t *encoded_len)
-{
-       int status;
-       z_streamp ctx = s->ctx;
-       
-       /* append input to our buffer */
-       php_http_buffer_append(PHP_HTTP_BUFFER(ctx->opaque), data, data_len);
-       
-       ctx->next_in = (Bytef *) PHP_HTTP_BUFFER(ctx->opaque)->data;
-       ctx->avail_in = PHP_HTTP_BUFFER(ctx->opaque)->used;
-       
-       /* deflate */
-       *encoded_len = PHP_HTTP_DEFLATE_BUFFER_SIZE_GUESS(data_len);
-       *encoded = emalloc(*encoded_len);
-       ctx->avail_out = *encoded_len;
-       ctx->next_out = (Bytef *) *encoded;
-       
-       switch (status = deflate(ctx, PHP_HTTP_ENCODING_STREAM_FLUSH_FLAG(s->flags))) {
-               case Z_OK:
-               case Z_STREAM_END:
-                       /* cut processed chunk off the buffer */
-                       if (ctx->avail_in) {
-                               php_http_buffer_cut(PHP_HTTP_BUFFER(ctx->opaque), 0, PHP_HTTP_BUFFER(ctx->opaque)->used - ctx->avail_in);
-                       } else {
-                               php_http_buffer_reset(PHP_HTTP_BUFFER(ctx->opaque));
-                       }
-                       
-                       /* size buffer down to actual size */
-                       *encoded_len -= ctx->avail_out;
-                       *encoded = erealloc(*encoded, *encoded_len + 1);
-                       (*encoded)[*encoded_len] = '\0';
-                       return SUCCESS;
-       }
-       
-       PTR_SET(*encoded, NULL);
-       *encoded_len = 0;
-       php_error_docref(NULL, E_WARNING, "Failed to update deflate stream: %s", zError(status));
-       return FAILURE;
-}
-
-static ZEND_RESULT_CODE inflate_update(php_http_encoding_stream_t *s, const char *data, size_t data_len, char **decoded, size_t *decoded_len)
-{
-       int status;
-       z_streamp ctx = s->ctx;
-       
-       /* append input to buffer */
-       php_http_buffer_append(PHP_HTTP_BUFFER(ctx->opaque), data, data_len);
-
-retry_raw_inflate:
-       ctx->next_in = (Bytef *) PHP_HTTP_BUFFER(ctx->opaque)->data;
-       ctx->avail_in = PHP_HTTP_BUFFER(ctx->opaque)->used;
-       
-       switch (status = php_http_inflate_rounds(ctx, PHP_HTTP_ENCODING_STREAM_FLUSH_FLAG(s->flags), decoded, decoded_len)) {
-               case Z_OK:
-               case Z_STREAM_END:
-                       /* cut off */
-                       if (ctx->avail_in) {
-                               php_http_buffer_cut(PHP_HTTP_BUFFER(ctx->opaque), 0, PHP_HTTP_BUFFER(ctx->opaque)->used - ctx->avail_in);
-                       } else {
-                               php_http_buffer_reset(PHP_HTTP_BUFFER(ctx->opaque));
-                       }
-                       return SUCCESS;
-               
-               case Z_DATA_ERROR:
-                       /* raw deflated data ? */
-                       if (!(s->flags & PHP_HTTP_INFLATE_TYPE_RAW) && !ctx->total_out) {
-                               inflateEnd(ctx);
-                               s->flags |= PHP_HTTP_INFLATE_TYPE_RAW;
-                               inflateInit2(ctx, PHP_HTTP_WINDOW_BITS_RAW);
-                               goto retry_raw_inflate;
-                       }
-                       break;
-       }
-       
-       php_error_docref(NULL, E_WARNING, "Failed to update inflate stream: %s", zError(status));
-       return FAILURE;
-}
-
 static ZEND_RESULT_CODE dechunk_update(php_http_encoding_stream_t *s, const char *data, size_t data_len, char **decoded, size_t *decoded_len)
 {
        php_http_buffer_t tmp;
@@ -671,34 +400,6 @@ static ZEND_RESULT_CODE dechunk_update(php_http_encoding_stream_t *s, const char
        return SUCCESS;
 }
 
-static ZEND_RESULT_CODE deflate_flush(php_http_encoding_stream_t *s, char **encoded, size_t *encoded_len)
-{
-       int status;
-       z_streamp ctx = s->ctx;
-       
-       *encoded_len = PHP_HTTP_DEFLATE_BUFFER_SIZE;
-       *encoded = emalloc(*encoded_len);
-       
-       ctx->avail_in = 0;
-       ctx->next_in = NULL;
-       ctx->avail_out = *encoded_len;
-       ctx->next_out = (Bytef *) *encoded;
-       
-       switch (status = deflate(ctx, Z_FULL_FLUSH)) {
-               case Z_OK:
-               case Z_STREAM_END:
-                       *encoded_len = PHP_HTTP_DEFLATE_BUFFER_SIZE - ctx->avail_out;
-                       *encoded = erealloc(*encoded, *encoded_len + 1);
-                       (*encoded)[*encoded_len] = '\0';
-                       return SUCCESS;
-       }
-       
-       PTR_SET(*encoded, NULL);
-       *encoded_len = 0;
-       php_error_docref(NULL, E_WARNING, "Failed to flush deflate stream: %s", zError(status));
-       return FAILURE;
-}
-
 static ZEND_RESULT_CODE dechunk_flush(php_http_encoding_stream_t *s, char **decoded, size_t *decoded_len)
 {
        struct dechunk_ctx *ctx = s->ctx;
@@ -719,125 +420,13 @@ static ZEND_RESULT_CODE dechunk_flush(php_http_encoding_stream_t *s, char **deco
        return SUCCESS;
 }
 
-static ZEND_RESULT_CODE deflate_finish(php_http_encoding_stream_t *s, char **encoded, size_t *encoded_len)
-{
-       int status;
-       z_streamp ctx = s->ctx;
-       
-       *encoded_len = PHP_HTTP_DEFLATE_BUFFER_SIZE;
-       *encoded = emalloc(*encoded_len);
-       
-       /* deflate remaining input */
-       ctx->next_in = (Bytef *) PHP_HTTP_BUFFER(ctx->opaque)->data;
-       ctx->avail_in = PHP_HTTP_BUFFER(ctx->opaque)->used;
-       
-       ctx->avail_out = *encoded_len;
-       ctx->next_out = (Bytef *) *encoded;
-       
-       do {
-               status = deflate(ctx, Z_FINISH);
-       } while (Z_OK == status);
-       
-       if (Z_STREAM_END == status) {
-               /* cut processed input off */
-               php_http_buffer_cut(PHP_HTTP_BUFFER(ctx->opaque), 0, PHP_HTTP_BUFFER(ctx->opaque)->used - ctx->avail_in);
-               
-               /* size down */
-               *encoded_len -= ctx->avail_out;
-               *encoded = erealloc(*encoded, *encoded_len + 1);
-               (*encoded)[*encoded_len] = '\0';
-               return SUCCESS;
-       }
-       
-       PTR_SET(*encoded, NULL);
-       *encoded_len = 0;
-       php_error_docref(NULL, E_WARNING, "Failed to finish deflate stream: %s", zError(status));
-       return FAILURE;
-}
-
-static ZEND_RESULT_CODE inflate_finish(php_http_encoding_stream_t *s, char **decoded, size_t *decoded_len)
-{
-       int status;
-       z_streamp ctx = s->ctx;
-       
-       if (!PHP_HTTP_BUFFER(ctx->opaque)->used) {
-               *decoded = NULL;
-               *decoded_len = 0;
-               return SUCCESS;
-       }
-       
-       *decoded_len = (PHP_HTTP_BUFFER(ctx->opaque)->used + 1) * PHP_HTTP_INFLATE_ROUNDS;
-       *decoded = emalloc(*decoded_len);
-       
-       /* inflate remaining input */
-       ctx->next_in = (Bytef *) PHP_HTTP_BUFFER(ctx->opaque)->data;
-       ctx->avail_in = PHP_HTTP_BUFFER(ctx->opaque)->used;
-       
-       ctx->avail_out = *decoded_len;
-       ctx->next_out = (Bytef *) *decoded;
-       
-       if (Z_STREAM_END == (status = inflate(ctx, Z_FINISH))) {
-               /* cut processed input off */
-               php_http_buffer_cut(PHP_HTTP_BUFFER(ctx->opaque), 0, PHP_HTTP_BUFFER(ctx->opaque)->used - ctx->avail_in);
-               
-               /* size down */
-               *decoded_len -= ctx->avail_out;
-               *decoded = erealloc(*decoded, *decoded_len + 1);
-               (*decoded)[*decoded_len] = '\0';
-               return SUCCESS;
-       }
-       
-       PTR_SET(*decoded, NULL);
-       *decoded_len = 0;
-       php_error_docref(NULL, E_WARNING, "Failed to finish inflate stream: %s", zError(status));
-       return FAILURE;
-}
-
-static zend_bool deflate_done(php_http_encoding_stream_t *s)
-{
-       z_streamp ctx = s->ctx;
-       return !ctx->avail_in && !PHP_HTTP_BUFFER(ctx->opaque)->used;
-}
 
-static zend_bool inflate_done(php_http_encoding_stream_t *s)
-{
-       z_streamp ctx = s->ctx;
-       return !ctx->avail_in && !PHP_HTTP_BUFFER(ctx->opaque)->used;
-}
 
 static zend_bool dechunk_done(php_http_encoding_stream_t *s)
 {
        return ((struct dechunk_ctx *) s->ctx)->zeroed;
 }
 
-static void deflate_dtor(php_http_encoding_stream_t *s)
-{
-       if (s->ctx) {
-               z_streamp ctx = s->ctx;
-
-               if (ctx->opaque) {
-                       php_http_buffer_free((php_http_buffer_t **) &ctx->opaque);
-               }
-               deflateEnd(ctx);
-               pefree(ctx, (s->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT));
-               s->ctx = NULL;
-       }
-}
-
-static void inflate_dtor(php_http_encoding_stream_t *s)
-{
-       if (s->ctx) {
-               z_streamp ctx = s->ctx;
-
-               if (ctx->opaque) {
-                       php_http_buffer_free((php_http_buffer_t **) &ctx->opaque);
-               }
-               inflateEnd(ctx);
-               pefree(ctx, (s->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT));
-               s->ctx = NULL;
-       }
-}
-
 static void dechunk_dtor(php_http_encoding_stream_t *s)
 {
        if (s->ctx) {
@@ -849,36 +438,6 @@ static void dechunk_dtor(php_http_encoding_stream_t *s)
        }
 }
 
-static php_http_encoding_stream_ops_t php_http_encoding_deflate_ops = {
-       deflate_init,
-       deflate_copy,
-       deflate_update,
-       deflate_flush,
-       deflate_done,
-       deflate_finish,
-       deflate_dtor
-};
-
-php_http_encoding_stream_ops_t *php_http_encoding_stream_get_deflate_ops(void)
-{
-       return &php_http_encoding_deflate_ops;
-}
-
-static php_http_encoding_stream_ops_t php_http_encoding_inflate_ops = {
-       inflate_init,
-       inflate_copy,
-       inflate_update,
-       NULL,
-       inflate_done,
-       inflate_finish,
-       inflate_dtor
-};
-
-php_http_encoding_stream_ops_t *php_http_encoding_stream_get_inflate_ops(void)
-{
-       return &php_http_encoding_inflate_ops;
-}
-
 static php_http_encoding_stream_ops_t php_http_encoding_dechunk_ops = {
        dechunk_init,
        dechunk_copy,
@@ -920,9 +479,13 @@ php_http_encoding_stream_object_t *php_http_encoding_stream_object_new_ex(zend_c
 
 zend_object *php_http_encoding_stream_object_clone(zval *object)
 {
-       php_http_encoding_stream_object_t *new_obj = NULL, *old_obj = PHP_HTTP_OBJ(NULL, object);
+       php_http_encoding_stream_object_t *new_obj, *old_obj = PHP_HTTP_OBJ(NULL, object);
        php_http_encoding_stream_t *cpy = php_http_encoding_stream_copy(old_obj->stream, NULL);
 
+       if (!cpy) {
+               return NULL;
+       }
+
        new_obj = php_http_encoding_stream_object_new_ex(old_obj->zo.ce, cpy);
        zend_objects_clone_members(&new_obj->zo, &old_obj->zo);
 
@@ -944,16 +507,7 @@ zend_class_entry *php_http_get_encoding_stream_class_entry(void)
 {
        return php_http_encoding_stream_class_entry;
 }
-static zend_class_entry *php_http_deflate_stream_class_entry;
-zend_class_entry *php_http_get_deflate_stream_class_entry(void)
-{
-       return php_http_deflate_stream_class_entry;
-}
-static zend_class_entry *php_http_inflate_stream_class_entry;
-zend_class_entry *php_http_get_inflate_stream_class_entry(void)
-{
-       return php_http_inflate_stream_class_entry;
-}
+
 static zend_class_entry *php_http_dechunk_stream_class_entry;
 zend_class_entry *php_http_get_dechunk_stream_class_entry(void)
 {
@@ -973,17 +527,23 @@ static PHP_METHOD(HttpEncodingStream, __construct)
 
        obj = PHP_HTTP_OBJ(NULL, getThis());
 
-       if (obj->stream) {
+       if (UNEXPECTED(obj->stream)) {
                php_http_throw(bad_method_call, "http\\Encoding\\Stream cannot be initialized twice", NULL);
                return;
        }
 
-       if (instanceof_function(obj->zo.ce, php_http_deflate_stream_class_entry)) {
-               ops = &php_http_encoding_deflate_ops;
-       } else if (instanceof_function(obj->zo.ce, php_http_inflate_stream_class_entry)) {
-               ops = &php_http_encoding_inflate_ops;
+       if (instanceof_function(obj->zo.ce, php_http_get_deflate_stream_class_entry())) {
+               ops = php_http_encoding_stream_get_deflate_ops();
+       } else if (instanceof_function(obj->zo.ce, php_http_get_inflate_stream_class_entry())) {
+               ops = php_http_encoding_stream_get_inflate_ops();
        } else if (instanceof_function(obj->zo.ce, php_http_dechunk_stream_class_entry)) {
                ops = &php_http_encoding_dechunk_ops;
+#if PHP_HTTP_HAVE_LIBBROTLI
+       } else if (instanceof_function(obj->zo.ce, php_http_get_enbrotli_stream_class_entry())) {
+               ops = php_http_encoding_stream_get_enbrotli_ops();
+       } else if (instanceof_function(obj->zo.ce, php_http_get_debrotli_stream_class_entry())) {
+               ops = php_http_encoding_stream_get_debrotli_ops();
+#endif
        } else {
                php_http_throw(runtime, "Unknown http\\Encoding\\Stream class '%s'", obj->zo.ce->name->val);
                return;
@@ -1000,15 +560,15 @@ static PHP_METHOD(HttpEncodingStream, update)
        size_t data_len;
        char *data_str;
 
-       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &data_str, &data_len)) {
+       if (EXPECTED(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &data_str, &data_len))) {
                php_http_encoding_stream_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
 
-               if (obj->stream) {
+               if (EXPECTED(obj->stream)) {
                        char *encoded_str = NULL;
                        size_t encoded_len;
 
-                       if (SUCCESS == php_http_encoding_stream_update(obj->stream, data_str, data_len, &encoded_str, &encoded_len)) {
-                               if (encoded_str) {
+                       if (EXPECTED(SUCCESS == php_http_encoding_stream_update(obj->stream, data_str, data_len, &encoded_str, &encoded_len))) {
+                               if (EXPECTED(encoded_str)) {
                                        RETURN_STR(php_http_cs2zs(encoded_str, encoded_len));
                                } else {
                                        RETURN_EMPTY_STRING();
@@ -1022,14 +582,14 @@ ZEND_BEGIN_ARG_INFO_EX(ai_HttpEncodingStream_flush, 0, 0, 0)
 ZEND_END_ARG_INFO();
 static PHP_METHOD(HttpEncodingStream, flush)
 {
-       if (SUCCESS == zend_parse_parameters_none()) {
+       if (EXPECTED(SUCCESS == zend_parse_parameters_none())) {
                php_http_encoding_stream_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
 
-               if (obj->stream) {
+               if (EXPECTED(obj->stream)) {
                        char *encoded_str = NULL;
                        size_t encoded_len;
 
-                       if (SUCCESS == php_http_encoding_stream_flush(obj->stream, &encoded_str, &encoded_len)) {
+                       if (EXPECTED(SUCCESS == php_http_encoding_stream_flush(obj->stream, &encoded_str, &encoded_len))) {
                                if (encoded_str) {
                                        RETURN_STR(php_http_cs2zs(encoded_str, encoded_len));
                                } else {
@@ -1044,10 +604,10 @@ ZEND_BEGIN_ARG_INFO_EX(ai_HttpEncodingStream_done, 0, 0, 0)
 ZEND_END_ARG_INFO();
 static PHP_METHOD(HttpEncodingStream, done)
 {
-       if (SUCCESS == zend_parse_parameters_none()) {
+       if (EXPECTED(SUCCESS == zend_parse_parameters_none())) {
                php_http_encoding_stream_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
 
-               if (obj->stream) {
+               if (EXPECTED(obj->stream)) {
                        RETURN_BOOL(php_http_encoding_stream_done(obj->stream));
                }
        }
@@ -1057,15 +617,15 @@ ZEND_BEGIN_ARG_INFO_EX(ai_HttpEncodingStream_finish, 0, 0, 0)
 ZEND_END_ARG_INFO();
 static PHP_METHOD(HttpEncodingStream, finish)
 {
-       if (SUCCESS == zend_parse_parameters_none()) {
+       if (EXPECTED(SUCCESS == zend_parse_parameters_none())) {
                php_http_encoding_stream_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
 
-               if (obj->stream) {
+               if (EXPECTED(obj->stream)) {
                        char *encoded_str = NULL;
                        size_t encoded_len;
 
-                       if (SUCCESS == php_http_encoding_stream_finish(obj->stream, &encoded_str, &encoded_len)) {
-                               if (SUCCESS == php_http_encoding_stream_reset(&obj->stream)) {
+                       if (EXPECTED(SUCCESS == php_http_encoding_stream_finish(obj->stream, &encoded_str, &encoded_len))) {
+                               if (EXPECTED(SUCCESS == php_http_encoding_stream_reset(&obj->stream))) {
                                        if (encoded_str) {
                                                RETURN_STR(php_http_cs2zs(encoded_str, encoded_len));
                                        } else {
@@ -1080,7 +640,7 @@ static PHP_METHOD(HttpEncodingStream, finish)
 }
 
 static zend_function_entry php_http_encoding_stream_methods[] = {
-       PHP_ME(HttpEncodingStream, __construct,  ai_HttpEncodingStream___construct,  ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
+       PHP_ME(HttpEncodingStream, __construct,  ai_HttpEncodingStream___construct,  ZEND_ACC_PUBLIC)
        PHP_ME(HttpEncodingStream, update,       ai_HttpEncodingStream_update,       ZEND_ACC_PUBLIC)
        PHP_ME(HttpEncodingStream, flush,        ai_HttpEncodingStream_flush,        ZEND_ACC_PUBLIC)
        PHP_ME(HttpEncodingStream, done,         ai_HttpEncodingStream_done,         ZEND_ACC_PUBLIC)
@@ -1088,64 +648,6 @@ static zend_function_entry php_http_encoding_stream_methods[] = {
        EMPTY_FUNCTION_ENTRY
 };
 
-ZEND_BEGIN_ARG_INFO_EX(ai_HttpDeflateStream_encode, 0, 0, 1)
-       ZEND_ARG_INFO(0, data)
-       ZEND_ARG_INFO(0, flags)
-ZEND_END_ARG_INFO();
-static PHP_METHOD(HttpDeflateStream, encode)
-{
-       char *str;
-       size_t len;
-       zend_long flags = 0;
-
-       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &str, &len, &flags)) {
-               char *enc_str = NULL;
-               size_t enc_len;
-
-               if (SUCCESS == php_http_encoding_deflate(flags, str, len, &enc_str, &enc_len)) {
-                       if (enc_str) {
-                               RETURN_STR(php_http_cs2zs(enc_str, enc_len));
-                       } else {
-                               RETURN_EMPTY_STRING();
-                       }
-               }
-       }
-       RETURN_FALSE;
-}
-
-static zend_function_entry php_http_deflate_stream_methods[] = {
-       PHP_ME(HttpDeflateStream, encode, ai_HttpDeflateStream_encode, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
-       EMPTY_FUNCTION_ENTRY
-};
-
-ZEND_BEGIN_ARG_INFO_EX(ai_HttpInflateStream_decode, 0, 0, 1)
-       ZEND_ARG_INFO(0, data)
-ZEND_END_ARG_INFO();
-static PHP_METHOD(HttpInflateStream, decode)
-{
-       char *str;
-       size_t len;
-
-       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &str, &len)) {
-               char *enc_str = NULL;
-               size_t enc_len;
-
-               if (SUCCESS == php_http_encoding_inflate(str, len, &enc_str, &enc_len)) {
-                       if (enc_str) {
-                               RETURN_STR(php_http_cs2zs(enc_str, enc_len));
-                       } else {
-                               RETURN_EMPTY_STRING();
-                       }
-               }
-       }
-       RETURN_FALSE;
-}
-
-static zend_function_entry php_http_inflate_stream_methods[] = {
-       PHP_ME(HttpInflateStream, decode, ai_HttpInflateStream_decode, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
-       EMPTY_FUNCTION_ENTRY
-};
-
 ZEND_BEGIN_ARG_INFO_EX(ai_HttpDechunkStream_decode, 0, 0, 1)
        ZEND_ARG_INFO(0, data)
        ZEND_ARG_INFO(1, decoded_len)
@@ -1156,12 +658,12 @@ static PHP_METHOD(HttpDechunkStream, decode)
        size_t len;
        zval *zlen = NULL;
 
-       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s|z!", &str, &len, &zlen)) {
+       if (EXPECTED(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s|z!", &str, &len, &zlen))) {
                const char *end_ptr;
                char *enc_str = NULL;
                size_t enc_len;
 
-               if ((end_ptr = php_http_encoding_dechunk(str, len, &enc_str, &enc_len))) {
+               if (EXPECTED(end_ptr = php_http_encoding_dechunk(str, len, &enc_str, &enc_len))) {
                        if (zlen) {
                                ZVAL_DEREF(zlen);
                                zval_dtor(zlen);
@@ -1199,28 +701,6 @@ PHP_MINIT_FUNCTION(http_encoding)
        zend_declare_class_constant_long(php_http_encoding_stream_class_entry, ZEND_STRL("FLUSH_SYNC"), PHP_HTTP_ENCODING_STREAM_FLUSH_SYNC);
        zend_declare_class_constant_long(php_http_encoding_stream_class_entry, ZEND_STRL("FLUSH_FULL"), PHP_HTTP_ENCODING_STREAM_FLUSH_FULL);
 
-       memset(&ce, 0, sizeof(ce));
-       INIT_NS_CLASS_ENTRY(ce, "http\\Encoding\\Stream", "Deflate", php_http_deflate_stream_methods);
-       php_http_deflate_stream_class_entry = zend_register_internal_class_ex(&ce, php_http_encoding_stream_class_entry);
-       php_http_deflate_stream_class_entry->create_object = php_http_encoding_stream_object_new;
-
-       zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("TYPE_GZIP"), PHP_HTTP_DEFLATE_TYPE_GZIP);
-       zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("TYPE_ZLIB"), PHP_HTTP_DEFLATE_TYPE_ZLIB);
-       zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("TYPE_RAW"), PHP_HTTP_DEFLATE_TYPE_RAW);
-       zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("LEVEL_DEF"), PHP_HTTP_DEFLATE_LEVEL_DEF);
-       zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("LEVEL_MIN"), PHP_HTTP_DEFLATE_LEVEL_MIN);
-       zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("LEVEL_MAX"), PHP_HTTP_DEFLATE_LEVEL_MAX);
-       zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("STRATEGY_DEF"), PHP_HTTP_DEFLATE_STRATEGY_DEF);
-       zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("STRATEGY_FILT"), PHP_HTTP_DEFLATE_STRATEGY_FILT);
-       zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("STRATEGY_HUFF"), PHP_HTTP_DEFLATE_STRATEGY_HUFF);
-       zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("STRATEGY_RLE"), PHP_HTTP_DEFLATE_STRATEGY_RLE);
-       zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("STRATEGY_FIXED"), PHP_HTTP_DEFLATE_STRATEGY_FIXED);
-
-       memset(&ce, 0, sizeof(ce));
-       INIT_NS_CLASS_ENTRY(ce, "http\\Encoding\\Stream", "Inflate", php_http_inflate_stream_methods);
-       php_http_inflate_stream_class_entry = zend_register_internal_class_ex(&ce, php_http_encoding_stream_class_entry);
-       php_http_inflate_stream_class_entry->create_object = php_http_encoding_stream_object_new;
-
        memset(&ce, 0, sizeof(ce));
        INIT_NS_CLASS_ENTRY(ce, "http\\Encoding\\Stream", "Dechunk", php_http_dechunk_stream_methods);
        php_http_dechunk_stream_class_entry = zend_register_internal_class_ex(&ce, php_http_encoding_stream_class_entry);
@@ -1229,7 +709,6 @@ PHP_MINIT_FUNCTION(http_encoding)
        return SUCCESS;
 }
 
-
 /*
  * Local variables:
  * tab-width: 4
index a924eaf4f1206461ace68454831a0cd3680d9ba6..3b59829d64338a10dc0c8d85b672e164540184ba 100644 (file)
 #ifndef PHP_HTTP_ENCODING_H
 #define PHP_HTTP_ENCODING_H
 
-#include <zlib.h>
-
 extern PHP_MINIT_FUNCTION(http_encoding);
-extern PHP_RINIT_FUNCTION(http_encoding);
-extern PHP_RSHUTDOWN_FUNCTION(http_encoding);
-
-#define PHP_HTTP_INFLATE_ROUNDS 100
-
-#define PHP_HTTP_DEFLATE_BUFFER_SIZE_GUESS(S) \
-       (((size_t) ((double) S * (double) 1.015)) + 10 + 8 + 4 + 1)
-#define PHP_HTTP_INFLATE_BUFFER_SIZE_GUESS(S) \
-       (((S) + 1) << 3)
-#define PHP_HTTP_INFLATE_BUFFER_SIZE_ALIGN(S) \
-       ((S) += (S) >> (3))
-
-#define PHP_HTTP_DEFLATE_BUFFER_SIZE           0x8000
-#define PHP_HTTP_INFLATE_BUFFER_SIZE           0x1000
-
-#define PHP_HTTP_DEFLATE_LEVEL_DEF                     0x00000000
-#define PHP_HTTP_DEFLATE_LEVEL_MIN                     0x00000001
-#define PHP_HTTP_DEFLATE_LEVEL_MAX                     0x00000009
-#define PHP_HTTP_DEFLATE_TYPE_ZLIB                     0x00000000
-#define PHP_HTTP_DEFLATE_TYPE_GZIP                     0x00000010
-#define PHP_HTTP_DEFLATE_TYPE_RAW                      0x00000020
-#define PHP_HTTP_DEFLATE_STRATEGY_DEF          0x00000000
-#define PHP_HTTP_DEFLATE_STRATEGY_FILT         0x00000100
-#define PHP_HTTP_DEFLATE_STRATEGY_HUFF         0x00000200
-#define PHP_HTTP_DEFLATE_STRATEGY_RLE          0x00000300
-#define PHP_HTTP_DEFLATE_STRATEGY_FIXED                0x00000400
-
-#define PHP_HTTP_DEFLATE_LEVEL_SET(flags, level) \
-       switch (flags & 0xf) \
-       { \
-               default: \
-                       if ((flags & 0xf) < 10) { \
-                               level = flags & 0xf; \
-                               break; \
-                       } \
-               case PHP_HTTP_DEFLATE_LEVEL_DEF: \
-                       level = Z_DEFAULT_COMPRESSION; \
-               break; \
-       }
-       
-#define PHP_HTTP_DEFLATE_WBITS_SET(flags, wbits) \
-       switch (flags & 0xf0) \
-       { \
-               case PHP_HTTP_DEFLATE_TYPE_GZIP: \
-                       wbits = PHP_HTTP_WINDOW_BITS_GZIP; \
-               break; \
-               case PHP_HTTP_DEFLATE_TYPE_RAW: \
-                       wbits = PHP_HTTP_WINDOW_BITS_RAW; \
-               break; \
-               default: \
-                       wbits = PHP_HTTP_WINDOW_BITS_ZLIB; \
-               break; \
-       }
-
-#define PHP_HTTP_INFLATE_WBITS_SET(flags, wbits) \
-       if (flags & PHP_HTTP_INFLATE_TYPE_RAW) { \
-               wbits = PHP_HTTP_WINDOW_BITS_RAW; \
-} else { \
-               wbits = PHP_HTTP_WINDOW_BITS_ANY; \
-}
-
-#define PHP_HTTP_DEFLATE_STRATEGY_SET(flags, strategy) \
-       switch (flags & 0xf00) \
-       { \
-               case PHP_HTTP_DEFLATE_STRATEGY_FILT: \
-                       strategy = Z_FILTERED; \
-               break; \
-               case PHP_HTTP_DEFLATE_STRATEGY_HUFF: \
-                       strategy = Z_HUFFMAN_ONLY; \
-               break; \
-               case PHP_HTTP_DEFLATE_STRATEGY_RLE: \
-                       strategy = Z_RLE; \
-               break; \
-               case PHP_HTTP_DEFLATE_STRATEGY_FIXED: \
-                       strategy = Z_FIXED; \
-               break; \
-               default: \
-                       strategy = Z_DEFAULT_STRATEGY; \
-               break; \
-       }
-
-#define PHP_HTTP_WINDOW_BITS_ZLIB      0x0000000f
-#define PHP_HTTP_WINDOW_BITS_GZIP      0x0000001f
-#define PHP_HTTP_WINDOW_BITS_ANY       0x0000002f
-#define PHP_HTTP_WINDOW_BITS_RAW       -0x000000f
-
-#ifndef Z_FIXED
-/* Z_FIXED does not exist prior 1.2.2.2 */
-#      define Z_FIXED 0
-#endif
 
-#define PHP_HTTP_INFLATE_TYPE_ZLIB                     0x00000000
-#define PHP_HTTP_INFLATE_TYPE_GZIP                     0x00000000
-#define PHP_HTTP_INFLATE_TYPE_RAW                      0x00000001
+#define PHP_HTTP_ENCODING_STREAM_PERSISTENT    0x01000000
+#define PHP_HTTP_ENCODING_STREAM_DIRTY         0x02000000
 
 #define PHP_HTTP_ENCODING_STREAM_FLUSH_NONE    0x00000000
 #define PHP_HTTP_ENCODING_STREAM_FLUSH_SYNC 0x00100000
 #define PHP_HTTP_ENCODING_STREAM_FLUSH_FULL 0x00200000
 
-#define PHP_HTTP_ENCODING_STREAM_FLUSH_FLAG(f) \
-       (((f) & PHP_HTTP_ENCODING_STREAM_FLUSH_FULL) ? Z_FULL_FLUSH : \
-       (((f) & PHP_HTTP_ENCODING_STREAM_FLUSH_SYNC) ? Z_SYNC_FLUSH : Z_NO_FLUSH))
-
-#define PHP_HTTP_ENCODING_STREAM_PERSISTENT    0x01000000
+#define PHP_HTTP_ENCODING_STREAM_FLUSH_FLAG(flags, full, sync, none) \
+       (((flags) & PHP_HTTP_ENCODING_STREAM_FLUSH_FULL) ? (full) : \
+       (((flags) & PHP_HTTP_ENCODING_STREAM_FLUSH_SYNC) ? (sync) : (none)))
 
 typedef struct php_http_encoding_stream php_http_encoding_stream_t;
 
@@ -147,9 +52,6 @@ struct php_http_encoding_stream {
        php_http_encoding_stream_ops_t *ops;
 };
 
-PHP_HTTP_API php_http_encoding_stream_ops_t *php_http_encoding_stream_get_deflate_ops(void);
-PHP_HTTP_API php_http_encoding_stream_ops_t *php_http_encoding_stream_get_inflate_ops(void);
-PHP_HTTP_API php_http_encoding_stream_ops_t *php_http_encoding_stream_get_dechunk_ops(void);
 
 PHP_HTTP_API php_http_encoding_stream_t *php_http_encoding_stream_init(php_http_encoding_stream_t *s, php_http_encoding_stream_ops_t *ops, unsigned flags);
 PHP_HTTP_API php_http_encoding_stream_t *php_http_encoding_stream_copy(php_http_encoding_stream_t *from, php_http_encoding_stream_t *to);
@@ -161,9 +63,9 @@ PHP_HTTP_API ZEND_RESULT_CODE php_http_encoding_stream_finish(php_http_encoding_
 PHP_HTTP_API void php_http_encoding_stream_dtor(php_http_encoding_stream_t *s);
 PHP_HTTP_API void php_http_encoding_stream_free(php_http_encoding_stream_t **s);
 
+PHP_HTTP_API php_http_encoding_stream_ops_t *php_http_encoding_stream_get_dechunk_ops(void);
 PHP_HTTP_API const char *php_http_encoding_dechunk(const char *encoded, size_t encoded_len, char **decoded, size_t *decoded_len);
-PHP_HTTP_API ZEND_RESULT_CODE php_http_encoding_deflate(int flags, const char *data, size_t data_len, char **encoded, size_t *encoded_len);
-PHP_HTTP_API ZEND_RESULT_CODE php_http_encoding_inflate(const char *data, size_t data_len, char **decoded, size_t *decoded_len);
+PHP_HTTP_API zend_class_entry *php_http_get_dechunk_stream_class_entry(void);
 
 typedef struct php_http_encoding_stream_object {
        php_http_encoding_stream_t *stream;
@@ -177,10 +79,6 @@ php_http_encoding_stream_object_t *php_http_encoding_stream_object_new_ex(zend_c
 zend_object *php_http_encoding_stream_object_clone(zval *object);
 void php_http_encoding_stream_object_free(zend_object *object);
 
-PHP_HTTP_API zend_class_entry *php_http_get_deflate_stream_class_entry(void);
-PHP_HTTP_API zend_class_entry *php_http_get_inflate_stream_class_entry(void);
-PHP_HTTP_API zend_class_entry *php_http_get_dechunk_stream_class_entry(void);
-
 #endif
 
 /*
diff --git a/src/php_http_encoding_brotli.c b/src/php_http_encoding_brotli.c
new file mode 100644 (file)
index 0000000..dbea978
--- /dev/null
@@ -0,0 +1,444 @@
+/*
+    +--------------------------------------------------------------------+
+    | PECL :: http                                                       |
+    +--------------------------------------------------------------------+
+    | Redistribution and use in source and binary forms, with or without |
+    | modification, are permitted provided that the conditions mentioned |
+    | in the accompanying LICENSE file are met.                          |
+    +--------------------------------------------------------------------+
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
+    +--------------------------------------------------------------------+
+*/
+
+#include "php_http_api.h"
+
+#if PHP_HTTP_HAVE_LIBBROTLI
+
+#define PHP_HTTP_DEBROTLI_ROUNDS 100
+#define PHP_HTTP_ENBROTLI_ROUNDS 100
+
+#define PHP_HTTP_ENBROTLI_BUFFER_SIZE_GUESS(S) \
+       BrotliEncoderMaxCompressedSize(S)
+#define PHP_HTTP_DEBROTLI_BUFFER_SIZE_ALIGN(S) \
+       ((S) += (S) >> 3)
+
+#define PHP_HTTP_ENBROTLI_FLUSH_FLAG(flags) \
+       PHP_HTTP_ENCODING_STREAM_FLUSH_FLAG((flags), BROTLI_OPERATION_FLUSH, BROTLI_OPERATION_FLUSH, BROTLI_OPERATION_PROCESS)
+
+#define PHP_HTTP_ENBROTLI_BUFFER_SIZE          0x2000
+#define PHP_HTTP_DEBROTLI_BUFFER_SIZE          0x1000
+
+#define PHP_HTTP_ENBROTLI_LEVEL_SET(flags, level) \
+       level = (((flags) & 0xf) ?: PHP_HTTP_ENBROTLI_LEVEL_DEF)
+#define PHP_HTTP_ENBROTLI_WBITS_SET(flags, wbits) \
+       wbits = ((((flags) >> 4) & 0xff) ?: (PHP_HTTP_ENBROTLI_WBITS_DEF >> 4))
+#define PHP_HTTP_ENBROTLI_MODE_SET(flags, mode) \
+       mode = (((flags) >> 12) & 0xf)
+
+
+static php_http_encoding_stream_t *enbrotli_init(php_http_encoding_stream_t *s)
+{
+       BrotliEncoderState *br;
+       int q, win, mode;
+
+       PHP_HTTP_ENBROTLI_LEVEL_SET(s->flags, q);
+       PHP_HTTP_ENBROTLI_WBITS_SET(s->flags, win);
+       PHP_HTTP_ENBROTLI_MODE_SET(s->flags, mode);
+
+       br = BrotliEncoderCreateInstance(NULL, NULL, NULL);
+       if (EXPECTED(br)) {
+               BrotliEncoderSetParameter(br, BROTLI_PARAM_QUALITY, q);
+               BrotliEncoderSetParameter(br, BROTLI_PARAM_LGWIN, win);
+               BrotliEncoderSetParameter(br, BROTLI_PARAM_MODE, mode);
+
+               s->ctx = br;
+               return s;
+       }
+
+       php_error_docref(NULL, E_WARNING, "Failed to initialize brotli encoding stream");
+       return NULL;
+}
+
+static ZEND_RESULT_CODE enbrotli_update(php_http_encoding_stream_t *s, const char *data, size_t data_len, char **encoded, size_t *encoded_len)
+{
+       php_http_buffer_t out;
+       const unsigned char *in_ptr;
+       size_t in_len;
+       BROTLI_BOOL rc;
+
+       php_http_buffer_init_ex(&out, PHP_HTTP_ENBROTLI_BUFFER_SIZE_GUESS(data_len), 0);
+
+       in_len = data_len;
+       in_ptr = (const unsigned char *) data;
+
+       while (in_len) {
+               size_t out_len = 0;
+
+               rc = BrotliEncoderCompressStream(s->ctx, PHP_HTTP_ENBROTLI_FLUSH_FLAG(s->flags), &in_len, &in_ptr, &out_len, NULL, NULL);
+
+               if (!rc) {
+                       break;
+               }
+
+               if (BrotliEncoderHasMoreOutput(s->ctx)) {
+                       const char *out_str = (const char *) BrotliEncoderTakeOutput(s->ctx, &out_len);
+
+                       php_http_buffer_append(&out, out_str, out_len);
+               }
+       }
+
+       if (rc) {
+               if (out.used) {
+                       php_http_buffer_shrink(&out);
+                       php_http_buffer_fix(&out);
+                       *encoded = out.data;
+                       *encoded_len = out.used;
+               } else {
+                       *encoded = NULL;
+                       *encoded_len = 0;
+                       php_http_buffer_dtor(&out);
+               }
+               return SUCCESS;
+       }
+
+       php_http_buffer_dtor(&out);
+
+       *encoded = NULL;
+       *encoded_len = 0;
+
+       php_error_docref(NULL, E_WARNING, "Failed to update brotli encoding stream");
+       return FAILURE;
+}
+
+static inline ZEND_RESULT_CODE enbrotli_flush_ex(php_http_encoding_stream_t *s, BrotliEncoderOperation op, char **encoded, size_t *encoded_len)
+{
+       php_http_buffer_t out;
+       BROTLI_BOOL rc;
+       int round = 0;
+
+       php_http_buffer_init_ex(&out, PHP_HTTP_ENBROTLI_BUFFER_SIZE, 0);
+
+       do {
+               const unsigned char *empty = NULL;
+               size_t unused = 0, out_len = 0;
+
+               rc = BrotliEncoderCompressStream(s->ctx, op, &unused, &empty, &out_len, NULL, NULL);
+
+               if (!rc) {
+                       break;
+               }
+
+               if (BrotliEncoderHasMoreOutput(s->ctx)) {
+                       const char *out_str = (const char *) BrotliEncoderTakeOutput(s->ctx, &out_len);
+
+                       php_http_buffer_append(&out, out_str, out_len);
+               } else {
+                       if (out.used) {
+                               php_http_buffer_shrink(&out);
+                               php_http_buffer_fix(&out);
+
+                               *encoded = out.data;
+                               *encoded_len = out.used;
+                       } else {
+                               *encoded = NULL;
+                               *encoded_len = 0;
+                       }
+                       return SUCCESS;
+               }
+       } while (++round < PHP_HTTP_ENBROTLI_ROUNDS);
+
+       php_http_buffer_dtor(&out);
+
+       *encoded = NULL;
+       *encoded_len = 0;
+
+       php_error_docref(NULL, E_WARNING, "Failed to flush brotli encoding stream");
+       return FAILURE;
+}
+
+static ZEND_RESULT_CODE enbrotli_flush(php_http_encoding_stream_t *s, char **encoded, size_t *encoded_len)
+{
+       return enbrotli_flush_ex(s, BROTLI_OPERATION_FLUSH, encoded, encoded_len);
+}
+
+static ZEND_RESULT_CODE enbrotli_finish(php_http_encoding_stream_t *s, char **encoded, size_t *encoded_len)
+{
+       ZEND_RESULT_CODE rc;
+
+       do {
+               rc = enbrotli_flush_ex(s, BROTLI_OPERATION_FINISH, encoded, encoded_len);
+       } while (SUCCESS == rc && !BrotliEncoderIsFinished(s->ctx));
+
+       return rc;
+}
+
+static zend_bool enbrotli_done(php_http_encoding_stream_t *s)
+{
+       return !(s->flags & PHP_HTTP_ENCODING_STREAM_DIRTY)
+                       || BrotliEncoderIsFinished(s->ctx);
+}
+
+static void enbrotli_dtor(php_http_encoding_stream_t *s)
+{
+       if (s->ctx) {
+               BrotliEncoderDestroyInstance(s->ctx);
+               s->ctx = NULL;
+       }
+}
+
+static php_http_encoding_stream_t *debrotli_init(php_http_encoding_stream_t *s)
+{
+       BrotliDecoderState *br;
+
+       br = BrotliDecoderCreateInstance(NULL, NULL, NULL);
+       if (br) {
+               s->ctx = br;
+               return s;
+       }
+
+       php_error_docref(NULL, E_WARNING, "Failed to initialize brotli decoding stream");
+       return NULL;
+}
+
+static ZEND_RESULT_CODE debrotli_update(php_http_encoding_stream_t *s, const char *encoded, size_t encoded_len, char **decoded, size_t *decoded_len)
+{
+       php_http_buffer_t out;
+       BrotliDecoderResult rc;
+       const unsigned char *in_ptr;
+       size_t in_len;
+
+       in_ptr = (const unsigned char *) encoded;
+       in_len = encoded_len;
+
+       php_http_buffer_init_ex(&out, encoded_len, PHP_HTTP_BUFFER_INIT_PREALLOC);
+
+       while (in_len) {
+               size_t out_len = 0;
+
+               rc = BrotliDecoderDecompressStream(s->ctx, &in_len, &in_ptr, &out_len, NULL, NULL);
+
+               if (BROTLI_DECODER_RESULT_ERROR == rc) {
+                       break;
+               }
+
+               if (BrotliDecoderHasMoreOutput(s->ctx)) {
+                       const char *out_str = (const char *) BrotliDecoderTakeOutput(s->ctx, &out_len);
+
+                       php_http_buffer_append(&out, out_str, out_len);
+               }
+       }
+
+       if (BROTLI_DECODER_RESULT_ERROR != rc) {
+               if (out.used) {
+                       php_http_buffer_shrink(&out);
+                       php_http_buffer_fix(&out);
+                       *decoded = out.data;
+                       *decoded_len = out.used;
+               } else {
+                       php_http_buffer_dtor(&out);
+                       *decoded = NULL;
+                       *decoded_len = 0;
+               }
+               return SUCCESS;
+       }
+
+       php_http_buffer_dtor(&out);
+
+       php_error_docref(NULL, E_WARNING, "Could not brotli decode data: %s", BrotliDecoderErrorString(BrotliDecoderGetErrorCode(s->ctx)));
+       return FAILURE;
+}
+
+static zend_bool debrotli_done(php_http_encoding_stream_t *s)
+{
+       return !BrotliDecoderIsUsed(s->ctx) || BrotliDecoderIsFinished(s->ctx);
+}
+
+static void debrotli_dtor(php_http_encoding_stream_t *s)
+{
+       if (s->ctx) {
+               BrotliDecoderDestroyInstance(s->ctx);
+               s->ctx = NULL;
+       }
+}
+
+static php_http_encoding_stream_ops_t php_http_encoding_enbrotli_ops = {
+       enbrotli_init,
+       NULL,
+       enbrotli_update,
+       enbrotli_flush,
+       enbrotli_done,
+       enbrotli_finish,
+       enbrotli_dtor
+};
+
+php_http_encoding_stream_ops_t *php_http_encoding_stream_get_enbrotli_ops(void)
+{
+       return &php_http_encoding_enbrotli_ops;
+}
+
+static php_http_encoding_stream_ops_t php_http_encoding_debrotli_ops = {
+       debrotli_init,
+       NULL,
+       debrotli_update,
+       NULL,
+       debrotli_done,
+       NULL,
+       debrotli_dtor
+};
+
+php_http_encoding_stream_ops_t *php_http_encoding_stream_get_debrotli_ops(void)
+{
+       return &php_http_encoding_debrotli_ops;
+}
+
+ZEND_RESULT_CODE php_http_encoding_enbrotli(int flags, const char *data, size_t data_len, char **encoded, size_t *encoded_len)
+{
+       BROTLI_BOOL rc;
+       int q, win, mode;
+
+       *encoded_len = PHP_HTTP_ENBROTLI_BUFFER_SIZE_GUESS(data_len);
+       *encoded = emalloc(*encoded_len + 1);
+
+       PHP_HTTP_ENBROTLI_LEVEL_SET(flags, q);
+       PHP_HTTP_ENBROTLI_WBITS_SET(flags, win);
+       PHP_HTTP_ENBROTLI_MODE_SET(flags, mode);
+
+       rc = BrotliEncoderCompress(q, win, mode, data_len, (const unsigned char *) data, encoded_len, (unsigned char *) *encoded);
+       if (rc) {
+               return SUCCESS;
+       }
+
+       PTR_SET(*encoded, NULL);
+       *encoded_len = 0;
+
+       php_error_docref(NULL, E_WARNING, "Could not brotli encode data");
+       return FAILURE;
+}
+
+ZEND_RESULT_CODE php_http_encoding_debrotli(const char *encoded, size_t encoded_len, char **decoded, size_t *decoded_len)
+{
+       php_http_encoding_stream_t s = {0};
+       ZEND_RESULT_CODE rc = FAILURE;
+
+       if (debrotli_init(&s)) {
+               rc = debrotli_update(&s, encoded, encoded_len, decoded, decoded_len);
+               debrotli_dtor(&s);
+       }
+
+       return rc;
+}
+
+static zend_class_entry *php_http_enbrotli_stream_class_entry;
+zend_class_entry *php_http_get_enbrotli_stream_class_entry(void)
+{
+       return php_http_enbrotli_stream_class_entry;
+}
+
+static zend_class_entry *php_http_debrotli_stream_class_entry;
+zend_class_entry *php_http_get_debrotli_stream_class_entry(void)
+{
+       return php_http_debrotli_stream_class_entry;
+}
+
+ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnbrotliStream_encode, 0, 0, 1)
+       ZEND_ARG_INFO(0, data)
+       ZEND_ARG_INFO(0, flags)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(HttpEnbrotliStream, encode)
+{
+       char *str;
+       size_t len;
+       zend_long flags = PHP_HTTP_ENBROTLI_MODE_GENERIC | PHP_HTTP_ENBROTLI_WBITS_DEF | PHP_HTTP_ENBROTLI_LEVEL_DEF;
+
+       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &str, &len, &flags)) {
+               char *enc_str = NULL;
+               size_t enc_len;
+
+               if (SUCCESS == php_http_encoding_enbrotli(flags, str, len, &enc_str, &enc_len)) {
+                       if (enc_str) {
+                               RETURN_STR(php_http_cs2zs(enc_str, enc_len));
+                       } else {
+                               RETURN_EMPTY_STRING();
+                       }
+               }
+       }
+       RETURN_FALSE;
+}
+static zend_function_entry php_http_enbrotli_stream_methods[] = {
+       PHP_ME(HttpEnbrotliStream, encode, ai_HttpEnbrotliStream_encode, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
+       EMPTY_FUNCTION_ENTRY
+};
+
+ZEND_BEGIN_ARG_INFO_EX(ai_HttpDebrotliStream_decode, 0, 0, 1)
+       ZEND_ARG_INFO(0, data)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(HttpDebrotliStream, decode)
+{
+       char *str;
+       size_t len;
+
+       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &str, &len)) {
+               char *enc_str = NULL;
+               size_t enc_len;
+
+               if (SUCCESS == php_http_encoding_debrotli(str, len, &enc_str, &enc_len)) {
+                       if (enc_str) {
+                               RETURN_STR(php_http_cs2zs(enc_str, enc_len));
+                       } else {
+                               RETURN_EMPTY_STRING();
+                       }
+               }
+       }
+       RETURN_FALSE;
+}
+
+static zend_function_entry php_http_debrotli_stream_methods[] = {
+       PHP_ME(HttpDebrotliStream, decode, ai_HttpDebrotliStream_decode, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
+       EMPTY_FUNCTION_ENTRY
+};
+
+/* POS */
+const void *BrotliGetDictionary();
+const void *(*php_http_brotli_get_dictionary)();
+
+PHP_MINIT_FUNCTION(http_encoding_brotli)
+{
+       zend_class_entry ce;
+
+       /* force link to libbrotlicommon, because their libraries don't */
+       php_http_brotli_get_dictionary = BrotliGetDictionary();
+
+       memset(&ce, 0, sizeof(ce));
+       INIT_NS_CLASS_ENTRY(ce, "http\\Encoding\\Stream", "Enbrotli", php_http_enbrotli_stream_methods);
+       php_http_enbrotli_stream_class_entry = zend_register_internal_class_ex(&ce, php_http_get_encoding_stream_class_entry());
+       php_http_enbrotli_stream_class_entry->create_object = php_http_encoding_stream_object_new;
+
+       zend_declare_class_constant_long(php_http_enbrotli_stream_class_entry, ZEND_STRL("LEVEL_MIN"), PHP_HTTP_ENBROTLI_LEVEL_MIN);
+       zend_declare_class_constant_long(php_http_enbrotli_stream_class_entry, ZEND_STRL("LEVEL_DEF"), PHP_HTTP_ENBROTLI_LEVEL_DEF);
+       zend_declare_class_constant_long(php_http_enbrotli_stream_class_entry, ZEND_STRL("LEVEL_MAX"), PHP_HTTP_ENBROTLI_LEVEL_MAX);
+       zend_declare_class_constant_long(php_http_enbrotli_stream_class_entry, ZEND_STRL("WBITS_MIN"), PHP_HTTP_ENBROTLI_WBITS_MIN);
+       zend_declare_class_constant_long(php_http_enbrotli_stream_class_entry, ZEND_STRL("WBITS_DEF"), PHP_HTTP_ENBROTLI_WBITS_DEF);
+       zend_declare_class_constant_long(php_http_enbrotli_stream_class_entry, ZEND_STRL("WBITS_MAX"), PHP_HTTP_ENBROTLI_WBITS_MAX);
+       zend_declare_class_constant_long(php_http_enbrotli_stream_class_entry, ZEND_STRL("MODE_GENERIC"), PHP_HTTP_ENBROTLI_MODE_GENERIC);
+       zend_declare_class_constant_long(php_http_enbrotli_stream_class_entry, ZEND_STRL("MODE_TEXT"), PHP_HTTP_ENBROTLI_MODE_TEXT);
+       zend_declare_class_constant_long(php_http_enbrotli_stream_class_entry, ZEND_STRL("MODE_FONT"), PHP_HTTP_ENBROTLI_MODE_FONT);
+
+       memset(&ce, 0, sizeof(ce));
+       INIT_NS_CLASS_ENTRY(ce, "http\\Encoding\\Stream", "Debrotli", php_http_debrotli_stream_methods);
+       php_http_debrotli_stream_class_entry = zend_register_internal_class_ex(&ce, php_http_get_encoding_stream_class_entry());
+       php_http_debrotli_stream_class_entry->create_object = php_http_encoding_stream_object_new;
+
+       return SUCCESS;
+}
+
+#endif
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
+
diff --git a/src/php_http_encoding_brotli.h b/src/php_http_encoding_brotli.h
new file mode 100644 (file)
index 0000000..504430f
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+    +--------------------------------------------------------------------+
+    | PECL :: http                                                       |
+    +--------------------------------------------------------------------+
+    | Redistribution and use in source and binary forms, with or without |
+    | modification, are permitted provided that the conditions mentioned |
+    | in the accompanying LICENSE file are met.                          |
+    +--------------------------------------------------------------------+
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
+    +--------------------------------------------------------------------+
+*/
+
+#ifndef PHP_HTTP_ENCODING_BROTLI_H
+#define PHP_HTTP_ENCODING_BROTLI_H
+#if PHP_HTTP_HAVE_LIBBROTLI
+
+#include <brotli/decode.h>
+#include <brotli/encode.h>
+
+extern PHP_MINIT_FUNCTION(http_encoding_brotli);
+
+PHP_HTTP_API zend_class_entry *php_http_get_enbrotli_stream_class_entry(void);
+PHP_HTTP_API zend_class_entry *php_http_get_debrotli_stream_class_entry(void);
+
+PHP_HTTP_API php_http_encoding_stream_ops_t *php_http_encoding_stream_get_enbrotli_ops(void);
+PHP_HTTP_API php_http_encoding_stream_ops_t *php_http_encoding_stream_get_debrotli_ops(void);
+
+PHP_HTTP_API ZEND_RESULT_CODE php_http_encoding_enbrotli(int flags, const char *data, size_t data_len, char **encoded, size_t *encoded_len);
+PHP_HTTP_API ZEND_RESULT_CODE php_http_encoding_debrotli(const char *encoded, size_t encoded_len, char **decoded, size_t *decoded_len);
+
+#define PHP_HTTP_ENBROTLI_LEVEL_MIN                    0x00000001
+#define PHP_HTTP_ENBROTLI_LEVEL_DEF                    0x00000004
+#define PHP_HTTP_ENBROTLI_LEVEL_MAX                    0x0000000b
+
+#define PHP_HTTP_ENBROTLI_WBITS_MIN                    0x000000a0
+#define PHP_HTTP_ENBROTLI_WBITS_DEF                    0x00000160
+#define PHP_HTTP_ENBROTLI_WBITS_MAX                    0x00000180
+
+#define PHP_HTTP_ENBROTLI_MODE_GENERIC         0x00000000
+#define PHP_HTTP_ENBROTLI_MODE_TEXT                    0x00001000
+#define PHP_HTTP_ENBROTLI_MODE_FONT                    0x00002000
+
+#endif
+#endif
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
+
diff --git a/src/php_http_encoding_zlib.c b/src/php_http_encoding_zlib.c
new file mode 100644 (file)
index 0000000..5e19cec
--- /dev/null
@@ -0,0 +1,650 @@
+/*
+    +--------------------------------------------------------------------+
+    | PECL :: http                                                       |
+    +--------------------------------------------------------------------+
+    | Redistribution and use in source and binary forms, with or without |
+    | modification, are permitted provided that the conditions mentioned |
+    | in the accompanying LICENSE file are met.                          |
+    +--------------------------------------------------------------------+
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
+    +--------------------------------------------------------------------+
+*/
+
+#include "php_http_api.h"
+
+#define PHP_HTTP_INFLATE_ROUNDS                                100
+#define PHP_HTTP_INFLATE_BUFFER_SIZE           0x1000
+
+#define PHP_HTTP_DEFLATE_BUFFER_SIZE           0x8000
+
+#define PHP_HTTP_DEFLATE_BUFFER_SIZE_GUESS(S) \
+       (((size_t) ((double) S * (double) 1.015)) + 10 + 8 + 4 + 1)
+
+#define PHP_HTTP_INFLATE_BUFFER_SIZE_GUESS(S) \
+       (((S) + 1) << 3)
+#define PHP_HTTP_INFLATE_BUFFER_SIZE_ALIGN(S) \
+       ((S) += (S) >> (3))
+
+#define PHP_HTTP_INFLATE_FLUSH_FLAG(flags) \
+       PHP_HTTP_ENCODING_STREAM_FLUSH_FLAG((flags), Z_FULL_FLUSH, Z_SYNC_FLUSH, Z_NO_FLUSH)
+#define PHP_HTTP_DEFLATE_FLUSH_FLAG(flags) \
+       PHP_HTTP_ENCODING_STREAM_FLUSH_FLAG((flags), Z_FULL_FLUSH, Z_SYNC_FLUSH, Z_NO_FLUSH)
+
+#define PHP_HTTP_WINDOW_BITS_ZLIB                      0x0000000f
+#define PHP_HTTP_WINDOW_BITS_GZIP                      0x0000001f
+#define PHP_HTTP_WINDOW_BITS_ANY                       0x0000002f
+#define PHP_HTTP_WINDOW_BITS_RAW                       -0x000000f
+
+#define PHP_HTTP_DEFLATE_LEVEL_SET(flags, level) \
+       switch (flags & 0xf) \
+       { \
+               default: \
+                       if ((flags & 0xf) < 10) { \
+                               level = flags & 0xf; \
+                               break; \
+                       } \
+               case PHP_HTTP_DEFLATE_LEVEL_DEF: \
+                       level = Z_DEFAULT_COMPRESSION; \
+               break; \
+       }
+
+#define PHP_HTTP_DEFLATE_WBITS_SET(flags, wbits) \
+       switch (flags & 0xf0) \
+       { \
+               case PHP_HTTP_DEFLATE_TYPE_GZIP: \
+                       wbits = PHP_HTTP_WINDOW_BITS_GZIP; \
+               break; \
+               case PHP_HTTP_DEFLATE_TYPE_RAW: \
+                       wbits = PHP_HTTP_WINDOW_BITS_RAW; \
+               break; \
+               default: \
+                       wbits = PHP_HTTP_WINDOW_BITS_ZLIB; \
+               break; \
+       }
+
+#define PHP_HTTP_INFLATE_WBITS_SET(flags, wbits) \
+       if (flags & PHP_HTTP_INFLATE_TYPE_RAW) { \
+               wbits = PHP_HTTP_WINDOW_BITS_RAW; \
+       } else { \
+                       wbits = PHP_HTTP_WINDOW_BITS_ANY; \
+       }
+
+#define PHP_HTTP_DEFLATE_STRATEGY_SET(flags, strategy) \
+       switch (flags & 0xf00) \
+       { \
+               case PHP_HTTP_DEFLATE_STRATEGY_FILT: \
+                       strategy = Z_FILTERED; \
+               break; \
+               case PHP_HTTP_DEFLATE_STRATEGY_HUFF: \
+                       strategy = Z_HUFFMAN_ONLY; \
+               break; \
+               case PHP_HTTP_DEFLATE_STRATEGY_RLE: \
+                       strategy = Z_RLE; \
+               break; \
+               case PHP_HTTP_DEFLATE_STRATEGY_FIXED: \
+                       strategy = Z_FIXED; \
+               break; \
+               default: \
+                       strategy = Z_DEFAULT_STRATEGY; \
+               break; \
+       }
+
+ZEND_RESULT_CODE php_http_encoding_deflate(int flags, const char *data, size_t data_len, char **encoded, size_t *encoded_len)
+{
+       int status, level, wbits, strategy;
+       z_stream Z;
+
+       PHP_HTTP_DEFLATE_LEVEL_SET(flags, level);
+       PHP_HTTP_DEFLATE_WBITS_SET(flags, wbits);
+       PHP_HTTP_DEFLATE_STRATEGY_SET(flags, strategy);
+
+       memset(&Z, 0, sizeof(z_stream));
+       *encoded = NULL;
+       *encoded_len = 0;
+
+       status = deflateInit2(&Z, level, Z_DEFLATED, wbits, MAX_MEM_LEVEL, strategy);
+       if (EXPECTED(Z_OK == status)) {
+               *encoded_len = PHP_HTTP_DEFLATE_BUFFER_SIZE_GUESS(data_len);
+               *encoded = emalloc(*encoded_len);
+
+               Z.next_in = (Bytef *) data;
+               Z.next_out = (Bytef *) *encoded;
+               Z.avail_in = data_len;
+               Z.avail_out = *encoded_len;
+
+               status = deflate(&Z, Z_FINISH);
+               deflateEnd(&Z);
+
+               if (EXPECTED(Z_STREAM_END == status)) {
+                       /* size buffer down to actual length */
+                       *encoded = erealloc(*encoded, Z.total_out + 1);
+                       (*encoded)[*encoded_len = Z.total_out] = '\0';
+                       return SUCCESS;
+               } else {
+                       PTR_SET(*encoded, NULL);
+                       *encoded_len = 0;
+               }
+       }
+
+       php_error_docref(NULL, E_WARNING, "Could not deflate data: %s", zError(status));
+       return FAILURE;
+}
+
+static php_http_encoding_stream_t *deflate_init(php_http_encoding_stream_t *s)
+{
+       int status, level, wbits, strategy, p = (s->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT);
+       z_streamp ctx = pecalloc(1, sizeof(z_stream), p);
+
+       PHP_HTTP_DEFLATE_LEVEL_SET(s->flags, level);
+       PHP_HTTP_DEFLATE_WBITS_SET(s->flags, wbits);
+       PHP_HTTP_DEFLATE_STRATEGY_SET(s->flags, strategy);
+
+       if (EXPECTED(Z_OK == (status = deflateInit2(ctx, level, Z_DEFLATED, wbits, MAX_MEM_LEVEL, strategy)))) {
+               if (EXPECTED(ctx->opaque = php_http_buffer_init_ex(NULL, PHP_HTTP_DEFLATE_BUFFER_SIZE, p ? PHP_HTTP_BUFFER_INIT_PERSISTENT : 0))) {
+                       s->ctx = ctx;
+                       return s;
+               }
+               deflateEnd(ctx);
+               status = Z_MEM_ERROR;
+       }
+       pefree(ctx, p);
+       php_error_docref(NULL, E_WARNING, "Failed to initialize deflate encoding stream: %s", zError(status));
+       return NULL;
+}
+
+static php_http_encoding_stream_t *deflate_copy(php_http_encoding_stream_t *from, php_http_encoding_stream_t *to)
+{
+       int status, p = to->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT;
+       z_streamp from_ctx = from->ctx, to_ctx = pecalloc(1, sizeof(*to_ctx), p);
+
+       if (Z_OK == (status = deflateCopy(to_ctx, from_ctx))) {
+               if ((to_ctx->opaque = php_http_buffer_init_ex(NULL, PHP_HTTP_DEFLATE_BUFFER_SIZE, p ? PHP_HTTP_BUFFER_INIT_PERSISTENT : 0))) {
+                       php_http_buffer_append(to_ctx->opaque, PHP_HTTP_BUFFER(from_ctx->opaque)->data, PHP_HTTP_BUFFER(from_ctx->opaque)->used);
+                       to->ctx = to_ctx;
+                       return to;
+               }
+               deflateEnd(to_ctx);
+               status = Z_MEM_ERROR;
+       }
+       php_error_docref(NULL, E_WARNING, "Failed to copy deflate encoding stream: %s", zError(status));
+       return NULL;
+}
+
+static ZEND_RESULT_CODE deflate_update(php_http_encoding_stream_t *s, const char *data, size_t data_len, char **encoded, size_t *encoded_len)
+{
+       int status;
+       z_streamp ctx = s->ctx;
+
+       /* append input to our buffer */
+       php_http_buffer_append(PHP_HTTP_BUFFER(ctx->opaque), data, data_len);
+
+       ctx->next_in = (Bytef *) PHP_HTTP_BUFFER(ctx->opaque)->data;
+       ctx->avail_in = PHP_HTTP_BUFFER(ctx->opaque)->used;
+
+       /* deflate */
+       *encoded_len = PHP_HTTP_DEFLATE_BUFFER_SIZE_GUESS(data_len);
+       *encoded = emalloc(*encoded_len);
+       ctx->avail_out = *encoded_len;
+       ctx->next_out = (Bytef *) *encoded;
+
+       switch (status = deflate(ctx, PHP_HTTP_DEFLATE_FLUSH_FLAG(s->flags))) {
+               case Z_OK:
+               case Z_STREAM_END:
+                       /* cut processed chunk off the buffer */
+                       if (ctx->avail_in) {
+                               php_http_buffer_cut(PHP_HTTP_BUFFER(ctx->opaque), 0, PHP_HTTP_BUFFER(ctx->opaque)->used - ctx->avail_in);
+                       } else {
+                               php_http_buffer_reset(PHP_HTTP_BUFFER(ctx->opaque));
+                       }
+
+                       /* size buffer down to actual size */
+                       *encoded_len -= ctx->avail_out;
+                       *encoded = erealloc(*encoded, *encoded_len + 1);
+                       (*encoded)[*encoded_len] = '\0';
+                       return SUCCESS;
+       }
+
+       PTR_SET(*encoded, NULL);
+       *encoded_len = 0;
+       php_error_docref(NULL, E_WARNING, "Failed to update deflate stream: %s", zError(status));
+       return FAILURE;
+}
+
+static ZEND_RESULT_CODE deflate_flush(php_http_encoding_stream_t *s, char **encoded, size_t *encoded_len)
+{
+       int status;
+       z_streamp ctx = s->ctx;
+
+       *encoded_len = PHP_HTTP_DEFLATE_BUFFER_SIZE;
+       *encoded = emalloc(*encoded_len);
+
+       ctx->avail_in = 0;
+       ctx->next_in = NULL;
+       ctx->avail_out = *encoded_len;
+       ctx->next_out = (Bytef *) *encoded;
+
+       status = deflate(ctx, Z_FULL_FLUSH);
+       if (EXPECTED(Z_OK == status || Z_STREAM_END == status)) {
+               *encoded_len = PHP_HTTP_DEFLATE_BUFFER_SIZE - ctx->avail_out;
+               *encoded = erealloc(*encoded, *encoded_len + 1);
+               (*encoded)[*encoded_len] = '\0';
+               return SUCCESS;
+       }
+
+       PTR_SET(*encoded, NULL);
+       *encoded_len = 0;
+       php_error_docref(NULL, E_WARNING, "Failed to flush deflate stream: %s", zError(status));
+       return FAILURE;
+}
+
+static ZEND_RESULT_CODE deflate_finish(php_http_encoding_stream_t *s, char **encoded, size_t *encoded_len)
+{
+       int status;
+       z_streamp ctx = s->ctx;
+
+       *encoded_len = PHP_HTTP_DEFLATE_BUFFER_SIZE;
+       *encoded = emalloc(*encoded_len);
+
+       /* deflate remaining input */
+       ctx->next_in = (Bytef *) PHP_HTTP_BUFFER(ctx->opaque)->data;
+       ctx->avail_in = PHP_HTTP_BUFFER(ctx->opaque)->used;
+
+       ctx->avail_out = *encoded_len;
+       ctx->next_out = (Bytef *) *encoded;
+
+       do {
+               status = deflate(ctx, Z_FINISH);
+       } while (Z_OK == status);
+
+       if (EXPECTED(Z_STREAM_END == status)) {
+               /* cut processed input off */
+               php_http_buffer_cut(PHP_HTTP_BUFFER(ctx->opaque), 0, PHP_HTTP_BUFFER(ctx->opaque)->used - ctx->avail_in);
+
+               /* size down */
+               *encoded_len -= ctx->avail_out;
+               *encoded = erealloc(*encoded, *encoded_len + 1);
+               (*encoded)[*encoded_len] = '\0';
+               return SUCCESS;
+       }
+
+       PTR_SET(*encoded, NULL);
+       *encoded_len = 0;
+       php_error_docref(NULL, E_WARNING, "Failed to finish deflate stream: %s", zError(status));
+       return FAILURE;
+}
+
+static zend_bool deflate_done(php_http_encoding_stream_t *s)
+{
+       z_streamp ctx = s->ctx;
+       return !ctx->avail_in && !PHP_HTTP_BUFFER(ctx->opaque)->used;
+}
+
+static void deflate_dtor(php_http_encoding_stream_t *s)
+{
+       if (EXPECTED(s->ctx)) {
+               z_streamp ctx = s->ctx;
+
+               if (EXPECTED(ctx->opaque)) {
+                       php_http_buffer_free((php_http_buffer_t **) &ctx->opaque);
+               }
+               deflateEnd(ctx);
+               pefree(ctx, (s->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT));
+               s->ctx = NULL;
+       }
+}
+
+static inline int php_http_inflate_rounds(z_stream *Z, int flush, char **buf, size_t *len)
+{
+       int status = 0, round = 0;
+       php_http_buffer_t buffer;
+
+       *buf = NULL;
+       *len = 0;
+
+       php_http_buffer_init_ex(&buffer, Z->avail_in, PHP_HTTP_BUFFER_INIT_PREALLOC);
+
+       do {
+               if (UNEXPECTED(PHP_HTTP_BUFFER_NOMEM == php_http_buffer_resize_ex(&buffer, buffer.size, 0, 1))) {
+                       status = Z_MEM_ERROR;
+               } else {
+                       Z->avail_out = buffer.free;
+                       Z->next_out = (Bytef *) buffer.data + buffer.used;
+#if 0
+                       fprintf(stderr, "\n%3d: %3d PRIOR: size=%7lu,\tfree=%7lu,\tused=%7lu,\tavail_in=%7lu,\tavail_out=%7lu\n", round, status, buffer.size, buffer.free, buffer.used, Z->avail_in, Z->avail_out);
+#endif
+                       status = inflate(Z, flush);
+                       php_http_buffer_account(&buffer, buffer.free - Z->avail_out);
+#if 0
+                       fprintf(stderr, "%3d: %3d AFTER: size=%7lu,\tfree=%7lu,\tused=%7lu,\tavail_in=%7lu,\tavail_out=%7lu\n", round, status, buffer.size, buffer.free, buffer.used, Z->avail_in, Z->avail_out);
+#endif
+                       PHP_HTTP_INFLATE_BUFFER_SIZE_ALIGN(buffer.size);
+               }
+       } while ((Z_BUF_ERROR == status || (Z_OK == status && Z->avail_in)) && ++round < PHP_HTTP_INFLATE_ROUNDS);
+
+       if (EXPECTED(status == Z_OK || status == Z_STREAM_END)) {
+               php_http_buffer_shrink(&buffer);
+               php_http_buffer_fix(&buffer);
+               *buf = buffer.data;
+               *len = buffer.used;
+       } else {
+               php_http_buffer_dtor(&buffer);
+       }
+
+       return status;
+}
+
+ZEND_RESULT_CODE php_http_encoding_inflate(const char *data, size_t data_len, char **decoded, size_t *decoded_len)
+{
+       z_stream Z;
+       int status, wbits = PHP_HTTP_WINDOW_BITS_ANY;
+
+       memset(&Z, 0, sizeof(z_stream));
+
+retry_raw_inflate:
+       status = inflateInit2(&Z, wbits);
+       if (EXPECTED(Z_OK == status)) {
+               Z.next_in = (Bytef *) data;
+               Z.avail_in = data_len + 1; /* include the terminating NULL, see #61287 */
+
+               switch (status = php_http_inflate_rounds(&Z, Z_NO_FLUSH, decoded, decoded_len)) {
+                       case Z_STREAM_END:
+                               inflateEnd(&Z);
+                               return SUCCESS;
+
+                       case Z_OK:
+                               status = Z_DATA_ERROR;
+                               break;
+
+                       case Z_DATA_ERROR:
+                               /* raw deflated data? */
+                               if (PHP_HTTP_WINDOW_BITS_ANY == wbits) {
+                                       inflateEnd(&Z);
+                                       wbits = PHP_HTTP_WINDOW_BITS_RAW;
+                                       goto retry_raw_inflate;
+                               }
+                               break;
+               }
+               inflateEnd(&Z);
+
+               if (*decoded_len && *decoded) {
+                       efree(*decoded);
+               }
+       }
+
+       php_error_docref(NULL, E_WARNING, "Could not inflate data: %s", zError(status));
+       return FAILURE;
+}
+
+static php_http_encoding_stream_t *inflate_init(php_http_encoding_stream_t *s)
+{
+       int status, wbits, p = (s->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT);
+       z_streamp ctx = pecalloc(1, sizeof(z_stream), p);
+
+       PHP_HTTP_INFLATE_WBITS_SET(s->flags, wbits);
+
+       if (EXPECTED(Z_OK == (status = inflateInit2(ctx, wbits)))) {
+               if ((ctx->opaque = php_http_buffer_init_ex(NULL, PHP_HTTP_DEFLATE_BUFFER_SIZE, p ? PHP_HTTP_BUFFER_INIT_PERSISTENT : 0))) {
+                       s->ctx = ctx;
+                       return s;
+               }
+               inflateEnd(ctx);
+               status = Z_MEM_ERROR;
+       }
+       pefree(ctx, p);
+       php_error_docref(NULL, E_WARNING, "Failed to initialize inflate stream: %s", zError(status));
+       return NULL;
+}
+
+static php_http_encoding_stream_t *inflate_copy(php_http_encoding_stream_t *from, php_http_encoding_stream_t *to)
+{
+       int status, p = from->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT;
+       z_streamp from_ctx = from->ctx, to_ctx = pecalloc(1, sizeof(*to_ctx), p);
+
+       if (Z_OK == (status = inflateCopy(to_ctx, from_ctx))) {
+               if ((to_ctx->opaque = php_http_buffer_init_ex(NULL, PHP_HTTP_DEFLATE_BUFFER_SIZE, p ? PHP_HTTP_BUFFER_INIT_PERSISTENT : 0))) {
+                       php_http_buffer_append(to_ctx->opaque, PHP_HTTP_BUFFER(from_ctx->opaque)->data, PHP_HTTP_BUFFER(from_ctx->opaque)->used);
+                       to->ctx = to_ctx;
+                       return to;
+               }
+               inflateEnd(to_ctx);
+               status = Z_MEM_ERROR;
+       }
+       php_error_docref(NULL, E_WARNING, "Failed to copy inflate encoding stream: %s", zError(status));
+       return NULL;
+}
+
+static ZEND_RESULT_CODE inflate_update(php_http_encoding_stream_t *s, const char *data, size_t data_len, char **decoded, size_t *decoded_len)
+{
+       int status;
+       z_streamp ctx = s->ctx;
+
+       /* append input to buffer */
+       php_http_buffer_append(PHP_HTTP_BUFFER(ctx->opaque), data, data_len);
+
+retry_raw_inflate:
+       ctx->next_in = (Bytef *) PHP_HTTP_BUFFER(ctx->opaque)->data;
+       ctx->avail_in = PHP_HTTP_BUFFER(ctx->opaque)->used;
+
+       switch (status = php_http_inflate_rounds(ctx, PHP_HTTP_INFLATE_FLUSH_FLAG(s->flags), decoded, decoded_len)) {
+               case Z_OK:
+               case Z_STREAM_END:
+                       /* cut off */
+                       if (ctx->avail_in) {
+                               php_http_buffer_cut(PHP_HTTP_BUFFER(ctx->opaque), 0, PHP_HTTP_BUFFER(ctx->opaque)->used - ctx->avail_in);
+                       } else {
+                               php_http_buffer_reset(PHP_HTTP_BUFFER(ctx->opaque));
+                       }
+                       return SUCCESS;
+
+               case Z_DATA_ERROR:
+                       /* raw deflated data ? */
+                       if (!(s->flags & PHP_HTTP_INFLATE_TYPE_RAW) && !ctx->total_out) {
+                               inflateEnd(ctx);
+                               s->flags |= PHP_HTTP_INFLATE_TYPE_RAW;
+                               inflateInit2(ctx, PHP_HTTP_WINDOW_BITS_RAW);
+                               goto retry_raw_inflate;
+                       }
+                       break;
+       }
+
+       php_error_docref(NULL, E_WARNING, "Failed to update inflate stream: %s", zError(status));
+       return FAILURE;
+}
+
+static ZEND_RESULT_CODE inflate_finish(php_http_encoding_stream_t *s, char **decoded, size_t *decoded_len)
+{
+       int status;
+       z_streamp ctx = s->ctx;
+
+       if (!PHP_HTTP_BUFFER(ctx->opaque)->used) {
+               *decoded = NULL;
+               *decoded_len = 0;
+               return SUCCESS;
+       }
+
+       *decoded_len = (PHP_HTTP_BUFFER(ctx->opaque)->used + 1) * PHP_HTTP_INFLATE_ROUNDS;
+       *decoded = emalloc(*decoded_len);
+
+       /* inflate remaining input */
+       ctx->next_in = (Bytef *) PHP_HTTP_BUFFER(ctx->opaque)->data;
+       ctx->avail_in = PHP_HTTP_BUFFER(ctx->opaque)->used;
+
+       ctx->avail_out = *decoded_len;
+       ctx->next_out = (Bytef *) *decoded;
+
+       if (Z_STREAM_END == (status = inflate(ctx, Z_FINISH))) {
+               /* cut processed input off */
+               php_http_buffer_cut(PHP_HTTP_BUFFER(ctx->opaque), 0, PHP_HTTP_BUFFER(ctx->opaque)->used - ctx->avail_in);
+
+               /* size down */
+               *decoded_len -= ctx->avail_out;
+               *decoded = erealloc(*decoded, *decoded_len + 1);
+               (*decoded)[*decoded_len] = '\0';
+               return SUCCESS;
+       }
+
+       PTR_SET(*decoded, NULL);
+       *decoded_len = 0;
+       php_error_docref(NULL, E_WARNING, "Failed to finish inflate stream: %s", zError(status));
+       return FAILURE;
+}
+
+static zend_bool inflate_done(php_http_encoding_stream_t *s)
+{
+       z_streamp ctx = s->ctx;
+       return !ctx->avail_in && !PHP_HTTP_BUFFER(ctx->opaque)->used;
+}
+
+static void inflate_dtor(php_http_encoding_stream_t *s)
+{
+       if (EXPECTED(s->ctx)) {
+               z_streamp ctx = s->ctx;
+
+               if (EXPECTED(ctx->opaque)) {
+                       php_http_buffer_free((php_http_buffer_t **) &ctx->opaque);
+               }
+               inflateEnd(ctx);
+               pefree(ctx, (s->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT));
+               s->ctx = NULL;
+       }
+}
+
+static php_http_encoding_stream_ops_t php_http_encoding_deflate_ops = {
+       deflate_init,
+       deflate_copy,
+       deflate_update,
+       deflate_flush,
+       deflate_done,
+       deflate_finish,
+       deflate_dtor
+};
+
+php_http_encoding_stream_ops_t *php_http_encoding_stream_get_deflate_ops(void)
+{
+       return &php_http_encoding_deflate_ops;
+}
+
+static php_http_encoding_stream_ops_t php_http_encoding_inflate_ops = {
+       inflate_init,
+       inflate_copy,
+       inflate_update,
+       NULL,
+       inflate_done,
+       inflate_finish,
+       inflate_dtor
+};
+
+php_http_encoding_stream_ops_t *php_http_encoding_stream_get_inflate_ops(void)
+{
+       return &php_http_encoding_inflate_ops;
+}
+
+static zend_class_entry *php_http_deflate_stream_class_entry;
+zend_class_entry *php_http_get_deflate_stream_class_entry(void)
+{
+       return php_http_deflate_stream_class_entry;
+}
+
+static zend_class_entry *php_http_inflate_stream_class_entry;
+zend_class_entry *php_http_get_inflate_stream_class_entry(void)
+{
+       return php_http_inflate_stream_class_entry;
+}
+
+
+ZEND_BEGIN_ARG_INFO_EX(ai_HttpDeflateStream_encode, 0, 0, 1)
+       ZEND_ARG_INFO(0, data)
+       ZEND_ARG_INFO(0, flags)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(HttpDeflateStream, encode)
+{
+       char *str;
+       size_t len;
+       zend_long flags = 0;
+
+       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &str, &len, &flags)) {
+               char *enc_str = NULL;
+               size_t enc_len;
+
+               if (SUCCESS == php_http_encoding_deflate(flags, str, len, &enc_str, &enc_len)) {
+                       if (enc_str) {
+                               RETURN_STR(php_http_cs2zs(enc_str, enc_len));
+                       } else {
+                               RETURN_EMPTY_STRING();
+                       }
+               }
+       }
+       RETURN_FALSE;
+}
+
+static zend_function_entry php_http_deflate_stream_methods[] = {
+       PHP_ME(HttpDeflateStream, encode, ai_HttpDeflateStream_encode, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
+       EMPTY_FUNCTION_ENTRY
+};
+
+ZEND_BEGIN_ARG_INFO_EX(ai_HttpInflateStream_decode, 0, 0, 1)
+       ZEND_ARG_INFO(0, data)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(HttpInflateStream, decode)
+{
+       char *str;
+       size_t len;
+
+       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &str, &len)) {
+               char *enc_str = NULL;
+               size_t enc_len;
+
+               if (SUCCESS == php_http_encoding_inflate(str, len, &enc_str, &enc_len)) {
+                       if (enc_str) {
+                               RETURN_STR(php_http_cs2zs(enc_str, enc_len));
+                       } else {
+                               RETURN_EMPTY_STRING();
+                       }
+               }
+       }
+       RETURN_FALSE;
+}
+
+static zend_function_entry php_http_inflate_stream_methods[] = {
+       PHP_ME(HttpInflateStream, decode, ai_HttpInflateStream_decode, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
+       EMPTY_FUNCTION_ENTRY
+};
+
+PHP_MINIT_FUNCTION(http_encoding_zlib)
+{
+       zend_class_entry ce;
+
+       memset(&ce, 0, sizeof(ce));
+       INIT_NS_CLASS_ENTRY(ce, "http\\Encoding\\Stream", "Deflate", php_http_deflate_stream_methods);
+       php_http_deflate_stream_class_entry = zend_register_internal_class_ex(&ce, php_http_get_encoding_stream_class_entry());
+       php_http_deflate_stream_class_entry->create_object = php_http_encoding_stream_object_new;
+
+       zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("TYPE_GZIP"), PHP_HTTP_DEFLATE_TYPE_GZIP);
+       zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("TYPE_ZLIB"), PHP_HTTP_DEFLATE_TYPE_ZLIB);
+       zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("TYPE_RAW"), PHP_HTTP_DEFLATE_TYPE_RAW);
+       zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("LEVEL_DEF"), PHP_HTTP_DEFLATE_LEVEL_DEF);
+       zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("LEVEL_MIN"), PHP_HTTP_DEFLATE_LEVEL_MIN);
+       zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("LEVEL_MAX"), PHP_HTTP_DEFLATE_LEVEL_MAX);
+       zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("STRATEGY_DEF"), PHP_HTTP_DEFLATE_STRATEGY_DEF);
+       zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("STRATEGY_FILT"), PHP_HTTP_DEFLATE_STRATEGY_FILT);
+       zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("STRATEGY_HUFF"), PHP_HTTP_DEFLATE_STRATEGY_HUFF);
+       zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("STRATEGY_RLE"), PHP_HTTP_DEFLATE_STRATEGY_RLE);
+       zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("STRATEGY_FIXED"), PHP_HTTP_DEFLATE_STRATEGY_FIXED);
+
+       memset(&ce, 0, sizeof(ce));
+       INIT_NS_CLASS_ENTRY(ce, "http\\Encoding\\Stream", "Inflate", php_http_inflate_stream_methods);
+       php_http_inflate_stream_class_entry = zend_register_internal_class_ex(&ce, php_http_get_encoding_stream_class_entry());
+       php_http_inflate_stream_class_entry->create_object = php_http_encoding_stream_object_new;
+
+       return SUCCESS;
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
+
diff --git a/src/php_http_encoding_zlib.h b/src/php_http_encoding_zlib.h
new file mode 100644 (file)
index 0000000..9d17560
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+    +--------------------------------------------------------------------+
+    | PECL :: http                                                       |
+    +--------------------------------------------------------------------+
+    | Redistribution and use in source and binary forms, with or without |
+    | modification, are permitted provided that the conditions mentioned |
+    | in the accompanying LICENSE file are met.                          |
+    +--------------------------------------------------------------------+
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
+    +--------------------------------------------------------------------+
+*/
+
+#ifndef PHP_HTTP_ENCODING_ZLIB_H
+#define PHP_HTTP_ENCODING_ZLIB_H
+
+#include "php_http_encoding.h"
+
+#include <zlib.h>
+
+#ifndef Z_FIXED
+/* Z_FIXED does not exist prior 1.2.2.2 */
+#      define Z_FIXED 0
+#endif
+
+extern PHP_MINIT_FUNCTION(http_encoding_zlib);
+
+zend_class_entry *php_http_get_deflate_stream_class_entry(void);
+zend_class_entry *php_http_get_inflate_stream_class_entry(void);
+
+PHP_HTTP_API php_http_encoding_stream_ops_t *php_http_encoding_stream_get_deflate_ops(void);
+PHP_HTTP_API php_http_encoding_stream_ops_t *php_http_encoding_stream_get_inflate_ops(void);
+
+PHP_HTTP_API ZEND_RESULT_CODE php_http_encoding_deflate(int flags, const char *data, size_t data_len, char **encoded, size_t *encoded_len);
+PHP_HTTP_API ZEND_RESULT_CODE php_http_encoding_inflate(const char *data, size_t data_len, char **decoded, size_t *decoded_len);
+
+#define PHP_HTTP_DEFLATE_LEVEL_DEF                     0x00000000
+#define PHP_HTTP_DEFLATE_LEVEL_MIN                     0x00000001
+#define PHP_HTTP_DEFLATE_LEVEL_MAX                     0x00000009
+#define PHP_HTTP_DEFLATE_TYPE_ZLIB                     0x00000000
+#define PHP_HTTP_DEFLATE_TYPE_GZIP                     0x00000010
+#define PHP_HTTP_DEFLATE_TYPE_RAW                      0x00000020
+#define PHP_HTTP_DEFLATE_STRATEGY_DEF          0x00000000
+#define PHP_HTTP_DEFLATE_STRATEGY_FILT         0x00000100
+#define PHP_HTTP_DEFLATE_STRATEGY_HUFF         0x00000200
+#define PHP_HTTP_DEFLATE_STRATEGY_RLE          0x00000300
+#define PHP_HTTP_DEFLATE_STRATEGY_FIXED                0x00000400
+
+#define PHP_HTTP_INFLATE_TYPE_ZLIB                     0x00000000
+#define PHP_HTTP_INFLATE_TYPE_GZIP                     0x00000000
+#define PHP_HTTP_INFLATE_TYPE_RAW                      0x00000001
+
+#endif
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
+
index b5454ed89253bfde4d999c5a56faa8667a57ed16..7c6eea8d959d4442cd894e72eafddd7428c13391 100644 (file)
@@ -245,7 +245,7 @@ static PHP_METHOD(HttpEnvRequest, getFiles)
 }
 
 static zend_function_entry php_http_env_request_methods[] = {
-       PHP_ME(HttpEnvRequest, __construct,  ai_HttpEnvRequest___construct,  ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
+       PHP_ME(HttpEnvRequest, __construct,  ai_HttpEnvRequest___construct,  ZEND_ACC_PUBLIC)
        PHP_ME(HttpEnvRequest, getForm,      ai_HttpEnvRequest_getForm,      ZEND_ACC_PUBLIC)
        PHP_ME(HttpEnvRequest, getQuery,     ai_HttpEnvRequest_getQuery,     ZEND_ACC_PUBLIC)
        PHP_ME(HttpEnvRequest, getCookie,    ai_HttpEnvRequest_getCookie,    ZEND_ACC_PUBLIC)
index 3a5a8e8905539d129335dbe731b29af08b464b7d..f5d2da9846c6d4958df30e7db6c5170a79a0d780 100644 (file)
@@ -15,7 +15,7 @@
 static void set_option(zval *options, const char *name_str, size_t name_len, int type, void *value_ptr, size_t value_len)
 {
        if (Z_TYPE_P(options) == IS_OBJECT) {
-               if (value_ptr) {
+               if (EXPECTED(value_ptr)) {
                        switch (type) {
                                case IS_DOUBLE:
                                        zend_update_property_double(Z_OBJCE_P(options), options, name_str, name_len, *(double *)value_ptr);
@@ -36,7 +36,7 @@ static void set_option(zval *options, const char *name_str, size_t name_len, int
                }
        } else {
                convert_to_array(options);
-               if (value_ptr) {
+               if (EXPECTED(value_ptr)) {
                        switch (type) {
                                case IS_DOUBLE:
                                        add_assoc_double_ex(options, name_str, name_len, *(double *)value_ptr);
@@ -64,9 +64,9 @@ static zval *get_option(zval *options, const char *name_str, size_t name_len, zv
 {
        zval *val = NULL;
 
-       if (Z_TYPE_P(options) == IS_OBJECT) {
+       if (EXPECTED(Z_TYPE_P(options) == IS_OBJECT)) {
                val = zend_read_property(Z_OBJCE_P(options), options, name_str, name_len, 0, tmp);
-       } else if (Z_TYPE_P(options) == IS_ARRAY) {
+       } else if (EXPECTED(Z_TYPE_P(options) == IS_ARRAY)) {
                val = zend_symtable_str_find(Z_ARRVAL_P(options), name_str, name_len);
        } else {
                abort();
@@ -81,7 +81,7 @@ static php_http_message_body_t *get_body(zval *options)
        zval zbody_tmp, *zbody;
        php_http_message_body_t *body = NULL;
 
-       if ((zbody = get_option(options, ZEND_STRL("body"), &zbody_tmp))) {
+       if (EXPECTED(zbody = get_option(options, ZEND_STRL("body"), &zbody_tmp))) {
                if ((Z_TYPE_P(zbody) == IS_OBJECT) && instanceof_function(Z_OBJCE_P(zbody), php_http_get_message_body_class_entry())) {
                        php_http_message_body_object_t *body_obj = PHP_HTTP_OBJ(NULL, zbody);
 
@@ -97,8 +97,8 @@ static php_http_message_t *get_request(zval *options)
        zval zrequest_tmp, *zrequest;
        php_http_message_t *request = NULL;
 
-       if ((zrequest = get_option(options, ZEND_STRL("request"), &zrequest_tmp))) {
-               if (Z_TYPE_P(zrequest) == IS_OBJECT && instanceof_function(Z_OBJCE_P(zrequest), php_http_message_get_class_entry())) {
+       if (EXPECTED(zrequest = get_option(options, ZEND_STRL("request"), &zrequest_tmp))) {
+               if (UNEXPECTED(Z_TYPE_P(zrequest) == IS_OBJECT && instanceof_function(Z_OBJCE_P(zrequest), php_http_message_get_class_entry()))) {
                        php_http_message_object_t *request_obj = PHP_HTTP_OBJ(NULL, zrequest);
 
                        request = request_obj->message;
@@ -144,11 +144,11 @@ php_http_cache_status_t php_http_env_is_response_cached_by_etag(zval *options, c
        zval zetag_tmp, *zetag;
 
 
-       if (!(body = get_body(options))) {
+       if (UNEXPECTED(!(body = get_body(options)))) {
                return ret;
        }
 
-       if ((zetag = get_option(options, ZEND_STRL("etag"), &zetag_tmp)) && Z_TYPE_P(zetag) != IS_NULL) {
+       if (EXPECTED(zetag = get_option(options, ZEND_STRL("etag"), &zetag_tmp)) && Z_TYPE_P(zetag) != IS_NULL) {
                zend_string *zs = zval_get_string(zetag);
                etag = estrndup(zs->val, zs->len);
                zend_string_release(zs);
@@ -177,16 +177,16 @@ php_http_cache_status_t php_http_env_is_response_cached_by_last_modified(zval *o
        php_http_message_body_t *body;
        zval zlm_tmp, *zlm;
 
-       if (!(body = get_body(options))) {
+       if (UNEXPECTED(!(body = get_body(options)))) {
                return ret;
        }
 
-       if ((zlm = get_option(options, ZEND_STRL("lastModified"), &zlm_tmp))) {
+       if (EXPECTED(zlm = get_option(options, ZEND_STRL("lastModified"), &zlm_tmp))) {
                lm = zval_get_long(zlm);
                zval_ptr_dtor(zlm);
        }
 
-       if (lm <= 0) {
+       if (EXPECTED(lm <= 0)) {
                lm = php_http_message_body_mtime(body);
                set_option(options, ZEND_STRL("lastModified"), IS_LONG, &lm, 0);
        }
@@ -228,13 +228,13 @@ static size_t output(void *context, char *buf, size_t len)
 {
        php_http_env_response_t *r = context;
 
-       if (SUCCESS != r->ops->write(r, buf, len)) {
+       if (UNEXPECTED(SUCCESS != r->ops->write(r, buf, len))) {
                return (size_t) -1;
        }
 
        /*      we really only need to flush when throttling is enabled,
                because we push the data as fast as possible anyway if not */
-       if (r->throttle.delay >= PHP_HTTP_DIFFSEC) {
+       if (UNEXPECTED(r->throttle.delay >= PHP_HTTP_DIFFSEC)) {
                r->ops->flush(r);
                php_http_sleep(r->throttle.delay);
        }
@@ -339,14 +339,14 @@ static ZEND_RESULT_CODE php_http_env_response_send_head(php_http_env_response_t
                return ret;
        }
 
-       if ((zoption = get_option(options, ZEND_STRL("headers"), &zoption_tmp))) {
-               if (Z_TYPE_P(zoption) == IS_ARRAY) {
+       if (EXPECTED(zoption = get_option(options, ZEND_STRL("headers"), &zoption_tmp))) {
+               if (EXPECTED(Z_TYPE_P(zoption) == IS_ARRAY)) {
                        php_http_header_to_callback(Z_ARRVAL_P(zoption), 0, (php_http_pass_format_callback_t) r->ops->set_header, r);
                }
                zval_ptr_dtor(zoption);
        }
 
-       if ((zoption = get_option(options, ZEND_STRL("responseCode"), &zoption_tmp))) {
+       if (EXPECTED(zoption = get_option(options, ZEND_STRL("responseCode"), &zoption_tmp))) {
                zend_long rc = zval_get_long(zoption);
 
                zval_ptr_dtor(zoption);
@@ -359,12 +359,12 @@ static ZEND_RESULT_CODE php_http_env_response_send_head(php_http_env_response_t
                return ret;
        }
 
-       if ((zoption = get_option(options, ZEND_STRL("httpVersion"), &zoption_tmp))) {
+       if (EXPECTED(zoption = get_option(options, ZEND_STRL("httpVersion"), &zoption_tmp))) {
                php_http_version_t v;
                zend_string *zs = zval_get_string(zoption);
 
                zval_ptr_dtor(zoption);
-               if (zs->len && php_http_version_parse(&v, zs->val)) {
+               if (EXPECTED(zs->len && php_http_version_parse(&v, zs->val))) {
                        ret = r->ops->set_protocol_version(r, &v);
                        php_http_version_dtor(&v);
                }
@@ -375,7 +375,7 @@ static ZEND_RESULT_CODE php_http_env_response_send_head(php_http_env_response_t
                return ret;
        }
 
-       if ((zoption = get_option(options, ZEND_STRL("cookies"), &zoption_tmp))) {
+       if (EXPECTED(zoption = get_option(options, ZEND_STRL("cookies"), &zoption_tmp))) {
                if (Z_TYPE_P(zoption) == IS_ARRAY) {
                        zval *zcookie;
 
@@ -403,7 +403,7 @@ static ZEND_RESULT_CODE php_http_env_response_send_head(php_http_env_response_t
                return ret;
        }
 
-       if ((zoption = get_option(options, ZEND_STRL("contentType"), &zoption_tmp))) {
+       if (EXPECTED(zoption = get_option(options, ZEND_STRL("contentType"), &zoption_tmp))) {
                zend_string *zs = zval_get_string(zoption);
 
                zval_ptr_dtor(zoption);
@@ -419,12 +419,12 @@ static ZEND_RESULT_CODE php_http_env_response_send_head(php_http_env_response_t
                return ret;
        }
 
-       if (r->range.status == PHP_HTTP_RANGE_OK) {
+       if (UNEXPECTED(r->range.status == PHP_HTTP_RANGE_OK)) {
                if (zend_hash_num_elements(&r->range.values) == 1) {
                        zval *range, *begin, *end;
 
-                       if (    1 == php_http_array_list(&r->range.values, 1, &range)
-                               &&      2 == php_http_array_list(Z_ARRVAL_P(range), 2, &begin, &end)
+                       if (EXPECTED(   1 == php_http_array_list(&r->range.values, 1, &range)
+                               &&      2 == php_http_array_list(Z_ARRVAL_P(range), 2, &begin, &end))
                        ) {
                                if (SUCCESS == (ret = r->ops->set_status(r, 206))) {
                                        ret = r->ops->set_header(r, "Content-Range: bytes %ld-%ld/%zu", Z_LVAL_P(begin), Z_LVAL_P(end), r->content.length);
@@ -441,7 +441,7 @@ static ZEND_RESULT_CODE php_http_env_response_send_head(php_http_env_response_t
                        }
                }
        } else {
-               if ((zoption = get_option(options, ZEND_STRL("cacheControl"), &zoption_tmp))) {
+               if (EXPECTED(zoption = get_option(options, ZEND_STRL("cacheControl"), &zoption_tmp))) {
                        zend_string *zs = zval_get_string(zoption);
 
                        zval_ptr_dtor(zoption);
@@ -455,7 +455,7 @@ static ZEND_RESULT_CODE php_http_env_response_send_head(php_http_env_response_t
                        return ret;
                }
 
-               if ((zoption = get_option(options, ZEND_STRL("contentDisposition"), &zoption_tmp))) {
+               if (EXPECTED(zoption = get_option(options, ZEND_STRL("contentDisposition"), &zoption_tmp))) {
 
                        if (Z_TYPE_P(zoption) == IS_ARRAY) {
                                php_http_buffer_t buf;
@@ -476,7 +476,7 @@ static ZEND_RESULT_CODE php_http_env_response_send_head(php_http_env_response_t
                        return ret;
                }
 
-               if ((zoption = get_option(options, ZEND_STRL("contentEncoding"), &zoption_tmp))) {
+               if (EXPECTED(zoption = get_option(options, ZEND_STRL("contentEncoding"), &zoption_tmp))) {
                        zend_long ce = zval_get_long(zoption);
                        zval zsupported;
                        HashTable *result = NULL;
@@ -551,22 +551,22 @@ static ZEND_RESULT_CODE php_http_env_response_send_head(php_http_env_response_t
                                        break;
                        }
 
-                       if ((zoption = get_option(options, ZEND_STRL("etag"), &zoption_tmp))) {
+                       if (EXPECTED(zoption = get_option(options, ZEND_STRL("etag"), &zoption_tmp))) {
                                zend_string *zs = zval_get_string(zoption);
 
                                zval_ptr_dtor(zoption);
-                               if (*zs->val != '"' && strncmp(zs->val, "W/\"", 3)) {
+                               if (EXPECTED(*zs->val != '"' && strncmp(zs->val, "W/\"", 3))) {
                                        ret = r->ops->set_header(r, "ETag: \"%s\"", zs->val);
                                } else {
                                        ret = r->ops->set_header(r, "ETag: %s", zs->val);
                                }
                                zend_string_release(zs);
                        }
-                       if ((zoption = get_option(options, ZEND_STRL("lastModified"), &zoption_tmp))) {
+                       if (EXPECTED(zoption = get_option(options, ZEND_STRL("lastModified"), &zoption_tmp))) {
                                zend_long lm = zval_get_long(zoption);
 
                                zval_ptr_dtor(zoption);
-                               if (lm) {
+                               if (EXPECTED(lm)) {
                                        zend_string *date = php_format_date(ZEND_STRL(PHP_HTTP_DATE_FORMAT), lm, 0);
                                        if (date) {
                                                ret = r->ops->set_header(r, "Last-Modified: %s", date->val);
@@ -590,17 +590,17 @@ static ZEND_RESULT_CODE php_http_env_response_send_body(php_http_env_response_t
                return ret;
        }
 
-       if ((body = get_body(&r->options))) {
-               if ((zoption = get_option(&r->options, ZEND_STRL("throttleDelay"), &zoption_tmp))) {
+       if (EXPECTED(body = get_body(&r->options))) {
+               if (EXPECTED(zoption = get_option(&r->options, ZEND_STRL("throttleDelay"), &zoption_tmp))) {
                        r->throttle.delay = zval_get_double(zoption);
                        zval_ptr_dtor(zoption);
                }
-               if ((zoption = get_option(&r->options, ZEND_STRL("throttleChunk"), &zoption_tmp))) {
+               if (EXPECTED(zoption = get_option(&r->options, ZEND_STRL("throttleChunk"), &zoption_tmp))) {
                        r->throttle.chunk = zval_get_long(zoption);
                        zval_ptr_dtor(zoption);
                }
 
-               if (r->range.status == PHP_HTTP_RANGE_OK) {
+               if (UNEXPECTED(r->range.status == PHP_HTTP_RANGE_OK)) {
                        if (zend_hash_num_elements(&r->range.values) == 1) {
                                /* single range */
                                zval *range, *begin, *end;
@@ -672,10 +672,10 @@ ZEND_RESULT_CODE php_http_env_response_send(php_http_env_response_t *r)
        request = get_request(&r->options);
 
        /* check for ranges */
-       if ((body = get_body(&r->options))) {
+       if (EXPECTED(body = get_body(&r->options))) {
                r->content.length = php_http_message_body_size(body);
 
-               if (SUCCESS != r->ops->set_header(r, "Accept-Ranges: bytes")) {
+               if (UNEXPECTED(SUCCESS != r->ops->set_header(r, "Accept-Ranges: bytes"))) {
                        return FAILURE;
                } else {
                        ZEND_INIT_SYMTABLE_EX(&r->range.values, 0, 0);
@@ -727,17 +727,17 @@ ZEND_RESULT_CODE php_http_env_response_send(php_http_env_response_t *r)
                }
        }
 
-       if (SUCCESS != php_http_env_response_send_head(r, request)) {
+       if (UNEXPECTED(SUCCESS != php_http_env_response_send_head(r, request))) {
                php_error_docref(NULL, E_WARNING, "Failed to send response headers");
                return FAILURE;
        }
 
-       if (SUCCESS != php_http_env_response_send_body(r)) {
+       if (UNEXPECTED(SUCCESS != php_http_env_response_send_body(r))) {
                php_error_docref(NULL, E_WARNING, "Failed to send response body");
                return FAILURE;
        }
 
-       if (SUCCESS != r->ops->finish(r)) {
+       if (UNEXPECTED(SUCCESS != r->ops->finish(r))) {
                php_error_docref(NULL, E_WARNING, "Failed to finish response");
                return FAILURE;
        }
@@ -848,7 +848,7 @@ static ZEND_RESULT_CODE php_http_env_response_stream_init(php_http_env_response_
        ctx = ecalloc(1, sizeof(*ctx));
 
        ctx->stream = init_arg;
-       ++GC_REFCOUNT(ctx->stream->res);
+       GC_ADDREF(ctx->stream->res);
        ZEND_INIT_SYMTABLE(&ctx->header);
        php_http_version_init(&ctx->version, 1, 1);
        php_stream_set_option(ctx->stream, PHP_STREAM_OPTION_WRITE_BUFFER, PHP_STREAM_BUFFER_FULL, &buffer_size);
@@ -857,7 +857,7 @@ static ZEND_RESULT_CODE php_http_env_response_stream_init(php_http_env_response_
        ctx->request = get_request(&r->options);
 
        /* there are some limitations regarding TE:chunked, see https://tools.ietf.org/html/rfc7230#section-3.3.1 */
-       if (ctx->request && ctx->request->http.version.major == 1 && ctx->request->http.version.minor == 0) {
+       if (UNEXPECTED(ctx->request && ctx->request->http.version.major == 1 && ctx->request->http.version.minor == 0)) {
                ctx->version.minor = 0;
        }
 
@@ -869,7 +869,7 @@ static void php_http_env_response_stream_dtor(php_http_env_response_t *r)
 {
        php_http_env_response_stream_ctx_t *ctx = r->ctx;
 
-       if (ctx->chunked_filter) {
+       if (UNEXPECTED(ctx->chunked_filter)) {
                ctx->chunked_filter = php_stream_filter_remove(ctx->chunked_filter, 1);
        }
        zend_hash_destroy(&ctx->header);
@@ -883,7 +883,7 @@ static void php_http_env_response_stream_header(php_http_env_response_stream_ctx
 
        ZEND_HASH_FOREACH_VAL(header, val)
        {
-               if (Z_TYPE_P(val) == IS_ARRAY) {
+               if (UNEXPECTED(Z_TYPE_P(val) == IS_ARRAY)) {
                        php_http_env_response_stream_header(ctx, Z_ARRVAL_P(val), buf);
                } else {
                        zend_string *zs = zval_get_string(val);
@@ -913,11 +913,11 @@ static ZEND_RESULT_CODE php_http_env_response_stream_start(php_http_env_response
        php_http_buffer_appendf(&header_buf, "HTTP/%u.%u %ld %s" PHP_HTTP_CRLF, ctx->version.major, ctx->version.minor, ctx->status_code, php_http_env_get_response_status_for_code(ctx->status_code));
 
        /* there are some limitations regarding TE:chunked, see https://tools.ietf.org/html/rfc7230#section-3.3.1 */
-       if (ctx->version.major == 1 && ctx->version.minor == 0) {
+       if (UNEXPECTED(ctx->version.major == 1 && ctx->version.minor == 0)) {
                ctx->chunked = 0;
-       } else if (ctx->status_code == 204 || ctx->status_code/100 == 1) {
+       } else if (UNEXPECTED(ctx->status_code == 204 || ctx->status_code/100 == 1)) {
                ctx->chunked = 0;
-       } else if (ctx->request && ctx->status_code/100 == 2 && !strcasecmp(ctx->request->http.info.request.method, "CONNECT")) {
+       } else if (UNEXPECTED(ctx->request && ctx->status_code/100 == 2 && !strcasecmp(ctx->request->http.info.request.method, "CONNECT"))) {
                ctx->chunked = 0;
        }
 
@@ -938,7 +938,9 @@ static ZEND_RESULT_CODE php_http_env_response_stream_start(php_http_env_response
 
        if (ctx->chunked) {
                ctx->chunked_filter = php_stream_filter_create("http.chunked_encode", NULL, 0);
-               php_stream_filter_append(&ctx->stream->writefilters, ctx->chunked_filter);
+               if (ctx->chunked_filter) {
+                       php_stream_filter_append(&ctx->stream->writefilters, ctx->chunked_filter);
+               }
        }
 
        return ctx->started ? SUCCESS : FAILURE;
@@ -982,13 +984,13 @@ static ZEND_RESULT_CODE php_http_env_response_stream_set_header_ex(php_http_env_
        zend_string *header_key;
        ZEND_RESULT_CODE rv;
 
-       if (stream_ctx->started || stream_ctx->finished) {
+       if (UNEXPECTED(stream_ctx->started || stream_ctx->finished)) {
                return FAILURE;
        }
 
        header_len = vspprintf(&header_str, 0, fmt, argv);
 
-       if (!(header_end = strchr(header_str, ':'))) {
+       if (UNEXPECTED(!(header_end = strchr(header_str, ':')))) {
                efree(header_str);
                return FAILURE;
        }
@@ -1080,10 +1082,10 @@ static ZEND_RESULT_CODE php_http_env_response_stream_finish(php_http_env_respons
 {
        php_http_env_response_stream_ctx_t *ctx = r->ctx;
 
-       if (ctx->finished) {
+       if (UNEXPECTED(ctx->finished)) {
                return FAILURE;
        }
-       if (!ctx->started) {
+       if (UNEXPECTED(!ctx->started)) {
                if (SUCCESS != php_http_env_response_stream_start(ctx)) {
                        return FAILURE;
                }
@@ -1391,7 +1393,7 @@ static PHP_METHOD(HttpEnvResponse, send)
 }
 
 static zend_function_entry php_http_env_response_methods[] = {
-       PHP_ME(HttpEnvResponse, __construct,             ai_HttpEnvResponse___construct,             ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
+       PHP_ME(HttpEnvResponse, __construct,             ai_HttpEnvResponse___construct,             ZEND_ACC_PUBLIC)
        PHP_ME(HttpEnvResponse, __invoke,                ai_HttpEnvResponse___invoke,                ZEND_ACC_PUBLIC)
        PHP_ME(HttpEnvResponse, setEnvRequest,           ai_HttpEnvResponse_setEnvRequest,           ZEND_ACC_PUBLIC)
        PHP_ME(HttpEnvResponse, setCookie,               ai_HttpEnvResponse_setCookie,               ZEND_ACC_PUBLIC)
index 5acf28031a9ad33758f25eacc38b61f8b698c4e1..e3e66f17403fd5379aad718065724e7c9f2c0f5e 100644 (file)
@@ -22,7 +22,7 @@
        do { \
                zend_error_handling __zeh; \
                zend_replace_error_handling(EH_THROW, php_http_get_exception_ ##e## _class_entry(), &__zeh); \
-               if (!(test)) { \
+               if (UNEXPECTED(!(test))) { \
                        zend_restore_error_handling(&__zeh); \
                        fail; \
                } \
index 92bfd1554ef946491b6819f5748d5d3b9b83059b..95ff5601e37323acd6c3b840a971e881f38f5464 100644 (file)
@@ -75,7 +75,7 @@ typedef struct _http_chunked_decode_filter_buffer_t {
        ulong   hexlen;
 } PHP_HTTP_FILTER_BUFFER(chunked_decode);
 
-typedef php_http_encoding_stream_t PHP_HTTP_FILTER_BUFFER(zlib);
+typedef php_http_encoding_stream_t PHP_HTTP_FILTER_BUFFER(stream);
 
 static PHP_HTTP_FILTER_FUNCTION(chunked_decode)
 {
@@ -266,22 +266,10 @@ static PHP_HTTP_FILTER_FUNCTION(chunked_encode)
        return PSFS_PASS_ON;
 }
 
-static PHP_HTTP_FILTER_OPS(chunked_decode) = {
-       PHP_HTTP_FILTER_FUNC(chunked_decode),
-       PHP_HTTP_FILTER_DTOR(chunked_decode),
-       "http.chunked_decode"
-};
-
-static PHP_HTTP_FILTER_OPS(chunked_encode) = {
-       PHP_HTTP_FILTER_FUNC(chunked_encode),
-       NULL,
-       "http.chunked_encode"
-};
-
-static PHP_HTTP_FILTER_FUNCTION(zlib)
+static PHP_HTTP_FILTER_FUNCTION(stream)
 {
        php_stream_bucket *ptr, *nxt;
-       PHP_HTTP_FILTER_BUFFER(zlib) *buffer = Z_PTR(this->abstract);
+       PHP_HTTP_FILTER_BUFFER(stream) *buffer = Z_PTR(this->abstract);
        
        if (bytes_consumed) {
                *bytes_consumed = 0;
@@ -307,7 +295,7 @@ static PHP_HTTP_FILTER_FUNCTION(zlib)
                }
                
 #if DBG_FILTER
-               fprintf(stderr, "update: deflate (-> %zu) (w: %zu, r: %zu)\n", encoded_len, stream->writepos, stream->readpos);
+               fprintf(stderr, "update: compress (-> %zu) (w: %zu, r: %zu)\n", encoded_len, stream->writepos, stream->readpos);
 #endif
                
                if (encoded) {
@@ -329,7 +317,7 @@ static PHP_HTTP_FILTER_FUNCTION(zlib)
                }
                
 #if DBG_FILTER
-               fprintf(stderr, "flush: deflate (-> %zu)\n", encoded_len);
+               fprintf(stderr, "flush: compress (-> %zu)\n", encoded_len);
 #endif
                
                if (encoded) {
@@ -349,7 +337,7 @@ static PHP_HTTP_FILTER_FUNCTION(zlib)
                }
                
 #if DBG_FILTER
-               fprintf(stderr, "finish: deflate (-> %zu)\n", encoded_len);
+               fprintf(stderr, "finish: compress (-> %zu)\n", encoded_len);
 #endif
                
                if (encoded) {
@@ -362,25 +350,56 @@ static PHP_HTTP_FILTER_FUNCTION(zlib)
        
        return PSFS_PASS_ON;
 }
-static PHP_HTTP_FILTER_DESTRUCTOR(zlib)
+
+static PHP_HTTP_FILTER_DESTRUCTOR(stream)
 {
-       PHP_HTTP_FILTER_BUFFER(zlib) *buffer = Z_PTR(this->abstract);
+       PHP_HTTP_FILTER_BUFFER(stream) *buffer = Z_PTR(this->abstract);
        php_http_encoding_stream_free(&buffer);
 }
 
+static PHP_HTTP_FILTER_OPS(chunked_decode) = {
+       PHP_HTTP_FILTER_FUNC(chunked_decode),
+       PHP_HTTP_FILTER_DTOR(chunked_decode),
+       "http.chunked_decode"
+};
+
+static PHP_HTTP_FILTER_OPS(chunked_encode) = {
+       PHP_HTTP_FILTER_FUNC(chunked_encode),
+       NULL,
+       "http.chunked_encode"
+};
+
 static PHP_HTTP_FILTER_OPS(deflate) = {
-       PHP_HTTP_FILTER_FUNC(zlib),
-       PHP_HTTP_FILTER_DTOR(zlib),
+       PHP_HTTP_FILTER_FUNC(stream),
+       PHP_HTTP_FILTER_DTOR(stream),
        "http.deflate"
 };
 
 static PHP_HTTP_FILTER_OPS(inflate) = {
-       PHP_HTTP_FILTER_FUNC(zlib),
-       PHP_HTTP_FILTER_DTOR(zlib),
+       PHP_HTTP_FILTER_FUNC(stream),
+       PHP_HTTP_FILTER_DTOR(stream),
        "http.inflate"
 };
 
+#if PHP_HTTP_HAVE_LIBBROTLI
+static PHP_HTTP_FILTER_OPS(brotli_encode) = {
+       PHP_HTTP_FILTER_FUNC(stream),
+       PHP_HTTP_FILTER_DTOR(stream),
+       "http.brotli_encode"
+};
+
+static PHP_HTTP_FILTER_OPS(brotli_decode) = {
+       PHP_HTTP_FILTER_FUNC(stream),
+       PHP_HTTP_FILTER_DTOR(stream),
+       "http.brotli_decode"
+};
+#endif
+
+#if PHP_VERSION_ID >= 70200
+static php_stream_filter *http_filter_create(const char *name, zval *params, uint8_t p)
+#else
 static php_stream_filter *http_filter_create(const char *name, zval *params, int p)
+#endif
 {
        zval *tmp = params;
        php_stream_filter *f = NULL;
@@ -416,7 +435,7 @@ static php_stream_filter *http_filter_create(const char *name, zval *params, int
        } else
        
        if (!strcasecmp(name, "http.inflate")) {
-               PHP_HTTP_FILTER_BUFFER(zlib) *b = NULL;
+               PHP_HTTP_FILTER_BUFFER(stream) *b = NULL;
                
                if ((b = php_http_encoding_stream_init(NULL, php_http_encoding_stream_get_inflate_ops(), flags))) {
                        if (!(f = php_stream_filter_alloc(&PHP_HTTP_FILTER_OP(inflate), b, p))) {
@@ -426,13 +445,35 @@ static php_stream_filter *http_filter_create(const char *name, zval *params, int
        } else
        
        if (!strcasecmp(name, "http.deflate")) {
-               PHP_HTTP_FILTER_BUFFER(zlib) *b = NULL;
+               PHP_HTTP_FILTER_BUFFER(stream) *b = NULL;
                
                if ((b = php_http_encoding_stream_init(NULL, php_http_encoding_stream_get_deflate_ops(), flags))) {
                        if (!(f = php_stream_filter_alloc(&PHP_HTTP_FILTER_OP(deflate), b, p))) {
                                php_http_encoding_stream_free(&b);
                        }
                }
+#if PHP_HTTP_HAVE_LIBBROTLI
+       } else
+
+       if (!strcasecmp(name, "http.brotli_encode")) {
+               PHP_HTTP_FILTER_BUFFER(stream) *b = NULL;
+
+               if ((b = php_http_encoding_stream_init(NULL, php_http_encoding_stream_get_enbrotli_ops(), flags))) {
+                       if (!(f = php_stream_filter_alloc(&PHP_HTTP_FILTER_OP(brotli_encode), b, p))) {
+                               php_http_encoding_stream_free(&b);
+                       }
+               }
+       } else
+
+       if (!strcasecmp(name, "http.brotli_decode")) {
+               PHP_HTTP_FILTER_BUFFER(stream) *b = NULL;
+
+               if ((b = php_http_encoding_stream_init(NULL, php_http_encoding_stream_get_debrotli_ops(), flags))) {
+                       if (!(f = php_stream_filter_alloc(&PHP_HTTP_FILTER_OP(brotli_decode), b, p))) {
+                               php_http_encoding_stream_free(&b);
+                       }
+               }
+#endif
        }
        
        return f;
index 8c71cdeceaae7f2c4d75db7abe998477b24b4490..4c9a7025684051ade431db1f730cff99083bbd11 100644 (file)
@@ -398,7 +398,7 @@ PHP_METHOD(HttpHeader, parse)
 }
 
 static zend_function_entry php_http_header_methods[] = {
-       PHP_ME(HttpHeader, __construct,   ai_HttpHeader___construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
+       PHP_ME(HttpHeader, __construct,   ai_HttpHeader___construct, ZEND_ACC_PUBLIC)
        PHP_ME(HttpHeader, serialize,     ai_HttpHeader_serialize, ZEND_ACC_PUBLIC)
        ZEND_MALIAS(HttpHeader, __toString, serialize, ai_HttpHeader_serialize, ZEND_ACC_PUBLIC)
        ZEND_MALIAS(HttpHeader, toString, serialize, ai_HttpHeader_serialize, ZEND_ACC_PUBLIC)
index fb844526dcc9bbebdb887fe4868ab67564ecafb0..cd76b763cc6b4642c2256265077480d830c67ab9 100644 (file)
@@ -40,42 +40,19 @@ php_http_header_parser_t *php_http_header_parser_init(php_http_header_parser_t *
        return parser;
 }
 
-php_http_header_parser_state_t php_http_header_parser_state_push(php_http_header_parser_t *parser, unsigned argc, ...)
-{
-       va_list va_args;
-       unsigned i;
-       php_http_header_parser_state_t state = 0;
-
-       /* short circuit */
-       ZEND_PTR_STACK_RESIZE_IF_NEEDED((&parser->stack), argc);
-
-       va_start(va_args, argc);
-       for (i = 0; i < argc; ++i) {
-               state = va_arg(va_args, php_http_header_parser_state_t);
-               zend_ptr_stack_push(&parser->stack, (void *) state);
-       }
-       va_end(va_args);
-
-       return state;
-}
+#define php_http_header_parser_state_push(parser, state) zend_ptr_stack_push(&(parser)->stack, (void *) (state)), (state)
+#define php_http_header_parser_state_ex(parser) ((parser)->stack.top \
+               ? (php_http_header_parser_state_t) (parser)->stack.elements[(parser)->stack.top - 1] \
+               : PHP_HTTP_HEADER_PARSER_STATE_START)
 
 php_http_header_parser_state_t php_http_header_parser_state_is(php_http_header_parser_t *parser)
 {
-       if (parser->stack.top) {
-               return (php_http_header_parser_state_t) parser->stack.elements[parser->stack.top - 1];
-       }
-
-       return PHP_HTTP_HEADER_PARSER_STATE_START;
+       return php_http_header_parser_state_ex(parser);
 }
 
-php_http_header_parser_state_t php_http_header_parser_state_pop(php_http_header_parser_t *parser)
-{
-       if (parser->stack.top) {
-               return (php_http_header_parser_state_t) zend_ptr_stack_pop(&parser->stack);
-       }
-
-       return PHP_HTTP_HEADER_PARSER_STATE_START;
-}
+#define php_http_header_parser_state_pop(parser) ((parser)->stack.top \
+               ? (php_http_header_parser_state_t) zend_ptr_stack_pop(&(parser)->stack) \
+               : PHP_HTTP_HEADER_PARSER_STATE_START)
 
 void php_http_header_parser_dtor(php_http_header_parser_t *parser)
 {
@@ -97,9 +74,14 @@ void php_http_header_parser_free(php_http_header_parser_t **parser)
 /* NOTE: 'str' has to be null terminated */
 static void php_http_header_parser_error(size_t valid_len, char *str, size_t len, const char *eol_str )
 {
-       zend_string *escaped_str = zend_string_init(str, len, 0);
+       zend_string *escaped_str, *zstr_str = zend_string_init(str, len, 0);
 
-       escaped_str = php_addcslashes(escaped_str, 1, ZEND_STRL("\x0..\x1F\x7F..\xFF"));
+#if PHP_VERSION_ID < 70300
+       escaped_str = php_addcslashes(zstr_str, 1, ZEND_STRL("\x0..\x1F\x7F..\xFF"));
+#else
+       escaped_str = php_addcslashes(zstr_str, ZEND_STRL("\x0..\x1F\x7F..\xFF"));
+       zend_string_release_ex(zstr_str, 0);
+#endif
 
        if (valid_len != len && (!eol_str || (str+valid_len) != eol_str)) {
                php_error_docref(NULL, E_WARNING, "Failed to parse headers: unexpected character '\\%03o' at pos %zu of '%s'", str[valid_len], valid_len, escaped_str->val);
@@ -114,7 +96,7 @@ static void php_http_header_parser_error(size_t valid_len, char *str, size_t len
 
 php_http_header_parser_state_t php_http_header_parser_parse(php_http_header_parser_t *parser, php_http_buffer_t *buffer, unsigned flags, HashTable *headers, php_http_info_callback_t callback_func, void *callback_arg)
 {
-       while (buffer->used || !php_http_header_parser_states[php_http_header_parser_state_is(parser)].need_data) {
+       while (buffer->used || !php_http_header_parser_states[php_http_header_parser_state_ex(parser)].need_data) {
 #if DBG_PARSER
                const char *state[] = {"START", "KEY", "VALUE", "VALUE_EX", "HEADER_DONE", "DONE"};
                fprintf(stderr, "#HP: %s (avail:%zu, num:%d cleanup:%u)\n", php_http_header_parser_state_is(parser) < 0 ? "FAILURE" : state[php_http_header_parser_state_is(parser)], buffer->used, headers?zend_hash_num_elements(headers):0, flags);
@@ -123,7 +105,7 @@ php_http_header_parser_state_t php_http_header_parser_parse(php_http_header_pars
                switch (php_http_header_parser_state_pop(parser)) {
                        case PHP_HTTP_HEADER_PARSER_STATE_FAILURE:
                                php_error_docref(NULL, E_WARNING, "Failed to parse headers");
-                               return php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_FAILURE);
+                               return php_http_header_parser_state_push(parser, PHP_HTTP_HEADER_PARSER_STATE_FAILURE);
 
                        case PHP_HTTP_HEADER_PARSER_STATE_START: {
                                char *ptr = buffer->data;
@@ -133,7 +115,7 @@ php_http_header_parser_state_t php_http_header_parser_parse(php_http_header_pars
                                }
 
                                php_http_buffer_cut(buffer, 0, ptr - buffer->data);
-                               php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_KEY);
+                               php_http_header_parser_state_push(parser, PHP_HTTP_HEADER_PARSER_STATE_KEY);
                                break;
                        }
 
@@ -147,7 +129,7 @@ php_http_header_parser_state_t php_http_header_parser_parse(php_http_header_pars
                                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);
+                                       php_http_header_parser_state_push(parser, PHP_HTTP_HEADER_PARSER_STATE_DONE);
                                } else if (php_http_info_parse(&parser->info, buffer->data)) {
                                        /* new message starting with request/response line */
                                        if (callback_func) {
@@ -155,7 +137,7 @@ php_http_header_parser_state_t php_http_header_parser_parse(php_http_header_pars
                                        }
                                        php_http_info_dtor(&parser->info);
                                        php_http_buffer_cut(buffer, 0, eol_str + eol_len - buffer->data);
-                                       php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_HEADER_DONE);
+                                       php_http_header_parser_state_push(parser, PHP_HTTP_HEADER_PARSER_STATE_HEADER_DONE);
                                } else if ((colon = memchr(buffer->data, ':', buffer->used)) && (!eol_str || eol_str > colon)) {
                                        /* header: string */
                                        size_t valid_len;
@@ -167,18 +149,18 @@ php_http_header_parser_state_t php_http_header_parser_parse(php_http_header_pars
                                        if (valid_len != parser->_key.len) {
                                                php_http_header_parser_error(valid_len, parser->_key.str, parser->_key.len, eol_str);
                                                PTR_SET(parser->_key.str, NULL);
-                                               return php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_FAILURE);
+                                               return php_http_header_parser_state_push(parser, PHP_HTTP_HEADER_PARSER_STATE_FAILURE);
                                        }
                                        while (PHP_HTTP_IS_CTYPE(space, *++colon) && *colon != '\n' && *colon != '\r');
                                        php_http_buffer_cut(buffer, 0, colon - buffer->data);
-                                       php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_VALUE);
+                                       php_http_header_parser_state_push(parser, 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_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);
+                                       return php_http_header_parser_state_push(parser, PHP_HTTP_HEADER_PARSER_STATE_FAILURE);
                                } else {
                                        /* keep feeding */
-                                       return php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_KEY);
+                                       return php_http_header_parser_state_push(parser, PHP_HTTP_HEADER_PARSER_STATE_KEY);
                                }
                                break;
                        }
@@ -217,26 +199,26 @@ php_http_header_parser_state_t php_http_header_parser_parse(php_http_header_pars
 
                                if ((eol_str = php_http_locate_bin_eol(buffer->data, buffer->used, &eol_len))) {
                                        SET_ADD_VAL(eol_str - buffer->data, eol_len);
-                                       php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_VALUE_EX);
+                                       php_http_header_parser_state_push(parser, PHP_HTTP_HEADER_PARSER_STATE_VALUE_EX);
                                } else if (flags & PHP_HTTP_HEADER_PARSER_CLEANUP) {
                                        if (buffer->used) {
                                                SET_ADD_VAL(buffer->used, 0);
                                        }
-                                       php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_HEADER_DONE);
+                                       php_http_header_parser_state_push(parser, PHP_HTTP_HEADER_PARSER_STATE_HEADER_DONE);
                                } else {
-                                       return php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_VALUE);
+                                       return php_http_header_parser_state_push(parser, PHP_HTTP_HEADER_PARSER_STATE_VALUE);
                                }
                                break;
                        }
 
                        case PHP_HTTP_HEADER_PARSER_STATE_VALUE_EX:
                                if (buffer->used && (*buffer->data == ' ' || *buffer->data == '\t')) {
-                                       php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_VALUE);
+                                       php_http_header_parser_state_push(parser, PHP_HTTP_HEADER_PARSER_STATE_VALUE);
                                } else if (buffer->used || (flags & PHP_HTTP_HEADER_PARSER_CLEANUP)) {
-                                       php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_HEADER_DONE);
+                                       php_http_header_parser_state_push(parser, PHP_HTTP_HEADER_PARSER_STATE_HEADER_DONE);
                                } else {
                                        /* keep feeding */
-                                       return php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_VALUE_EX);
+                                       return php_http_header_parser_state_push(parser, PHP_HTTP_HEADER_PARSER_STATE_VALUE_EX);
                                }
                                break;
 
@@ -252,7 +234,7 @@ php_http_header_parser_state_t php_http_header_parser_parse(php_http_header_pars
                                                PTR_SET(parser->_key.str, NULL);
                                                PTR_SET(parser->_val.str, NULL);
 
-                                               return php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_FAILURE);
+                                               return php_http_header_parser_state_push(parser, PHP_HTTP_HEADER_PARSER_STATE_FAILURE);
                                        }
 
                                        if (!headers && callback_func) {
@@ -273,7 +255,7 @@ php_http_header_parser_state_t php_http_header_parser_parse(php_http_header_pars
                                PTR_SET(parser->_key.str, NULL);
                                PTR_SET(parser->_val.str, NULL);
 
-                               php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_KEY);
+                               php_http_header_parser_state_push(parser, PHP_HTTP_HEADER_PARSER_STATE_KEY);
                                break;
 
                        case PHP_HTTP_HEADER_PARSER_STATE_DONE:
index c22c6a74408f8dca947281f63198c65e32dd5fe1..c923998d9fc8fe4e3982a05e23e1e5b53ba98102 100644 (file)
@@ -41,9 +41,7 @@ typedef struct php_http_header_parser {
 } php_http_header_parser_t;
 
 PHP_HTTP_API php_http_header_parser_t *php_http_header_parser_init(php_http_header_parser_t *parser);
-PHP_HTTP_API php_http_header_parser_state_t php_http_header_parser_state_push(php_http_header_parser_t *parser, unsigned argc, ...);
 PHP_HTTP_API php_http_header_parser_state_t php_http_header_parser_state_is(php_http_header_parser_t *parser);
-PHP_HTTP_API php_http_header_parser_state_t php_http_header_parser_state_pop(php_http_header_parser_t *parser);
 PHP_HTTP_API void php_http_header_parser_dtor(php_http_header_parser_t *parser);
 PHP_HTTP_API void php_http_header_parser_free(php_http_header_parser_t **parser);
 PHP_HTTP_API php_http_header_parser_state_t php_http_header_parser_parse(php_http_header_parser_t *parser, php_http_buffer_t *buffer, unsigned flags, HashTable *headers, php_http_info_callback_t callback_func, void *callback_arg);
index 1470f976e2b554f4cd193732a25ee6a6cea2ac3c..48da6bfe2170452f4aa3adb5d2a20d35dabc6ed4 100644 (file)
@@ -96,12 +96,12 @@ php_http_info_t *php_http_info_parse(php_http_info_t *info, const char *pre_head
        zend_bool free_info = !info;
 
        /* sane parameter */
-       if ((!pre_header) || (!*pre_header)) {
+       if (UNEXPECTED((!pre_header) || (!*pre_header))) {
                return NULL;
        }
 
        /* where's the end of the line */
-       if (!(end = php_http_locate_eol(pre_header, NULL))) {
+       if (UNEXPECTED(!(end = php_http_locate_eol(pre_header, NULL)))) {
                end = pre_header + strlen(pre_header);
        }
 
@@ -112,7 +112,7 @@ php_http_info_t *php_http_info_parse(php_http_info_t *info, const char *pre_head
 
        info = php_http_info_init(info);
 
-       if (!php_http_version_parse(&info->http.version, http)) {
+       if (UNEXPECTED(!php_http_version_parse(&info->http.version, http))) {
                if (free_info) {
                        php_http_info_free(&info);
                }
@@ -126,7 +126,7 @@ php_http_info_t *php_http_info_parse(php_http_info_t *info, const char *pre_head
        }
 
        /* and nothing than SPACE or NUL after HTTP/X(.x) */
-       if (*off && (!PHP_HTTP_IS_CTYPE(space, *off))) {
+       if (UNEXPECTED(*off && (!PHP_HTTP_IS_CTYPE(space, *off)))) {
                if (free_info) {
                        php_http_info_free(&info);
                }
@@ -147,7 +147,7 @@ php_http_info_t *php_http_info_parse(php_http_info_t *info, const char *pre_head
 
                info->type = PHP_HTTP_RESPONSE;
                while (code < end && ' ' == *code) ++code;
-               if (end > code) {
+               if (EXPECTED(end > code)) {
                        /* rfc7230#3.1.2 The status-code element is a 3-digit integer code */
                        PHP_HTTP_INFO(info).response.code = 100*(*code++ - '0');
                        PHP_HTTP_INFO(info).response.code += 10*(*code++ - '0');
@@ -162,8 +162,8 @@ php_http_info_t *php_http_info_parse(php_http_info_t *info, const char *pre_head
                } else {
                        PHP_HTTP_INFO(info).response.code = 0;
                }
-               if (status && end > status) {
-                       while (' ' == *status) ++status;
+               if (EXPECTED(status && end > status)) {
+                       while (' ' == *status && end > status) ++status;
                        PHP_HTTP_INFO(info).response.status = estrndup(status, end - status);
                } else {
                        PHP_HTTP_INFO(info).response.status = NULL;
@@ -177,17 +177,17 @@ php_http_info_t *php_http_info_parse(php_http_info_t *info, const char *pre_head
                const char *url = strchr(pre_header, ' ');
 
                info->type = PHP_HTTP_REQUEST;
-               if (url && http > url) {
+               if (EXPECTED(url && http > url)) {
                        size_t url_len = url - pre_header;
 
                        PHP_HTTP_INFO(info).request.method = estrndup(pre_header, url_len);
 
-                       while (' ' == *url) ++url;
+                       while (' ' == *url && http > url) ++url;
                        while (' ' == *(http-1)) --http;
 
-                       if (http > url) {
+                       if (EXPECTED(http > url)) {
                                /* CONNECT presents an authority only */
-                               if (strcasecmp(PHP_HTTP_INFO(info).request.method, "CONNECT")) {
+                               if (UNEXPECTED(strcasecmp(PHP_HTTP_INFO(info).request.method, "CONNECT"))) {
                                        PHP_HTTP_INFO(info).request.url = php_http_url_parse(url, http - url, PHP_HTTP_URL_STDFLAGS);
                                } else {
                                        PHP_HTTP_INFO(info).request.url = php_http_url_parse_authority(url, http - url, PHP_HTTP_URL_STDFLAGS);
index 3f08ee46f681bb2860bb8c5ed8294bf005c2f415..d70ced4993c5a16cd199e189f3a49e62c80a4166 100644 (file)
@@ -75,7 +75,7 @@ php_http_message_t *php_http_message_init_env(php_http_message_t *message, php_h
                        break;
 
                case PHP_HTTP_RESPONSE:
-                       message = php_http_message_init(NULL, type, NULL);
+                       message = php_http_message_init(message, type, NULL);
                        if (!SG(sapi_headers).http_status_line || !php_http_info_parse((php_http_info_t *) &message->http, SG(sapi_headers).http_status_line)) {
                                if (!(message->http.info.response.code = SG(sapi_headers).http_response_code)) {
                                        message->http.info.response.code = 200;
@@ -177,24 +177,24 @@ zend_bool php_http_message_is_multipart(php_http_message_t *msg, char **boundary
                popts.input.str = ct->val;
                popts.input.len = ct->len;
 
-               if (php_http_params_parse(&params, &popts)) {
+               if (EXPECTED(php_http_params_parse(&params, &popts))) {
                        zval *cur, *arg;
                        zend_string *ct_str;
                        zend_ulong index;
 
                        zend_hash_internal_pointer_reset(&params);
 
-                       if ((cur = zend_hash_get_current_data(&params))
+                       if (EXPECTED((cur = zend_hash_get_current_data(&params))
                        &&      (Z_TYPE_P(cur) == IS_ARRAY)
-                       &&      (HASH_KEY_IS_STRING == zend_hash_get_current_key(&params, &ct_str, &index))
+                       &&      (HASH_KEY_IS_STRING == zend_hash_get_current_key(&params, &ct_str, &index)))
                        ) {
                                if (php_http_match(ct_str->val, "multipart", PHP_HTTP_MATCH_WORD)) {
                                        is_multipart = 1;
 
                                        /* get boundary */
-                                       if (boundary
+                                       if (EXPECTED(boundary
                                        &&      (arg = zend_hash_str_find(Z_ARRVAL_P(cur), ZEND_STRL("arguments")))
-                                       &&      Z_TYPE_P(arg) == IS_ARRAY
+                                       &&      Z_TYPE_P(arg) == IS_ARRAY)
                                        ) {
                                                zval *val;
                                                php_http_arrkey_t key;
@@ -204,7 +204,7 @@ zend_bool php_http_message_is_multipart(php_http_message_t *msg, char **boundary
                                                        if (key.key && key.key->len == lenof("boundary") && !strcasecmp(key.key->val, "boundary")) {
                                                                zend_string *bnd = zval_get_string(val);
 
-                                                               if (bnd->len) {
+                                                               if (EXPECTED(bnd->len)) {
                                                                        *boundary = estrndup(bnd->val, bnd->len);
                                                                }
                                                                zend_string_release(bnd);
@@ -471,7 +471,7 @@ php_http_message_t *php_http_message_copy_ex(php_http_message_t *from, php_http_
 
 void php_http_message_dtor(php_http_message_t *message)
 {
-       if (message) {
+       if (EXPECTED(message)) {
                zend_hash_destroy(&message->hdrs);
                php_http_message_body_free(&message->body);
 
@@ -493,7 +493,7 @@ void php_http_message_dtor(php_http_message_t *message)
 
 void php_http_message_free(php_http_message_t **message)
 {
-       if (*message) {
+       if (EXPECTED(*message)) {
                if ((*message)->parent) {
                        php_http_message_free(&(*message)->parent);
                }
@@ -538,12 +538,14 @@ static php_http_message_object_prophandler_t *php_http_message_object_get_propha
        return zend_hash_str_find_ptr(&php_http_message_object_prophandlers, name_str->val, name_str->len);
 }
 static void php_http_message_object_prophandler_get_type(php_http_message_object_t *obj, zval *return_value) {
+       zval_ptr_dtor(return_value);
        RETVAL_LONG(obj->message->type);
 }
 static void php_http_message_object_prophandler_set_type(php_http_message_object_t *obj, zval *value) {
        php_http_message_set_type(obj->message, zval_get_long(value));
 }
 static void php_http_message_object_prophandler_get_request_method(php_http_message_object_t *obj, zval *return_value) {
+       zval_ptr_dtor(return_value);
        if (PHP_HTTP_MESSAGE_TYPE(REQUEST, obj->message) && obj->message->http.info.request.method) {
                RETVAL_STRING(obj->message->http.info.request.method);
        } else {
@@ -561,6 +563,7 @@ static void php_http_message_object_prophandler_get_request_url(php_http_message
        char *url_str;
        size_t url_len;
 
+       zval_ptr_dtor(return_value);
        if (PHP_HTTP_MESSAGE_TYPE(REQUEST, obj->message) && obj->message->http.info.request.url && php_http_url_to_string(obj->message->http.info.request.url, &url_str, &url_len, 0)) {
                RETVAL_STR(php_http_cs2zs(url_str, url_len));
        } else {
@@ -573,6 +576,7 @@ static void php_http_message_object_prophandler_set_request_url(php_http_message
        }
 }
 static void php_http_message_object_prophandler_get_response_status(php_http_message_object_t *obj, zval *return_value) {
+       zval_ptr_dtor(return_value);
        if (PHP_HTTP_MESSAGE_TYPE(RESPONSE, obj->message) && obj->message->http.info.response.status) {
                RETVAL_STRING(obj->message->http.info.response.status);
        } else {
@@ -587,6 +591,7 @@ static void php_http_message_object_prophandler_set_response_status(php_http_mes
        }
 }
 static void php_http_message_object_prophandler_get_response_code(php_http_message_object_t *obj, zval *return_value) {
+       zval_ptr_dtor(return_value);
        if (PHP_HTTP_MESSAGE_TYPE(RESPONSE, obj->message)) {
                RETVAL_LONG(obj->message->http.info.response.code);
        } else {
@@ -603,6 +608,7 @@ static void php_http_message_object_prophandler_get_http_version(php_http_messag
        char *version_str;
        size_t version_len;
 
+       zval_ptr_dtor(return_value);
        php_http_version_to_string(&obj->message->http.version, &version_str, &version_len, NULL, NULL);
        RETVAL_STR(php_http_cs2zs(version_str, version_len));
 }
@@ -612,28 +618,41 @@ static void php_http_message_object_prophandler_set_http_version(php_http_messag
        zend_string_release(zs);
 }
 static void php_http_message_object_prophandler_get_headers(php_http_message_object_t *obj, zval *return_value ) {
+       zval tmp;
+
+       ZVAL_COPY_VALUE(&tmp, return_value);
        array_init(return_value);
        array_copy(&obj->message->hdrs, Z_ARRVAL_P(return_value));
+       zval_ptr_dtor(&tmp);
 }
 static void php_http_message_object_prophandler_set_headers(php_http_message_object_t *obj, zval *value) {
-       HashTable *headers;
-       zval *orig_value = value;
+       int converted = 0;
+       HashTable garbage, *src;
 
        if (Z_TYPE_P(value) != IS_ARRAY && Z_TYPE_P(value) != IS_OBJECT) {
-               convert_to_array_ex(value);
+               converted = 1;
+               SEPARATE_ZVAL(value);
+               convert_to_array(value);
        }
-       headers = HASH_OF(value);
+       src = HASH_OF(value);
 
-       zend_hash_clean(&obj->message->hdrs);
-       array_copy(headers, &obj->message->hdrs);
+       garbage = obj->message->hdrs;
+       zend_hash_init(&obj->message->hdrs, zend_hash_num_elements(src), NULL, ZVAL_PTR_DTOR, 0);
+       array_copy(HASH_OF(value), &obj->message->hdrs);
 
-       if (orig_value != value) {
+       zend_hash_destroy(&garbage);
+
+       if (converted) {
                zval_ptr_dtor(value);
        }
 }
 static void php_http_message_object_prophandler_get_body(php_http_message_object_t *obj, zval *return_value) {
        if (obj->body) {
+               zval tmp;
+
+               ZVAL_COPY_VALUE(&tmp, return_value);
                RETVAL_OBJECT(&obj->body->zo, 1);
+               zval_ptr_dtor(&tmp);
        } else {
                RETVAL_NULL();
        }
@@ -643,7 +662,11 @@ static void php_http_message_object_prophandler_set_body(php_http_message_object
 }
 static void php_http_message_object_prophandler_get_parent_message(php_http_message_object_t *obj, zval *return_value) {
        if (obj->message->parent) {
+               zval tmp;
+
+               ZVAL_COPY_VALUE(&tmp, return_value);
                RETVAL_OBJECT(&obj->parent->zo, 1);
+               zval_ptr_dtor(&tmp);
        } else {
                RETVAL_NULL();
        }
@@ -652,10 +675,10 @@ static void php_http_message_object_prophandler_set_parent_message(php_http_mess
        if (Z_TYPE_P(value) == IS_OBJECT && instanceof_function(Z_OBJCE_P(value), php_http_message_class_entry)) {
                php_http_message_object_t *parent_obj = PHP_HTTP_OBJ(NULL, value);
 
+               Z_ADDREF_P(value);
                if (obj->message->parent) {
                        zend_object_release(&obj->parent->zo);
                }
-               Z_ADDREF_P(value);
                obj->parent = parent_obj;
                obj->message->parent = parent_obj->message;
        }
@@ -835,7 +858,7 @@ php_http_message_object_t *php_http_message_object_new_ex(zend_class_entry *ce,
 
 zend_object *php_http_message_object_clone(zval *this_ptr)
 {
-       php_http_message_object_t *new_obj = NULL;
+       php_http_message_object_t *new_obj;
        php_http_message_object_t *old_obj = PHP_HTTP_OBJ(NULL, this_ptr);
 
        new_obj = php_http_message_object_new_ex(old_obj->zo.ce, php_http_message_copy(old_obj->message, NULL));
@@ -877,31 +900,27 @@ static zval *php_http_message_object_read_prop(zval *object, zval *member, int t
        zend_string *member_name = zval_get_string(member);
        php_http_message_object_prophandler_t *handler = php_http_message_object_get_prophandler(member_name);
 
-       if (!handler || type == BP_VAR_R || type == BP_VAR_IS) {
-               return_value = zend_get_std_object_handlers()->read_property(object, member, type, cache_slot, tmp);
+       return_value = zend_get_std_object_handlers()->read_property(object, member, type, cache_slot, tmp);
 
-               if (handler) {
+       if (handler && handler->read) {
+               if (type == BP_VAR_R || type == BP_VAR_IS) {
                        php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, object);
 
-                       PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
-                       handler->read(obj, tmp);
-
-                       //zval_ptr_dtor(return_value);
-                       ZVAL_COPY_VALUE(return_value, tmp);
-               }
-               zend_string_release(member_name);
-               return return_value;
-       } else {
-               php_property_proxy_t *proxy;
-               php_property_proxy_object_t *proxy_obj;
+                       handler->read(obj, return_value);
+               } else {
+                       php_property_proxy_t *proxy;
+                       php_property_proxy_object_t *proxy_obj;
 
-               proxy = php_property_proxy_init(object, member_name);
-               proxy_obj = php_property_proxy_object_new_ex(NULL, proxy);
+                       proxy = php_property_proxy_init(object, member_name);
+                       proxy_obj = php_property_proxy_object_new_ex(NULL, proxy);
 
-               ZVAL_OBJ(tmp, &proxy_obj->zo);
-               zend_string_release(member_name);
-               return tmp;
+                       ZVAL_OBJ(tmp, &proxy_obj->zo);
+                       return_value = tmp;
+               }
        }
+
+       zend_string_release(member_name);
+       return return_value;
 }
 
 static void php_http_message_object_write_prop(zval *object, zval *member, zval *value, void **cache_slot)
@@ -1102,7 +1121,6 @@ static PHP_METHOD(HttpMessage, getBody)
 
        if (!obj->body) {
                php_http_message_object_init_body_object(obj);
-
        }
        if (obj->body) {
                RETVAL_OBJECT(&obj->body->zo, 1);
@@ -1975,7 +1993,7 @@ static PHP_METHOD(HttpMessage, current)
 }
 
 static zend_function_entry php_http_message_methods[] = {
-       PHP_ME(HttpMessage, __construct,        ai_HttpMessage___construct,        ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
+       PHP_ME(HttpMessage, __construct,        ai_HttpMessage___construct,        ZEND_ACC_PUBLIC)
        PHP_ME(HttpMessage, getBody,            ai_HttpMessage_getBody,            ZEND_ACC_PUBLIC)
        PHP_ME(HttpMessage, setBody,            ai_HttpMessage_setBody,            ZEND_ACC_PUBLIC)
        PHP_ME(HttpMessage, addBody,            ai_HttpMessage_addBody,            ZEND_ACC_PUBLIC)
index 18859a3b409cb8fe1a4d30479892f62afa37fc55..79c8bf765095852bd2798cf1ae80e077a287de12 100644 (file)
@@ -40,13 +40,13 @@ php_http_message_body_t *php_http_message_body_init(php_http_message_body_t **bo
                php_http_message_body_addref(body);
                return body;
        }
-       
+
        body = ecalloc(1, sizeof(php_http_message_body_t));
        body->refcount = 1;
 
        if (stream) {
                body->res = stream->res;
-               ++GC_REFCOUNT(body->res);
+               GC_ADDREF(body->res);
        } else {
                body->res = php_stream_temp_create(TEMP_STREAM_DEFAULT, 0xffff)->res;
        }
@@ -90,9 +90,9 @@ void php_http_message_body_free(php_http_message_body_t **body_ptr)
 {
        if (*body_ptr) {
                php_http_message_body_t *body = *body_ptr;
-
                if (!--body->refcount) {
                        zend_list_delete(body->res);
+                       body->res = NULL;
                        PTR_FREE(body->boundary);
                        efree(body);
                }
@@ -262,9 +262,14 @@ void php_http_message_body_add_part(php_http_message_body_t *body, php_http_mess
 
 ZEND_RESULT_CODE php_http_message_body_add_form_field(php_http_message_body_t *body, const char *name, const char *value_str, size_t value_len)
 {
-       zend_string *safe_name = zend_string_init(name, strlen(name), 0);
+       zend_string *safe_name, *zstr_name = zend_string_init(name, strlen(name), 0);
 
-       safe_name = php_addslashes(safe_name, 1);
+#if PHP_VERSION_ID < 70300
+       safe_name = php_addslashes(zstr_name, 1);
+#else
+       safe_name = php_addslashes(zstr_name);
+       zend_string_release_ex(zstr_name, 0);
+#endif
 
        BOUNDARY_OPEN(body);
        php_http_message_body_appendf(
@@ -284,9 +289,14 @@ ZEND_RESULT_CODE php_http_message_body_add_form_file(php_http_message_body_t *bo
 {
        size_t path_len = strlen(path);
        char *path_dup = estrndup(path, path_len);
-       zend_string *base_name, *safe_name = zend_string_init(name, strlen(name), 0);
-
-       safe_name = php_addslashes(safe_name, 1);
+       zend_string *base_name, *safe_name, *zstr_name = zend_string_init(name, strlen(name), 0);
+
+#if PHP_VERSION_ID < 70300
+       safe_name = php_addslashes(zstr_name, 1);
+#else
+       safe_name = php_addslashes(zstr_name);
+       zend_string_release_ex(zstr_name, 0);
+#endif
        base_name = php_basename(path_dup, path_len, NULL, 0);
 
        BOUNDARY_OPEN(body);
@@ -339,8 +349,8 @@ static ZEND_RESULT_CODE add_recursive_fields(php_http_message_body_t *body, cons
        zval *val;
        php_http_arrkey_t key;
 
-       if (!ZEND_HASH_GET_APPLY_COUNT(fields)) {
-               ZEND_HASH_INC_APPLY_COUNT(fields);
+       if (!HT_IS_RECURSIVE(fields)) {
+               HT_PROTECT_RECURSION(fields);
                ZEND_HASH_FOREACH_KEY_VAL_IND(fields, key.h, key.key, val)
                {
                        char *str = format_key(&key, name);
@@ -348,18 +358,18 @@ static ZEND_RESULT_CODE add_recursive_fields(php_http_message_body_t *body, cons
                        if (Z_TYPE_P(val) != IS_ARRAY && Z_TYPE_P(val) != IS_OBJECT) {
                                if (SUCCESS != add_recursive_field_value(body, str, val)) {
                                        efree(str);
-                                       ZEND_HASH_DEC_APPLY_COUNT(fields);
+                                       HT_UNPROTECT_RECURSION(fields);
                                        return FAILURE;
                                }
                        } else if (SUCCESS != add_recursive_fields(body, str, HASH_OF(val))) {
                                efree(str);
-                               ZEND_HASH_DEC_APPLY_COUNT(fields);
+                               HT_UNPROTECT_RECURSION(fields);
                                return FAILURE;
                        }
                        efree(str);
                }
                ZEND_HASH_FOREACH_END();
-               ZEND_HASH_DEC_APPLY_COUNT(fields);
+               HT_UNPROTECT_RECURSION(fields);
        }
 
        return SUCCESS;
@@ -377,8 +387,8 @@ static ZEND_RESULT_CODE add_recursive_files(php_http_message_body_t *body, const
                zval *val;
                php_http_arrkey_t key;
 
-               if (!ZEND_HASH_GET_APPLY_COUNT(files)) {
-                       ZEND_HASH_INC_APPLY_COUNT(files);
+               if (!HT_IS_RECURSIVE(files)) {
+                       HT_PROTECT_RECURSION(files);
                        ZEND_HASH_FOREACH_KEY_VAL_IND(files, key.h, key.key, val)
                        {
                                if (Z_TYPE_P(val) == IS_ARRAY || Z_TYPE_P(val) == IS_OBJECT) {
@@ -386,14 +396,14 @@ static ZEND_RESULT_CODE add_recursive_files(php_http_message_body_t *body, const
 
                                        if (SUCCESS != add_recursive_files(body, str, HASH_OF(val))) {
                                                efree(str);
-                                               ZEND_HASH_DEC_APPLY_COUNT(files);
+                                               HT_UNPROTECT_RECURSION(files);
                                                return FAILURE;
                                        }
                                        efree(str);
                                }
                        }
                        ZEND_HASH_FOREACH_END();
-                       ZEND_HASH_DEC_APPLY_COUNT(files);
+                       HT_UNPROTECT_RECURSION(files);
                }
                return SUCCESS;
        } else {
@@ -570,8 +580,6 @@ php_http_message_body_object_t *php_http_message_body_object_new_ex(zend_class_e
 
        if (body) {
                o->body = body;
-               php_stream_to_zval(php_http_message_body_stream(o->body), o->gc);
-
        }
 
        o->zo.handlers = &php_http_message_body_object_handlers;
@@ -581,7 +589,7 @@ php_http_message_body_object_t *php_http_message_body_object_new_ex(zend_class_e
 
 zend_object *php_http_message_body_object_clone(zval *object)
 {
-       php_http_message_body_object_t *new_obj = NULL;
+       php_http_message_body_object_t *new_obj;
        php_http_message_body_object_t *old_obj = PHP_HTTP_OBJ(NULL, object);
        php_http_message_body_t *body = php_http_message_body_copy(old_obj->body, NULL);
 
@@ -597,12 +605,18 @@ static HashTable *php_http_message_body_object_get_gc(zval *object, zval **table
        HashTable *props = Z_OBJPROP_P(object);
        uint32_t count = zend_hash_num_elements(props);
 
-       *n = 1;
+       obj->gc = erealloc(obj->gc, (1 + count) * sizeof(zval));
+
+       if (php_http_message_body_stream(obj->body)) {
+               *n = 1;
+               php_stream_to_zval(php_http_message_body_stream(obj->body), obj->gc);
+       } else {
+               *n = 0;
+       }
+
        if (count) {
                zval *val;
 
-               obj->gc = erealloc(obj->gc, (*n + count) * sizeof(zval));
-
                ZEND_HASH_FOREACH_VAL(props, val)
                {
                        ZVAL_COPY_VALUE(&obj->gc[(*n)++], val);
@@ -893,7 +907,7 @@ PHP_METHOD(HttpMessageBody, stat)
 }
 
 static zend_function_entry php_http_message_body_methods[] = {
-       PHP_ME(HttpMessageBody, __construct,  ai_HttpMessageBody___construct,  ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
+       PHP_ME(HttpMessageBody, __construct,  ai_HttpMessageBody___construct,  ZEND_ACC_PUBLIC)
        PHP_ME(HttpMessageBody, __toString,   ai_HttpMessageBody___toString,   ZEND_ACC_PUBLIC)
        PHP_MALIAS(HttpMessageBody, toString, __toString, ai_HttpMessageBody___toString, ZEND_ACC_PUBLIC)
        PHP_MALIAS(HttpMessageBody, serialize, __toString, ai_HttpMessageBody___toString, ZEND_ACC_PUBLIC)
index db935d913cbc694f3b0000bdd0009dbc64e4d5cc..49a6013ae561d9b0bcec0cc4e52fc55172d7f4b2 100644 (file)
@@ -57,41 +57,16 @@ php_http_message_parser_t *php_http_message_parser_init(php_http_message_parser_
        return parser;
 }
 
-php_http_message_parser_state_t php_http_message_parser_state_push(php_http_message_parser_t *parser, unsigned argc, ...)
-{
-       php_http_message_parser_state_t state = PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE;
-       va_list va_args;
-       unsigned i;
-
-       if (argc > 0) {
-               /* short circuit */
-               ZEND_PTR_STACK_RESIZE_IF_NEEDED((&parser->stack), argc);
-
-               va_start(va_args, argc);
-               for (i = 0; i < argc; ++i) {
-                       state  = va_arg(va_args, php_http_message_parser_state_t);
-                       zend_ptr_stack_push(&parser->stack, (void *) state);
-               }
-               va_end(va_args);
-       }
-
-       return state;
-}
-
+#define php_http_message_parser_state_push(parser, state) zend_ptr_stack_push(&(parser)->stack, (void *) (state)), (state)
+#define php_http_message_parser_state_pop(parser) ((parser)->stack.top \
+               ? (php_http_message_parser_state_t) zend_ptr_stack_pop(&parser->stack) \
+               : PHP_HTTP_MESSAGE_PARSER_STATE_START)
+#define php_http_message_parser_state_is_ex(parser) ((parser)->stack.top \
+               ? (php_http_message_parser_state_t) (parser)->stack.elements[(parser)->stack.top - 1] \
+               : PHP_HTTP_MESSAGE_PARSER_STATE_START)
 php_http_message_parser_state_t php_http_message_parser_state_is(php_http_message_parser_t *parser)
 {
-       if (parser->stack.top) {
-               return (php_http_message_parser_state_t) parser->stack.elements[parser->stack.top - 1];
-       }
-       return PHP_HTTP_MESSAGE_PARSER_STATE_START;
-}
-
-php_http_message_parser_state_t php_http_message_parser_state_pop(php_http_message_parser_t *parser)
-{
-       if (parser->stack.top) {
-               return (php_http_message_parser_state_t) zend_ptr_stack_pop(&parser->stack);
-       }
-       return PHP_HTTP_MESSAGE_PARSER_STATE_START;
+       return php_http_message_parser_state_is_ex(parser);
 }
 
 void php_http_message_parser_dtor(php_http_message_parser_t *parser)
@@ -188,7 +163,7 @@ php_http_message_parser_state_t php_http_message_parser_parse_stream(php_http_me
 
                        case PHP_HTTP_MESSAGE_PARSER_STATE_DONE:
                        case PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE:
-                               return php_http_message_parser_state_is(parser);
+                               return php_http_message_parser_state_is_ex(parser);
                }
 
                if (justread) {
@@ -210,7 +185,7 @@ php_http_message_parser_state_t php_http_message_parser_parse(php_http_message_p
        size_t len = 0;
        size_t cut = 0;
 
-       while (buffer->used || !php_http_message_parser_states[php_http_message_parser_state_is(parser)].need_data) {
+       while (buffer->used || !php_http_message_parser_states[php_http_message_parser_state_is_ex(parser)].need_data) {
 #if DBG_PARSER
                fprintf(stderr, "#MP: %s (f: %u, t:%d, l:%zu)\n", 
                        php_http_message_parser_state_name(php_http_message_parser_state_is(parser)),
@@ -224,7 +199,7 @@ php_http_message_parser_state_t php_http_message_parser_parse(php_http_message_p
                switch (php_http_message_parser_state_pop(parser))
                {
                        case PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE:
-                               return php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE);
+                               return php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE);
 
                        case PHP_HTTP_MESSAGE_PARSER_STATE_START:
                        {
@@ -237,7 +212,7 @@ php_http_message_parser_state_t php_http_message_parser_parse(php_http_message_p
                                php_http_buffer_cut(buffer, 0, ptr - buffer->data);
 
                                if (buffer->used) {
-                                       php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_HEADER);
+                                       php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_HEADER);
                                }
                                break;
                        }
@@ -251,14 +226,14 @@ php_http_message_parser_state_t php_http_message_parser_parse(php_http_message_p
                                                return PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE;
 
                                        case PHP_HTTP_HEADER_PARSER_STATE_DONE:
-                                               php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_HEADER_DONE);
+                                               php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_HEADER_DONE);
                                                break;
 
                                        default:
                                                if (buffer->used || !(flags & PHP_HTTP_MESSAGE_PARSER_CLEANUP)) {
-                                                       return php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_HEADER);
+                                                       return php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_HEADER);
                                                } else {
-                                                       php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_HEADER_DONE);
+                                                       php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_HEADER_DONE);
                                                }
                                }
                                break;
@@ -313,7 +288,7 @@ php_http_message_parser_state_t php_http_message_parser_parse(php_http_message_p
 
                                        if (php_http_match(con->val, "close", PHP_HTTP_MATCH_WORD)) {
                                                zend_string_release(con);
-                                               php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_DONE);
+                                               php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_DONE);
                                                break;
                                        }
                                        zend_string_release(con);
@@ -339,11 +314,11 @@ php_http_message_parser_state_t php_http_message_parser_parse(php_http_message_p
                                }
 
                                if ((flags & PHP_HTTP_MESSAGE_PARSER_DUMB_BODIES)) {
-                                       php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DUMB);
+                                       php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DUMB);
                                } else {
                                        if (chunked) {
                                                parser->dechunk = php_http_encoding_stream_init(parser->dechunk, php_http_encoding_stream_get_dechunk_ops(), 0);
-                                               php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_CHUNKED);
+                                               php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_CHUNKED);
                                                break;
                                        }
 
@@ -368,7 +343,11 @@ php_http_message_parser_state_t php_http_message_parser_parse(php_http_message_p
 
                                                                if (end >= start && (!total || end <= total)) {
                                                                        parser->body_length = end + 1 - start;
-                                                                       php_http_message_parser_state_push(parser, 1, !parser->body_length?PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE:PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH);
+                                                                       if (parser->body_length) {
+                                                                               php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH);
+                                                                       } else {
+                                                                               php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE);
+                                                                       }
                                                                        zend_string_release(content_range);
                                                                        break;
                                                                }
@@ -380,14 +359,18 @@ php_http_message_parser_state_t php_http_message_parser_parse(php_http_message_p
 
                                        if (content_length >= 0) {
                                                parser->body_length = content_length;
-                                               php_http_message_parser_state_push(parser, 1, !parser->body_length?PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE:PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH);
+                                               if (parser->body_length) {
+                                                       php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH);
+                                               } else {
+                                                       php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE);
+                                               }
                                                break;
                                        }
 
                                        if ((*message)->type == PHP_HTTP_REQUEST) {
-                                               php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_DONE);
+                                               php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_DONE);
                                        } else {
-                                               php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DUMB);
+                                               php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DUMB);
                                        }
                                }
                                break;
@@ -401,7 +384,7 @@ php_http_message_parser_state_t php_http_message_parser_parse(php_http_message_p
                                                size_t dec_len;
 
                                                if (SUCCESS != php_http_encoding_stream_update(parser->inflate, str, len, &dec_str, &dec_len)) {
-                                                       return php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE);
+                                                       return php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE);
                                                }
 
                                                if (str != buffer->data) {
@@ -434,7 +417,8 @@ php_http_message_parser_state_t php_http_message_parser_parse(php_http_message_p
                                len = buffer->used;
                                cut = len;
 
-                               php_http_message_parser_state_push(parser, 2, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE, PHP_HTTP_MESSAGE_PARSER_STATE_BODY);
+                               php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE);
+                               php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY);
                                break;
                        }
 
@@ -446,7 +430,12 @@ php_http_message_parser_state_t php_http_message_parser_parse(php_http_message_p
 
                                parser->body_length -= len;
 
-                               php_http_message_parser_state_push(parser, 2, !parser->body_length?PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE:PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH, PHP_HTTP_MESSAGE_PARSER_STATE_BODY);
+                               if (parser->body_length) {
+                                       php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH);
+                               } else {
+                                       php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE);
+                               }
+                               php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY);
                                break;
                        }
 
@@ -472,24 +461,26 @@ php_http_message_parser_state_t php_http_message_parser_parse(php_http_message_p
 
                                if (php_http_encoding_stream_done(parser->dechunk)) {
                                        cut = buffer->used - PHP_HTTP_BUFFER(parser->dechunk->ctx)->used;
-                                       php_http_message_parser_state_push(parser, 2, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE, PHP_HTTP_MESSAGE_PARSER_STATE_BODY);
+                                       php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE);
+                                       php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY);
                                } else {
                                        cut = buffer->used;
-                                       php_http_message_parser_state_push(parser, 2, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_CHUNKED, PHP_HTTP_MESSAGE_PARSER_STATE_BODY);
+                                       php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_CHUNKED);
+                                       php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY);
                                }
                                break;
                        }
 
                        case PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE:
                        {
-                               php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_DONE);
+                               php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_DONE);
 
                                if (parser->dechunk && parser->dechunk->ctx) {
                                        char *dec_str = NULL;
                                        size_t dec_len;
 
                                        if (SUCCESS != php_http_encoding_stream_finish(parser->dechunk, &dec_str, &dec_len)) {
-                                               return php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE);
+                                               return php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE);
                                        }
                                        php_http_encoding_stream_dtor(parser->dechunk);
 
@@ -497,7 +488,8 @@ php_http_message_parser_state_t php_http_message_parser_parse(php_http_message_p
                                                str = dec_str;
                                                len = dec_len;
                                                cut = 0;
-                                               php_http_message_parser_state_push(parser, 2, PHP_HTTP_MESSAGE_PARSER_STATE_UPDATE_CL, PHP_HTTP_MESSAGE_PARSER_STATE_BODY);
+                                               php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_UPDATE_CL);
+                                               php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY);
                                        }
                                }
 
@@ -531,7 +523,7 @@ php_http_message_parser_state_t php_http_message_parser_parse(php_http_message_p
                }
        }
 
-       return php_http_message_parser_state_is(parser);
+       return php_http_message_parser_state_is_ex(parser);
 }
 
 static zend_class_entry *php_http_message_parser_class_entry;
@@ -584,7 +576,7 @@ static PHP_METHOD(HttpMessageParser, getState)
 
        zend_parse_parameters_none();
        /* always return the real state */
-       RETVAL_LONG(php_http_message_parser_state_is(parser_obj->parser));
+       RETVAL_LONG(php_http_message_parser_state_is_ex(parser_obj->parser));
 }
 
 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessageParser_parse, 0, 0, 3)
index 9b6174d12951ac26030ec82bc8f8d0c8276e369b..edc6c2b3857033835a1216ad4031f464733d910f 100644 (file)
@@ -46,9 +46,7 @@ typedef struct php_http_message_parser {
 } php_http_message_parser_t;
 
 PHP_HTTP_API php_http_message_parser_t *php_http_message_parser_init(php_http_message_parser_t *parser);
-PHP_HTTP_API php_http_message_parser_state_t php_http_message_parser_state_push(php_http_message_parser_t *parser, unsigned argc, ...);
 PHP_HTTP_API php_http_message_parser_state_t php_http_message_parser_state_is(php_http_message_parser_t *parser);
-PHP_HTTP_API php_http_message_parser_state_t php_http_message_parser_state_pop(php_http_message_parser_t *parser);
 PHP_HTTP_API void php_http_message_parser_dtor(php_http_message_parser_t *parser);
 PHP_HTTP_API void php_http_message_parser_free(php_http_message_parser_t **parser);
 PHP_HTTP_API php_http_message_parser_state_t php_http_message_parser_parse(php_http_message_parser_t *parser, php_http_buffer_t *buffer, unsigned flags, php_http_message_t **message);
index 36e3490a12a04d2fadaf4de1016538aea3013a3f..f0cc25fa32e0d2bf07eac0ef2295d839d009f741 100644 (file)
@@ -50,11 +50,11 @@ int php_http_match(const char *haystack_str, const char *needle_str, int flags)
 {
        int result = 0;
 
-       if (!haystack_str || !needle_str) {
+       if (UNEXPECTED(!haystack_str || !needle_str)) {
                return result;
        }
 
-       if (flags & PHP_HTTP_MATCH_FULL) {
+       if (UNEXPECTED(flags & PHP_HTTP_MATCH_FULL)) {
                if (flags & PHP_HTTP_MATCH_CASE) {
                        result = !strcmp(haystack_str, needle_str);
                } else {
@@ -64,7 +64,7 @@ int php_http_match(const char *haystack_str, const char *needle_str, int flags)
                const char *found;
                char *haystack = estrdup(haystack_str), *needle = estrdup(needle_str);
 
-               if (flags & PHP_HTTP_MATCH_CASE) {
+               if (UNEXPECTED(flags & PHP_HTTP_MATCH_CASE)) {
                        found = zend_memnstr(haystack, needle, strlen(needle), haystack+strlen(haystack));
                } else {
                        found = php_stristr(haystack, needle, strlen(haystack), strlen(needle));
@@ -73,7 +73,7 @@ int php_http_match(const char *haystack_str, const char *needle_str, int flags)
                if (found) {
                        if (!(flags & PHP_HTTP_MATCH_WORD)
                        ||      (       (found == haystack || !PHP_HTTP_IS_CTYPE(alnum, *(found - 1)))
-                               &&      (!*(found + strlen(needle)) || !PHP_HTTP_IS_CTYPE(alnum, *(found + strlen(needle))))
+                               &&      EXPECTED(!*(found + strlen(needle)) || !PHP_HTTP_IS_CTYPE(alnum, *(found + strlen(needle))))
                                )
                        ) {
                                result = 1;
@@ -87,27 +87,37 @@ int php_http_match(const char *haystack_str, const char *needle_str, int flags)
        return result;
 }
 
-char *php_http_pretty_key(register char *key, size_t key_len, zend_bool uctitle, zend_bool xhyphen)
+char *php_http_pretty_key(char *key, size_t key_len, zend_bool uctitle, zend_bool xhyphen)
 {
-       size_t i = 1;
+       size_t i;
        int wasalpha;
 
        if (key && key_len) {
-               if ((wasalpha = PHP_HTTP_IS_CTYPE(alpha, key[0]))) {
-                       key[0] = (char) (uctitle ? PHP_HTTP_TO_CTYPE(upper, key[0]) : PHP_HTTP_TO_CTYPE(lower, key[0]));
+               if (EXPECTED(wasalpha = PHP_HTTP_IS_CTYPE(alpha, key[0]))) {
+                       if (EXPECTED(uctitle)) {
+                               key[0] = PHP_HTTP_TO_CTYPE(upper, key[0]);
+                       } else {
+                               key[0] = PHP_HTTP_TO_CTYPE(lower, key[0]);
+                       }
                }
-               PHP_HTTP_DUFF(key_len,
-                       if (PHP_HTTP_IS_CTYPE(alpha, key[i])) {
-                               key[i] = (char) (((!wasalpha) && uctitle) ? PHP_HTTP_TO_CTYPE(upper, key[i]) : PHP_HTTP_TO_CTYPE(lower, key[i]));
-                               wasalpha = 1;
+               for (i = 1; i < key_len; ++i) {
+                       if (EXPECTED(PHP_HTTP_IS_CTYPE(alpha, key[i]))) {
+                               if (EXPECTED(wasalpha)) {
+                                       key[i] = PHP_HTTP_TO_CTYPE(lower, key[i]);
+                               } else if (EXPECTED(uctitle)) {
+                                       key[i] = PHP_HTTP_TO_CTYPE(upper, key[i]);
+                                       wasalpha = 1;
+                               } else {
+                                       key[i] = PHP_HTTP_TO_CTYPE(lower, key[i]);
+                                       wasalpha = 1;
+                               }
                        } else {
-                               if (xhyphen && (key[i] == '_')) {
+                               if (EXPECTED(xhyphen && (key[i] == '_'))) {
                                        key[i] = '-';
                                }
                                wasalpha = 0;
                        }
-                       ++i;
-               );
+               }
        }
        return key;
 }
@@ -190,7 +200,7 @@ int php_http_array_apply_append_func(zval *value, int num_args, va_list args, ze
                if (flags & ARRAY_JOIN_STRINGIFY) {
                        convert_to_string_ex(value);
                }
-               Z_ADDREF_P(value);
+               Z_TRY_ADDREF_P(value);
 
                if (data) {
                        if (Z_TYPE_P(data) != IS_ARRAY) {
index ae3359c3b00921eb9e75486396715361bf58f132..35de35ef385428be67f4949955148322d2adcd33 100644 (file)
@@ -67,47 +67,7 @@ char *php_http_pretty_key(register char *key, size_t key_len, zend_bool uctitle,
 size_t php_http_boundary(char *buf, size_t len);
 int php_http_select_str(const char *cmp, int argc, ...);
 
-/* See "A Reusable Duff Device" By Ralf Holly, August 01, 2005 */
-#define PHP_HTTP_DUFF_BREAK() times_=1
-#define PHP_HTTP_DUFF(c, a) do { \
-       size_t count_ = (c); \
-       size_t times_ = (count_ + 7) >> 3; \
-       switch (count_ & 7){ \
-               case 0: do { \
-                       a; \
-               case 7: \
-                       a; \
-               case 6: \
-                       a; \
-               case 5: \
-                       a; \
-               case 4: \
-                       a; \
-               case 3: \
-                       a; \
-               case 2: \
-                       a; \
-               case 1: \
-                       a; \
-                                       } while (--times_ > 0); \
-       } \
-} while (0)
-
-static inline const char *php_http_locate_str(register const char *h, size_t h_len, const char *n, size_t n_len)
-{
-       if (!n_len || !h_len || h_len < n_len) {
-               return NULL;
-       }
-
-       PHP_HTTP_DUFF(h_len - n_len + 1,
-               if (*h == *n && !strncmp(h + 1, n + 1, n_len - 1)) {
-                       return h;
-               }
-               ++h;
-       );
-
-       return NULL;
-}
+#define php_http_locate_str(h, h_len, n, n_len) zend_memnstr((h), (n), (n_len), (h)+(h_len))
 
 static inline const char *php_http_locate_eol(const char *line, int *eol_len)
 {
@@ -123,16 +83,14 @@ static inline const char *php_http_locate_bin_eol(const char *bin, size_t len, i
 {
        register const char *eol = bin;
 
-       if (len > 0) {
-               PHP_HTTP_DUFF(len,
-                       if (*eol == '\r' || *eol == '\n') {
-                               if (eol_len) {
-                                       *eol_len = ((eol[0] == '\r' && eol[1] == '\n') ? 2 : 1);
-                               }
-                               return eol;
+       while (len--) {
+               if (UNEXPECTED(*eol == '\r' || *eol == '\n')) {
+                       if (EXPECTED(eol_len)) {
+                               *eol_len = (EXPECTED(eol[0] == '\r' && eol[1] == '\n') ? 2 : 1);
                        }
-                       ++eol;
-               );
+                       return eol;
+               }
+               ++eol;
        }
        return NULL;
 }
@@ -144,6 +102,32 @@ static inline const char *php_http_locate_bin_eol(const char *bin, size_t len, i
 #      define HASH_OF(p) ((HashTable*)(Z_TYPE_P(p)==IS_ARRAY ? Z_ARRVAL_P(p) : ((Z_TYPE_P(p)==IS_OBJECT ? Z_OBJ_HT_P(p)->get_properties((p)) : NULL))))
 #endif
 
+#ifndef GC_SET_REFCOUNT
+#      define GC_SET_REFCOUNT(gc, rc) GC_REFCOUNT(gc) = rc
+#endif
+#ifndef GC_ADDREF
+#      define GC_ADDREF(gc) ++GC_REFCOUNT(gc)
+#endif
+#ifndef GC_DELREF
+#      define GC_DELREF(gc) --GC_REFCOUNT(gc)
+#endif
+
+#ifdef ZEND_HASH_GET_APPLY_COUNT
+#      define HT_IS_RECURSIVE(ht) (ZEND_HASH_GET_APPLY_COUNT(ht) > 0)
+#else
+#      define HT_IS_RECURSIVE(ht) GC_IS_RECURSIVE(ht)
+#endif
+#ifdef ZEND_HASH_INC_APPLY_COUNT
+#      define HT_PROTECT_RECURSION(ht) ZEND_HASH_INC_APPLY_COUNT(ht)
+#else
+#      define HT_PROTECT_RECURSION(ht) GC_PROTECT_RECURSION(ht)
+#endif
+#ifdef ZEND_HASH_DEC_APPLY_COUNT
+#      define HT_UNPROTECT_RECURSION(ht) ZEND_HASH_DEC_APPLY_COUNT(ht)
+#else
+#      define HT_UNPROTECT_RECURSION(ht) GC_UNPROTECT_RECURSION(ht)
+#endif
+
 static inline void *PHP_HTTP_OBJ(zend_object *zo, zval *zv)
 {
        if (!zo) {
@@ -161,7 +145,7 @@ static inline zend_string *php_http_cs2zs(char *s, size_t l)
        str->len = l;
        str->h = 0;
 
-       GC_REFCOUNT(str) = 1;
+       GC_SET_REFCOUNT(str, 1);
        GC_TYPE_INFO(str) = IS_STRING;
 
        return str;
index e42998ea773407c830ac3cb9282a3ade55cd7081..2d09860ee5ba57ae4acfaa40b6b5e1233f194855 100644 (file)
@@ -66,7 +66,9 @@ php_http_object_method_t *php_http_object_method_init(php_http_object_method_t *
 
        cb->fci.size = sizeof(cb->fci);
        ZVAL_STRINGL(&cb->fci.function_name, method_str, method_len);
+#if PHP_VERSION_ID < 70300
        cb->fcc.initialized = 1;
+#endif
        cb->fcc.calling_scope = cb->fcc.called_scope = Z_OBJCE_P(zobject);
        cb->fcc.function_handler = Z_OBJ_HT_P(zobject)->get_method(&Z_OBJ_P(zobject), Z_STR(cb->fci.function_name), NULL);
 
index d4be512a7e1e9584cdace1a12429054fee90e471..4cb6ed37b648cabf62d305024427ece77796f9ba 100644 (file)
@@ -16,7 +16,7 @@ static void php_http_options_hash_dtor(zval *pData)
 {
        php_http_option_t *opt = Z_PTR_P(pData);
 
-       zval_ptr_dtor(&opt->defval);
+       zval_internal_dtor(&opt->defval);
        zend_hash_destroy(&opt->suboptions.options);
        zend_string_release(opt->name);
        pefree(opt, opt->persistent);
index 9b40cfefdc767dafc1945213db20fdd45c17001a..92c144154c8866d4af009ded0ef893eea51ed240 100644 (file)
@@ -67,7 +67,11 @@ static inline zend_string *quote_string(zend_string *zs, zend_bool force)
 {
        size_t len = (zs)->len;
 
+#if PHP_VERSION_ID < 70300
        zs = php_addcslashes(zs, 0, ZEND_STRL("\0..\37\173\\\""));
+#else
+       zs = php_addcslashes(zs, ZEND_STRL("\0..\37\173\\\""));
+#endif
 
        if (force || len != (zs)->len || strpbrk((zs)->val, "()<>@,;:\"[]?={} ")) {
                int len = (zs)->len + 2;
@@ -136,12 +140,11 @@ static inline void prepare_urlencoded(zval *zv)
 
 static void sanitize_dimension(zval *zv)
 {
-       zval arr, tmp, *cur = NULL;
+       zval arr, tmp, *cur = &arr;
        char *var = NULL, *ptr = Z_STRVAL_P(zv), *end = Z_STRVAL_P(zv) + Z_STRLEN_P(zv);
        long level = 0;
 
        array_init(&arr);
-       cur = &arr;
 
        while (ptr < end) {
                if (!var) {
@@ -200,8 +203,8 @@ static void prepare_dimension(php_http_buffer_t *buf, php_http_buffer_t *keybuf,
        zval *val;
        php_http_buffer_t prefix;
 
-       if (!ZEND_HASH_GET_APPLY_COUNT(ht)) {
-               ZEND_HASH_INC_APPLY_COUNT(ht);
+       if (!HT_IS_RECURSIVE(ht)) {
+               HT_PROTECT_RECURSION(ht);
                php_http_buffer_init(&prefix);
                php_http_buffer_append(&prefix, keybuf->data, keybuf->used);
 
@@ -235,7 +238,7 @@ static void prepare_dimension(php_http_buffer_t *buf, php_http_buffer_t *keybuf,
                        php_http_buffer_cut(&prefix, keybuf->used, prefix.used - keybuf->used);
                }
                ZEND_HASH_FOREACH_END();
-               ZEND_HASH_DEC_APPLY_COUNT(ht);
+               HT_UNPROTECT_RECURSION(ht);
 
                php_http_buffer_dtor(&prefix);
        }
@@ -1287,7 +1290,7 @@ PHP_METHOD(HttpParams, offsetSet)
 }
 
 static zend_function_entry php_http_params_methods[] = {
-       PHP_ME(HttpParams, __construct,   ai_HttpParams___construct,   ZEND_ACC_PUBLIC|ZEND_ACC_CTOR|ZEND_ACC_FINAL)
+       PHP_ME(HttpParams, __construct,   ai_HttpParams___construct,   ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
 
        PHP_ME(HttpParams, toArray,       ai_HttpParams_toArray,       ZEND_ACC_PUBLIC)
        PHP_ME(HttpParams, toString,      ai_HttpParams_toString,      ZEND_ACC_PUBLIC)
index 681d0097155e96ab3f08c6f2f4adb1feb10f5f6f..a302bbd732dc2167bfacebde87396395f05e277a 100644 (file)
@@ -385,8 +385,6 @@ PHP_METHOD(HttpQueryString, getGlobalInstance)
 
                ZVAL_MAKE_REF(_GET);
                zend_update_property(php_http_querystring_class_entry, return_value, ZEND_STRL("queryArray"), _GET);
-
-               zend_update_static_property(php_http_querystring_class_entry, ZEND_STRL("instance"), return_value);
        } else {
                php_http_throw(unexpected_val, "Could not acquire reference to superglobal GET array", NULL);
        }
@@ -682,7 +680,7 @@ PHP_METHOD(HttpQueryString, offsetUnset)
 }
 
 static zend_function_entry php_http_querystring_methods[] = {
-       PHP_ME(HttpQueryString, __construct, ai_HttpQueryString___construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR|ZEND_ACC_FINAL)
+       PHP_ME(HttpQueryString, __construct, ai_HttpQueryString___construct, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
 
        PHP_ME(HttpQueryString, toArray, ai_HttpQueryString_toArray, ZEND_ACC_PUBLIC)
        PHP_ME(HttpQueryString, toString, ai_HttpQueryString_toString, ZEND_ACC_PUBLIC)
index 029e6a8ca37c3cf64a59c06ddb1e280fb7b63239..2055df7a33890724162dd292e4f085f06e071ee6 100644 (file)
 
 #include "php_http_api.h"
 
-#if PHP_HTTP_HAVE_LIBIDN2
-#      include <idn2.h>
-#endif
 #if PHP_HTTP_HAVE_LIBIDN
 #      include <idna.h>
 #endif
+#if PHP_HTTP_HAVE_LIBIDN2
+#      include <idn2.h>
+#endif
 #if PHP_HTTP_HAVE_LIBICU
+#      include <unicode/uchar.h>
 #      include <unicode/uidna.h>
 #endif
 #if PHP_HTTP_HAVE_LIBIDNKIT || PHP_HTTP_HAVE_LIBIDNKIT2
@@ -40,7 +41,7 @@
 static inline char *localhostname(void)
 {
        char hostname[1024] = {0};
-       
+
 #if PHP_WIN32
        if (SUCCESS == gethostname(hostname, lenof(hostname))) {
                return estrdup(hostname);
@@ -188,9 +189,9 @@ php_http_url_t *php_http_url_mod(const php_http_url_t *old_url, const php_http_u
        if (!(flags & PHP_HTTP_URL_STRIP_PASS)) {
                url_copy(pass);
        }
-       
+
        url_copy(host);
-       
+
        if (!(flags & PHP_HTTP_URL_STRIP_PORT)) {
                url(buf)->port = url_isset(new_url, port) ? new_url->port : ((old_url) ? old_url->port : 0);
        }
@@ -199,14 +200,14 @@ php_http_url_t *php_http_url_mod(const php_http_url_t *old_url, const php_http_u
                if ((flags & PHP_HTTP_URL_JOIN_PATH) && url_isset(old_url, path) && url_isset(new_url, path) && *new_url->path != '/') {
                        size_t old_path_len = strlen(old_url->path), new_path_len = strlen(new_url->path);
                        char *path = ecalloc(1, old_path_len + new_path_len + 1 + 1);
-                       
+
                        strcat(path, old_url->path);
                        if (path[old_path_len - 1] != '/') {
                                php_dirname(path, old_path_len);
                                strcat(path, "/");
                        }
                        strcat(path, new_url->path);
-                       
+
                        url(buf)->path = &buf.data[buf.used];
                        if (path[0] != '/') {
                                url_append(&buf, php_http_buffer_append(&buf, "/", 1));
@@ -235,16 +236,16 @@ php_http_url_t *php_http_url_mod(const php_http_url_t *old_url, const php_http_u
        if (!(flags & PHP_HTTP_URL_STRIP_QUERY)) {
                if ((flags & PHP_HTTP_URL_JOIN_QUERY) && url_isset(new_url, query) && url_isset(old_url, query)) {
                        zval qarr, qstr;
-                       
+
                        array_init(&qarr);
-                       
+
                        ZVAL_STRING(&qstr, old_url->query);
                        php_http_querystring_update(&qarr, &qstr, NULL);
                        zval_ptr_dtor(&qstr);
                        ZVAL_STRING(&qstr, new_url->query);
                        php_http_querystring_update(&qarr, &qstr, NULL);
                        zval_ptr_dtor(&qstr);
-                       
+
                        ZVAL_NULL(&qstr);
                        php_http_querystring_update(&qarr, NULL, &qstr);
 
@@ -261,7 +262,7 @@ php_http_url_t *php_http_url_mod(const php_http_url_t *old_url, const php_http_u
        if (!(flags & PHP_HTTP_URL_STRIP_FRAGMENT)) {
                url_copy(fragment);
        }
-       
+
        /* done with copy & combine & strip */
 
        if (flags & PHP_HTTP_URL_FROM_ENV) {
@@ -274,13 +275,13 @@ php_http_url_t *php_http_url_mod(const php_http_url_t *old_url, const php_http_u
        &&      url(buf)->path
        &&      url(buf)->path[0] && url(buf)->path[1]) {
                char *ptr, *end = url(buf)->path + strlen(url(buf)->path) + 1;
-                       
+
                for (ptr = strchr(url(buf)->path, '/'); ptr; ptr = strchr(ptr, '/')) {
                        switch (ptr[1]) {
                                case '/':
                                        memmove(&ptr[1], &ptr[2], end - &ptr[2]);
                                        break;
-                                       
+
                                case '.':
                                        switch (ptr[2]) {
                                                case '\0':
@@ -328,7 +329,7 @@ php_http_url_t *php_http_url_mod(const php_http_url_t *old_url, const php_http_u
                        url(buf)->port = 0;
                }
        }
-       
+
        return url(buf);
 }
 
@@ -663,7 +664,7 @@ php_http_url_t *php_http_url_copy(const php_http_url_t *url, zend_bool persisten
        return cpy;
 }
 
-static size_t parse_mb_utf8(unsigned *wc, const char *ptr, const char *end)
+static inline size_t parse_mb_utf8(unsigned *wc, const char *ptr, const char *end)
 {
        unsigned wchar;
        size_t consumed = utf8towc(&wchar, (const unsigned char *) ptr, end - ptr);
@@ -679,7 +680,7 @@ static size_t parse_mb_utf8(unsigned *wc, const char *ptr, const char *end)
 }
 
 #if PHP_HTTP_HAVE_WCHAR
-static size_t parse_mb_loc(unsigned *wc, const char *ptr, const char *end)
+static inline size_t parse_mb_loc(unsigned *wc, const char *ptr, const char *end)
 {
        wchar_t wchar;
        size_t consumed = 0;
@@ -723,7 +724,7 @@ static const char * const parse_what[] = {
 
 static const char parse_xdigits[] = "0123456789ABCDEF";
 
-static size_t parse_mb(struct parse_state *state, parse_mb_what_t what, const char *ptr, const char *end, const char *begin, zend_bool force_silent)
+static inline size_t parse_mb(struct parse_state *state, parse_mb_what_t what, const char *ptr, const char *end, const char *begin, zend_bool force_silent)
 {
        unsigned wchar;
        size_t consumed = 0;
@@ -742,7 +743,11 @@ static size_t parse_mb(struct parse_state *state, parse_mb_what_t what, const ch
                        if (what == PARSE_HOSTINFO && (state->flags & PHP_HTTP_URL_PARSE_TOIDN)) {
                                /* idna */
                        } else if (state->flags & PHP_HTTP_URL_PARSE_MBUTF8) {
+#if PHP_HTTP_HAVE_LIBICU
+                               if (!u_isalnum(wchar)) {
+#else
                                if (!isualnum(wchar)) {
+#endif
                                        break;
                                }
 #if PHP_HTTP_HAVE_WCHAR
@@ -752,16 +757,17 @@ static size_t parse_mb(struct parse_state *state, parse_mb_what_t what, const ch
                                }
 #endif
                        }
-                       PHP_HTTP_DUFF(consumed, state->buffer[state->offset++] = *ptr++);
+
+                       memcpy(&state->buffer[state->offset], ptr, consumed);
+                       state->offset += consumed;
                } else {
-                       int i = 0;
-
-                       PHP_HTTP_DUFF(consumed,
-                                       state->buffer[state->offset++] = '%';
-                                       state->buffer[state->offset++] = parse_xdigits[((unsigned char) ptr[i]) >> 4];
-                                       state->buffer[state->offset++] = parse_xdigits[((unsigned char) ptr[i]) & 0xf];
-                                       ++i;
-                       );
+                       size_t i;
+
+                       for (i = 0; i < consumed; ++i) {
+                               state->buffer[state->offset++] = '%';
+                               state->buffer[state->offset++] = parse_xdigits[((unsigned char) ptr[i]) >> 4];
+                               state->buffer[state->offset++] = parse_xdigits[((unsigned char) ptr[i]) & 0xf];
+                       }
                }
 
                return consumed;
@@ -982,10 +988,10 @@ typedef uint16_t UChar;
 typedef enum { U_ZERO_ERROR = 0 } UErrorCode;
 int32_t uidna_IDNToASCII(const UChar *src, int32_t srcLength, UChar *dest, int32_t destCapacity, int32_t options, void *parseError, UErrorCode *status);
 #      endif
-static ZEND_RESULT_CODE parse_uidn_2003(struct parse_state *state)
+static ZEND_RESULT_CODE parse_uidn_2003(struct parse_state *state, size_t prev_len)
 {
-       char *host_ptr = state->url.host, ebuf[64] = {0}, *error = NULL;
-       uint16_t *uhost_str, ahost_str[256], *ahost_ptr;
+       char ebuf[64] = {0}, *error = NULL;
+       uint16_t *uhost_str, ahost_str[256];
        size_t uhost_len, ahost_len;
        UErrorCode rc = U_ZERO_ERROR;
 
@@ -1019,10 +1025,11 @@ static ZEND_RESULT_CODE parse_uidn_2003(struct parse_state *state)
                goto error;
        }
 
-       ahost_ptr = ahost_str;
-       PHP_HTTP_DUFF(ahost_len, *host_ptr++ = *ahost_ptr++);
-       *host_ptr = '\0';
-       state->offset += host_ptr - state->url.host;
+       state->url.host[ahost_len] = '\0';
+       state->offset += ahost_len - prev_len;
+       while (ahost_len--) {
+               state->url.host[ahost_len] = ahost_str[ahost_len];
+       }
 
        return SUCCESS;
 
@@ -1038,9 +1045,9 @@ static ZEND_RESULT_CODE parse_uidn_2003(struct parse_state *state)
 #endif
 
 #if PHP_HTTP_HAVE_LIBICU && HAVE_UIDNA_NAMETOASCII_UTF8
-static ZEND_RESULT_CODE parse_uidn_2008(struct parse_state *state)
+static ZEND_RESULT_CODE parse_uidn_2008(struct parse_state *state, size_t prev_len)
 {
-       char *host_ptr, *error = NULL, ebuf[64] = {0};
+       char *error = NULL, ebuf[64] = {0};
        UErrorCode rc = U_ZERO_ERROR;
        UIDNAInfo info = UIDNA_INFO_INITIALIZER;
        UIDNA *uidna = uidna_openUTS46(UIDNA_ALLOW_UNASSIGNED, &rc);
@@ -1049,42 +1056,46 @@ static ZEND_RESULT_CODE parse_uidn_2008(struct parse_state *state)
                return FAILURE;
        }
 
-       host_ptr = state->url.host;
-
        if (state->flags & PHP_HTTP_URL_PARSE_MBUTF8) {
-               char ahost_str[256], *ahost_ptr = &ahost_str[0];
-               size_t ahost_len = uidna_nameToASCII_UTF8(uidna, host_ptr, -1, ahost_str, sizeof(ahost_str)-1, &info, &rc);
+               char ahost_str[256];
+               size_t ahost_len = uidna_nameToASCII_UTF8(uidna, state->url.host, -1, ahost_str, sizeof(ahost_str)-1, &info, &rc);
 
                if (U_FAILURE(rc) || info.errors) {
                        goto error;
                }
-               PHP_HTTP_DUFF(ahost_len, *host_ptr++ = *ahost_ptr++);
+
+               memcpy(state->url.host, ahost_str, ahost_len);
+               state->url.host[ahost_len] = '\0';
+               state->offset += ahost_len - prev_len;
+
 #if PHP_HTTP_HAVE_WCHAR
        } else if (state->flags & PHP_HTTP_URL_PARSE_MBLOC) {
-               uint16_t *uhost_str, whost_str[256], *whost_ptr = &whost_str[0];
+               uint16_t *uhost_str, whost_str[256];
                size_t uhost_len, whost_len;
 
-               if (SUCCESS != to_utf16(parse_mb_loc, host_ptr, &uhost_str, &uhost_len)) {
+               if (SUCCESS != to_utf16(parse_mb_loc, state->url.host, &uhost_str, &uhost_len)) {
                        error = "could not convert to UTF-16";
                        goto error;
                }
 
                whost_len = uidna_nameToASCII(uidna, uhost_str, uhost_len, whost_str, sizeof(whost_str)-1, &info, &rc);
-               whost_ptr = whost_str;
                efree(uhost_str);
+
                if (U_FAILURE(rc) || info.errors) {
                        goto error;
                }
-               PHP_HTTP_DUFF(whost_len, *host_ptr++ = *whost_ptr++);
+
+               state->url.host[whost_len] = '\0';
+               state->offset += whost_len - prev_len;
+               while (whost_len--) {
+                       state->url.host[whost_len] = whost_str[whost_len];
+               }
 #endif
        } else {
                error = "codepage not specified";
                goto error;
        }
 
-       *host_ptr = '\0';
-       state->offset += host_ptr - state->url.host;
-
        uidna_close(uidna);
        return SUCCESS;
 
@@ -1111,7 +1122,7 @@ static ZEND_RESULT_CODE parse_uidn_2008(struct parse_state *state)
 #      if __GNUC__
 __attribute__ ((unused))
 #      endif
-static ZEND_RESULT_CODE parse_kidn(struct parse_state *state)
+static ZEND_RESULT_CODE parse_kidn(struct parse_state *state, size_t prev_len)
 {
        idn_result_t rc;
 #if PHP_HTTP_HAVE_LIBIDNKIT
@@ -1119,7 +1130,7 @@ static ZEND_RESULT_CODE parse_kidn(struct parse_state *state)
 #elif PHP_HTTP_HAVE_LIBIDNKIT2
        int actions = IDN_MAP|IDN_ASCLOWER|IDN_RTCONV|IDN_PROHCHECK|IDN_NFCCHECK|IDN_PREFCHECK|IDN_COMBCHECK|IDN_CTXOLITECHECK|IDN_BIDICHECK|IDN_LOCALCHECK|IDN_IDNCONV|IDN_LENCHECK|IDN_RTCHECK;
 #endif
-       char ahost_str[256] = {0}, *ahost_ptr = &ahost_str[0], *host_ptr = state->url.host;
+       char ahost_str[256] = {0};
 
        if (state->flags & PHP_HTTP_URL_PARSE_MBLOC) {
 #if PHP_HTTP_HAVE_LIBIDNKIT
@@ -1131,10 +1142,10 @@ static ZEND_RESULT_CODE parse_kidn(struct parse_state *state)
 
        rc = idn_encodename(actions, state->url.host, ahost_str, 256);
        if (rc == idn_success) {
-               PHP_HTTP_DUFF(strlen(ahost_str), *host_ptr++ = *ahost_ptr++);
+               size_t ahost_len = strlen(ahost_str);
 
-               *host_ptr = '\0';
-               state->offset += host_ptr - state->url.host;
+               memcpy(state->url.host, ahost_str, ahost_len + 1);
+               state->offset += ahost_len - prev_len;
 
                return SUCCESS;
        } else {
@@ -1145,11 +1156,11 @@ static ZEND_RESULT_CODE parse_kidn(struct parse_state *state)
 #endif
 
 #if 0 && PHP_WIN32
-static ZEND_RESULT_CODE parse_widn_2003(struct parse_state *state)
+static ZEND_RESULT_CODE parse_widn_2003(struct parse_state *state, size_t prev_len)
 {
        char *host_ptr;
-       uint16_t *uhost_str, ahost_str[256], *ahost_ptr;
-       size_t uhost_len;
+       uint16_t *uhost_str, ahost_str[256];
+       size_t uhost_len, ahost_len;
 
        if (state->flags & PHP_HTTP_URL_PARSE_MBUTF8) {
                if (SUCCESS != to_utf16(parse_mb_utf8, state->url.host, &uhost_str, &uhost_len)) {
@@ -1175,12 +1186,12 @@ static ZEND_RESULT_CODE parse_widn_2003(struct parse_state *state)
        }
 
        efree(uhost_str);
-       host_ptr = state->url.host;
-       ahost_ptr = ahost_str;
-       PHP_HTTP_DUFF(wcslen(ahost_str), *host_ptr++ = *ahost_ptr++);
-
-       *host_ptr = '\0';
-       state->offset += host_ptr - state->url.host;
+       ahost_len = wcslen(ahost_str);
+       state->url.host[ahost_len] = '\0';
+       state->offset += ahost_len - prev_len;
+       while (ahost_len--) {
+               state->url.host[ahost_len] = ahost_str[ahost_len];
+       }
 
        return SUCCESS;
 }
@@ -1195,11 +1206,11 @@ static ZEND_RESULT_CODE parse_idna(struct parse_state *state, size_t len)
 #      endif
        ) {
 #if PHP_HTTP_HAVE_LIBICU && HAVE_UIDNA_NAMETOASCII_UTF8
-               return parse_uidn_2008(state);
+               return parse_uidn_2008(state, len);
 #elif PHP_HTTP_HAVE_LIBIDN2
                return parse_gidn_2008(state, len);
 #elif PHP_HTTP_HAVE_LIBIDNKIT2
-               return parse_kidn(state);
+               return parse_kidn(state, len);
 #endif
        }
 #endif
@@ -1211,31 +1222,31 @@ static ZEND_RESULT_CODE parse_idna(struct parse_state *state, size_t len)
 #endif
        ) {
 #if HAVE_UIDNA_IDNTOASCII
-               return parse_uidn_2003(state);
+               return parse_uidn_2003(state, len);
 #elif PHP_HTTP_HAVE_LIBIDN
                return parse_gidn_2003(state, len);
 #elif PHP_HTTP_HAVE_LIBIDNKIT
-               return parse_kidn(state);
+               return parse_kidn(state, len);
 #endif
        }
 #endif
 
 #if 0 && PHP_WIN32
-       return parse_widn_2003(state);
+       return parse_widn_2003(state, len);
 #endif
 
 #if PHP_HTTP_HAVE_LIBICU && HAVE_UIDNA_NAMETOASCII_UTF8
-               return parse_uidn_2008(state);
+               return parse_uidn_2008(state, len);
 #elif PHP_HTTP_HAVE_LIBIDN2
                return parse_gidn_2008(state, len);
 #elif PHP_HTTP_HAVE_LIBIDNKIT2
-               return parse_kidn(state);
+               return parse_kidn(state, len);
 #elif HAVE_UIDNA_IDNTOASCII
-               return parse_uidn_2003(state);
+               return parse_uidn_2003(state, len);
 #elif PHP_HTTP_HAVE_LIBIDN
                return parse_gidn_2003(state, len);
 #elif PHP_HTTP_HAVE_LIBIDNKIT
-               return parse_kidn(state);
+               return parse_kidn(state, len);
 #endif
 
        return SUCCESS;
@@ -1810,7 +1821,9 @@ php_http_url_t *php_http_url_parse(const char *str, size_t len, unsigned flags)
        state->maxlen = maxlen;
 
        if (!parse_scheme(state)) {
-               php_error_docref(NULL, E_WARNING, "Failed to parse URL scheme: '%s'", state->ptr);
+               if (!(flags & PHP_HTTP_URL_SILENT_ERRORS)) {
+                       php_error_docref(NULL, E_WARNING, "Failed to parse URL scheme: '%s'", state->ptr);
+               }
                efree(state);
                return NULL;
        }
@@ -1821,13 +1834,17 @@ php_http_url_t *php_http_url_parse(const char *str, size_t len, unsigned flags)
        }
 
        if (!parse_query(state)) {
-               php_error_docref(NULL, E_WARNING, "Failed to parse URL query: '%s'", state->ptr);
+               if (!(flags & PHP_HTTP_URL_SILENT_ERRORS)) {
+                       php_error_docref(NULL, E_WARNING, "Failed to parse URL query: '%s'", state->ptr);
+               }
                efree(state);
                return NULL;
        }
 
        if (!parse_fragment(state)) {
-               php_error_docref(NULL, E_WARNING, "Failed to parse URL fragment: '%s'", state->ptr);
+               if (!(flags & PHP_HTTP_URL_SILENT_ERRORS)) {
+                       php_error_docref(NULL, E_WARNING, "Failed to parse URL fragment: '%s'", state->ptr);
+               }
                efree(state);
                return NULL;
        }
@@ -1896,9 +1913,7 @@ PHP_METHOD(HttpUrl, __construct)
                flags |= PHP_HTTP_URL_FROM_ENV;
        }
 
-       if (flags & PHP_HTTP_URL_SILENT_ERRORS) {
-               zend_replace_error_handling(EH_SUPPRESS, NULL, &zeh);
-       } else if (flags & PHP_HTTP_URL_IGNORE_ERRORS) {
+       if (flags & (PHP_HTTP_URL_SILENT_ERRORS|PHP_HTTP_URL_IGNORE_ERRORS)) {
                zend_replace_error_handling(EH_NORMAL, NULL, &zeh);
        } else {
                zend_replace_error_handling(EH_THROW, php_http_get_exception_bad_url_class_entry(), &zeh);
@@ -1950,9 +1965,7 @@ PHP_METHOD(HttpUrl, mod)
 
        php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "z!|l", &new_url, &flags), invalid_arg, return);
 
-       if (flags & PHP_HTTP_URL_SILENT_ERRORS) {
-               zend_replace_error_handling(EH_SUPPRESS, NULL, &zeh);
-       } else if (flags & PHP_HTTP_URL_IGNORE_ERRORS) {
+       if (flags & (PHP_HTTP_URL_SILENT_ERRORS|PHP_HTTP_URL_IGNORE_ERRORS)) {
                zend_replace_error_handling(EH_NORMAL, NULL, &zeh);
        } else {
                zend_replace_error_handling(EH_THROW, php_http_get_exception_bad_url_class_entry(), &zeh);
@@ -2022,7 +2035,7 @@ PHP_METHOD(HttpUrl, toArray)
 }
 
 static zend_function_entry php_http_url_methods[] = {
-       PHP_ME(HttpUrl, __construct,  ai_HttpUrl___construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
+       PHP_ME(HttpUrl, __construct,  ai_HttpUrl___construct, ZEND_ACC_PUBLIC)
        PHP_ME(HttpUrl, mod,          ai_HttpUrl_mod, ZEND_ACC_PUBLIC)
        PHP_ME(HttpUrl, toString,     ai_HttpUrl_toString, ZEND_ACC_PUBLIC)
        ZEND_MALIAS(HttpUrl, __toString, toString, ai_HttpUrl_toString, ZEND_ACC_PUBLIC)
index f9008032dff0eea98abc8c59cb1134b35ab3b7c3..82a58d105d02aaf515131fe9e6ea112b296c2440 100644 (file)
 #ifndef PHP_HTTP_UTF8_H
 #define PHP_HTTP_UTF8_H
 
-typedef struct utf8_range {
-       unsigned int start;
-       unsigned int end;
-       unsigned char step;
-} utf8_range_t;
-
 static const unsigned char utf8_mblen[256] = {
     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
@@ -42,515 +36,234 @@ static const unsigned char utf8_mask[] = {
                0, 0x7f, 0x1f, 0x0f, 0x07, 0x03, 0x01
 };
 
-static const utf8_range_t utf8_ranges[] = {
+typedef struct utf8_range {
+       const unsigned int start;
+       const unsigned int end;
+} utf8_range_t;
+
 /* BEGIN::UTF8TABLE */
-       {    0x0041,     0x005A, 1},
-       {    0x0061,     0x007A, 1},
-       {    0x00AA,          0, 0},
-       {    0x00B5,          0, 0},
-       {    0x00BA,          0, 0},
-       {    0x00C0,     0x00D6, 1},
-       {    0x00D8,     0x00F6, 1},
-       {    0x00F8,     0x00FF, 1},
-       {    0x0100,     0x017F, 1},
-       {    0x0180,     0x024F, 1},
-       {    0x0250,     0x02AF, 1},
-       {    0x02B0,     0x02C1, 1},
-       {    0x02C6,     0x02D1, 1},
-       {    0x02E0,     0x02E4, 1},
-       {    0x02EE,          0, 0},
-       {    0x0345,          0, 0},
-       {    0x0370,     0x0373, 1},
-       {    0x0376,     0x0377, 1},
-       {    0x037A,     0x037D, 1},
-       {    0x0386,          0, 0},
-       {    0x0388,     0x038A, 1},
-       {    0x038C,          0, 0},
-       {    0x038E,     0x03A1, 1},
-       {    0x03A3,     0x03CE, 1},
-       {    0x03D0,     0x03F5, 1},
-       {    0x03F7,     0x03FF, 1},
-       {    0x0400,     0x0481, 1},
-       {    0x048A,     0x04FF, 1},
-       {    0x0500,     0x0523, 1},
-       {    0x0531,     0x0556, 1},
-       {    0x0559,          0, 0},
-       {    0x0561,     0x0587, 1},
-       {    0x05D0,     0x05EA, 1},
-       {    0x05F0,     0x05F2, 1},
-       {    0x0621,     0x064A, 1},
-       {    0x066E,     0x066F, 1},
-       {    0x0671,     0x06D3, 1},
-       {    0x06D5,          0, 0},
-       {    0x06E5,     0x06E6, 1},
-       {    0x06EE,     0x06EF, 1},
-       {    0x06FA,     0x06FC, 1},
-       {    0x06FF,          0, 0},
-       {    0x0710,          0, 0},
-       {    0x0712,     0x072F, 1},
-       {    0x074D,     0x074F, 1},
-       {    0x0750,     0x077F, 1},
-       {    0x0780,     0x07A5, 1},
-       {    0x07B1,          0, 0},
-       {    0x07C0,     0x07EA, 1},
-       {    0x07F4,     0x07F5, 1},
-       {    0x07FA,          0, 0},
-       {    0x0901,     0x0939, 1},
-       {    0x093C,     0x094D, 1},
-       {    0x0950,     0x0954, 1},
-       {    0x0958,     0x0961, 1},
-       {    0x0962,          0, 0},
-       {    0x0963,          0, 0},
-       {    0x0972,          0, 0},
-       {    0x097B,     0x097F, 1},
-       {    0x0981,     0x0983, 1},
-       {    0x0985,     0x098C, 1},
-       {    0x098F,          0, 0},
-       {    0x0990,          0, 0},
-       {    0x0993,     0x09A8, 1},
-       {    0x09AA,     0x09B0, 1},
-       {    0x09B2,          0, 0},
-       {    0x09B6,     0x09B9, 1},
-       {    0x09BC,     0x09C4, 1},
-       {    0x09C7,          0, 0},
-       {    0x09C8,          0, 0},
-       {    0x09CB,     0x09CE, 1},
-       {    0x09D7,          0, 0},
-       {    0x09DC,          0, 0},
-       {    0x09DD,          0, 0},
-       {    0x09DF,     0x09E3, 1},
-       {    0x09F0,     0x09FA, 1},
-       {    0x0A01,     0x0A03, 1},
-       {    0x0A05,     0x0A0A, 1},
-       {    0x0A0F,          0, 0},
-       {    0x0A10,          0, 0},
-       {    0x0A13,     0x0A28, 1},
-       {    0x0A2A,     0x0A30, 1},
-       {    0x0A32,          0, 0},
-       {    0x0A33,          0, 0},
-       {    0x0A35,          0, 0},
-       {    0x0A36,          0, 0},
-       {    0x0A38,          0, 0},
-       {    0x0A39,          0, 0},
-       {    0x0A3C,          0, 0},
-       {    0x0A3E,     0x0A42, 1},
-       {    0x0A47,          0, 0},
-       {    0x0A48,          0, 0},
-       {    0x0A4B,     0x0A4D, 1},
-       {    0x0A51,          0, 0},
-       {    0x0A59,     0x0A5C, 1},
-       {    0x0A5E,          0, 0},
-       {    0x0A70,     0x0A75, 1},
-       {    0x0A81,     0x0A83, 1},
-       {    0x0A85,     0x0A8D, 1},
-       {    0x0A8F,     0x0A91, 1},
-       {    0x0A93,     0x0AA8, 1},
-       {    0x0AAA,     0x0AB0, 1},
-       {    0x0AB2,          0, 0},
-       {    0x0AB3,          0, 0},
-       {    0x0AB5,     0x0AB9, 1},
-       {    0x0ABC,     0x0AC5, 1},
-       {    0x0AC7,     0x0AC9, 1},
-       {    0x0ACB,     0x0ACD, 1},
-       {    0x0AD0,          0, 0},
-       {    0x0AE0,     0x0AE3, 1},
-       {    0x0AF1,          0, 0},
-       {    0x0B01,     0x0B03, 1},
-       {    0x0B05,     0x0B0C, 1},
-       {    0x0B0F,          0, 0},
-       {    0x0B10,          0, 0},
-       {    0x0B13,     0x0B28, 1},
-       {    0x0B2A,     0x0B30, 1},
-       {    0x0B32,          0, 0},
-       {    0x0B33,          0, 0},
-       {    0x0B35,     0x0B39, 1},
-       {    0x0B3C,     0x0B44, 1},
-       {    0x0B47,     0x0B48, 1},
-       {    0x0B4B,     0x0B4D, 1},
-       {    0x0B56,     0x0B57, 1},
-       {    0x0B5C,          0, 0},
-       {    0x0B5D,          0, 0},
-       {    0x0B5F,     0x0B63, 1},
-       {    0x0B70,          0, 0},
-       {    0x0B71,          0, 0},
-       {    0x0B82,          0, 0},
-       {    0x0B83,          0, 0},
-       {    0x0B85,     0x0B8A, 1},
-       {    0x0B8E,     0x0B90, 1},
-       {    0x0B92,     0x0B95, 1},
-       {    0x0B99,          0, 0},
-       {    0x0B9A,          0, 0},
-       {    0x0B9C,          0, 0},
-       {    0x0B9E,          0, 0},
-       {    0x0B9F,          0, 0},
-       {    0x0BA3,          0, 0},
-       {    0x0BA4,          0, 0},
-       {    0x0BA8,     0x0BAA, 1},
-       {    0x0BAE,     0x0BB9, 1},
-       {    0x0BBE,     0x0BC2, 1},
-       {    0x0BC6,     0x0BC8, 1},
-       {    0x0BCA,     0x0BCD, 1},
-       {    0x0BD0,          0, 0},
-       {    0x0BD7,          0, 0},
-       {    0x0BF0,     0x0BFA, 1},
-       {    0x0C01,     0x0C03, 1},
-       {    0x0C05,     0x0C0C, 1},
-       {    0x0C0E,     0x0C10, 1},
-       {    0x0C12,     0x0C28, 1},
-       {    0x0C2A,     0x0C33, 1},
-       {    0x0C35,     0x0C39, 1},
-       {    0x0C3D,     0x0C44, 1},
-       {    0x0C46,     0x0C48, 1},
-       {    0x0C4A,     0x0C4D, 1},
-       {    0x0C55,     0x0C56, 1},
-       {    0x0C58,     0x0C59, 1},
-       {    0x0C60,     0x0C63, 1},
-       {    0x0C82,     0x0C83, 1},
-       {    0x0C85,     0x0C8C, 1},
-       {    0x0C8E,     0x0C90, 1},
-       {    0x0C92,     0x0CA8, 1},
-       {    0x0CAA,     0x0CB3, 1},
-       {    0x0CB5,     0x0CB9, 1},
-       {    0x0CBC,     0x0CC4, 1},
-       {    0x0CC6,     0x0CC8, 1},
-       {    0x0CCA,     0x0CCD, 1},
-       {    0x0CD5,     0x0CD6, 1},
-       {    0x0CDE,          0, 0},
-       {    0x0CE0,     0x0CE3, 1},
-       {    0x0CF1,          0, 0},
-       {    0x0CF2,          0, 0},
-       {    0x0D02,     0x0D03, 1},
-       {    0x0D05,     0x0D0C, 1},
-       {    0x0D0E,     0x0D10, 1},
-       {    0x0D12,     0x0D28, 1},
-       {    0x0D2A,     0x0D39, 1},
-       {    0x0D3D,     0x0D44, 1},
-       {    0x0D46,     0x0D48, 1},
-       {    0x0D4A,     0x0D4D, 1},
-       {    0x0D57,          0, 0},
-       {    0x0D60,     0x0D63, 1},
-       {    0x0D79,     0x0D7F, 1},
-       {    0x0D82,     0x0D83, 1},
-       {    0x0D85,     0x0D96, 1},
-       {    0x0D9A,     0x0DB1, 1},
-       {    0x0DB3,     0x0DBB, 1},
-       {    0x0DBD,          0, 0},
-       {    0x0DC0,     0x0DC6, 1},
-       {    0x0DCA,          0, 0},
-       {    0x0DCF,     0x0DD4, 1},
-       {    0x0DD6,          0, 0},
-       {    0x0DD8,     0x0DDF, 1},
-       {    0x0DF2,     0x0DF4, 1},
-       {    0x0E01,     0x0E2E, 1},
-       {    0x0E30,     0x0E3A, 1},
-       {    0x0E40,     0x0E45, 1},
-       {    0x0E47,     0x0E4E, 1},
-       {    0x0E81,     0x0E82, 1},
-       {    0x0E84,          0, 0},
-       {    0x0E87,     0x0E88, 1},
-       {    0x0E8A,          0, 0},
-       {    0x0E8D,          0, 0},
-       {    0x0E94,     0x0E97, 1},
-       {    0x0E99,     0x0E9F, 1},
-       {    0x0EA1,     0x0EA3, 1},
-       {    0x0EA5,          0, 0},
-       {    0x0EA7,          0, 0},
-       {    0x0EAA,     0x0EAB, 1},
-       {    0x0EAD,     0x0EB0, 1},
-       {    0x0EB2,     0x0EB3, 1},
-       {    0x0EBD,          0, 0},
-       {    0x0EC0,     0x0EC4, 1},
-       {    0x0EC6,          0, 0},
-       {    0x0EDC,     0x0EDD, 1},
-       {    0x0F00,          0, 0},
-       {    0x0F40,     0x0F47, 1},
-       {    0x0F49,     0x0F6C, 1},
-       {    0x0F88,     0x0F8B, 1},
-       {    0x1000,     0x102A, 1},
-       {    0x1050,     0x1055, 1},
-       {    0x105A,     0x105D, 1},
-       {    0x1061,          0, 0},
-       {    0x0165,          0, 0},
-       {    0x1066,          0, 0},
-       {    0x106E,     0x1070, 1},
-       {    0x1075,     0x1081, 1},
-       {    0x108E,          0, 0},
-       {    0x10A0,     0x10C5, 1},
-       {    0x10D0,     0x10FA, 1},
-       {    0x10FC,          0, 0},
-       {    0x1100,     0x1159, 1},
-       {    0x115F,     0x11A2, 1},
-       {    0x11A8,     0x11F9, 1},
-       {    0x1200,     0x1248, 1},
-       {    0x124A,     0x124D, 1},
-       {    0x1250,     0x1256, 1},
-       {    0x1258,          0, 0},
-       {    0x125A,     0x125D, 1},
-       {    0x1260,     0x1288, 1},
-       {    0x128A,     0x128D, 1},
-       {    0x1290,     0x12B0, 1},
-       {    0x12B2,     0x12B5, 1},
-       {    0x12B8,     0x12BE, 1},
-       {    0x12C0,          0, 0},
-       {    0x12C2,     0x12C5, 1},
-       {    0x12C8,     0x12D6, 1},
-       {    0x12D8,     0x1310, 1},
-       {    0x1312,     0x1315, 1},
-       {    0x1318,     0x135A, 1},
-       {    0x1380,     0x138F, 1},
-       {    0x13A0,     0x13F4, 1},
-       {    0x1401,     0x166C, 1},
-       {    0x166F,     0x1676, 1},
-       {    0x1681,     0x169A, 1},
-       {    0x16A0,     0x16EA, 1},
-       {    0x16EE,     0x16F0, 1},
-       {    0x1700,     0x170C, 1},
-       {    0x170E,     0x1711, 1},
-       {    0x1720,     0x1731, 1},
-       {    0x1740,     0x1751, 1},
-       {    0x1760,     0x176C, 1},
-       {    0x176E,     0x1770, 1},
-       {    0x1780,     0x17B3, 1},
-       {    0x17D7,          0, 0},
-       {    0x17DC,          0, 0},
-       {    0x1820,     0x1877, 1},
-       {    0x1880,     0x18A8, 1},
-       {    0x18AA,          0, 0},
-       {    0x1900,     0x191C, 1},
-       {    0x1946,     0x194F, 1},
-       {    0x1950,     0x196D, 1},
-       {    0x1970,     0x1974, 1},
-       {    0x1980,     0x19A9, 1},
-       {    0x19C1,     0x19C7, 1},
-       {    0x19D0,     0x19D9, 1},
-       {    0x1A00,     0x1A16, 1},
-       {    0x1B05,     0x1B33, 1},
-       {    0x1B45,     0x1B4B, 1},
-       {    0x1B50,     0x1B59, 1},
-       {    0x1B83,     0x1BA0, 1},
-       {    0x1BAE,     0x1BAF, 1},
-       {    0x1C00,     0x1C23, 1},
-       {    0x1C4D,     0x1C4F, 1},
-       {    0x1C5A,     0x1C7D, 1},
-       {    0x1D00,     0x1DBF, 1},
-       {    0x1E00,     0x1E9F, 1},
-       {    0x1EA0,     0x1EFF, 1},
-       {    0x1F00,     0x1F15, 1},
-       {    0x1F18,     0x1F1D, 1},
-       {    0x1F20,     0x1F45, 1},
-       {    0x1F48,     0x1F4D, 1},
-       {    0x1F50,     0x1F57, 1},
-       {    0x1F59,          0, 0},
-       {    0x1F5B,          0, 0},
-       {    0x1F5D,          0, 0},
-       {    0x1F5F,     0x1F7D, 1},
-       {    0x1F80,     0x1FB4, 1},
-       {    0x1FB6,     0x1FBC, 1},
-       {    0x1FBE,          0, 0},
-       {    0x1FC2,     0x1FC4, 1},
-       {    0x1FC6,     0x1FCC, 1},
-       {    0x1FD0,     0x1FD3, 1},
-       {    0x1FD6,     0x1FDB, 1},
-       {    0x1FE0,     0x1FEC, 1},
-       {    0x1FF2,     0x1FF4, 1},
-       {    0x1FF6,     0x1FFC, 1},
-       {    0x2071,          0, 0},
-       {    0x207F,          0, 0},
-       {    0x2090,     0x2094, 1},
-       {    0x2102,          0, 0},
-       {    0x2107,          0, 0},
-       {    0x210A,     0x2113, 1},
-       {    0x2115,          0, 0},
-       {    0x2119,     0x211D, 1},
-       {    0x2124,          0, 0},
-       {    0x2126,          0, 0},
-       {    0x2128,     0x212D, 1},
-       {    0x212F,     0x2139, 1},
-       {    0x213C,     0x213F, 1},
-       {    0x2145,     0x2149, 1},
-       {    0x214E,          0, 0},
-       {    0x2160,     0x2188, 1},
-       {    0x249C,     0x24E9, 1},
-       {    0x2C00,     0x2C2E, 1},
-       {    0x2C30,     0x2C5E, 1},
-       {    0x2C60,     0x2C6F, 1},
-       {    0x2C71,     0x2C7D, 1},
-       {    0x2C80,     0x2CE4, 1},
-       {    0x2D00,     0x2D25, 1},
-       {    0x2D30,     0x2D65, 1},
-       {    0x2D6F,          0, 0},
-       {    0x2D80,     0x2D96, 1},
-       {    0x2DA0,     0x2DA6, 1},
-       {    0x2DA8,     0x2DAE, 1},
-       {    0x2DB0,     0x2DB6, 1},
-       {    0x2DB8,     0x2DBE, 1},
-       {    0x2DC0,     0x2DC6, 1},
-       {    0x2DC8,     0x2DCE, 1},
-       {    0x2DD0,     0x2DD6, 1},
-       {    0x2DD8,     0x2DDE, 1},
-       {    0x3005,     0x3007, 1},
-       {    0x3021,     0x3029, 1},
-       {    0x3031,     0x3035, 1},
-       {    0x3038,     0x303C, 1},
-       {    0x3041,     0x3096, 1},
-       {    0x309D,     0x309F, 1},
-       {    0x30A1,     0x30FA, 1},
-       {    0x30FC,     0x30FF, 1},
-       {    0x3105,     0x312D, 1},
-       {    0x3131,     0x318E, 1},
-       {    0x31A0,     0x31B7, 1},
-       {    0x31F0,     0x31FF, 1},
-       {    0x3400,     0x4DB5, 1},
-       {    0x4E00,     0x9FBB, 1},
-       {    0xA000,     0xA48C, 1},
-       {    0xA500,     0xA60B, 1},
-       {    0xA610,     0xA61F, 1},
-       {    0xA62A,     0xA62B, 1},
-       {    0xA640,     0xA65F, 1},
-       {    0xA662,     0xA66E, 1},
-       {    0xA680,     0xA697, 1},
-       {    0xA717,     0xA71F, 1},
-       {    0xA722,     0xA78C, 1},
-       {    0xA7FB,     0xA7FF, 1},
-       {    0xA800,          0, 0},
-       {    0xA801,          0, 0},
-       {    0xA803,     0xA805, 1},
-       {    0xA807,     0xA80A, 1},
-       {    0xA80C,     0xA822, 1},
-       {    0xA840,     0xA873, 1},
-       {    0xA882,     0xA8B3, 1},
-       {    0xA90A,     0xA92D, 1},
-       {    0xA930,     0xA946, 1},
-       {    0xAA00,     0xAA28, 1},
-       {    0xAA40,     0xAA42, 1},
-       {    0xAA44,     0xAA4B, 1},
-       {    0xAC00,     0xD7A3, 1},
-       {    0xF900,     0xFA2D, 1},
-       {    0xFA30,     0xFA6A, 1},
-       {    0xFA70,     0xFAD9, 1},
-       {    0xFB00,     0xFB06, 1},
-       {    0xFB13,     0xFB17, 1},
-       {    0xFB1D,          0, 0},
-       {    0xFB1F,     0xFB28, 1},
-       {    0xFB2A,     0xFB36, 1},
-       {    0xFB38,     0xFB3C, 1},
-       {    0xFB3E,          0, 0},
-       {    0xFB40,          0, 0},
-       {    0xFB41,          0, 0},
-       {    0xFB43,          0, 0},
-       {    0xFB44,          0, 0},
-       {    0xFB46,     0xFB4F, 1},
-       {    0xFB50,     0xFBB1, 1},
-       {    0xFBD3,     0xFD3D, 1},
-       {    0xFD50,     0xFD8F, 1},
-       {    0xFD92,     0xFDC7, 1},
-       {    0xFDF0,     0xFDFB, 1},
-       {    0xFE70,     0xFE74, 1},
-       {    0xFE76,     0xFEFC, 1},
-       {    0xFF21,     0xFF3A, 1},
-       {    0xFF41,     0xFF5A, 1},
-       {    0xFF66,     0xFFBE, 1},
-       {    0xFFC2,     0xFFC7, 1},
-       {    0xFFCA,     0xFFCF, 1},
-       {    0xFFD2,     0xFFD7, 1},
-       {    0xFFDA,     0xFFDC, 1},
-       {0x00010000, 0x0001000B, 1},
-       {0x0001000D, 0x00010026, 1},
-       {0x00010028, 0x0001003A, 1},
-       {0x0001003C, 0x0001003D, 1},
-       {0x0001003F, 0x0001004D, 1},
-       {0x00010050, 0x0001005D, 1},
-       {0x00010080, 0x000100FA, 1},
-       {0x00010140, 0x00010174, 1},
-       {0x00010280, 0x0001029C, 1},
-       {0x000102A0, 0x000102D0, 1},
-       {0x00010300, 0x0001031E, 1},
-       {0x00010330, 0x0001034A, 1},
-       {0x00010380, 0x0001039D, 1},
-       {0x000103A0, 0x000103C3, 1},
-       {0x000103C8, 0x000103CF, 1},
-       {0x000103D1, 0x000103D5, 1},
-       {0x00010400, 0x0001044F, 1},
-       {0x00010450, 0x0001047F, 1},
-       {0x00010480, 0x0001049D, 1},
-       {0x000104A0, 0x000104A9, 1},
-       {0x00010800, 0x00010805, 1},
-       {0x00010808,          0, 0},
-       {0x0001080A, 0x00010835, 1},
-       {0x00010837, 0x00010838, 1},
-       {0x0001083C,          0, 0},
-       {0x0001083F,          0, 0},
-       {0x00010900, 0x00010915, 1},
-       {0x00010A00,          0, 0},
-       {0x00010A10, 0x00010A13, 1},
-       {0x00010A15, 0x00010A17, 1},
-       {0x00010A19, 0x00010A33, 1},
-       {0x00012000, 0x0001236E, 1},
-       {0x00012400, 0x00012462, 1},
-       {0x0001D400, 0x0001D454, 1},
-       {0x0001D456, 0x0001D49C, 1},
-       {0x0001D49E, 0x0001D49F, 1},
-       {0x0001D4A2,          0, 0},
-       {0x0001D4A5, 0x0001D4A6, 1},
-       {0x0001D4A9, 0x0001D4AC, 1},
-       {0x0001D4AE, 0x0001D4B9, 1},
-       {0x0001D4BB,          0, 0},
-       {0x0001D4BD, 0x0001D4C3, 1},
-       {0x0001D4C5, 0x0001D505, 1},
-       {0x0001D507, 0x0001D50A, 1},
-       {0x0001D50D, 0x0001D514, 1},
-       {0x0001D516, 0x0001D51C, 1},
-       {0x0001D51E, 0x0001D539, 1},
-       {0x0001D53B, 0x0001D53E, 1},
-       {0x0001D540, 0x0001D544, 1},
-       {0x0001D546,          0, 0},
-       {0x0001D54A, 0x0001D550, 1},
-       {0x0001D552, 0x0001D6A5, 1},
-       {0x0001D6A8, 0x0001D6C0, 1},
-       {0x0001D6C2, 0x0001D6DA, 1},
-       {0x0001D6DC, 0x0001D6FA, 1},
-       {0x0001D6FC, 0x0001D714, 1},
-       {0x0001D716, 0x0001D734, 1},
-       {0x0001D736, 0x0001D74E, 1},
-       {0x0001D750, 0x0001D76E, 1},
-       {0x0001D770, 0x0001D788, 1},
-       {0x0001D78A, 0x0001D7A8, 1},
-       {0x0001D7AA, 0x0001D7C2, 1},
-       {0x0001D7C4, 0x0001D7CB, 1},
-       {0x0001D7CE, 0x0001D7FF, 1},
-       {0x00020000, 0x0002A6D6, 1},
-       {0x0002F800, 0x0002FA1D, 1},
-       {    0x0660,     0x0669, 1},
-       {    0x06F0,     0x06F9, 1},
-       {    0x0966,     0x096F, 1},
-       {    0x09E6,     0x09EF, 1},
-       {    0x0A66,     0x0A6F, 1},
-       {    0x0AE6,     0x0AEF, 1},
-       {    0x0B66,     0x0B6F, 1},
-       {    0x0BE6,     0x0BEF, 1},
-       {    0x0C66,     0x0C6F, 1},
-       {    0x0C78,     0x0C7F, 1},
-       {    0x0CE6,     0x0CEF, 1},
-       {    0x0D66,     0x0D75, 1},
-       {    0x0D70,     0x0D75, 1},
-       {    0x0E50,     0x0E59, 1},
-       {    0x0ED0,     0x0ED9, 1},
-       {    0x0F20,     0x0F29, 1},
-       {    0x1040,     0x1049, 1},
-       {    0x17E0,     0x17E9, 1},
-       {    0x1810,     0x1819, 1},
-       {    0x1BB0,     0x1BB9, 1},
-       {    0x1C40,     0x1C49, 1},
-       {    0x1C50,     0x1C59, 1},
-       {    0xA620,     0xA629, 1},
-       {    0xA8D0,     0xA8D9, 1},
-       {    0xA900,     0xA909, 1},
-       {    0xAA50,     0xAA59, 1},
-       {    0xFF10,     0xFF19, 1},
+static const utf8_range_t utf8_ranges[] = {
+       {0x00000041, 0x0000005A}, {0x00000061, 0x0000007A}, {0x000000C0, 0x000000D6},
+       {0x000000D8, 0x000000F6}, {0x000000F8, 0x000002C1}, {0x000002C6, 0x000002D1},
+       {0x000002E0, 0x000002E4}, {0x00000370, 0x00000374}, {0x00000376, 0x00000377},
+       {0x0000037A, 0x0000037D}, {0x00000388, 0x0000038A}, {0x0000038E, 0x000003A1},
+       {0x000003A3, 0x000003F5}, {0x000003F7, 0x00000481}, {0x0000048A, 0x0000052F},
+       {0x00000531, 0x00000556}, {0x00000561, 0x00000587}, {0x000005B0, 0x000005BD},
+       {0x000005C1, 0x000005C2}, {0x000005C4, 0x000005C5}, {0x000005D0, 0x000005EA},
+       {0x000005F0, 0x000005F2}, {0x00000610, 0x0000061A}, {0x00000620, 0x00000657},
+       {0x00000659, 0x00000669}, {0x0000066E, 0x000006D3}, {0x000006D5, 0x000006DC},
+       {0x000006E1, 0x000006E8}, {0x000006ED, 0x000006FC}, {0x00000710, 0x0000073F},
+       {0x0000074D, 0x000007B1}, {0x000007C0, 0x000007EA}, {0x000007F4, 0x000007F5},
+       {0x00000800, 0x00000817}, {0x0000081A, 0x0000082C}, {0x00000840, 0x00000858},
+       {0x00000860, 0x0000086A}, {0x000008A0, 0x000008B4}, {0x000008B6, 0x000008BD},
+       {0x000008D4, 0x000008DF}, {0x000008E3, 0x000008E9}, {0x000008F0, 0x0000093B},
+       {0x0000093D, 0x0000094C}, {0x0000094E, 0x00000950}, {0x00000955, 0x00000963},
+       {0x00000966, 0x0000096F}, {0x00000971, 0x00000983}, {0x00000985, 0x0000098C},
+       {0x0000098F, 0x00000990}, {0x00000993, 0x000009A8}, {0x000009AA, 0x000009B0},
+       {0x000009B6, 0x000009B9}, {0x000009BD, 0x000009C4}, {0x000009C7, 0x000009C8},
+       {0x000009CB, 0x000009CC}, {0x000009DC, 0x000009DD}, {0x000009DF, 0x000009E3},
+       {0x000009E6, 0x000009F1}, {0x00000A01, 0x00000A03}, {0x00000A05, 0x00000A0A},
+       {0x00000A0F, 0x00000A10}, {0x00000A13, 0x00000A28}, {0x00000A2A, 0x00000A30},
+       {0x00000A32, 0x00000A33}, {0x00000A35, 0x00000A36}, {0x00000A38, 0x00000A39},
+       {0x00000A3E, 0x00000A42}, {0x00000A47, 0x00000A48}, {0x00000A4B, 0x00000A4C},
+       {0x00000A59, 0x00000A5C}, {0x00000A66, 0x00000A75}, {0x00000A81, 0x00000A83},
+       {0x00000A85, 0x00000A8D}, {0x00000A8F, 0x00000A91}, {0x00000A93, 0x00000AA8},
+       {0x00000AAA, 0x00000AB0}, {0x00000AB2, 0x00000AB3}, {0x00000AB5, 0x00000AB9},
+       {0x00000ABD, 0x00000AC5}, {0x00000AC7, 0x00000AC9}, {0x00000ACB, 0x00000ACC},
+       {0x00000AE0, 0x00000AE3}, {0x00000AE6, 0x00000AEF}, {0x00000AF9, 0x00000AFC},
+       {0x00000B01, 0x00000B03}, {0x00000B05, 0x00000B0C}, {0x00000B0F, 0x00000B10},
+       {0x00000B13, 0x00000B28}, {0x00000B2A, 0x00000B30}, {0x00000B32, 0x00000B33},
+       {0x00000B35, 0x00000B39}, {0x00000B3D, 0x00000B44}, {0x00000B47, 0x00000B48},
+       {0x00000B4B, 0x00000B4C}, {0x00000B56, 0x00000B57}, {0x00000B5C, 0x00000B5D},
+       {0x00000B5F, 0x00000B63}, {0x00000B66, 0x00000B6F}, {0x00000B82, 0x00000B83},
+       {0x00000B85, 0x00000B8A}, {0x00000B8E, 0x00000B90}, {0x00000B92, 0x00000B95},
+       {0x00000B99, 0x00000B9A}, {0x00000B9E, 0x00000B9F}, {0x00000BA3, 0x00000BA4},
+       {0x00000BA8, 0x00000BAA}, {0x00000BAE, 0x00000BB9}, {0x00000BBE, 0x00000BC2},
+       {0x00000BC6, 0x00000BC8}, {0x00000BCA, 0x00000BCC}, {0x00000BE6, 0x00000BEF},
+       {0x00000C00, 0x00000C03}, {0x00000C05, 0x00000C0C}, {0x00000C0E, 0x00000C10},
+       {0x00000C12, 0x00000C28}, {0x00000C2A, 0x00000C39}, {0x00000C3D, 0x00000C44},
+       {0x00000C46, 0x00000C48}, {0x00000C4A, 0x00000C4C}, {0x00000C55, 0x00000C56},
+       {0x00000C58, 0x00000C5A}, {0x00000C60, 0x00000C63}, {0x00000C66, 0x00000C6F},
+       {0x00000C80, 0x00000C83}, {0x00000C85, 0x00000C8C}, {0x00000C8E, 0x00000C90},
+       {0x00000C92, 0x00000CA8}, {0x00000CAA, 0x00000CB3}, {0x00000CB5, 0x00000CB9},
+       {0x00000CBD, 0x00000CC4}, {0x00000CC6, 0x00000CC8}, {0x00000CCA, 0x00000CCC},
+       {0x00000CD5, 0x00000CD6}, {0x00000CE0, 0x00000CE3}, {0x00000CE6, 0x00000CEF},
+       {0x00000CF1, 0x00000CF2}, {0x00000D00, 0x00000D03}, {0x00000D05, 0x00000D0C},
+       {0x00000D0E, 0x00000D10}, {0x00000D12, 0x00000D3A}, {0x00000D3D, 0x00000D44},
+       {0x00000D46, 0x00000D48}, {0x00000D4A, 0x00000D4C}, {0x00000D54, 0x00000D57},
+       {0x00000D5F, 0x00000D63}, {0x00000D66, 0x00000D6F}, {0x00000D7A, 0x00000D7F},
+       {0x00000D82, 0x00000D83}, {0x00000D85, 0x00000D96}, {0x00000D9A, 0x00000DB1},
+       {0x00000DB3, 0x00000DBB}, {0x00000DC0, 0x00000DC6}, {0x00000DCF, 0x00000DD4},
+       {0x00000DD8, 0x00000DDF}, {0x00000DE6, 0x00000DEF}, {0x00000DF2, 0x00000DF3},
+       {0x00000E01, 0x00000E3A}, {0x00000E40, 0x00000E46}, {0x00000E50, 0x00000E59},
+       {0x00000E81, 0x00000E82}, {0x00000E87, 0x00000E88}, {0x00000E94, 0x00000E97},
+       {0x00000E99, 0x00000E9F}, {0x00000EA1, 0x00000EA3}, {0x00000EAA, 0x00000EAB},
+       {0x00000EAD, 0x00000EB9}, {0x00000EBB, 0x00000EBD}, {0x00000EC0, 0x00000EC4},
+       {0x00000ED0, 0x00000ED9}, {0x00000EDC, 0x00000EDF}, {0x00000F20, 0x00000F29},
+       {0x00000F40, 0x00000F47}, {0x00000F49, 0x00000F6C}, {0x00000F71, 0x00000F81},
+       {0x00000F88, 0x00000F97}, {0x00000F99, 0x00000FBC}, {0x00001000, 0x00001036},
+       {0x0000103B, 0x00001049}, {0x00001050, 0x00001062}, {0x00001065, 0x00001068},
+       {0x0000106E, 0x00001086}, {0x00001090, 0x00001099}, {0x0000109C, 0x0000109D},
+       {0x000010A0, 0x000010C5}, {0x000010D0, 0x000010FA}, {0x000010FC, 0x00001248},
+       {0x0000124A, 0x0000124D}, {0x00001250, 0x00001256}, {0x0000125A, 0x0000125D},
+       {0x00001260, 0x00001288}, {0x0000128A, 0x0000128D}, {0x00001290, 0x000012B0},
+       {0x000012B2, 0x000012B5}, {0x000012B8, 0x000012BE}, {0x000012C2, 0x000012C5},
+       {0x000012C8, 0x000012D6}, {0x000012D8, 0x00001310}, {0x00001312, 0x00001315},
+       {0x00001318, 0x0000135A}, {0x00001380, 0x0000138F}, {0x000013A0, 0x000013F5},
+       {0x000013F8, 0x000013FD}, {0x00001401, 0x0000166C}, {0x0000166F, 0x0000167F},
+       {0x00001681, 0x0000169A}, {0x000016A0, 0x000016EA}, {0x000016EE, 0x000016F8},
+       {0x00001700, 0x0000170C}, {0x0000170E, 0x00001713}, {0x00001720, 0x00001733},
+       {0x00001740, 0x00001753}, {0x00001760, 0x0000176C}, {0x0000176E, 0x00001770},
+       {0x00001772, 0x00001773}, {0x00001780, 0x000017B3}, {0x000017B6, 0x000017C8},
+       {0x000017E0, 0x000017E9}, {0x00001810, 0x00001819}, {0x00001820, 0x00001877},
+       {0x00001880, 0x000018AA}, {0x000018B0, 0x000018F5}, {0x00001900, 0x0000191E},
+       {0x00001920, 0x0000192B}, {0x00001930, 0x00001938}, {0x00001946, 0x0000196D},
+       {0x00001970, 0x00001974}, {0x00001980, 0x000019AB}, {0x000019B0, 0x000019C9},
+       {0x000019D0, 0x000019D9}, {0x00001A00, 0x00001A1B}, {0x00001A20, 0x00001A5E},
+       {0x00001A61, 0x00001A74}, {0x00001A80, 0x00001A89}, {0x00001A90, 0x00001A99},
+       {0x00001B00, 0x00001B33}, {0x00001B35, 0x00001B43}, {0x00001B45, 0x00001B4B},
+       {0x00001B50, 0x00001B59}, {0x00001B80, 0x00001BA9}, {0x00001BAC, 0x00001BE5},
+       {0x00001BE7, 0x00001BF1}, {0x00001C00, 0x00001C35}, {0x00001C40, 0x00001C49},
+       {0x00001C4D, 0x00001C7D}, {0x00001C80, 0x00001C88}, {0x00001CE9, 0x00001CEC},
+       {0x00001CEE, 0x00001CF3}, {0x00001CF5, 0x00001CF6}, {0x00001D00, 0x00001DBF},
+       {0x00001DE7, 0x00001DF4}, {0x00001E00, 0x00001F15}, {0x00001F18, 0x00001F1D},
+       {0x00001F20, 0x00001F45}, {0x00001F48, 0x00001F4D}, {0x00001F50, 0x00001F57},
+       {0x00001F5F, 0x00001F7D}, {0x00001F80, 0x00001FB4}, {0x00001FB6, 0x00001FBC},
+       {0x00001FC2, 0x00001FC4}, {0x00001FC6, 0x00001FCC}, {0x00001FD0, 0x00001FD3},
+       {0x00001FD6, 0x00001FDB}, {0x00001FE0, 0x00001FEC}, {0x00001FF2, 0x00001FF4},
+       {0x00001FF6, 0x00001FFC}, {0x00002090, 0x0000209C}, {0x0000210A, 0x00002113},
+       {0x00002119, 0x0000211D}, {0x0000212A, 0x0000212D}, {0x0000212F, 0x00002139},
+       {0x0000213C, 0x0000213F}, {0x00002145, 0x00002149}, {0x00002160, 0x00002188},
+       {0x000024B6, 0x000024E9}, {0x00002C00, 0x00002C2E}, {0x00002C30, 0x00002C5E},
+       {0x00002C60, 0x00002CE4}, {0x00002CEB, 0x00002CEE}, {0x00002CF2, 0x00002CF3},
+       {0x00002D00, 0x00002D25}, {0x00002D30, 0x00002D67}, {0x00002D80, 0x00002D96},
+       {0x00002DA0, 0x00002DA6}, {0x00002DA8, 0x00002DAE}, {0x00002DB0, 0x00002DB6},
+       {0x00002DB8, 0x00002DBE}, {0x00002DC0, 0x00002DC6}, {0x00002DC8, 0x00002DCE},
+       {0x00002DD0, 0x00002DD6}, {0x00002DD8, 0x00002DDE}, {0x00002DE0, 0x00002DFF},
+       {0x00003005, 0x00003007}, {0x00003021, 0x00003029}, {0x00003031, 0x00003035},
+       {0x00003038, 0x0000303C}, {0x00003041, 0x00003096}, {0x0000309D, 0x0000309F},
+       {0x000030A1, 0x000030FA}, {0x000030FC, 0x000030FF}, {0x00003105, 0x0000312E},
+       {0x00003131, 0x0000318E}, {0x000031A0, 0x000031BA}, {0x000031F0, 0x000031FF},
+       {0x00003400, 0x00004DB5}, {0x00004E00, 0x00009FEA}, {0x0000A000, 0x0000A48C},
+       {0x0000A4D0, 0x0000A4FD}, {0x0000A500, 0x0000A60C}, {0x0000A610, 0x0000A62B},
+       {0x0000A640, 0x0000A66E}, {0x0000A674, 0x0000A67B}, {0x0000A67F, 0x0000A6EF},
+       {0x0000A717, 0x0000A71F}, {0x0000A722, 0x0000A788}, {0x0000A78B, 0x0000A7AE},
+       {0x0000A7B0, 0x0000A7B7}, {0x0000A7F7, 0x0000A801}, {0x0000A803, 0x0000A805},
+       {0x0000A807, 0x0000A80A}, {0x0000A80C, 0x0000A827}, {0x0000A840, 0x0000A873},
+       {0x0000A880, 0x0000A8C3}, {0x0000A8D0, 0x0000A8D9}, {0x0000A8F2, 0x0000A8F7},
+       {0x0000A900, 0x0000A92A}, {0x0000A930, 0x0000A952}, {0x0000A960, 0x0000A97C},
+       {0x0000A980, 0x0000A9B2}, {0x0000A9B4, 0x0000A9BF}, {0x0000A9CF, 0x0000A9D9},
+       {0x0000A9E0, 0x0000A9E4}, {0x0000A9E6, 0x0000A9FE}, {0x0000AA00, 0x0000AA36},
+       {0x0000AA40, 0x0000AA4D}, {0x0000AA50, 0x0000AA59}, {0x0000AA60, 0x0000AA76},
+       {0x0000AA7E, 0x0000AABE}, {0x0000AADB, 0x0000AADD}, {0x0000AAE0, 0x0000AAEF},
+       {0x0000AAF2, 0x0000AAF5}, {0x0000AB01, 0x0000AB06}, {0x0000AB09, 0x0000AB0E},
+       {0x0000AB11, 0x0000AB16}, {0x0000AB20, 0x0000AB26}, {0x0000AB28, 0x0000AB2E},
+       {0x0000AB30, 0x0000AB5A}, {0x0000AB5C, 0x0000AB65}, {0x0000AB70, 0x0000ABEA},
+       {0x0000ABF0, 0x0000ABF9}, {0x0000AC00, 0x0000D7A3}, {0x0000D7B0, 0x0000D7C6},
+       {0x0000D7CB, 0x0000D7FB}, {0x0000F900, 0x0000FA6D}, {0x0000FA70, 0x0000FAD9},
+       {0x0000FB00, 0x0000FB06}, {0x0000FB13, 0x0000FB17}, {0x0000FB1D, 0x0000FB28},
+       {0x0000FB2A, 0x0000FB36}, {0x0000FB38, 0x0000FB3C}, {0x0000FB40, 0x0000FB41},
+       {0x0000FB43, 0x0000FB44}, {0x0000FB46, 0x0000FBB1}, {0x0000FBD3, 0x0000FD3D},
+       {0x0000FD50, 0x0000FD8F}, {0x0000FD92, 0x0000FDC7}, {0x0000FDF0, 0x0000FDFB},
+       {0x0000FE70, 0x0000FE74}, {0x0000FE76, 0x0000FEFC}, {0x0000FF10, 0x0000FF19},
+       {0x0000FF21, 0x0000FF3A}, {0x0000FF41, 0x0000FF5A}, {0x0000FF66, 0x0000FFBE},
+       {0x0000FFC2, 0x0000FFC7}, {0x0000FFCA, 0x0000FFCF}, {0x0000FFD2, 0x0000FFD7},
+       {0x0000FFDA, 0x0000FFDC}, {0x00010000, 0x0001000B}, {0x0001000D, 0x00010026},
+       {0x00010028, 0x0001003A}, {0x0001003C, 0x0001003D}, {0x0001003F, 0x0001004D},
+       {0x00010050, 0x0001005D}, {0x00010080, 0x000100FA}, {0x00010140, 0x00010174},
+       {0x00010280, 0x0001029C}, {0x000102A0, 0x000102D0}, {0x00010300, 0x0001031F},
+       {0x0001032D, 0x0001034A}, {0x00010350, 0x0001037A}, {0x00010380, 0x0001039D},
+       {0x000103A0, 0x000103C3}, {0x000103C8, 0x000103CF}, {0x000103D1, 0x000103D5},
+       {0x00010400, 0x0001049D}, {0x000104A0, 0x000104A9}, {0x000104B0, 0x000104D3},
+       {0x000104D8, 0x000104FB}, {0x00010500, 0x00010527}, {0x00010530, 0x00010563},
+       {0x00010600, 0x00010736}, {0x00010740, 0x00010755}, {0x00010760, 0x00010767},
+       {0x00010800, 0x00010805}, {0x0001080A, 0x00010835}, {0x00010837, 0x00010838},
+       {0x0001083F, 0x00010855}, {0x00010860, 0x00010876}, {0x00010880, 0x0001089E},
+       {0x000108E0, 0x000108F2}, {0x000108F4, 0x000108F5}, {0x00010900, 0x00010915},
+       {0x00010920, 0x00010939}, {0x00010980, 0x000109B7}, {0x000109BE, 0x000109BF},
+       {0x00010A00, 0x00010A03}, {0x00010A05, 0x00010A06}, {0x00010A0C, 0x00010A13},
+       {0x00010A15, 0x00010A17}, {0x00010A19, 0x00010A33}, {0x00010A60, 0x00010A7C},
+       {0x00010A80, 0x00010A9C}, {0x00010AC0, 0x00010AC7}, {0x00010AC9, 0x00010AE4},
+       {0x00010B00, 0x00010B35}, {0x00010B40, 0x00010B55}, {0x00010B60, 0x00010B72},
+       {0x00010B80, 0x00010B91}, {0x00010C00, 0x00010C48}, {0x00010C80, 0x00010CB2},
+       {0x00010CC0, 0x00010CF2}, {0x00011000, 0x00011045}, {0x00011066, 0x0001106F},
+       {0x00011082, 0x000110B8}, {0x000110D0, 0x000110E8}, {0x000110F0, 0x000110F9},
+       {0x00011100, 0x00011132}, {0x00011136, 0x0001113F}, {0x00011150, 0x00011172},
+       {0x00011180, 0x000111BF}, {0x000111C1, 0x000111C4}, {0x000111D0, 0x000111DA},
+       {0x00011200, 0x00011211}, {0x00011213, 0x00011234}, {0x00011280, 0x00011286},
+       {0x0001128A, 0x0001128D}, {0x0001128F, 0x0001129D}, {0x0001129F, 0x000112A8},
+       {0x000112B0, 0x000112E8}, {0x000112F0, 0x000112F9}, {0x00011300, 0x00011303},
+       {0x00011305, 0x0001130C}, {0x0001130F, 0x00011310}, {0x00011313, 0x00011328},
+       {0x0001132A, 0x00011330}, {0x00011332, 0x00011333}, {0x00011335, 0x00011339},
+       {0x0001133D, 0x00011344}, {0x00011347, 0x00011348}, {0x0001134B, 0x0001134C},
+       {0x0001135D, 0x00011363}, {0x00011400, 0x00011441}, {0x00011443, 0x00011445},
+       {0x00011447, 0x0001144A}, {0x00011450, 0x00011459}, {0x00011480, 0x000114C1},
+       {0x000114C4, 0x000114C5}, {0x000114D0, 0x000114D9}, {0x00011580, 0x000115B5},
+       {0x000115B8, 0x000115BE}, {0x000115D8, 0x000115DD}, {0x00011600, 0x0001163E},
+       {0x00011650, 0x00011659}, {0x00011680, 0x000116B5}, {0x000116C0, 0x000116C9},
+       {0x00011700, 0x00011719}, {0x0001171D, 0x0001172A}, {0x00011730, 0x00011739},
+       {0x000118A0, 0x000118E9}, {0x00011A00, 0x00011A32}, {0x00011A35, 0x00011A3E},
+       {0x00011A50, 0x00011A83}, {0x00011A86, 0x00011A97}, {0x00011AC0, 0x00011AF8},
+       {0x00011C00, 0x00011C08}, {0x00011C0A, 0x00011C36}, {0x00011C38, 0x00011C3E},
+       {0x00011C50, 0x00011C59}, {0x00011C72, 0x00011C8F}, {0x00011C92, 0x00011CA7},
+       {0x00011CA9, 0x00011CB6}, {0x00011D00, 0x00011D06}, {0x00011D08, 0x00011D09},
+       {0x00011D0B, 0x00011D36}, {0x00011D3C, 0x00011D3D}, {0x00011D3F, 0x00011D41},
+       {0x00011D46, 0x00011D47}, {0x00011D50, 0x00011D59}, {0x00012000, 0x00012399},
+       {0x00012400, 0x0001246E}, {0x00012480, 0x00012543}, {0x00013000, 0x0001342E},
+       {0x00014400, 0x00014646}, {0x00016800, 0x00016A38}, {0x00016A40, 0x00016A5E},
+       {0x00016A60, 0x00016A69}, {0x00016AD0, 0x00016AED}, {0x00016B00, 0x00016B36},
+       {0x00016B40, 0x00016B43}, {0x00016B50, 0x00016B59}, {0x00016B63, 0x00016B77},
+       {0x00016B7D, 0x00016B8F}, {0x00016F00, 0x00016F44}, {0x00016F50, 0x00016F7E},
+       {0x00016F93, 0x00016F9F}, {0x00016FE0, 0x00016FE1}, {0x00017000, 0x000187EC},
+       {0x00018800, 0x00018AF2}, {0x0001B000, 0x0001B11E}, {0x0001B170, 0x0001B2FB},
+       {0x0001BC00, 0x0001BC6A}, {0x0001BC70, 0x0001BC7C}, {0x0001BC80, 0x0001BC88},
+       {0x0001BC90, 0x0001BC99}, {0x0001D400, 0x0001D454}, {0x0001D456, 0x0001D49C},
+       {0x0001D49E, 0x0001D49F}, {0x0001D4A5, 0x0001D4A6}, {0x0001D4A9, 0x0001D4AC},
+       {0x0001D4AE, 0x0001D4B9}, {0x0001D4BD, 0x0001D4C3}, {0x0001D4C5, 0x0001D505},
+       {0x0001D507, 0x0001D50A}, {0x0001D50D, 0x0001D514}, {0x0001D516, 0x0001D51C},
+       {0x0001D51E, 0x0001D539}, {0x0001D53B, 0x0001D53E}, {0x0001D540, 0x0001D544},
+       {0x0001D54A, 0x0001D550}, {0x0001D552, 0x0001D6A5}, {0x0001D6A8, 0x0001D6C0},
+       {0x0001D6C2, 0x0001D6DA}, {0x0001D6DC, 0x0001D6FA}, {0x0001D6FC, 0x0001D714},
+       {0x0001D716, 0x0001D734}, {0x0001D736, 0x0001D74E}, {0x0001D750, 0x0001D76E},
+       {0x0001D770, 0x0001D788}, {0x0001D78A, 0x0001D7A8}, {0x0001D7AA, 0x0001D7C2},
+       {0x0001D7C4, 0x0001D7CB}, {0x0001D7CE, 0x0001D7FF}, {0x0001E000, 0x0001E006},
+       {0x0001E008, 0x0001E018}, {0x0001E01B, 0x0001E021}, {0x0001E023, 0x0001E024},
+       {0x0001E026, 0x0001E02A}, {0x0001E800, 0x0001E8C4}, {0x0001E900, 0x0001E943},
+       {0x0001E950, 0x0001E959}, {0x0001EE00, 0x0001EE03}, {0x0001EE05, 0x0001EE1F},
+       {0x0001EE21, 0x0001EE22}, {0x0001EE29, 0x0001EE32}, {0x0001EE34, 0x0001EE37},
+       {0x0001EE4D, 0x0001EE4F}, {0x0001EE51, 0x0001EE52}, {0x0001EE61, 0x0001EE62},
+       {0x0001EE67, 0x0001EE6A}, {0x0001EE6C, 0x0001EE72}, {0x0001EE74, 0x0001EE77},
+       {0x0001EE79, 0x0001EE7C}, {0x0001EE80, 0x0001EE89}, {0x0001EE8B, 0x0001EE9B},
+       {0x0001EEA1, 0x0001EEA3}, {0x0001EEA5, 0x0001EEA9}, {0x0001EEAB, 0x0001EEBB},
+       {0x0001F130, 0x0001F149}, {0x0001F150, 0x0001F169}, {0x0001F170, 0x0001F189},
+       {0x00020000, 0x0002A6D6}, {0x0002A700, 0x0002B734}, {0x0002B740, 0x0002B81D},
+       {0x0002B820, 0x0002CEA1}, {0x0002CEB0, 0x0002EBE0}, {0x0002F800, 0x0002FA1D}
+};
 
-/* END::UTF8TABLE */
+static const unsigned utf8_chars[] = {
+       0x000000AA, 0x000000B5, 0x000000BA, 0x000002EC, 0x000002EE, 0x00000345,
+       0x0000037F, 0x00000386, 0x0000038C, 0x00000559, 0x000005BF, 0x000005C7,
+       0x000006FF, 0x000007FA, 0x000009B2, 0x000009CE, 0x000009D7, 0x000009FC,
+       0x00000A51, 0x00000A5E, 0x00000AD0, 0x00000B71, 0x00000B9C, 0x00000BD0,
+       0x00000BD7, 0x00000CDE, 0x00000D4E, 0x00000DBD, 0x00000DD6, 0x00000E4D,
+       0x00000E84, 0x00000E8A, 0x00000E8D, 0x00000EA5, 0x00000EA7, 0x00000EC6,
+       0x00000ECD, 0x00000F00, 0x00001038, 0x0000108E, 0x000010C7, 0x000010CD,
+       0x00001258, 0x000012C0, 0x0000135F, 0x000017D7, 0x000017DC, 0x00001AA7,
+       0x00001F59, 0x00001F5B, 0x00001F5D, 0x00001FBE, 0x00002071, 0x0000207F,
+       0x00002102, 0x00002107, 0x00002115, 0x00002124, 0x00002126, 0x00002128,
+       0x0000214E, 0x00002D27, 0x00002D2D, 0x00002D6F, 0x00002E2F, 0x0000A8C5,
+       0x0000A8FB, 0x0000A8FD, 0x0000AA7A, 0x0000AAC0, 0x0000AAC2, 0x0000FB3E,
+       0x00010808, 0x0001083C, 0x00011176, 0x000111DC, 0x00011237, 0x0001123E,
+       0x00011288, 0x00011350, 0x00011357, 0x000114C7, 0x00011640, 0x00011644,
+       0x000118FF, 0x00011C40, 0x00011D3A, 0x00011D43, 0x0001BC9E, 0x0001D4A2,
+       0x0001D4BB, 0x0001D546, 0x0001E947, 0x0001EE24, 0x0001EE27, 0x0001EE39,
+       0x0001EE3B, 0x0001EE42, 0x0001EE47, 0x0001EE49, 0x0001EE4B, 0x0001EE54,
+       0x0001EE57, 0x0001EE59, 0x0001EE5B, 0x0001EE5D, 0x0001EE5F, 0x0001EE64,
+       0x0001EE7E
 };
 
+/* END::UTF8TABLE */
+
 static inline size_t utf8towc(unsigned *wc, const unsigned char *uc, size_t len)
 {
        unsigned char ub = utf8_mblen[*uc];
@@ -595,24 +308,62 @@ static inline size_t utf8towc(unsigned *wc, const unsigned char *uc, size_t len)
 
 static inline zend_bool isualpha(unsigned ch)
 {
-       unsigned i = 0, j;
+       unsigned hi = sizeof(utf8_ranges)/sizeof(utf8_ranges[0])-1,
+                       cur = hi/2, lo = 0, prev;
+
+#undef u
+#define u (utf8_ranges[cur])
 
-       PHP_HTTP_DUFF(sizeof(utf8_ranges)/sizeof(utf8_range_t),
-               if (utf8_ranges[i].start == ch) {
+       do {
+#if 0
+               fprintf(stderr, "=> cur=%u lo=%u hi=%u (%u in %u-%u)\n", cur, lo, hi, ch, u.start, u.end);
+#endif
+               if (u.start <= ch && u.end >= ch) {
                        return 1;
-               } else if (utf8_ranges[i].start <= ch && utf8_ranges[i].end >= ch) {
-                       if (utf8_ranges[i].step == 1) {
-                               return 1;
-                       }
-                       for (j = utf8_ranges[i].start; j <= utf8_ranges[i].end; j+= utf8_ranges[i].step) {
-                               if (ch == j) {
-                                       return 1;
-                               }
-                       }
-                       return 0;
                }
-               ++i;
-       );
+
+               prev = cur;
+
+               if (u.start > ch) {
+                       hi = cur;
+                       cur -= (cur - lo) / 2;
+               } else if ((u.end && u.end < ch) || (!u.end && u.start < ch)) {
+                       lo = cur;
+                       cur += (hi - cur) / 2;
+               } else {
+                       break;
+               }
+
+       } while (cur != prev);
+
+#undef u
+#define u (utf8_chars[cur])
+
+       hi = sizeof(utf8_chars)/sizeof(utf8_chars[0]);
+       cur = hi/2;
+       lo = 0;
+
+       do {
+#if 0
+               fprintf(stderr, "=> cur=%u lo=%u hi=%u (%u is %u)\n", cur, lo, hi, ch, u);
+#endif
+               if (u == ch) {
+                       return 1;
+               }
+
+               prev = cur;
+
+               if (u > ch) {
+                       hi = cur;
+                       cur -= (cur - lo) / 2;
+               } else {
+                       lo = cur;
+                       cur += (hi - cur) / 2;
+               }
+       } while (cur != prev);
+
+#undef u
+
        return 0;
 }
 
index 97f8419603369e152c0bbbd078d276c4016beff9..df53d9c0c0d40570bc6ddcb0ab20ced21d73580e 100644 (file)
@@ -25,6 +25,7 @@ server("proxy.inc", function($port) {
                        'Content-Length' => 0
                )
        );
+       $client->setOptions(["timeout" => 30]);
        $client->enqueue($request);
        echo $client->send()->getResponse()->getResponseCode();
 });
index aeb2d8ac7041e888475178b190db8175823f63b5..6f01a444e97a20d72e95bb6edf1a84c26b659e5d 100644 (file)
@@ -16,7 +16,7 @@ class Observer implements SplObserver
 {
        function update(SplSubject $client, http\Client\Request $request = null, StdClass $progress = null) {
                echo "P";
-               if ($client->getProgressInfo($request) != $progress) {
+               if ($progress->info !== "prepare" && $client->getProgressInfo($request) != $progress) {
                        var_dump($progress);
                }
        }
index 1e603099f32dd40d2eec48cf8f2097784c730f74..bb599db44c2619b1eac6612f84d7b74f098ac5c1 100644 (file)
@@ -5,6 +5,7 @@ client ssl
 include "skipif.inc";
 skip_online_test();
 skip_client_test();
+skip_curl_test("7.34.0");
 ?>
 --FILE--
 <?php 
@@ -21,17 +22,36 @@ var_dump(
        ) === $client->getSslOptions()
 );
 
+$client->attach($observer = new class implements SplObserver { 
+       public $data = [];
+       function update(SplSubject $client, $req = null, $progress = null) {
+               $ti = $client->getTransferInfo($req);
+               if (isset($ti->tls_session["internals"])) {
+                       foreach ((array) $ti->tls_session["internals"] as $key => $val) {
+                               if (!isset($this->data[$key]) || $this->data[$key] < $val) {
+                                       $this->data[$key] = $val;
+                               }
+                       }
+               }
+       }
+});
+
 $client->enqueue($req = new http\Client\Request("GET", "https://twitter.com/"));
 $client->send();
 
-$ti = (array) $client->getTransferInfo($req);
-var_dump(array_key_exists("ssl_engines", $ti));
-var_dump(0 < count($ti["ssl_engines"]) || $ti["tls_session"]["backend"] != "openssl");
+switch ($client->getTransferInfo($req)->tls_session["backend"]) {
+       case "openssl":
+       case "gnutls":
+               if (count($observer->data) < 1) {
+                       die("failed count(ssl.internals) >= 1\n");
+               }
+               break;
+       default:
+               break;
+}
 ?>
 Done
 --EXPECTF--
 Test
 bool(true)
-bool(true)
-bool(true)
 Done
index fdf6c969c37587884ebc472214e21c3598335a50..477edf7fa6d18122efbe919c5b8be69b61382ba3 100644 (file)
@@ -43,6 +43,9 @@ server("proxy.inc", function($port) {
                        $o3 = new CallbackObserver(
                                        function ($c, $r) {
                                                $p = (array) $c->getProgressInfo($r);
+                                               if (!$p) {
+                                                       return;
+                                               }
                                                var_dump(array_key_exists("started", $p));
                                                var_dump(array_key_exists("finished", $p));
                                                var_dump(array_key_exists("dlnow", $p));
index b0550df01b27ba96cf33edeafa06a0d91dd1cf09..e266243f758df14ac89682a117644ac74398e128 100644 (file)
@@ -138,4 +138,4 @@ server("proxy.inc", function($port) {
 --EXPECTREGEX--
 Test
 [ST][WST]*([OWST]*)+U+int\(200\)
-===DONE===
+O*===DONE===
diff --git a/tests/encstream015.phpt b/tests/encstream015.phpt
new file mode 100644 (file)
index 0000000..6f63fc5
--- /dev/null
@@ -0,0 +1,42 @@
+--TEST--
+encoding stream brotli static
+--SKIPIF--
+<?php
+include "skipif.inc";
+class_exists("http\\Encoding\\Stream\\Enbrotli", false) or die("SKIP need brotli support");
+?>
+--FILE--
+<?php
+echo "Test\n";
+
+$file = file_get_contents(__FILE__);
+var_dump($file ===
+       http\Encoding\Stream\Debrotli::decode(
+               http\Encoding\Stream\Enbrotli::encode(
+                       $file, http\Encoding\Stream\Enbrotli::MODE_GENERIC
+               )
+       )
+);
+var_dump($file ===
+       http\Encoding\Stream\Debrotli::decode(
+               http\Encoding\Stream\Enbrotli::encode(
+                       $file, http\Encoding\Stream\Enbrotli::MODE_TEXT
+               )
+       )
+);
+var_dump($file ===
+       http\Encoding\Stream\Debrotli::decode(
+               http\Encoding\Stream\Enbrotli::encode(
+                       $file, http\Encoding\Stream\Enbrotli::MODE_FONT
+               )
+       )
+);
+
+?>
+DONE
+--EXPECT--
+Test
+bool(true)
+bool(true)
+bool(true)
+DONE
diff --git a/tests/encstream016.phpt b/tests/encstream016.phpt
new file mode 100644 (file)
index 0000000..2ecf9b6
--- /dev/null
@@ -0,0 +1,34 @@
+--TEST--
+encoding stream brotli auto flush
+--SKIPIF--
+<?php
+include "skipif.inc";
+class_exists("http\\Encoding\\Stream\\Enbrotli") or die("SKIP need brotli support");
+
+?>
+--FILE--
+<?php
+echo "Test\n";
+
+$defl = new http\Encoding\Stream\Enbrotli(http\Encoding\Stream::FLUSH_FULL);
+$infl = new http\Encoding\Stream\Debrotli;
+
+for ($f = fopen(__FILE__, "rb"); !feof($f); $data = fread($f, 0x100)) {
+       if (isset($data)) {
+               if ($data !== $d=$infl->update($defl->update($data))) {
+                       printf("uh-oh »%s« != »%s«\n", $data, $d);
+               }
+       }
+}
+
+echo $infl->update($defl->finish());
+echo $infl->finish();
+
+var_dump($infl->done(), $defl->done());
+?>
+DONE
+--EXPECT--
+Test
+bool(true)
+bool(true)
+DONE
diff --git a/tests/encstream017.phpt b/tests/encstream017.phpt
new file mode 100644 (file)
index 0000000..6ca281d
--- /dev/null
@@ -0,0 +1,33 @@
+--TEST--
+encoding stream brotli without flush
+--SKIPIF--
+<?php
+include "skipif.inc";
+class_exists("http\\Encoding\\Stream\\Enbrotli") or die("SKIP need brotli support");
+?>
+--FILE--
+<?php
+echo "Test\n";
+
+$defl = new http\Encoding\Stream\Enbrotli;
+$infl = new http\Encoding\Stream\Debrotli;
+$file = file(__FILE__);
+$data = "";
+foreach ($file as $line) {
+       if (strlen($temp = $defl->update($line))) {
+               foreach(str_split($temp) as $byte) {
+                       $data .= $infl->update($byte);
+               }
+       }
+}
+if (strlen($temp = $defl->finish())) {
+       $data .= $infl->update($temp);
+}
+$data .= $infl->finish();
+var_dump(implode("", $file) === $data);
+?>
+DONE
+--EXPECT--
+Test
+bool(true)
+DONE
diff --git a/tests/encstream018.phpt b/tests/encstream018.phpt
new file mode 100644 (file)
index 0000000..8b98bec
--- /dev/null
@@ -0,0 +1,42 @@
+--TEST--
+encoding stream brotli with explicit flush
+--SKIPIF--
+<?php
+include "skipif.inc";
+class_exists("http\\Encoding\\Stream\\Enbrotli") or die("SKIP need brotli support");
+?>
+--FILE--
+<?php
+echo "Test\n";
+
+$enc = new http\Encoding\Stream\Enbrotli;
+$dec = new http\Encoding\Stream\Debrotli;
+$file = file(__FILE__);
+$data = "";
+foreach ($file as $line) {
+       $data .= $dec->flush();
+       if (strlen($temp = $enc->update($line))) {
+               $data .= $dec->update($temp);
+               $data .= $dec->flush();
+       }
+       if (strlen($temp = $enc->flush())) {
+               $data .= $dec->update($temp);
+               $data .= $dec->flush();
+       }
+}
+if (strlen($temp = $enc->finish())) {
+       $data .= $dec->update($temp);
+}
+var_dump($enc->done());
+$data .= $dec->finish();
+var_dump($dec->done());
+var_dump(implode("", $file) === $data);
+
+?>
+DONE
+--EXPECT--
+Test
+bool(true)
+bool(true)
+bool(true)
+DONE
diff --git a/tests/encstream019.phpt b/tests/encstream019.phpt
new file mode 100644 (file)
index 0000000..7fa83c8
--- /dev/null
@@ -0,0 +1,21 @@
+--TEST--
+encoding stream brotli error
+--SKIPIF--
+<?php
+include "skipif.inc";
+class_exists("http\\Encoding\\Stream\\Enbrotli") or die("SKIP need brotli support");
+?>
+--FILE--
+<?php
+echo "Test\n";
+
+var_dump(http\Encoding\Stream\Debrotli::decode("if this goes through, something's pretty wrong"));
+
+?>
+DONE
+--EXPECTF--
+Test
+
+Warning: http\Encoding\Stream\Debrotli::decode(): Could not brotli decode data: %s in %s on line %d
+bool(false)
+DONE
index 7a02814c27c5b5ea60ecfbeee42ba1c917ecb5da..d12c1c646f5f4f147525539175140765f4359bbc 100644 (file)
@@ -18,7 +18,7 @@ $r->setBody(new http\Message\Body(fopen(__FILE__, "rb")));
 $r->send();
 
 ?>
---EXPECTHEADERSF--
-Content-Type: text/plain%s
+--EXPECTHEADERS--
+Content-Range: bytes 2-4/248
 --EXPECTF--
 php
diff --git a/tests/filterbrotli.phpt b/tests/filterbrotli.phpt
new file mode 100644 (file)
index 0000000..7c4ffaf
--- /dev/null
@@ -0,0 +1,32 @@
+--TEST--
+brotli filter
+--SKIPIF--
+<?php 
+include "skipif.inc";
+class_exists("http\\Encoding\\Stream\\Enbrotli", false) or die("SKIP need brotli support");
+?>
+--FILE--
+<?php
+list($in, $out) = stream_socket_pair(
+    STREAM_PF_UNIX,
+    STREAM_SOCK_STREAM,
+    STREAM_IPPROTO_IP
+);
+stream_filter_append($in, "http.brotli_decode", STREAM_FILTER_READ);
+stream_filter_append($out, "http.brotli_encode", STREAM_FILTER_WRITE,
+    http\Encoding\Stream\Enbrotli::LEVEL_MAX);
+
+$file = file(__FILE__);
+foreach ($file as $line) {
+    fwrite($out, $line);
+    fflush($out);
+}
+fclose($out);
+if (implode("",$file) !== ($read = fread($in, filesize(__FILE__)))) {
+    echo "got: $read\n";
+}
+fclose($in);
+?>
+DONE
+--EXPECT--
+DONE
index 78a63eee3098f71de890ad2dce7e88956b4ecda5..ea83f70679b073f1dc75dbbf30261c14f6567ef7 100644 (file)
@@ -26,14 +26,49 @@ if ($php) {
 
 foreach (array("raphf", "propro", "http") as $ext) {
        if (!extension_loaded($ext)) {
-               switch (PHP_SHLIB_SUFFIX) {
-                       case "dll":
-                               dl("php_$ext.dll"); 
-                               break;
-                       default:
-                               dl($ext .".". PHP_SHLIB_SUFFIX);
+               dl(ext_lib_name($ext));
+       }
+}
+
+function get_extension_load_arg($bin, $args, $ext) {
+       $bin = escapeshellcmd($bin);
+       $args = implode(' ', array_map('escapeshellarg', $args));
+
+       // check if php will load the extension with the existing args
+       exec(sprintf('%s %s -m', $bin, $args), $output);
+
+       foreach ($output as $line ) {
+               if (trim($line) === $ext) {
+                       return null;
+               }
+       }
+
+       // try to load the extension with an arg
+       $arg = '-dextension=' . ini_get('extension_dir') . '/' . ext_lib_name($ext);
+       exec(sprintf('%s %s %s -m', $bin, $args, escapeshellarg($arg)), $output);
+
+       foreach ($output as $line ) {
+               if (trim($line) === $ext) {
+                       return $arg;
                }
        }
+
+       // check if the child will be able to dl() the extension
+       $success = shell_exec(sprintf('%s %s -r "echo (int)dl(%s);', $bin, $args, var_export(ext_lib_name($ext), true)));
+       if ($success) {
+               return null;
+       }
+
+       echo "Unable to load extension '{$ext}' in child process";
+       exit(1);
+}
+
+function ext_lib_name($ext) {
+       if (PHP_SHLIB_SUFFIX === 'dll') {
+               return "php_{$ext}.dll";
+       }
+
+       return $ext . "." . PHP_SHLIB_SUFFIX;
 }
 
 function serve($cb) {
@@ -77,11 +112,31 @@ function serve($cb) {
 }
 
 function server($handler, $cb) {
-       $args = explode(' ', getenv('TEST_PHP_ARGS'));
-       $args[] = __DIR__."/$handler";
-       foreach ($args as $k => $v) {
-               if (!$v) unset($args[$k]);
+       $args = [];
+       $argList = preg_split('#\s+#', getenv('TEST_PHP_ARGS'), -1, PREG_SPLIT_NO_EMPTY);
+       for ($i = 0; isset($argList[$i]); $i++) {
+               if ($argList[$i] === '-c') {
+                       array_push($args, '-c', $argList[++$i]);
+                       continue;
+               }
+               if ($argList[$i] === '-n') {
+                       $args[] = '-n';
+                       continue;
+               }
+               if ($argList[$i] === '-d') {
+                       $args[] = '-d' . $args[++$i];
+                       continue;
+               }
+               if (substr($argList[$i], 0, 2) === '-d') {
+                       $args[] = $argList[$i];
+               }
        }
+       foreach (['raphf', 'propro', 'http'] as $ext) {
+               if (null !== $arg = get_extension_load_arg(PHP_BIN, $args, $ext)) {
+                       $args[] = $arg;
+               }
+       }
+       $args[] = __DIR__ . '/' . $handler;
        proc(PHP_BIN, $args, $cb);
 }
 
@@ -95,9 +150,9 @@ function nghttpd($cb) {
                        $stdout = $pipes[1];
                        $stderr = $pipes[2];
                        
-                       usleep(50000);
+                       sleep(1);
                        $status = proc_get_status($proc);
-                       
+                       logger("nghttpd: %s", new http\Params($status));
                        if (!$status["running"]) {
                                continue;
                        }
@@ -121,6 +176,7 @@ function nghttpd($cb) {
 function proc($bin, $args, $cb) {
        $spec = array(array("pipe","r"), array("pipe","w"), array("pipe","w"));
        $comm = escapeshellcmd($bin) . " ". implode(" ", array_map("escapeshellarg", $args));
+       logger("proc: %s %s", $bin, implode(" ", $args));
        if (($proc = proc_open($comm, $spec, $pipes, __DIR__))) {
                $stdin = $pipes[0];
                $stdout = $pipes[1];
index 59971e551989c0073c7dd65fdc54718e1c119448..88a35436b18e680a725306f99657adb520b0c80b 100644 (file)
@@ -8,14 +8,16 @@ include "skipif.inc";
 <?php
 
 class m extends http\Message { 
-    function test() { 
+    function test1() { 
         $this->headers["bykey"] = 1; 
         var_dump($this->headers); 
-
+       }
+       function test2() {
         $h = &$this->headers; 
         $h["by1ref"] = 2; 
         var_dump($this->headers); 
-
+       }
+       function test3() {
         $x = &$this->headers["byXref"];
 
         $h = &$this->headers["by2ref"]; 
@@ -24,7 +26,8 @@ class m extends http\Message {
 
         $x = 2;
         var_dump($this->headers);
-
+       }
+       function test4() {
         $this->headers["bynext"][] = 1;
         $this->headers["bynext"][] = 2;
         $this->headers["bynext"][] = 3;
@@ -33,7 +36,10 @@ class m extends http\Message {
 } 
 
 $m=new m; 
-$m->test(); 
+$m->test1(); 
+$m->test2(); 
+$m->test3(); 
+$m->test4(); 
 echo $m,"\n";
 
 ?>
index 4844defba0ad07ea61918f1aa4c023d1ed9a95d5..85dbac2902d2c2ae7915b9fe9dcc18d4d6d053c5 100644 (file)
@@ -1,7 +1,23 @@
 <?php
-function _ext($ext) { extension_loaded($ext) or die("skip $ext extension needed\n"); }
 _ext("http");
 
+function _ext($ext) { 
+       if (!extension_loaded($ext)) {
+               die("skip $ext extension needed\n");
+       }
+}
+
+function utf8locale() {
+       if (stristr(setlocale(LC_CTYPE, "C.UTF-8"), "utf")) {
+               return true;
+       }
+       $locale = setlocale(LC_CTYPE, null);
+       if (stristr($locale, "utf") && substr($locale, -1) === "8") {
+               return true;
+       }
+       return false;
+}
+
 function skip_online_test($message = "skip test requiring internet connection\n") {
        if (getenv("SKIP_ONLINE_TESTS")) {
                die($message);
@@ -20,6 +36,12 @@ function skip_client_test($message = "skip need a client driver\n") {
        }
 }
 
+function skip_curl_test($version) {
+       if (!version_compare(http\Client\Curl\Versions\CURL, $version, "<=")) {
+               die("need at least libcurl version $version\n");
+       }
+}
+
 function skip_http2_test($message = "skip need http2 support") {
        if (!defined("http\\Client\\Curl\\HTTP_VERSION_2_0")) {
                die("$message (HTTP_VERSION_2_0)\n");
@@ -33,4 +55,4 @@ function skip_http2_test($message = "skip need http2 support") {
                }
        }
        die("$message (nghttpd in PATH)\n");
-}
\ No newline at end of file
+}
index 9172138eeb971b7330ae7a401a047f37e2712cf5..36d6983eed9e09bb4fc65f1331b42d5358c65621 100644 (file)
@@ -4,7 +4,7 @@ url parser multibyte/locale
 <?php
 include "skipif.inc";
 if (!defined("http\\Url::PARSE_MBLOC") or
-       !stristr(setlocale(LC_CTYPE, "C.UTF-8"), "utf")) {
+       !utf8locale()) {
        die("skip need http\\Url::PARSE_MBLOC support and LC_CTYPE=*.UTF-8");
 }
 ?>
index d701bf57c64b9b0db356d5af96b8dbb4ce4cd467..e047ada501481cd9bd3acefc53d7bfe768833107 100644 (file)
@@ -5,7 +5,7 @@ url parser multibyte/locale/idna
 include "skipif.inc";
 if (!defined("http\\Url::PARSE_MBLOC") or
        !defined("http\\Url::PARSE_TOIDN_2003") or
-       !stristr(setlocale(LC_CTYPE, "C.UTF-8"), ".utf")) {
+       !utf8locale()) {
        die("skip need http\\Url::PARSE_MBLOC|http\\Url::PARSE_TOIDN_2003 support and LC_CTYPE=*.UTF-8");
 }
 ?>
index e1675ce409f3985acce0f6af9be3767e4bd884bf..f5382085e17a481ac626c3fa0a50a75bdeb9058e 100644 (file)
@@ -4,7 +4,7 @@ url parser multibyte/locale/topct
 <?php
 include "skipif.inc";
 if (!defined("http\\Url::PARSE_MBLOC") or
-       !stristr(setlocale(LC_CTYPE, "C.UTF-8"), ".utf")) {
+       !utf8locale()) {
        die("skip need http\\Url::PARSE_MBLOC support and LC_CTYPE=*.UTF-8");
 }
 
index 5f8efae457f0b15e6105d385868fa49303e18db6..d80cd1313556649e049ca4ba34f9aa3e5548394c 100644 (file)
@@ -5,7 +5,7 @@ url parser multibyte/locale/topct
 include "skipif.inc";
 if (!defined("http\\Url::PARSE_MBLOC") or
        !defined("http\\Url::PARSE_TOIDN") or
-       !stristr(setlocale(LC_CTYPE, "C.UTF-8"), ".utf")) {
+       !utf8locale()) {
        die("skip need http\\Url::PARSE_MBLOC|http\Url::PARSE_TOIDN support and LC_CTYPE=*.UTF-8");
 }
 
index 53889dd877144d7e286798e009a8c1d3bb07944b..85ab3cbdcee86b8952f29baee83ce57221e1636a 100644 (file)
@@ -3,9 +3,8 @@ url parser multibyte/utf-8/topct
 --SKIPIF--
 <?php
 include "skipif.inc";
-if (!defined("http\\Url::PARSE_TOIDN") or
+defined("http\\Url::PARSE_TOIDN") or
        die("skip need http\\Url::PARSE_TOIDN support");
-}
 ?>
 --FILE--
 <?php
diff --git a/travis/brotli.sh b/travis/brotli.sh
new file mode 100755 (executable)
index 0000000..d23dd19
--- /dev/null
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+BROTLI_DIR="$with_http_libbrotli_dir"
+BROTLI_SRC="$BROTLI_DIR.git"
+
+if test -n "$BROTLI_DIR" && test "$BROTLI_DIR" != "no"; then
+       if test -d "$BROTLI_SRC"; then
+               cd "$BROTLI_SRC"
+               git pull
+       else
+               git clone https://github.com/google/brotli.git "$BROTLI_SRC"
+               cd "$BROTLI_SRC"
+       fi
+       git checkout $1
+       ./bootstrap
+       ./configure -C --prefix="$BROTLI_DIR"
+       make -j ${JOBS:2}
+       make install INSTALL=install
+fi
index 79de9c8e52f16a2e06324683cf4c00c91df1b6c1..dd0a2e61211836ac7b24a271a5bd68af99dee3d6 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 79de9c8e52f16a2e06324683cf4c00c91df1b6c1
+Subproject commit dd0a2e61211836ac7b24a271a5bd68af99dee3d6