Merge branch 'merge-DEV_2'
authorMichael Wallner <mike@php.net>
Tue, 5 Aug 2014 16:47:19 +0000 (18:47 +0200)
committerMichael Wallner <mike@php.net>
Tue, 5 Aug 2014 16:47:19 +0000 (18:47 +0200)
166 files changed:
.gitattributes [new file with mode: 0644]
.gitignore [new file with mode: 0644]
LICENSE
TODO
ThanksTo.txt
check_package-xml.php [new file with mode: 0755]
config.w32
config9.m4
gen_curlinfo.php
package.xml
php_http.c
php_http.h
php_http_api.h
php_http_buffer.c
php_http_buffer.h
php_http_client.c
php_http_client.h
php_http_client_curl.c
php_http_client_curl.h
php_http_client_request.c
php_http_client_request.h
php_http_client_response.c
php_http_client_response.h
php_http_cookie.c
php_http_cookie.h
php_http_curl.c
php_http_curl.h
php_http_encoding.c
php_http_encoding.h
php_http_env.c
php_http_env.h
php_http_env_request.c
php_http_env_request.h
php_http_env_response.c
php_http_env_response.h
php_http_etag.c
php_http_etag.h
php_http_exception.c
php_http_exception.h
php_http_filter.c
php_http_filter.h
php_http_header.c
php_http_header.h
php_http_header_parser.c
php_http_header_parser.h
php_http_info.c
php_http_info.h
php_http_message.c
php_http_message.h
php_http_message_body.c
php_http_message_body.h
php_http_message_parser.c
php_http_message_parser.h
php_http_misc.c
php_http_misc.h
php_http_negotiate.c
php_http_negotiate.h
php_http_object.c
php_http_object.h
php_http_options.c
php_http_options.h
php_http_params.c
php_http_params.h
php_http_querystring.c
php_http_querystring.h
php_http_strlist.c
php_http_strlist.h
php_http_url.c
php_http_url.h
php_http_version.c
php_http_version.h
phpunit.php [deleted file]
phpunit/CookieTest.php [deleted file]
phpunit/EncodingTest.php [deleted file]
phpunit/MessageBodyTest.php [deleted file]
phpunit/ParamsTest.php [deleted file]
phpunit/QueryStringTest.php [deleted file]
phpunit/UrlTest.php [deleted file]
tests/bug66388.phpt [new file with mode: 0644]
tests/client002.phpt
tests/client003.phpt
tests/client004.phpt
tests/client005.phpt
tests/client006.phpt
tests/client007.phpt
tests/client008.phpt
tests/client009.phpt
tests/client010.phpt
tests/client011.phpt
tests/client012.phpt
tests/client013.phpt
tests/client014.phpt [new file with mode: 0644]
tests/clientresponse001.phpt
tests/clientresponse002.phpt
tests/clientresponse003.phpt
tests/cookie001.phpt [new file with mode: 0644]
tests/cookie002.phpt [new file with mode: 0644]
tests/cookie003.phpt [new file with mode: 0644]
tests/cookie004.phpt [new file with mode: 0644]
tests/cookie005.phpt [new file with mode: 0644]
tests/cookie006.phpt [new file with mode: 0644]
tests/cookie007.phpt [new file with mode: 0644]
tests/cookie008.phpt [new file with mode: 0644]
tests/cookie009.phpt [new file with mode: 0644]
tests/cookie010.phpt [new file with mode: 0644]
tests/cookie011.phpt [new file with mode: 0644]
tests/cookie012.phpt [new file with mode: 0644]
tests/encstream001.phpt [new file with mode: 0644]
tests/encstream002.phpt [new file with mode: 0644]
tests/encstream003.phpt [new file with mode: 0644]
tests/encstream004.phpt [new file with mode: 0644]
tests/encstream005.phpt [new file with mode: 0644]
tests/encstream006.phpt [new file with mode: 0644]
tests/encstream007.phpt [new file with mode: 0644]
tests/encstream008.phpt [new file with mode: 0644]
tests/encstream009.phpt [new file with mode: 0644]
tests/envrequestbody001.phpt
tests/envrequestbody002.phpt
tests/envrequestbody003.phpt
tests/envrequestheader001.phpt
tests/envresponse003.phpt
tests/envresponse004.phpt
tests/envresponse015.phpt [new file with mode: 0644]
tests/envresponse016.phpt [new file with mode: 0644]
tests/envresponseheader001.phpt
tests/envresponseranges001.phpt
tests/etag001.phpt
tests/message002.phpt
tests/message003.phpt
tests/message004.phpt
tests/messagebody001.phpt [new file with mode: 0644]
tests/messagebody002.phpt [new file with mode: 0644]
tests/messagebody003.phpt [new file with mode: 0644]
tests/messagebody004.phpt [new file with mode: 0644]
tests/messagebody005.phpt [new file with mode: 0644]
tests/messagebody006.phpt [new file with mode: 0644]
tests/messagebody007.phpt [new file with mode: 0644]
tests/messagebody008.phpt [new file with mode: 0644]
tests/messagebody009.phpt [new file with mode: 0644]
tests/messagebody010.phpt [new file with mode: 0644]
tests/negotiate001.phpt
tests/params001.phpt
tests/params003.phpt [new file with mode: 0644]
tests/params004.phpt [new file with mode: 0644]
tests/params005.phpt [new file with mode: 0644]
tests/params006.phpt [new file with mode: 0644]
tests/params007.phpt [new file with mode: 0644]
tests/params008.phpt [new file with mode: 0644]
tests/params009.phpt [new file with mode: 0644]
tests/params010.phpt [new file with mode: 0644]
tests/params011.phpt [new file with mode: 0644]
tests/params012.phpt [new file with mode: 0644]
tests/params013.phpt [new file with mode: 0644]
tests/params014.phpt [new file with mode: 0644]
tests/params015.phpt [new file with mode: 0644]
tests/phpunit.phpt [deleted file]
tests/propertyproxy001.phpt
tests/querystring001.phpt [new file with mode: 0644]
tests/querystring002.phpt [new file with mode: 0644]
tests/querystring_001.phpt [deleted file]
tests/skipif.inc
tests/url001.phpt
tests/url002.phpt [new file with mode: 0644]
tests/url003.phpt [new file with mode: 0644]
tests/url004.phpt [new file with mode: 0644]
tests/url005.phpt [new file with mode: 0644]

diff --git a/.gitattributes b/.gitattributes
new file mode 100644 (file)
index 0000000..a55a7ae
--- /dev/null
@@ -0,0 +1,2 @@
+package.xml            merge=touch
+php_http.h             merge=touch
diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..64b23b6
--- /dev/null
@@ -0,0 +1,39 @@
+.cproject
+.deps
+.libs/
+.project
+Makefile
+Makefile.fragments
+Makefile.global
+Makefile.objects
+acinclude.m4
+aclocal.m4
+autom4te.cache/
+build/
+config.guess
+config.h
+config.h.in
+config.log
+config.nice
+config.status
+config.sub
+configure
+configure.in
+http.la
+install-sh
+lcov_data
+libtool
+ltmain.sh
+missing
+mkinstalldirs
+modules/
+pecl_http-*.tgz
+*.lo
+run-tests.php
+tests/*.diff
+tests/*.exp
+tests/*.log
+tests/*.out
+tests/*.php
+tests/*.sh
+lcov_data
diff --git a/LICENSE b/LICENSE
index 0fa6885..786ba27 100644 (file)
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2004-2013, Michael Wallner <mike@iworks.at>.
+Copyright (c) 2004-2014, Michael Wallner <mike@iworks.at>.
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without 
diff --git a/TODO b/TODO
index db7d39d..3981099 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,8 +1,4 @@
 * let http_info.request.url be a php_url
 * let the message body be a simple query string unless files are added
 * php_http_message_serialize reverses the chain twice; remove that
-* revisit error handling
- * ditch http\Object
- * interfacize http\Exception
- * subclass Exceptions
- * zend_throw_exception
\ No newline at end of file
+* CURLOPT_PROXY_HEADER and CURLOPT_HEADEROPT
\ No newline at end of file
index 48003f9..67c5b32 100644 (file)
@@ -8,6 +8,7 @@ to implement, in alphabetical order:
        Ilia Alshanetsky (ilia at php dot net)
        Anatol Belski (ab at php dot net)
        Petr Czaderna (petr at hroch dot info)
+       Remi Collet (remi at php dot net)
        Benjamin Eberlei (kontakt at beberlei dot de)
        David James (james82 at gmail dot com)
        Thomas Landro Johnsen (thomas dot l dot johnsen at gmail dot com)
diff --git a/check_package-xml.php b/check_package-xml.php
new file mode 100755 (executable)
index 0000000..4000054
--- /dev/null
@@ -0,0 +1,92 @@
+#!/usr/bin/env php
+<?php
+
+ini_set("log_errors", false);
+ini_set("display_errors", true);
+
+if ($argc > 1) {
+       if ($argv[1] === "-") {
+               $file = "php://stdin";
+       } else {
+               $file = $argv[1];
+       }
+} elseif (stdin_is_readable()) {
+       $file = "php://stdin";
+} else {
+       $file = "./package.xml";
+}
+
+if (($xml = simplexml_load_file($file))) {
+       $xml_files = xmllist($xml->contents[0]);
+       $dirs = ["."];
+       while ($dir = array_shift($dirs)) {
+               foreach (dirlist($dir) as $file) {
+                       if (is_gitignored($file)) {
+                               continue;
+                       }
+                       if (!is_dir($file)) {
+                               if (!in_array($file, $xml_files)) {
+                                       echo "Missing file $file\n";
+                               }
+                       } else {
+                               $base = basename($file);
+                               if ($base{0} !== ".") {
+                                       array_push($dirs, $file);
+                               }
+                       }
+               }
+       }
+}
+
+###
+
+function error($fmt) {
+       trigger_error(call_user_func_array("sprintf", func_get_args()));
+}
+
+function stdin_is_readable() {
+       $r = [STDIN]; $w = $e = [];
+       return stream_select($r, $w, $e, 0);
+}
+
+function is_gitignored($file) {
+       static $gitignore;
+       
+       if (!isset($gitignore)) {
+               if (is_readable(".gitignore")) {
+                       $gitignore = explode("\n", `find | git check-ignore --stdin`);
+               } else {
+                       $gitignore = false;
+               }
+       }
+       if ($gitignore) {
+               return in_array($file, $gitignore);
+       }
+       return false;
+}
+
+function xmllist(SimpleXmlElement $dir, $p = ".", &$a = null) {
+       settype($a, "array");
+       $p = trim($p, "/") . "/" . trim($dir["name"], "/") . "/";
+       foreach ($dir as $file) {
+               switch ($file->getName()) {
+                       case "dir":
+                               xmllist($file, $p, $a);
+                               break;
+                       case "file":
+                               $a[] = sprintf("%s/%s", trim($p, "/"), trim($file["name"]));
+                               break;
+                       default:
+                               error("Unknown content type: %s", $file->getName());
+                               break;
+               }
+       }
+       return $a;
+}
+
+function dirlist($dir, $p = null) {
+       $p = implode("/", array_filter([trim($p, "/"), trim($dir, "/")]));
+       foreach (scandir($p) as $file) {
+               yield $p."/".$file;
+       }
+}
index f74f152..497fb65 100644 (file)
@@ -51,7 +51,7 @@ if (PHP_HTTP != "no") {
                "php_http_cookie.c php_http_curl.c php_http_client_curl.c " +\r
                "php_http_encoding.c php_http_env.c php_http_env_request.c " +\r
                "php_http_env_response.c php_http_etag.c php_http_exception.c php_http_filter.c php_http_header_parser.c " +\r
-               "php_http_headers.c php_http_info.c php_http_message.c php_http_message_body.c php_http_message_parser.c " +\r
+               "php_http_header.c php_http_info.c php_http_message.c php_http_message_body.c php_http_message_parser.c " +\r
                "php_http_misc.c php_http_negotiate.c php_http_object.c php_http_options.c php_http_params.c " +\r
                "php_http_querystring.c " +\r
                "php_http_strlist.c php_http_url.c php_http_version.c",\r
index aff67ca..ba1b935 100644 (file)
@@ -187,13 +187,13 @@ dnl ----
                        save_LIBS="$LIBS"
                        LIBS=
                        save_CFLAGS="$CFLAGS"
-                       CFLAGS=`$CURL_CONFIG --cflags`
+                       CFLAGS="$CFLAGS `$CURL_CONFIG --cflags`"
                        save_LDFLAGS="$LDFLAGS"
-                       LDFLAGS=`$CURL_CONFIG --libs`
-                       LDFLAGS="$LDFLAGS $ld_runpath_switch$CURL_DIR/$PHP_LIBDIR"
+                       LDFLAGS="$LDFLAGS `$CURL_CONFIG --libs` $ld_runpath_switch$CURL_DIR/$PHP_LIBDIR"
                
                        AC_MSG_CHECKING([for SSL support in libcurl])
                        CURL_SSL=`$CURL_CONFIG --feature | $EGREP SSL`
+                       CURL_SSL_LIBS=()
                        if test "$CURL_SSL" = "SSL"; then
                                AC_MSG_RESULT([yes])
                                AC_DEFINE([PHP_HTTP_HAVE_SSL], [1], [ ])
@@ -212,9 +212,11 @@ dnl ----
                                        }
                                ], [
                                        AC_MSG_RESULT([yes])
-                                       AC_CHECK_HEADER([openssl/crypto.h], [
-                                               AC_DEFINE([PHP_HTTP_HAVE_OPENSSL], [1], [ ])
-                                               CURL_SSL="crypto"
+                                       AC_CHECK_HEADER([openssl/ssl.h], [
+                                               AC_CHECK_HEADER([openssl/crypto.h], [
+                                                       AC_DEFINE([PHP_HTTP_HAVE_OPENSSL], [1], [ ])
+                                                       CURL_SSL_LIBS=(ssl crypto)
+                                               ])
                                        ])
                                ], [
                                        AC_MSG_RESULT([no])
@@ -236,9 +238,11 @@ dnl ----
                                        }
                                ], [
                                        AC_MSG_RESULT([yes])
-                                       AC_CHECK_HEADER([gcrypt.h], [
-                                               AC_DEFINE([PHP_HTTP_HAVE_GNUTLS], [1], [ ])
-                                               CURL_SSL="gcrypt"
+                                       AC_CHECK_HEADER([gnutls.h], [
+                                               AC_CHECK_HEADER([gcrypt.h], [
+                                                       AC_DEFINE([PHP_HTTP_HAVE_GNUTLS], [1], [ ])
+                                                       CURL_SSL_LIBS=(gnutls gcrypt)
+                                               ])
                                        ])
                                ], [
                                        AC_MSG_RESULT([no])
@@ -248,17 +252,40 @@ dnl ----
                        else
                                AC_MSG_RESULT([no])
                        fi
+                       
+                       AC_MSG_CHECKING([for ares support in libcurl])
+                       AC_TRY_RUN([
+                               #include <curl/curl.h>
+                               int main(int argc, char *argv[]) {
+                                       curl_version_info_data *data = curl_version_info(CURLVERSION_NOW);
+                                       if (data && data->ares && data->ares_num0) {
+                                               return 0;
+                                       }
+                                       return 1;
+                               }
+                       ], [
+                               AC_MSG_RESULT([yes])
+                               AC_DEFINE([PHP_HTTP_HAVE_ARES], [1], [ ])
+                       ], [
+                               AC_MSG_RESULT([no])
+                       ], [
+                               AC_MSG_RESULT([no])
+                       ])
                
                        INCLUDES="$save_INCLUDES"
                        LIBS="$save_LIBS"
                        CFLAGS="$save_CFLAGS"
                        LDFLAGS="$save_LDFLAGS"
-               
+                       
+                       for CURL_SSL_LIB in "${CURL_SSL_LIBS[[@]]}"; do
+                               PHP_ADD_LIBRARY_WITH_PATH([$CURL_SSL_LIB], $CURL_DIR/$PHP_LIBDIR, PHP_HTTP_SHARED_LIBADD)
+                       done
+                       
                        dnl end compile tests
                
                        AC_MSG_CHECKING([for bundled SSL CA info])
                        CURL_CAINFO=
-                       for i in `$CURL_CONFIG --ca` "/etc/ssl/certs/ca-certificates.crt"; do
+                       for i in `$CURL_CONFIG --ca` "/etc/ssl/certs/ca-certificates.crt" "/etc/ssl/certs/ca-bundle.crt"; do
                                if test -f "$i"; then
                                        CURL_CAINFO="$i"
                                        break
@@ -274,9 +301,6 @@ dnl ----
                        PHP_ADD_INCLUDE($CURL_DIR/include)
                        PHP_ADD_LIBRARY_WITH_PATH(curl, $CURL_DIR/$PHP_LIBDIR, HTTP_SHARED_LIBADD)
                        PHP_EVAL_LIBLINE(`$CURL_CONFIG --libs`, HTTP_SHARED_LIBADD)
-                       if test "x$CURL_SSL" != "x"; then
-                               PHP_ADD_LIBRARY_WITH_PATH([$CURL_SSL], $CURL_DIR/$PHP_LIBDIR, PHP_HTTP_SHARED_LIBADD)
-                       fi
                        AC_DEFINE([PHP_HTTP_HAVE_CURL], [1], [Have libcurl support])
                        HTTP_HAVE_A_REQUEST_LIB=true
                fi
@@ -289,50 +313,45 @@ dnl ----
        if test "$PHP_HTTP_LIBEVENT_DIR" = "no"; then
                AC_DEFINE([PHP_HTTP_HAVE_EVENT], [0], [ ])
        else
-               HTTP_HAVE_PHP_EXT([event], [
-                       AC_MSG_WARN([event support is incompatible with pecl/event; continuing without libevent support])
+               AC_MSG_CHECKING([for event2/event.h])
+               EVENT_DIR=
+               for i in "$PHP_HTTP_LIBEVENT_DIR" /usr/local /usr /opt; do
+                       if test -f "$i/include/event.h"; then
+                               EVENT_DIR=$i
+                               break
+                       fi
+               done
+               if test "x$EVENT_DIR" = "x"; then
+                       AC_MSG_RESULT([not found])
+                       AC_MSG_WARN([continuing without libevent support])
                        AC_DEFINE([PHP_HTTP_HAVE_EVENT], [0], [ ])
-               ], [
-                       AC_MSG_CHECKING([for event2/event.h])
-                       EVENT_DIR=
-                       for i in "$PHP_HTTP_LIBEVENT_DIR" /usr/local /usr /opt; do
-                               if test -f "$i/include/event.h"; then
-                                       EVENT_DIR=$i
-                                       break
-                               fi
-                       done
-                       if test "x$EVENT_DIR" = "x"; then
-                               AC_MSG_RESULT([not found])
-                               AC_MSG_WARN([continuing without libevent support])
-                               AC_DEFINE([PHP_HTTP_HAVE_EVENT], [0], [ ])
+               else
+                       AC_MSG_RESULT([found in $EVENT_DIR])
+                       
+                       AC_MSG_CHECKING([for libevent version, roughly])
+                       
+                       if test -f "$EVENT_DIR/include/event2/event.h"; then
+                               EVENT_VER="`$AWK '/_EVENT_VERSION/ {gsub(/\"/,\"\",$3); print $3}' < $EVENT_DIR/include/event2/event-config.h`"
+                               AC_DEFINE([PHP_HTTP_HAVE_EVENT2], [1], [ ])
                        else
-                               AC_MSG_RESULT([found in $EVENT_DIR])
-                               
-                               AC_MSG_CHECKING([for libevent version, roughly])
-                               
-                               if test -f "$EVENT_DIR/include/event2/event.h"; then
-                                       EVENT_VER="`$EGREP _EVENT_VERSION $EVENT_DIR/include/event2/event-config.h | $AWK '{print $3}'`"
-                                       AC_DEFINE([PHP_HTTP_HAVE_EVENT2], [1], [ ])
-                               else
-                                       AC_DEFINE([PHP_HTTP_HAVE_EVENT2], [0], [ ])
-                                       if test -f "$EVENT_DIR/include/evhttp.h" && test -f "$EVENT_DIR/include/evdns.h"; then
-                                               if test -f "$EVENT_DIR/include/evrpc.h"; then
-                                                       EVENT_VER="1.4 or greater"
-                                               else
-                                                       EVENT_VER="1.2 or greater"
-                                               fi
+                               AC_DEFINE([PHP_HTTP_HAVE_EVENT2], [0], [ ])
+                               if test -f "$EVENT_DIR/include/evhttp.h" && test -f "$EVENT_DIR/include/evdns.h"; then
+                                       if test -f "$EVENT_DIR/include/evrpc.h"; then
+                                               EVENT_VER="1.4 or greater"
                                        else
-                                               EVENT_VER="1.1b or lower"
+                                               EVENT_VER="1.2 or greater"
                                        fi
+                               else
+                                       EVENT_VER="1.1b or lower"
                                fi
-                               AC_DEFINE_UNQUOTED([PHP_HTTP_EVENT_VERSION], ["$EVENT_VER"], [ ])
-                               AC_MSG_RESULT([$EVENT_VER])
-                               
-                               PHP_ADD_INCLUDE($EVENT_DIR/include)
-                               PHP_ADD_LIBRARY_WITH_PATH(event, $EVENT_DIR/$PHP_LIBDIR, HTTP_SHARED_LIBADD)
-                               AC_DEFINE([PHP_HTTP_HAVE_EVENT], [1], [Have libevent support for cURL])
                        fi
-               ])
+                       AC_DEFINE_UNQUOTED([PHP_HTTP_EVENT_VERSION], ["$EVENT_VER"], [ ])
+                       AC_MSG_RESULT([$EVENT_VER])
+                       
+                       PHP_ADD_INCLUDE($EVENT_DIR/include)
+                       PHP_ADD_LIBRARY_WITH_PATH(event, $EVENT_DIR/$PHP_LIBDIR, HTTP_SHARED_LIBADD)
+                       AC_DEFINE([PHP_HTTP_HAVE_EVENT], [1], [Have libevent support for cURL])
+               fi
        fi
 
 dnl ----
@@ -359,6 +378,8 @@ dnl ----
                        AC_DEFINE([PHP_HTTP_HAVE_PHP_RAPHF_H], [1], [Have ext/raphf support])
                        PHP_ADD_INCLUDE([$HTTP_EXT_RAPHF_INCDIR])
                fi
+       ], [
+               AC_MSG_ERROR([Please install pecl/raphf])
        ])
 
 dnl ----
@@ -385,6 +406,8 @@ dnl ----
                        AC_DEFINE([PHP_HTTP_HAVE_PHP_PROPRO_H], [1], [Have ext/propro support])
                        PHP_ADD_INCLUDE([$HTTP_EXT_PROPRO_INCDIR])
                fi
+       ], [
+               AC_MSG_ERROR([Please install pecl/propro])
        ])
 
 PHP_ARG_WITH([http-shared-deps], [whether to depend on extensions which have been built shared],
index fea14bb..0e8dfa1 100644 (file)
@@ -40,7 +40,7 @@ $ifdefs = array(
     'LOCAL_IP' => 'PHP_HTTP_CURL_VERSION(7,21,0)',
 );
 $exclude = array(
-    'PRIVATE', 'LASTSOCKET', 'FTP_ENTRY_PATH', 'CERTINFO',
+    'PRIVATE', 'LASTSOCKET', 'FTP_ENTRY_PATH', 'CERTINFO', 'TLS_SESSION',
     'RTSP_SESSION_ID', 'RTSP_CLIENT_CSEQ', 'RTSP_SERVER_CSEQ', 'RTSP_CSEQ_RECV'
 );
 
@@ -91,8 +91,8 @@ foreach ($infos as $info) {
        if (isset($ifdefs[$short])) printf("#endif\n");
 }
 
-file_put_contents("php_http_curl_client.c", 
+file_put_contents("php_http_client_curl.c", 
        preg_replace('/(\/\* BEGIN::CURLINFO \*\/\n).*(\n\s*\/\* END::CURLINFO \*\/)/s', '$1'. ob_get_contents() .'$2',
-               file_get_contents("php_http_curl_client.c")));
+               file_get_contents("php_http_client_curl.c")));
 
 ?>
index 5467a83..bd7b579 100644 (file)
@@ -19,8 +19,17 @@ means for negotiation of a client's preferred content type,
 language and charset, as well as a convenient way to send any 
 arbitrary data with caching and resuming capabilities.
 
-It provides powerful request functionality, if built with CURL 
-support. Parallel requests are available for PHP 5 and greater.
+It provides powerful request functionality with support for
+parallel requests.
+
+Documentation:
+v1: http://php.net/http
+v2: http://devel-m6w6.rhcloud.com/mdref/http
+
+Code Coverage:
+v1: http://dev.iworks.at/ext-http/lcov_html/ext/http/
+v2: http://dev.iworks.at/ext-http/lcov/ext/http/
+
 ]]></description>
  <lead>
   <name>Michael Wallner</name>
@@ -28,30 +37,24 @@ support. Parallel requests are available for PHP 5 and greater.
   <email>mike@php.net</email>
   <active>yes</active>
  </lead>
- <date>2013-08-12</date>
+ <date>2014-08-05</date>
  <version>
-  <release>2.0.0RC1</release>
-  <api>2.0.0</api>
+  <release>2.1.0dev</release>
+  <api>2.1.0</api>
  </version>
  <stability>
   <release>beta</release>
-  <api>beta</api>
+  <api>stable</api>
  </stability>
  <license>BSD, revised</license>
  <notes><![CDATA[
-Extended HTTP support. Again. Keep in mind that it's got the major version 2, because it's incompatible with pecl_http v1.
-
-Documentation:
-http://devel-m6w6.rhcloud.com/mdref/http
-
-Code Coverage:
-http://dev.iworks.at/ext-http/lcov/ext/http/
-
+Changes from RC2:
 ]]></notes>
  <contents>
   <dir name="/">
    <file role="doc" name="LICENSE"/>
    <file role="doc" name="CREDITS"/>
+   <file role="doc" name="Exceptions.txt"/>
    <file role="doc" name="KnownIssues.txt"/>
    <file role="doc" name="ThanksTo.txt"/>
    <file role="src" name="config.m4"/>
@@ -131,6 +134,7 @@ http://dev.iworks.at/ext-http/lcov/ext/http/
      <file role="test" name="urls.txt"/>
     </dir>
      <file role="test" name="bug61444.phpt"/>
+     <file role="test" name="bug66388.phpt"/>
      <file role="test" name="client001.phpt"/>
      <file role="test" name="client002.phpt"/>
      <file role="test" name="client003.phpt"/>
@@ -144,6 +148,7 @@ http://dev.iworks.at/ext-http/lcov/ext/http/
      <file role="test" name="client011.phpt"/>
      <file role="test" name="client012.phpt"/>
      <file role="test" name="client013.phpt"/>
+     <file role="test" name="client014.phpt"/>
      <file role="test" name="clientrequest001.phpt"/>
      <file role="test" name="clientrequest002.phpt"/>
      <file role="test" name="clientrequest003.phpt"/>
@@ -151,6 +156,27 @@ http://dev.iworks.at/ext-http/lcov/ext/http/
      <file role="test" name="clientresponse001.phpt"/>
      <file role="test" name="clientresponse002.phpt"/>
      <file role="test" name="clientresponse003.phpt"/>
+     <file role="test" name="cookie001.phpt"/>
+     <file role="test" name="cookie002.phpt"/>
+     <file role="test" name="cookie003.phpt"/>
+     <file role="test" name="cookie004.phpt"/>
+     <file role="test" name="cookie005.phpt"/>
+     <file role="test" name="cookie006.phpt"/>
+     <file role="test" name="cookie007.phpt"/>
+     <file role="test" name="cookie008.phpt"/>
+     <file role="test" name="cookie009.phpt"/>
+     <file role="test" name="cookie010.phpt"/>
+     <file role="test" name="cookie011.phpt"/>
+     <file role="test" name="cookie012.phpt"/>
+     <file role="test" name="encstream001.phpt"/>
+     <file role="test" name="encstream002.phpt"/>
+     <file role="test" name="encstream003.phpt"/>
+     <file role="test" name="encstream004.phpt"/>
+     <file role="test" name="encstream005.phpt"/>
+     <file role="test" name="encstream006.phpt"/>
+     <file role="test" name="encstream007.phpt"/>
+     <file role="test" name="encstream008.phpt"/>
+     <file role="test" name="encstream009.phpt"/>
      <file role="test" name="envrequestbody001.phpt"/>
      <file role="test" name="envrequestbody002.phpt"/>
      <file role="test" name="envrequestbody003.phpt"/>
@@ -175,6 +201,8 @@ http://dev.iworks.at/ext-http/lcov/ext/http/
      <file role="test" name="envresponse012.phpt"/>
      <file role="test" name="envresponse013.phpt"/>
      <file role="test" name="envresponse014.phpt"/>
+     <file role="test" name="envresponse015.phpt"/>
+     <file role="test" name="envresponse016.phpt"/>
      <file role="test" name="envresponsebody001.phpt"/>
      <file role="test" name="envresponsebody002.phpt"/>
      <file role="test" name="envresponsecodes.phpt"/>
@@ -209,24 +237,43 @@ http://dev.iworks.at/ext-http/lcov/ext/http/
      <file role="test" name="message013.phpt"/>
      <file role="test" name="message014.phpt"/>
      <file role="test" name="message015.phpt"/>
+     <file role="test" name="messagebody001.phpt"/>
+     <file role="test" name="messagebody002.phpt"/>
+     <file role="test" name="messagebody003.phpt"/>
+     <file role="test" name="messagebody004.phpt"/>
+     <file role="test" name="messagebody005.phpt"/>
+     <file role="test" name="messagebody006.phpt"/>
+     <file role="test" name="messagebody007.phpt"/>
+     <file role="test" name="messagebody008.phpt"/>
+     <file role="test" name="messagebody009.phpt"/>
+     <file role="test" name="messagebody010.phpt"/>
      <file role="test" name="negotiate001.phpt"/>
      <file role="test" name="params001.phpt"/>
      <file role="test" name="params002.phpt"/>
-     <file role="test" name="phpunit.phpt"/>
+     <file role="test" name="params003.phpt"/>
+     <file role="test" name="params004.phpt"/>
+     <file role="test" name="params005.phpt"/>
+     <file role="test" name="params006.phpt"/>
+     <file role="test" name="params007.phpt"/>
+     <file role="test" name="params008.phpt"/>
+     <file role="test" name="params009.phpt"/>
+     <file role="test" name="params010.phpt"/>
+     <file role="test" name="params011.phpt"/>
+     <file role="test" name="params012.phpt"/>
+     <file role="test" name="params013.phpt"/>
+     <file role="test" name="params014.phpt"/>
+     <file role="test" name="params015.phpt"/>
      <file role="test" name="propertyproxy001.phpt"/>
-     <file role="test" name="querystring_001.phpt"/>
+     <file role="test" name="querystring001.phpt"/>
+     <file role="test" name="querystring002.phpt"/>
      <file role="test" name="serialize001.phpt"/>
+     <file role="test" name="url002.phpt"/>
+     <file role="test" name="url003.phpt"/>
+     <file role="test" name="url004.phpt"/>
+     <file role="test" name="url005.phpt"/>
      <file role="test" name="url001.phpt"/>
      <file role="test" name="version001.phpt"/>
    </dir>
-   <dir name="phpunit">
-    <file role="test" name="CookieTest.php"/>
-    <file role="test" name="EncodingTest.php"/>
-    <file role="test" name="MessageBodyTest.php"/>
-    <file role="test" name="ParamsTest.php"/>
-    <file role="test" name="QueryStringTest.php"/>
-    <file role="test" name="UrlTest.php"/>
-   </dir>
   </dir>
  </contents>
  <dependencies>
@@ -240,13 +287,13 @@ http://dev.iworks.at/ext-http/lcov/ext/http/
    <package>
     <name>raphf</name>
     <channel>pecl.php.net</channel>
-    <min>0.1.0</min>
+    <min>1.0.0</min>
     <providesextension>raphf</providesextension>
    </package>
    <package>
     <name>propro</name>
     <channel>pecl.php.net</channel>
-    <min>0.1.0</min>
+    <min>1.0.0</min>
     <providesextension>propro</providesextension>
    </package>
   </required>
@@ -273,11 +320,6 @@ http://dev.iworks.at/ext-http/lcov/ext/http/
    name="with-http-libevent-dir"
    prompt="where to find libevent"
    default="/usr" />
-  <filelist>
-   <!-- install as="http.ini" name="docs/http.ini"/>
-   <install as="examples/tutorial.txt" name="docs/examples/tutorial.txt"/>
-   <install as="pecl/http/.php" name="lib/.php"/ -->
-  </filelist>
  </extsrcrelease>
  <changelog />
 </package>
index 2ed94c8..2101f0b 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
 #if PHP_HTTP_HAVE_CURL
 #      include <curl/curl.h>
 #      if PHP_HTTP_HAVE_EVENT
-#              include <event.h>
+#              if PHP_HTTP_HAVE_EVENT2
+#                      include <event2/event.h>
+#                      include <event2/event_struct.h>
+#              else
+#                      include <event.h>
+#              endif
 #      endif
 #endif
 #if PHP_HTTP_HAVE_SERF
@@ -55,9 +60,6 @@ static zend_module_dep http_module_deps[] = {
 #endif
 #ifdef PHP_HTTP_HAVE_JSON
        ZEND_MOD_REQUIRED("json")
-#endif
-#ifdef PHP_HTTP_HAVE_EVENT
-       ZEND_MOD_CONFLICTS("event")
 #endif
        {NULL, NULL, NULL, 0}
 };
@@ -73,7 +75,7 @@ zend_module_entry http_module_entry = {
        PHP_RINIT(http),
        PHP_RSHUTDOWN(http),
        PHP_MINFO(http),
-       PHP_HTTP_EXT_VERSION,
+       PHP_PECL_HTTP_VERSION,
        STANDARD_MODULE_PROPERTIES
 };
 
@@ -217,7 +219,7 @@ PHP_MINFO_FUNCTION(http)
 
        php_info_print_table_start();
        php_info_print_table_header(2, "HTTP Support", "enabled");
-       php_info_print_table_row(2, "Extension Version", PHP_HTTP_EXT_VERSION);
+       php_info_print_table_row(2, "Extension Version", PHP_PECL_HTTP_VERSION);
        php_info_print_table_end();
        
        php_info_print_table_start();
index 8e341ca..a911044 100644 (file)
@@ -6,14 +6,14 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
 #ifndef PHP_EXT_HTTP_H
 #define PHP_EXT_HTTP_H
 
-#define PHP_HTTP_EXT_VERSION "2.0.0dev"
+#define PHP_PECL_HTTP_VERSION "2.1.0dev"
 
 extern zend_module_entry http_module_entry;
 #define phpext_http_ptr &http_module_entry
index 42d34fc..9e0dc6c 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
index 84272d0..8ccee08 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
@@ -103,7 +103,7 @@ PHP_HTTP_BUFFER_API size_t php_http_buffer_shrink(php_http_buffer_t *buf)
 
 PHP_HTTP_BUFFER_API size_t php_http_buffer_append(php_http_buffer_t *buf, const char *append, size_t append_len)
 {
-       if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_resize(buf, append_len)) {
+       if (buf->free < append_len && PHP_HTTP_BUFFER_NOMEM == php_http_buffer_resize(buf, append_len)) {
                return PHP_HTTP_BUFFER_NOMEM;
        }
        memcpy(buf->data + buf->used, append, append_len);
@@ -160,7 +160,7 @@ PHP_HTTP_BUFFER_API size_t php_http_buffer_cut(php_http_buffer_t *buf, size_t of
 
 PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_fix(php_http_buffer_t *buf)
 {
-       if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_resize_ex(buf, 1, 1, 0)) {
+       if (buf->free < 1 && PHP_HTTP_BUFFER_NOMEM == php_http_buffer_resize_ex(buf, 1, 1, 0)) {
                return NULL;
        }
        buf->data[buf->used] = '\0';
@@ -222,13 +222,17 @@ PHP_HTTP_BUFFER_API size_t php_http_buffer_chunk_buffer(php_http_buffer_t **s, c
        return 0;
 }
 
-PHP_HTTP_BUFFER_API void php_http_buffer_chunked_output(php_http_buffer_t **s, const char *data, size_t data_len, size_t chunk_len, php_http_buffer_pass_func_t passout, void *opaque TSRMLS_DC)
+PHP_HTTP_BUFFER_API size_t php_http_buffer_chunked_output(php_http_buffer_t **s, const char *data, size_t data_len, size_t chunk_len, php_http_buffer_pass_func_t passout, void *opaque TSRMLS_DC)
 {
        char *chunk = NULL;
-       size_t got = 0;
+       size_t passed = 0, got = 0;
 
        while ((got = php_http_buffer_chunk_buffer(s, data, data_len, &chunk, chunk_len))) {
-               passout(opaque, chunk, got TSRMLS_CC);
+               if (PHP_HTTP_BUFFER_PASS0 == passout(opaque, chunk, got TSRMLS_CC)) {
+                       STR_SET(chunk, NULL);
+                       return PHP_HTTP_BUFFER_PASS0;
+               }
+               ++passed;
                if (!chunk_len) {
                        /*      we already got the last chunk,
                                and freed all resources */
@@ -239,6 +243,7 @@ PHP_HTTP_BUFFER_API void php_http_buffer_chunked_output(php_http_buffer_t **s, c
                STR_SET(chunk, NULL);
        }
        STR_FREE(chunk);
+       return passed;
 }
 
 PHP_HTTP_BUFFER_API ssize_t php_http_buffer_passthru(php_http_buffer_t **s, size_t chunk_size, php_http_buffer_pass_func_t passin, void *passin_arg, php_http_buffer_pass_func_t passon, void *passon_arg TSRMLS_DC)
index 8ee4eae..cf9b458 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
@@ -191,7 +191,7 @@ typedef size_t (*php_http_buffer_pass_func_t)(void *opaque, char *, size_t TSRML
 PHP_HTTP_BUFFER_API ssize_t php_http_buffer_passthru(php_http_buffer_t **s, size_t chunk_size, php_http_buffer_pass_func_t passin, void *passin_arg, php_http_buffer_pass_func_t passon, void *passon_arg TSRMLS_DC);
 
 /* wrapper around php_http_buffer_chunk_buffer, which passes available chunks to passthru() */
-PHP_HTTP_BUFFER_API void php_http_buffer_chunked_output(php_http_buffer_t **s, const char *data, size_t data_len, size_t chunk_size, php_http_buffer_pass_func_t passout, void *opaque TSRMLS_DC);
+PHP_HTTP_BUFFER_API size_t php_http_buffer_chunked_output(php_http_buffer_t **s, const char *data, size_t data_len, size_t chunk_size, php_http_buffer_pass_func_t passout, void *opaque TSRMLS_DC);
 
 /* write chunks directly into php_http_buffer_t buffer */
 PHP_HTTP_BUFFER_API size_t php_http_buffer_chunked_input(php_http_buffer_t **s, size_t chunk_size, php_http_buffer_pass_func_t passin, void *opaque TSRMLS_DC);
index 6dced66..f96164b 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
@@ -377,6 +377,7 @@ static void handle_history(zval *zclient, php_http_message_t *request, php_http_
 
 static STATUS handle_response(void *arg, php_http_client_t *client, php_http_client_enqueue_t *e, php_http_message_t **request, php_http_message_t **response)
 {
+       zend_bool dequeue = 0;
        zval zclient;
        php_http_message_t *msg;
        php_http_client_progress_state_t *progress;
@@ -390,7 +391,10 @@ static STATUS handle_response(void *arg, php_http_client_t *client, php_http_cli
                zval *info, *zresponse, *zrequest;
                HashTable *info_ht;
 
-               if (i_zend_is_true(zend_read_property(php_http_client_class_entry, &zclient, ZEND_STRL("recordHistory"), 0 TSRMLS_CC))) {
+               /* ensure the message is of type response (could be uninitialized in case of early error, like DNS) */
+               php_http_message_set_type(msg, PHP_HTTP_RESPONSE);
+
+               if (z_is_true(zend_read_property(php_http_client_class_entry, &zclient, ZEND_STRL("recordHistory"), 0 TSRMLS_CC))) {
                        handle_history(&zclient, *request, *response TSRMLS_CC);
                }
 
@@ -427,8 +431,8 @@ static STATUS handle_response(void *arg, php_http_client_t *client, php_http_cli
                        zend_fcall_info_argn(&e->closure.fci TSRMLS_CC, 0);
 
                        if (retval) {
-                               if (Z_TYPE_P(retval) == IS_BOOL && Z_BVAL_P(retval)) {
-                                       php_http_client_dequeue(client, e->request);
+                               if (Z_TYPE_P(retval) == IS_BOOL) {
+                                       dequeue = Z_BVAL_P(retval);
                                }
                                zval_ptr_dtor(&retval);
                        }
@@ -444,6 +448,10 @@ static STATUS handle_response(void *arg, php_http_client_t *client, php_http_cli
                client->callback.progress.func(client->callback.progress.arg, client, e, progress);
        }
 
+       if (dequeue) {
+               php_http_client_dequeue(client, e->request);
+       }
+
        return SUCCESS;
 }
 
@@ -720,7 +728,9 @@ ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_count, 0, 0, 0)
 ZEND_END_ARG_INFO();
 static PHP_METHOD(HttpClient, count)
 {
-       if (SUCCESS == zend_parse_parameters_none()) {
+       long count_mode = -1;
+
+       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &count_mode)) {
                php_http_client_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
 
                RETVAL_LONG(zend_llist_count(&obj->client->requests));
index 9bc5295..6c45516 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
index fbb950a..baf99ce 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
 #if PHP_HTTP_HAVE_CURL
 
 #if PHP_HTTP_HAVE_EVENT
-#      include <event.h>
 #      if !PHP_HTTP_HAVE_EVENT2 && /* just be really sure */ !(LIBEVENT_VERSION_NUMBER >= 0x02000000)
+#              include <event.h>
 #              define event_base_new event_init
 #              define event_assign(e, b, s, a, cb, d) do {\
                        event_set(e, s, a, cb, d); \
                        event_base_set(b, e); \
                } while(0)
+#      else
+#              if PHP_HTTP_HAVE_EVENT2
+#                      include <event2/event.h>
+#                      include <event2/event_struct.h>
+#              else
+#                      error "libevent presence is unknown"
+#              endif
 #      endif
 #      ifndef DBG_EVENTS
 #              define DBG_EVENTS 0
 #      endif
 #endif
 
+#ifdef PHP_HTTP_HAVE_OPENSSL
+#      include <openssl/ssl.h>
+#endif
+#ifdef PHP_HTTP_HAVE_GNUTLS
+#      include <gnutls.h>
+#endif
+
 typedef struct php_http_client_curl {
        CURLM *handle;
 
@@ -169,14 +183,22 @@ static size_t php_http_curle_read_callback(void *data, size_t len, size_t n, voi
 {
        php_http_message_body_t *body = ctx;
 
-       if (body) {
-               TSRMLS_FETCH_FROM_CTX(body->ts);
-               return php_stream_read(php_http_message_body_stream(body), data, len * n);
+       if (body && body->stream_id) {
+               php_stream *s = php_http_message_body_stream(body);
+
+               if (s) {
+                       TSRMLS_FETCH_FROM_CTX(body->ts);
+                       return php_stream_read(s, data, len * n);
+               } else abort();
        }
        return 0;
 }
 
+#if PHP_HTTP_CURL_VERSION(7,32,0)
+static int php_http_curle_xferinfo_callback(void *ctx, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow)
+#else
 static int php_http_curle_progress_callback(void *ctx, double dltotal, double dlnow, double ultotal, double ulnow)
+#endif
 {
        php_http_client_curl_handler_t *h = ctx;
        zend_bool update = 0;
@@ -247,6 +269,8 @@ static int php_http_curle_raw_callback(CURL *ch, curl_infotype type, char *data,
                                h->progress.info = "blacklist check";
                        } else if (php_memnstr(data, ZEND_STRL("SSL"), data + length)) {
                                h->progress.info = "ssl negotiation";
+                       } 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)) {
                                h->progress.info = "not disconnected";
                        } else if (php_memnstr(data, ZEND_STRL("closed"), data + length)) {
@@ -258,6 +282,7 @@ static int php_http_curle_raw_callback(CURL *ch, curl_infotype type, char *data,
                        } else {
 #if PHP_DEBUG
                                h->progress.info = data;
+                               data[length - 1] = '\0';
 #endif
                        }
                        if (h->client->callback.progress.func) {
@@ -460,6 +485,87 @@ static STATUS php_http_curle_get_info(CURL *ch, HashTable *info)
 
        /* END::CURLINFO */
 
+#if PHP_HTTP_CURL_VERSION(7,34,0)
+       {
+               int i;
+               zval *ti_array;
+               struct curl_tlssessioninfo *ti;
+
+               if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_TLS_SESSION, &ti)) {
+                       const char *backend;
+
+                       MAKE_STD_ZVAL(subarray);
+                       ZVAL_NULL(subarray);
+                       MAKE_STD_ZVAL(ti_array);
+                       array_init(ti_array);
+
+                       switch (ti->backend) {
+                       case CURLSSLBACKEND_NONE:
+                               backend = "none";
+                               break;
+                       case CURLSSLBACKEND_OPENSSL:
+                               backend = "openssl";
+#ifdef PHP_HTTP_HAVE_OPENSSL
+                               {
+                                       SSL_CTX *ctx = ti->internals;
+
+                                       array_init(subarray);
+                                       add_assoc_long_ex(subarray, ZEND_STRS("number"), SSL_CTX_sess_number(ctx));
+                                       add_assoc_long_ex(subarray, ZEND_STRS("connect"), SSL_CTX_sess_connect(ctx));
+                                       add_assoc_long_ex(subarray, ZEND_STRS("connect_good"), SSL_CTX_sess_connect_good(ctx));
+                                       add_assoc_long_ex(subarray, ZEND_STRS("connect_renegotiate"), SSL_CTX_sess_connect_renegotiate(ctx));
+                                       add_assoc_long_ex(subarray, ZEND_STRS("hits"), SSL_CTX_sess_hits(ctx));
+                                       add_assoc_long_ex(subarray, ZEND_STRS("cache_full"), SSL_CTX_sess_cache_full(ctx));
+                               }
+#endif
+                               break;
+                       case CURLSSLBACKEND_GNUTLS:
+                               backend = "gnutls";
+#ifdef PHP_HTTP_HAVE_GNUTLS
+                               {
+                                       gnutls_session_t sess = ti->internals;
+                                       char *desc;
+
+                                       array_init(subarray);
+                                       if ((desc = gnutls_session_get_desc(sess))) {
+                                               add_assoc_string_ex(subarray, ZEND_STRS("desc"), desc, 1);
+                                               gnutls_free(desc);
+                                       }
+                                       add_assoc_bool_ex(subarray, ZEND_STRS("resumed"), gnutls_session_is_resumed(sess));
+                               }
+#endif
+                               break;
+                       case CURLSSLBACKEND_NSS:
+                               backend = "nss";
+                               break;
+                       case CURLSSLBACKEND_QSOSSL:
+                               backend = "qsossl";
+                               break;
+                       case CURLSSLBACKEND_GSKIT:
+                               backend = "gskit";
+                               break;
+                       case CURLSSLBACKEND_POLARSSL:
+                               backend = "polarssl";
+                               break;
+                       case CURLSSLBACKEND_CYASSL:
+                               backend = "cyassl";
+                               break;
+                       case CURLSSLBACKEND_SCHANNEL:
+                               backend = "schannel";
+                               break;
+                       case CURLSSLBACKEND_DARWINSSL:
+                               backend = "darwinssl";
+                               break;
+                       default:
+                               backend = "unknown";
+                       }
+                       add_assoc_string_ex(ti_array, ZEND_STRS("backend"), estrdup(backend), 0);
+                       add_assoc_zval_ex(ti_array, ZEND_STRS("internals"), subarray);
+                       add_assoc_zval_ex(&array, "tls_session", sizeof("tls_session"), ti_array);
+               }
+       }
+#endif
+
 #if PHP_HTTP_CURL_VERSION(7,19,1) && defined(PHP_HTTP_HAVE_OPENSSL)
        {
                int i;
@@ -690,9 +796,9 @@ static void php_http_curlm_timer_callback(CURLM *multi, long timeout_ms, void *t
 
 static php_http_options_t php_http_curle_options;
 
-#define PHP_HTTP_CURLE_OPTION_CHECK_STRLEN     0x0001
-#define PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR    0x0002
-#define PHP_HTTP_CURLE_OPTION_TRANSFORM_MS     0x0004
+#define PHP_HTTP_CURLE_OPTION_CHECK_STRLEN             0x0001
+#define PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR            0x0002
+#define PHP_HTTP_CURLE_OPTION_TRANSFORM_MS             0x0004
 
 static STATUS php_http_curle_option_set_ssl_verifyhost(php_http_option_t *opt, zval *val, void *userdata)
 {
@@ -709,19 +815,20 @@ static STATUS php_http_curle_option_set_cookiestore(php_http_option_t *opt, zval
 {
        php_http_client_curl_handler_t *curl = userdata;
        CURL *ch = curl->handle;
+       php_http_curle_storage_t *storage = php_http_curle_get_storage(curl->handle);
 
-       if (val) {
-               php_http_curle_storage_t *storage = php_http_curle_get_storage(curl->handle);
-
-               if (storage->cookiestore) {
-                       pefree(storage->cookiestore, 1);
-               }
+       if (storage->cookiestore) {
+               pefree(storage->cookiestore, 1);
+       }
+       if (val && Z_STRLEN_P(val)) {
                storage->cookiestore = pestrndup(Z_STRVAL_P(val), Z_STRLEN_P(val), 1);
-               if (    CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIEFILE, storage->cookiestore)
-                       ||      CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIEJAR, storage->cookiestore)
-               ) {
-                       return FAILURE;
-               }
+       } else {
+               storage->cookiestore = NULL;
+       }
+       if (    CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIEFILE, storage->cookiestore)
+               ||      CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIEJAR, storage->cookiestore)
+       ) {
+               return FAILURE;
        }
        return SUCCESS;
 }
@@ -764,6 +871,11 @@ static STATUS php_http_curle_option_set_cookies(php_http_option_t *opt, zval *va
                                }
                        }
                }
+       } else {
+               php_http_buffer_reset(&curl->options.cookies);
+               if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIE, NULL)) {
+                       return FAILURE;
+               }
        }
        return SUCCESS;
 }
@@ -819,13 +931,15 @@ static STATUS php_http_curle_option_set_etag(php_http_option_t *opt, zval *val,
 {
        php_http_client_curl_handler_t *curl = userdata;
        php_http_buffer_t header;
-       zend_bool is_quoted = !((Z_STRVAL_P(val)[0] != '"') || (Z_STRVAL_P(val)[Z_STRLEN_P(val)-1] != '"'));
 
-       php_http_buffer_init(&header);
-       php_http_buffer_appendf(&header, is_quoted?"%s: %s":"%s: \"%s\"", curl->options.range_request?"If-Match":"If-None-Match", Z_STRVAL_P(val));
-       php_http_buffer_fix(&header);
-       curl->options.headers = curl_slist_append(curl->options.headers, header.data);
-       php_http_buffer_dtor(&header);
+       if (Z_STRLEN_P(val)) {
+               zend_bool is_quoted = !((Z_STRVAL_P(val)[0] != '"') || (Z_STRVAL_P(val)[Z_STRLEN_P(val)-1] != '"'));
+               php_http_buffer_init(&header);
+               php_http_buffer_appendf(&header, is_quoted?"%s: %s":"%s: \"%s\"", curl->options.range_request?"If-Match":"If-None-Match", Z_STRVAL_P(val));
+               php_http_buffer_fix(&header);
+               curl->options.headers = curl_slist_append(curl->options.headers, header.data);
+               php_http_buffer_dtor(&header);
+       }
        return SUCCESS;
 }
 
@@ -1015,10 +1129,23 @@ static void php_http_curle_options_init(php_http_options_t *registry TSRMLS_DC)
                opt->setter = php_http_curle_option_set_resolve;
        }
 #endif
-#if PHP_HTTP_CURL_VERSION(7,24,0)
+#if PHP_HTTP_HAVE_ARES
+# if PHP_HTTP_CURL_VERSION(7,24,0)
        if ((opt = php_http_option_register(registry, ZEND_STRL("dns_servers"), CURLOPT_DNS_SERVERS, IS_STRING))) {
                opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
        }
+# endif
+# if PHP_HTTP_CURL_VERSION(7,33,0)
+       if ((opt = php_http_option_register(registry, ZEND_STRL("dns_interface"), CURLOPT_DNS_INTERFACE, IS_STRING))) {
+               opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
+       }
+       if ((opt = php_http_option_register(registry, ZEND_STRL("dns_local_ip4"), CURLOPT_DNS_LOCAL_IP4, IS_STRING))) {
+               opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
+       }
+       if ((opt = php_http_option_register(registry, ZEND_STRL("dns_local_ip6"), CURLOPT_DNS_LOCAL_IP6, IS_STRING))) {
+               opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
+       }
+# endif
 #endif
 
        /* limits */
@@ -1089,7 +1216,11 @@ static void php_http_curle_options_init(php_http_options_t *registry TSRMLS_DC)
        /* useragent */
        if ((opt = php_http_option_register(registry, ZEND_STRL("useragent"), CURLOPT_USERAGENT, IS_STRING))) {
                /* don't check strlen, to allow sending no useragent at all */
-               ZVAL_STRING(&opt->defval, "PECL::HTTP/" PHP_HTTP_EXT_VERSION " (PHP/" PHP_VERSION ")", 0);
+               ZVAL_STRING(&opt->defval,
+                               "PECL_HTTP/" PHP_PECL_HTTP_VERSION " "
+                               "PHP/" PHP_VERSION " "
+                               "libcurl/" LIBCURL_VERSION
+                       , 0);
        }
 
        /* resume */
@@ -1149,8 +1280,15 @@ static void php_http_curle_options_init(php_http_options_t *registry TSRMLS_DC)
                opt->flags |= PHP_HTTP_CURLE_OPTION_TRANSFORM_MS;
                Z_DVAL(opt->defval) = 3;
        }
+#if PHP_HTTP_CURL_VERSION(7,36,0)
+       if ((opt = php_http_option_register(registry, ZEND_STRL("expect_100_timeout"), CURLOPT_EXPECT_100_TIMEOUT_MS, IS_DOUBLE))) {
+               opt->flags |= PHP_HTTP_CURLE_OPTION_TRANSFORM_MS;
+               Z_DVAL(opt->defval) = 1;
+       }
+#endif
 
        /* tcp */
+       php_http_option_register(registry, ZEND_STRL("tcp_nodelay"), CURLOPT_TCP_NODELAY, IS_BOOL);
 #if PHP_HTTP_CURL_VERSION(7,25,0)
        php_http_option_register(registry, ZEND_STRL("tcp_keepalive"), CURLOPT_TCP_KEEPALIVE, IS_BOOL);
        if ((opt = php_http_option_register(registry, ZEND_STRL("tcp_keepidle"), CURLOPT_TCP_KEEPIDLE, IS_LONG))) {
@@ -1169,14 +1307,21 @@ static void php_http_curle_options_init(php_http_options_t *registry TSRMLS_DC)
                        opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
                        opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR;
                }
-               php_http_option_register(registry, ZEND_STRL("certtype"), CURLOPT_SSLCERTTYPE, IS_STRING);
-
+               if ((opt = php_http_option_register(registry, ZEND_STRL("certtype"), CURLOPT_SSLCERTTYPE, IS_STRING))) {
+                       opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
+                       ZVAL_STRING(&opt->defval, "PEM", 0);
+               }
                if ((opt = php_http_option_register(registry, ZEND_STRL("key"), CURLOPT_SSLKEY, IS_STRING))) {
                        opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
                        opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR;
                }
-               php_http_option_register(registry, ZEND_STRL("keytype"), CURLOPT_SSLKEYTYPE, IS_STRING);
-               php_http_option_register(registry, ZEND_STRL("keypasswd"), CURLOPT_SSLKEYPASSWD, IS_STRING);
+               if ((opt = php_http_option_register(registry, ZEND_STRL("keytype"), CURLOPT_SSLKEYTYPE, IS_STRING))) {
+                       opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
+                       ZVAL_STRING(&opt->defval, "PEM", 0);
+               }
+               if ((opt = php_http_option_register(registry, ZEND_STRL("keypasswd"), CURLOPT_SSLKEYPASSWD, IS_STRING))) {
+                       opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
+               }
                php_http_option_register(registry, ZEND_STRL("engine"), CURLOPT_SSLENGINE, IS_STRING);
                php_http_option_register(registry, ZEND_STRL("version"), CURLOPT_SSLVERSION, IS_LONG);
                if ((opt = php_http_option_register(registry, ZEND_STRL("verifypeer"), CURLOPT_SSL_VERIFYPEER, IS_BOOL))) {
@@ -1220,6 +1365,14 @@ static void php_http_curle_options_init(php_http_options_t *registry TSRMLS_DC)
 #endif
 #if PHP_HTTP_CURL_VERSION(7,19,1) && defined(PHP_HTTP_HAVE_OPENSSL)
                php_http_option_register(registry, ZEND_STRL("certinfo"), CURLOPT_CERTINFO, IS_BOOL);
+#endif
+#if PHP_HTTP_CURL_VERSION(7,36,0)
+               if ((opt = php_http_option_register(registry, ZEND_STRL("enable_npn"), CURLOPT_SSL_ENABLE_NPN, IS_BOOL))) {
+                       ZVAL_BOOL(&opt->defval, 1);
+               }
+               if ((opt = php_http_option_register(registry, ZEND_STRL("enable_alpn"), CURLOPT_SSL_ENABLE_ALPN, IS_BOOL))) {
+                       ZVAL_BOOL(&opt->defval, 1);
+               }
 #endif
        }
 }
@@ -1241,6 +1394,7 @@ static STATUS php_http_curle_set_option(php_http_option_t *opt, zval *val, void
        php_http_client_curl_handler_t *curl = userdata;
        CURL *ch = curl->handle;
        zval tmp;
+       CURLcode rc = CURLE_OK;
        STATUS rv = SUCCESS;
        TSRMLS_FETCH_FROM_CTX(curl->client->ts);
 
@@ -1266,14 +1420,18 @@ static STATUS php_http_curle_set_option(php_http_option_t *opt, zval *val, void
                break;
 
        case IS_STRING:
-               if (!(opt->flags & PHP_HTTP_CURLE_OPTION_CHECK_STRLEN) || Z_STRLEN_P(val)) {
-                       if (!(opt->flags & PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR) || !Z_STRVAL_P(val) || SUCCESS == php_check_open_basedir(Z_STRVAL_P(val) TSRMLS_CC)) {
-                               if (opt->setter) {
-                                       rv = opt->setter(opt, val, curl);
-                               } else if (CURLE_OK != curl_easy_setopt(ch, opt->option, Z_STRVAL_P(val))) {
-                                       rv = FAILURE;
-                               }
+               if (opt->setter) {
+                       rv = opt->setter(opt, val, curl);
+               } else if ((opt->flags & PHP_HTTP_CURLE_OPTION_CHECK_STRLEN) && !Z_STRLEN_P(val)) {
+                       if (CURLE_OK != (rc = curl_easy_setopt(ch, opt->option, NULL))) {
+                               rv = FAILURE;
                        }
+               } else if ((opt->flags & PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR) && Z_STRVAL_P(val) && SUCCESS != php_check_open_basedir(Z_STRVAL_P(val) TSRMLS_CC)) {
+                       if (CURLE_OK != (rc = curl_easy_setopt(ch, opt->option, NULL))) {
+                               rv = FAILURE;
+                       }
+               } else if (CURLE_OK != (rc = curl_easy_setopt(ch, opt->option, Z_STRVAL_P(val)))) {
+                       rv = FAILURE;
                }
                break;
 
@@ -1307,7 +1465,7 @@ static STATUS php_http_curle_set_option(php_http_option_t *opt, zval *val, void
                break;
        }
        if (rv != SUCCESS) {
-               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Could not set option %s", opt->name.s);
+               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Could not set option %s (%s)", opt->name.s, curl_easy_strerror(rc));
        }
        return rv;
 }
@@ -1401,9 +1559,14 @@ static php_http_client_curl_handler_t *php_http_client_curl_handler_init(php_htt
        curl_easy_setopt(handle, CURLOPT_DEBUGFUNCTION, php_http_curle_raw_callback);
        curl_easy_setopt(handle, CURLOPT_READFUNCTION, php_http_curle_read_callback);
        curl_easy_setopt(handle, CURLOPT_IOCTLFUNCTION, php_http_curle_ioctl_callback);
+#if PHP_HTTP_CURL_VERSION(7,32,0)
+       curl_easy_setopt(handle, CURLOPT_XFERINFOFUNCTION, php_http_curle_xferinfo_callback);
+       curl_easy_setopt(handle, CURLOPT_XFERINFODATA, handler);
+#else
        curl_easy_setopt(handle, CURLOPT_PROGRESSFUNCTION, php_http_curle_progress_callback);
-       curl_easy_setopt(handle, CURLOPT_DEBUGDATA, handler);
        curl_easy_setopt(handle, CURLOPT_PROGRESSDATA, handler);
+#endif
+       curl_easy_setopt(handle, CURLOPT_DEBUGDATA, handler);
 
        php_http_client_curl_handler_reset(handler);
 
@@ -1481,8 +1644,8 @@ static STATUS php_http_client_curl_handler_prepare(php_http_client_curl_handler_
                        }
                }
                php_http_buffer_dtor(&header);
-               curl_easy_setopt(curl->handle, CURLOPT_HTTPHEADER, curl->options.headers);
        }
+       curl_easy_setopt(curl->handle, CURLOPT_HTTPHEADER, curl->options.headers);
 
        /* attach request body */
        if ((body_size = php_http_message_body_size(msg->body))) {
@@ -1497,6 +1660,11 @@ static STATUS php_http_client_curl_handler_prepare(php_http_client_curl_handler_
                curl_easy_setopt(curl->handle, CURLOPT_READDATA, msg->body);
                curl_easy_setopt(curl->handle, CURLOPT_INFILESIZE, body_size);
                curl_easy_setopt(curl->handle, CURLOPT_POSTFIELDSIZE, body_size);
+       } else {
+               curl_easy_setopt(curl->handle, CURLOPT_IOCTLDATA, NULL);
+               curl_easy_setopt(curl->handle, CURLOPT_READDATA, NULL);
+               curl_easy_setopt(curl->handle, CURLOPT_INFILESIZE, 0L);
+               curl_easy_setopt(curl->handle, CURLOPT_POSTFIELDSIZE, 0L);
        }
 
        php_http_options_apply(&php_http_curle_options, enqueue->options, curl);
@@ -1509,7 +1677,11 @@ static void php_http_client_curl_handler_dtor(php_http_client_curl_handler_t *ha
        TSRMLS_FETCH_FROM_CTX(handler->client->ts);
 
        curl_easy_setopt(handler->handle, CURLOPT_NOPROGRESS, 1L);
+#if PHP_HTTP_CURL_VERSION(7,32,0)
+       curl_easy_setopt(handler->handle, CURLOPT_XFERINFOFUNCTION, NULL);
+#else
        curl_easy_setopt(handler->handle, CURLOPT_PROGRESSFUNCTION, NULL);
+#endif
        curl_easy_setopt(handler->handle, CURLOPT_VERBOSE, 0L);
        curl_easy_setopt(handler->handle, CURLOPT_DEBUGFUNCTION, NULL);
 
@@ -1762,11 +1934,12 @@ static int php_http_client_curl_once(php_http_client_t *h)
 
 static STATUS php_http_client_curl_exec(php_http_client_t *h)
 {
-       TSRMLS_FETCH_FROM_CTX(h->ts);
-
 #if PHP_HTTP_HAVE_EVENT
        php_http_client_curl_t *curl = h->ctx;
+#endif
+       TSRMLS_FETCH_FROM_CTX(h->ts);
 
+#if PHP_HTTP_HAVE_EVENT
        if (curl->useevents) {
                php_http_curlm_timeout_callback(CURL_SOCKET_TIMEOUT, /*EV_READ|EV_WRITE*/0, h);
                do {
@@ -1790,7 +1963,7 @@ static STATUS php_http_client_curl_exec(php_http_client_t *h)
                                /* see http://msdn.microsoft.com/library/en-us/winsock/winsock/windows_sockets_error_codes_2.asp */
                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "WinSock error: %d", WSAGetLastError());
 #else
-                               php_error_docref(NULL TSRMLS_CC, E_WARNING, strerror(errno));
+                               php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
 #endif
                                return FAILURE;
                        }
@@ -1972,7 +2145,11 @@ PHP_MINIT_FUNCTION(http_client_curl)
 
 PHP_MSHUTDOWN_FUNCTION(http_client_curl)
 {
+       php_persistent_handle_cleanup(ZEND_STRL("http\\Client\\Curl"), NULL, 0 TSRMLS_CC);
+       php_persistent_handle_cleanup(ZEND_STRL("http\\Client\\Curl\\Request"), NULL, 0 TSRMLS_CC);
+
        php_http_options_dtor(&php_http_curle_options);
+
        return SUCCESS;
 }
 
index 6495568..03b9b6f 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
index 12f2014..ea223be 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
index 5f4da53..474114b 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
index b269caf..8d512ec 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
index 6cf677a..15d004e 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
index 1234e38..4bd8d80 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
@@ -526,7 +526,7 @@ static PHP_METHOD(HttpCookie, setCookies)
 
        zend_hash_clean(&obj->list->cookies);
        if (cookies) {
-               array_copy(cookies, &obj->list->cookies);
+               array_copy_strings(cookies, &obj->list->cookies);
        }
 
        RETVAL_ZVAL(getThis(), 1, 0);
@@ -546,7 +546,7 @@ static PHP_METHOD(HttpCookie, addCookies)
 
        PHP_HTTP_COOKIE_OBJECT_INIT(obj);
 
-       array_join(cookies, &obj->list->cookies, 1, ARRAY_JOIN_STRONLY);
+       array_join(cookies, &obj->list->cookies, 1, ARRAY_JOIN_STRONLY|ARRAY_JOIN_STRINGIFY);
 
        RETVAL_ZVAL(getThis(), 1, 0);
 }
@@ -585,7 +585,7 @@ static PHP_METHOD(HttpCookie, setExtras)
 
        zend_hash_clean(&obj->list->extras);
        if (extras) {
-               array_copy(extras, &obj->list->extras);
+               array_copy_strings(extras, &obj->list->extras);
        }
 
        RETVAL_ZVAL(getThis(), 1, 0);
@@ -605,7 +605,7 @@ static PHP_METHOD(HttpCookie, addExtras)
 
        PHP_HTTP_COOKIE_OBJECT_INIT(obj);
 
-       array_join(extras, &obj->list->extras, 1, ARRAY_JOIN_STRONLY);
+       array_join(extras, &obj->list->extras, 1, ARRAY_JOIN_STRONLY|ARRAY_JOIN_STRINGIFY);
 
        RETVAL_ZVAL(getThis(), 1, 0);
 }
index 9d5b7c8..7cf00fe 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
index 6607ca1..a995094 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
 #              elif defined(PHP_HTTP_HAVE_GNUTLS)
 #                      define PHP_HTTP_NEED_GNUTLS_TSL
 #                      include <gcrypt.h>
-#              else
-#                      warning \
-                               "libcurl was compiled with SSL support, but configure could not determine which" \
-                               "library was used; thus no SSL crypto locking callbacks will be set, which may " \
-                               "cause random crashes on SSL requests"
 #              endif /* PHP_HTTP_HAVE_OPENSSL || PHP_HTTP_HAVE_GNUTLS */
 #      endif /* PHP_WIN32 */
 #endif /* ZTS && PHP_HTTP_HAVE_SSL */
index 4621d5a..ab8b63c 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
index 3c5393b..7f0462c 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
@@ -53,7 +53,6 @@ const char *php_http_encoding_dechunk(const char *encoded, size_t encoded_len, c
                                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Data does not seem to be chunked encoded");
                                memcpy(*decoded, encoded, encoded_len);
                                *decoded_len = encoded_len;
-                               decoded[*decoded_len] = '\0';
                                return encoded + encoded_len;
                        } else {
                                efree(*decoded);
index decc585..59bbd27 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
index c98701b..10d54fe 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
@@ -715,6 +715,7 @@ static PHP_METHOD(HttpEnv, getRequestBody)
 
        body = php_http_env_get_request_body(TSRMLS_C);
        if (SUCCESS == php_http_new(&ov, class_entry, (php_http_new_t) php_http_message_body_object_new_ex, php_http_message_body_class_entry, body, NULL TSRMLS_CC)) {
+               php_http_message_body_addref(body);
                RETVAL_OBJVAL(ov, 0);
        }
 }
@@ -957,26 +958,29 @@ static SAPI_POST_HANDLER_FUNC(php_http_json_post_handler)
        size_t json_len = 0;
 
 #if PHP_VERSION_ID >= 50600
-       php_http_message_body_to_string(php_http_env_get_request_body(TSRMLS_C),
-                       &json_str, &json_len, 0, -1);
+       if (SG(request_info).request_body) {
+               /* FG(stream_wrappers) not initialized yet, so we cannot use php://input */
+               php_stream_rewind(SG(request_info).request_body);
+               json_len = php_stream_copy_to_mem(SG(request_info).request_body, &json_str, PHP_STREAM_COPY_ALL, 0);
+       }
 #else
        json_str = SG(request_info).raw_post_data;
        json_len = SG(request_info).raw_post_data_length;
 #endif
 
        if (json_len) {
-               zval_dtor(zarg);
-               ZVAL_NULL(zarg);
-               php_json_decode(zarg, json_str, json_len, 1, PG(max_input_nesting_level) TSRMLS_CC);
+               zval zjson;
+
+               INIT_ZVAL(zjson);
+               php_json_decode(&zjson, json_str, json_len, 1, PG(max_input_nesting_level) TSRMLS_CC);
+               if (Z_TYPE(zjson) != IS_NULL) {
+                       zval_dtor(zarg);
+                       ZVAL_COPY_VALUE(zarg, (&zjson));
+               }
        }
 #if PHP_VERSION_ID >= 50600
        STR_FREE(json_str);
 #endif
-
-       /* always let $_POST be array() */
-       if (Z_TYPE_P(zarg) == IS_NULL) {
-               array_init(zarg);
-       }
 }
 
 static void php_http_env_register_json_handler(TSRMLS_D)
index dac10da..ee1afe9 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
index 01c2f6d..6aff0c0 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
@@ -96,7 +96,11 @@ static int grab_files(void *zpp TSRMLS_DC, int argc, va_list argv, zend_hash_key
                                add_assoc_zval_ex(cpy, ZEND_STRS("file"), *tmp);
                                zend_hash_del_key_or_index(Z_ARRVAL_P(cpy), ZEND_STRS("tmp_name"), 0, HASH_DEL_KEY);
                        }
-                       zend_hash_quick_update(Z_ARRVAL_P(zfiles), key->arKey, key->nKeyLength, key->h, (void *) &cpy, sizeof(zval *), NULL);
+                       if (key->nKeyLength > 0) {
+                               zend_hash_quick_update(Z_ARRVAL_P(zfiles), key->arKey, key->nKeyLength, key->h, (void *) &cpy, sizeof(zval *), NULL);
+                       } else {
+                               zend_hash_index_update(Z_ARRVAL_P(zfiles), key->h, (void *) &cpy, sizeof(zval *), NULL);
+                       }
                }
        }
 
index f6b8f40..a97836b 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
index cb52752..4d6ef03 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
@@ -217,7 +217,9 @@ static size_t output(void *context, char *buf, size_t len TSRMLS_DC)
 {
        php_http_env_response_t *r = context;
 
-       r->ops->write(r, buf, len);
+       if (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 */
@@ -231,7 +233,7 @@ static size_t output(void *context, char *buf, size_t len TSRMLS_DC)
 #define php_http_env_response_send_done(r) php_http_env_response_send_data((r), NULL, 0)
 static STATUS php_http_env_response_send_data(php_http_env_response_t *r, const char *buf, size_t len)
 {
-       size_t chunk = r->throttle.chunk ? r->throttle.chunk : PHP_HTTP_SENDBUF_SIZE;
+       size_t chunks_sent, chunk = r->throttle.chunk ? r->throttle.chunk : PHP_HTTP_SENDBUF_SIZE;
        TSRMLS_FETCH_FROM_CTX(r->ts);
 
        if (r->content.encoder) {
@@ -248,15 +250,16 @@ static STATUS php_http_env_response_send_data(php_http_env_response_t *r, const
                        }
                }
 
-               if (enc_str) {
-                       php_http_buffer_chunked_output(&r->buffer, enc_str, enc_len, buf ? chunk : 0, output, r TSRMLS_CC);
-                       STR_FREE(enc_str);
+               if (!enc_str) {
+                       return SUCCESS;
                }
+               chunks_sent = php_http_buffer_chunked_output(&r->buffer, enc_str, enc_len, buf ? chunk : 0, output, r TSRMLS_CC);
+               STR_FREE(enc_str);
        } else {
-               php_http_buffer_chunked_output(&r->buffer, buf, len, buf ? chunk : 0, output, r TSRMLS_CC);
+               chunks_sent = php_http_buffer_chunked_output(&r->buffer, buf, len, buf ? chunk : 0, output, r TSRMLS_CC);
        }
 
-       return SUCCESS;
+       return chunks_sent != (size_t) -1 ? SUCCESS : FAILURE;
 }
 
 php_http_env_response_t *php_http_env_response_init(php_http_env_response_t *r, zval *options, php_http_env_response_ops_t *ops, void *init_arg TSRMLS_DC)
@@ -996,7 +999,9 @@ static STATUS php_http_env_response_stream_write(php_http_env_response_t *r, con
                }
        }
 
-       php_stream_write(stream_ctx->stream, data_str, data_len);
+       if (data_len != php_stream_write(stream_ctx->stream, data_str, data_len)) {
+               return FAILURE;
+       }
 
        return SUCCESS;
 }
@@ -1089,11 +1094,9 @@ static PHP_METHOD(HttpEnvResponse, __invoke)
 
                PHP_HTTP_ENV_RESPONSE_OBJECT_INIT(obj);
 
-               if (obj->body || SUCCESS == php_http_new(NULL, php_http_message_body_class_entry, (php_http_new_t) php_http_message_body_object_new_ex, NULL, (void *) php_http_message_body_init(&obj->message->body, NULL TSRMLS_CC), (void *) &obj->body TSRMLS_CC)) {
-                       php_http_message_body_append(obj->message->body, ob_str, ob_len);
-                       RETURN_TRUE;
-               }
-               RETURN_FALSE;
+               php_http_message_object_init_body_object(obj);
+               php_http_message_body_append(obj->message->body, ob_str, ob_len);
+               RETURN_TRUE;
        }
 }
 
index f79730f..3a702b2 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
index 72a7927..4562324 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
index dd0e3d1..bf6cf49 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
index 00add62..25a33e6 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
index 82a4b55..969a351 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
index f0ba862..b6d967b 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
index b2b8682..21fe4db 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
index 08e643b..92a2de4 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
index 2c0d2e8..d420e3f 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
index e7fc886..ec41a24 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
@@ -44,10 +44,13 @@ php_http_header_parser_state_t php_http_header_parser_state_push(php_http_header
        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_stack_push(&parser->stack, &state, sizeof(state));
+               zend_ptr_stack_push(&parser->stack, (void *) state);
        }
        va_end(va_args);
 
@@ -56,28 +59,27 @@ php_http_header_parser_state_t php_http_header_parser_state_push(php_http_header
 
 php_http_header_parser_state_t php_http_header_parser_state_is(php_http_header_parser_t *parser)
 {
-       php_http_header_parser_state_t *state;
+       php_http_header_parser_state_t state;
 
-       if (SUCCESS == zend_stack_top(&parser->stack, (void *) &state)) {
-               return *state;
+       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;
 }
 
 php_http_header_parser_state_t php_http_header_parser_state_pop(php_http_header_parser_t *parser)
 {
-       php_http_header_parser_state_t state, *state_ptr;
-       if (SUCCESS == zend_stack_top(&parser->stack, (void *) &state_ptr)) {
-               state = *state_ptr;
-               zend_stack_del_top(&parser->stack);
-               return state;
+       if (parser->stack.top) {
+               return (php_http_header_parser_state_t) zend_ptr_stack_pop(&parser->stack);
        }
+
        return PHP_HTTP_HEADER_PARSER_STATE_START;
 }
 
 void php_http_header_parser_dtor(php_http_header_parser_t *parser)
 {
-       zend_stack_destroy(&parser->stack);
+       zend_ptr_stack_destroy(&parser->stack);
        php_http_info_dtor(&parser->info);
        STR_FREE(parser->_key.str);
        STR_FREE(parser->_val.str);
index 1c07da2..4c60f6e 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
@@ -28,7 +28,7 @@ typedef enum php_http_header_parser_state {
 #define PHP_HTTP_HEADER_PARSER_CLEANUP 0x1
 
 typedef struct php_http_header_parser {
-       zend_stack stack;
+       zend_ptr_stack stack;
        php_http_info_t info;
        struct {
                char *str;
index dca784f..10ea0a3 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
index 87aa791..afd747c 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
index f3509a4..cc04edc 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
@@ -149,7 +149,13 @@ php_http_message_t *php_http_message_parse(php_http_message_t *msg, const char *
 zval *php_http_message_header(php_http_message_t *msg, const char *key_str, size_t key_len, int join)
 {
        zval *ret = NULL, **header;
-       char *key = php_http_pretty_key(estrndup(key_str, key_len), key_len, 1, 1);
+       char *key;
+       ALLOCA_FLAG(free_key);
+
+       key = do_alloca(key_len + 1, free_key);
+       memcpy(key, key_str, key_len);
+       key[key_len] = '\0';
+       php_http_pretty_key(key, key_len, 1, 1);
 
        if (SUCCESS == zend_symtable_find(&msg->hdrs, key, key_len + 1, (void *) &header)) {
                if (join && Z_TYPE_PP(header) == IS_ARRAY) {
@@ -162,7 +168,7 @@ zval *php_http_message_header(php_http_message_t *msg, const char *key_str, size
                }
        }
 
-       efree(key);
+       free_alloca(key, free_key);
 
        return ret;
 }
@@ -300,6 +306,14 @@ void php_http_message_update_headers(php_http_message_t *msg)
                                zval_ptr_dtor(&h);
                        }
                }
+       } else if ((h = php_http_message_header(msg, ZEND_STRL("Content-Length"), 1))) {
+               zval *h_cpy = php_http_ztyp(IS_LONG, h);
+
+               zval_ptr_dtor(&h);
+               if (Z_LVAL_P(h_cpy)) {
+                       zend_hash_del(&msg->hdrs, "Content-Length", sizeof("Content-Length"));
+               }
+               zval_ptr_dtor(&h_cpy);
        }
 }
 
@@ -764,7 +778,9 @@ STATUS php_http_message_object_set_body(php_http_message_object_t *msg_obj, zval
        }
 
        body_obj = zend_object_store_get_object(zbody TSRMLS_CC);
-
+       if (!body_obj->body) {
+               body_obj->body = php_http_message_body_init(NULL, NULL TSRMLS_CC);
+       }
        if (msg_obj->body) {
                zend_objects_store_del_ref_by_handle(msg_obj->body->zv.handle TSRMLS_CC);
        }
@@ -782,6 +798,14 @@ STATUS php_http_message_object_set_body(php_http_message_object_t *msg_obj, zval
        return SUCCESS;
 }
 
+STATUS php_http_message_object_init_body_object(php_http_message_object_t *obj)
+{
+       TSRMLS_FETCH_FROM_CTX(obj->message->ts);
+
+       php_http_message_body_addref(obj->message->body);
+       return php_http_new(NULL, php_http_message_body_class_entry, (php_http_new_t) php_http_message_body_object_new_ex, NULL, obj->message->body, (void *) &obj->body TSRMLS_CC);
+}
+
 zend_object_value php_http_message_object_new(zend_class_entry *ce TSRMLS_DC)
 {
        return php_http_message_object_new_ex(ce, NULL, NULL TSRMLS_CC);
@@ -1050,8 +1074,8 @@ static PHP_METHOD(HttpMessage, getBody)
        PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
 
        if (!obj->body) {
-               php_http_message_body_addref(obj->message->body);
-               php_http_new(NULL, php_http_message_body_class_entry, (php_http_new_t) php_http_message_body_object_new_ex, NULL, obj->message->body, (void *) &obj->body TSRMLS_CC);
+               php_http_message_object_init_body_object(obj);
+
        }
        if (obj->body) {
                RETVAL_OBJVAL(obj->body->zv, 1);
@@ -1800,7 +1824,9 @@ ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_count, 0, 0, 0)
 ZEND_END_ARG_INFO();
 static PHP_METHOD(HttpMessage, count)
 {
-       if (SUCCESS == zend_parse_parameters_none()) {
+       long count_mode = -1;
+
+       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &count_mode)) {
                long i = 0;
                php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
 
index 32af834..6524a27 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
@@ -83,6 +83,7 @@ PHP_MSHUTDOWN_FUNCTION(http_message);
 void php_http_message_object_prepend(zval *this_ptr, zval *prepend, zend_bool top /* = 1 */ TSRMLS_DC);
 void php_http_message_object_reverse(zval *this_ptr, zval *return_value TSRMLS_DC);
 STATUS php_http_message_object_set_body(php_http_message_object_t *obj, zval *zbody TSRMLS_DC);
+STATUS php_http_message_object_init_body_object(php_http_message_object_t *obj);
 
 zend_object_value php_http_message_object_new(zend_class_entry *ce TSRMLS_DC);
 zend_object_value php_http_message_object_new_ex(zend_class_entry *ce, php_http_message_t *msg, php_http_message_object_t **ptr TSRMLS_DC);
index 2749fac..4be45ef 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
@@ -55,6 +55,10 @@ php_http_message_body_t *php_http_message_body_init(php_http_message_body_t **bo
        }
        TSRMLS_SET_CTX(body->ts);
 
+       if (body_ptr) {
+               *body_ptr = body;
+       }
+
        return body;
 }
 
index 028ad62..860cd8a 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
index b64eb00..20ef3ac 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
@@ -54,7 +54,6 @@ php_http_message_parser_t *php_http_message_parser_init(php_http_message_parser_
        TSRMLS_SET_CTX(parser->ts);
 
        php_http_header_parser_init(&parser->header TSRMLS_CC);
-       zend_stack_init(&parser->stack);
 
        return parser;
 }
@@ -65,10 +64,13 @@ php_http_message_parser_state_t php_http_message_parser_state_push(php_http_mess
        va_list va_args;
        unsigned i;
 
+       /* 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_stack_push(&parser->stack, &state, sizeof(state));
+               zend_ptr_stack_push(&parser->stack, (void *) state);
        }
        va_end(va_args);
 
@@ -77,21 +79,16 @@ php_http_message_parser_state_t php_http_message_parser_state_push(php_http_mess
 
 php_http_message_parser_state_t php_http_message_parser_state_is(php_http_message_parser_t *parser)
 {
-       php_http_message_parser_state_t *state;
-
-       if (SUCCESS == zend_stack_top(&parser->stack, (void *) &state)) {
-               return *state;
+       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)
 {
-       php_http_message_parser_state_t state, *state_ptr;
-       if (SUCCESS == zend_stack_top(&parser->stack, (void *) &state_ptr)) {
-               state = *state_ptr;
-               zend_stack_del_top(&parser->stack);
-               return state;
+       if (parser->stack.top) {
+               return (php_http_message_parser_state_t) zend_ptr_stack_pop(&parser->stack);
        }
        return PHP_HTTP_MESSAGE_PARSER_STATE_START;
 }
@@ -99,7 +96,7 @@ php_http_message_parser_state_t php_http_message_parser_state_pop(php_http_messa
 void php_http_message_parser_dtor(php_http_message_parser_t *parser)
 {
        php_http_header_parser_dtor(&parser->header);
-       zend_stack_destroy(&parser->stack);
+       zend_ptr_stack_destroy(&parser->stack);
        if (parser->dechunk) {
                php_http_encoding_stream_free(&parser->dechunk);
        }
index 8ecf991..ebc2142 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
@@ -37,7 +37,7 @@ typedef enum php_http_message_parser_state {
 
 typedef struct php_http_message_parser {
        php_http_header_parser_t header;
-       zend_stack stack;
+       zend_ptr_stack stack;
        size_t body_length;
        php_http_message_t *message;
        php_http_encoding_stream_t *dechunk;
index 0ba19f9..7afa006 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
@@ -61,7 +61,8 @@ int php_http_match(const char *haystack_str, const char *needle_str, int flags)
                        result = !strcasecmp(haystack_str, needle_str);
                }
        } else {
-               char *found, *haystack = estrdup(haystack_str), *needle = estrdup(needle_str);
+               const char *found;
+               char *haystack = estrdup(haystack_str), *needle = estrdup(needle_str);
 
                if (flags & PHP_HTTP_MATCH_CASE) {
                        found = zend_memnstr(haystack, needle, strlen(needle), haystack+strlen(haystack));
@@ -86,16 +87,16 @@ int php_http_match(const char *haystack_str, const char *needle_str, int flags)
        return result;
 }
 
-char *php_http_pretty_key(char *key, size_t key_len, zend_bool uctitle, zend_bool xhyphen)
+char *php_http_pretty_key(register char *key, size_t key_len, zend_bool uctitle, zend_bool xhyphen)
 {
-       size_t i;
+       size_t i = 1;
        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]));
                }
-               for (i = 1; i < key_len; i++) {
+               PHP_HTTP_DUFF(1, 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;
@@ -105,7 +106,8 @@ char *php_http_pretty_key(char *key, size_t key_len, zend_bool uctitle, zend_boo
                                }
                                wasalpha = 0;
                        }
-               }
+                       ++i;
+               );
        }
        return key;
 }
@@ -165,12 +167,19 @@ unsigned php_http_array_list(HashTable *ht TSRMLS_DC, unsigned argc, ...)
        return argl;
 }
 
+void php_http_array_copy_strings(void *zpp)
+{
+       zval **zvpp = ((zval **) zpp);
+
+       *zvpp = php_http_zsep(1, IS_STRING, *zvpp);
+}
+
 int php_http_array_apply_append_func(void *pDest TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
 {
        int flags;
        char *key = NULL;
        HashTable *dst;
-       zval **data = NULL, **value = (zval **) pDest;
+       zval **data = NULL, *value = *((zval **) pDest);
 
        dst = va_arg(args, HashTable *);
        flags = va_arg(args, int);
@@ -183,16 +192,21 @@ int php_http_array_apply_append_func(void *pDest TSRMLS_DC, int num_args, va_lis
                        zend_hash_quick_find(dst, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void *) &data);
                }
 
-               Z_ADDREF_P(*value);
+               if (flags & ARRAY_JOIN_STRINGIFY) {
+                       value = php_http_zsep(1, IS_STRING, value);
+               } else {
+                       Z_ADDREF_P(value);
+               }
+
                if (data) {
                        if (Z_TYPE_PP(data) != IS_ARRAY) {
                                convert_to_array(*data);
                        }
-                       add_next_index_zval(*data, *value);
+                       add_next_index_zval(*data, value);
                } else if (key) {
-                       zend_symtable_update(dst, key, hash_key->nKeyLength, value, sizeof(zval *), NULL);
+                       zend_symtable_update(dst, key, hash_key->nKeyLength, &value, sizeof(zval *), NULL);
                } else {
-                       zend_hash_quick_add(dst, hash_key->arKey, hash_key->nKeyLength, hash_key->h, value, sizeof(zval *), NULL);
+                       zend_hash_quick_add(dst, hash_key->arKey, hash_key->nKeyLength, hash_key->h, &value, sizeof(zval *), NULL);
                }
 
                if (key) {
@@ -208,19 +222,24 @@ int php_http_array_apply_merge_func(void *pDest TSRMLS_DC, int num_args, va_list
        int flags;
        char *key = NULL;
        HashTable *dst;
-       zval **value = (zval **) pDest;
+       zval *value = *((zval **) pDest);
 
        dst = va_arg(args, HashTable *);
        flags = va_arg(args, int);
 
        if ((!(flags & ARRAY_JOIN_STRONLY)) || hash_key->nKeyLength) {
-               Z_ADDREF_P(*value);
+               if (flags & ARRAY_JOIN_STRINGIFY) {
+                       value = php_http_zsep(1, IS_STRING, value);
+               } else {
+                       Z_ADDREF_P(value);
+               }
+
                if ((flags & ARRAY_JOIN_PRETTIFY) && hash_key->nKeyLength) {
                        key = php_http_pretty_key(estrndup(hash_key->arKey, hash_key->nKeyLength - 1), hash_key->nKeyLength - 1, 1, 1);
-                       zend_hash_update(dst, key, hash_key->nKeyLength, (void *) value, sizeof(zval *), NULL);
+                       zend_hash_update(dst, key, hash_key->nKeyLength, (void *) &value, sizeof(zval *), NULL);
                        efree(key);
                } else {
-                       zend_hash_quick_update(dst, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void *) value, sizeof(zval *), NULL);
+                       zend_hash_quick_update(dst, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void *) &value, sizeof(zval *), NULL);
                }
        }
 
index 17cfec7..d47477c 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
@@ -60,25 +60,51 @@ PHP_HTTP_API void php_http_sleep(double s);
 #define PHP_HTTP_MATCH_STRICT  (PHP_HTTP_MATCH_CASE|PHP_HTTP_MATCH_FULL)
 
 int php_http_match(const char *haystack, const char *needle, int flags);
-char *php_http_pretty_key(char *key, size_t key_len, zend_bool uctitle, zend_bool xhyphen);
+char *php_http_pretty_key(register char *key, size_t key_len, zend_bool uctitle, zend_bool xhyphen);
 size_t php_http_boundary(char *buf, size_t len TSRMLS_DC);
 int php_http_select_str(const char *cmp, int argc, ...);
 
-static inline const char *php_http_locate_str(const char *h, size_t h_len, const char *n, size_t n_len)
+/* See "A Reusable Duff Device" By Ralf Holly, August 01, 2005 */
+#define PHP_HTTP_DUFF_BREAK(i) do { \
+       times_##i = 1; \
+} while (0)
+
+#define PHP_HTTP_DUFF(i, c, a) do { \
+               size_t count_##i = (c); \
+               size_t times_##i = (count_##i + 7) >> 3; \
+               switch (count_##i & 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_##i > 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)
 {
-       const char *p, *e;
+       register const char *p1, *p2;
 
-       if (n_len && h_len) {
-               e = h + h_len;
-               do {
+       if (n_len && h_len && h_len >= n_len) {
+               PHP_HTTP_DUFF(1, h_len - n_len + 1,
                        if (*h == *n) {
-                               for (p = n; *p == h[p-n]; ++p) {
-                                       if (p == n+n_len-1) {
+                               p1 = h;
+                               p2 = n;
+                               PHP_HTTP_DUFF(2, n_len,
+                                       if (*p1++ != *p2++) {
+                                               PHP_HTTP_DUFF_BREAK(2);
+                                       } else if (p2 == n + n_len - 1) {
                                                return h;
                                        }
-                               }
+                               );
                        }
-               } while (h++ != e);
+                       ++h;
+               );
        }
 
        return NULL;
@@ -96,17 +122,19 @@ static inline const char *php_http_locate_eol(const char *line, int *eol_len)
 
 static inline const char *php_http_locate_bin_eol(const char *bin, size_t len, int *eol_len)
 {
-       const char *eol;
+       register const char *eol = bin;
 
-       for (eol = bin; eol - bin < len; ++eol) {
-               if (*eol == '\r' || *eol == '\n') {
-                       if (eol_len) {
-                               *eol_len = ((eol[0] == '\r' && eol[1] == '\n') ? 2 : 1);
+       if (len > 0) {
+               PHP_HTTP_DUFF(1, len,
+                       if (*eol == '\r' || *eol == '\n') {
+                               if (eol_len) {
+                                       *eol_len = ((eol[0] == '\r' && eol[1] == '\n') ? 2 : 1);
+                               }
+                               return eol;
                        }
-                       return eol;
-               }
+                       ++eol;
+               );
        }
-
        return NULL;
 }
 
@@ -127,6 +155,12 @@ static inline const char *php_http_locate_bin_eol(const char *bin, size_t len, i
 #      define PHP_HTTP_ZEND_LITERAL_CCN , NULL
 #endif
 
+#if PHP_VERSION_ID < 50700
+#      define z_is_true zend_is_true
+#else
+#      define z_is_true(z) zend_is_true(z TSRMLS_CC)
+#endif
+
 #define INIT_PZVAL_ARRAY(zv, ht) \
        { \
                INIT_PZVAL((zv)); \
@@ -134,42 +168,37 @@ static inline const char *php_http_locate_bin_eol(const char *bin, size_t len, i
                Z_ARRVAL_P(zv) = (ht); \
        }
 
-static inline zval *php_http_ztyp(int type, zval *z)
+static inline zval *php_http_zconv(int type, zval *z)
 {
-       SEPARATE_ARG_IF_REF(z);
-       if (Z_TYPE_P(z) != type) {
-               switch (type) {
-                       case IS_NULL:   convert_to_null_ex(&z);         break;
-                       case IS_BOOL:   convert_to_boolean_ex(&z);      break;
-                       case IS_LONG:   convert_to_long_ex(&z);         break;
-                       case IS_DOUBLE: convert_to_double_ex(&z);       break;
-                       case IS_STRING: convert_to_string_ex(&z);       break;
-                       case IS_ARRAY:  convert_to_array_ex(&z);        break;
-                       case IS_OBJECT: convert_to_object_ex(&z);       break;
-               }
+       switch (type) {
+               case IS_NULL:   convert_to_null_ex(&z);         break;
+               case IS_BOOL:   convert_to_boolean_ex(&z);      break;
+               case IS_LONG:   convert_to_long_ex(&z);         break;
+               case IS_DOUBLE: convert_to_double_ex(&z);       break;
+               case IS_STRING: convert_to_string_ex(&z);       break;
+               case IS_ARRAY:  convert_to_array_ex(&z);        break;
+               case IS_OBJECT: convert_to_object_ex(&z);       break;
        }
        return z;
 }
 
+static inline zval *php_http_ztyp(int type, zval *z)
+{
+       SEPARATE_ARG_IF_REF(z);
+       return (Z_TYPE_P(z) == type) ? z : php_http_zconv(type, z);
+}
+
 static inline zval *php_http_zsep(zend_bool add_ref, int type, zval *z)
 {
        if (add_ref) {
                Z_ADDREF_P(z);
        }
        if (Z_TYPE_P(z) != type) {
-               switch (type) {
-                       case IS_NULL:   convert_to_null_ex(&z);         break;
-                       case IS_BOOL:   convert_to_boolean_ex(&z);      break;
-                       case IS_LONG:   convert_to_long_ex(&z);         break;
-                       case IS_DOUBLE: convert_to_double_ex(&z);       break;
-                       case IS_STRING: convert_to_string_ex(&z);       break;
-                       case IS_ARRAY:  convert_to_array_ex(&z);        break;
-                       case IS_OBJECT: convert_to_object_ex(&z);       break;
-               }
+               return php_http_zconv(type, z);
        } else {
                SEPARATE_ZVAL_IF_NOT_REF(&z);
+               return z;
        }
-       return z;
 }
 
 static inline STATUS php_http_ini_entry(const char *name_str, size_t name_len, const char **value_str, size_t *value_len, zend_bool orig TSRMLS_DC)
@@ -240,6 +269,11 @@ static inline STATUS php_http_ini_entry(const char *name_str, size_t name_len, c
 #define PHP_RSHUTDOWN_CALL(func) PHP_RSHUTDOWN(func)(SHUTDOWN_FUNC_ARGS_PASSTHRU)
 
 /* ARRAYS */
+
+#ifndef HASH_KEY_NON_EXISTENT
+#      define HASH_KEY_NON_EXISTENT HASH_KEY_NON_EXISTANT
+#endif
+
 PHP_HTTP_API unsigned php_http_array_list(HashTable *ht TSRMLS_DC, unsigned argc, ...);
 
 typedef struct php_http_array_hashkey {
@@ -285,10 +319,13 @@ static inline void php_http_array_hashkey_stringfree(php_http_array_hashkey_t *k
                        zend_hash_move_forward_ex(hash, &pos))
 
 #define array_copy(src, dst) zend_hash_copy(dst, src, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *))
-#define ARRAY_JOIN_STRONLY 1
-#define ARRAY_JOIN_PRETTIFY 2
+#define array_copy_strings(src, dst) zend_hash_copy(dst, src, php_http_array_copy_strings, NULL, sizeof(zval *))
+#define ARRAY_JOIN_STRONLY   0x01
+#define ARRAY_JOIN_PRETTIFY  0x02
+#define ARRAY_JOIN_STRINGIFY 0x04
 #define array_join(src, dst, append, flags) zend_hash_apply_with_arguments(src TSRMLS_CC, (append)?php_http_array_apply_append_func:php_http_array_apply_merge_func, 2, dst, (int)flags)
 
+void php_http_array_copy_strings(void *zpp);
 int php_http_array_apply_append_func(void *pDest TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key);
 int php_http_array_apply_merge_func(void *pDest TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key);
 
index ae10ddf..76106a8 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
index f31226b..3a12ab7 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
index d4785f1..abf7229 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
index a3786bb..63730b4 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
index ca455a7..1ba987a 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
index 479b155..6726815 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
index c64df95..65504ac 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
@@ -47,9 +47,10 @@ typedef struct php_http_params_state {
        } current;
        unsigned quotes:1;
        unsigned escape:1;
+       unsigned rfc5987:1;
 } php_http_params_state_t;
 
-static inline void sanitize_default(zval *zv TSRMLS_DC)
+static inline void sanitize_escaped(zval *zv TSRMLS_DC)
 {
        if (Z_STRVAL_P(zv)[0] == '"' && Z_STRVAL_P(zv)[Z_STRLEN_P(zv) - 1] == '"') {
                size_t deq_len = Z_STRLEN_P(zv) - 2;
@@ -59,17 +60,18 @@ static inline void sanitize_default(zval *zv TSRMLS_DC)
                ZVAL_STRINGL(zv, deq, deq_len, 0);
        }
 
-       php_stripslashes(Z_STRVAL_P(zv), &Z_STRLEN_P(zv) TSRMLS_CC);
+       php_stripcslashes(Z_STRVAL_P(zv), &Z_STRLEN_P(zv));
 }
 
-static inline void prepare_default(zval *zv TSRMLS_DC)
+static inline void prepare_escaped(zval *zv TSRMLS_DC)
 {
        if (Z_TYPE_P(zv) == IS_STRING) {
                int len = Z_STRLEN_P(zv);
 
-               Z_STRVAL_P(zv) = php_addslashes(Z_STRVAL_P(zv), Z_STRLEN_P(zv), &Z_STRLEN_P(zv), 1 TSRMLS_CC);
+               Z_STRVAL_P(zv) = php_addcslashes(Z_STRVAL_P(zv), Z_STRLEN_P(zv), &Z_STRLEN_P(zv), 1,
+                               ZEND_STRL("\0..\37\173\\\"") TSRMLS_CC);
 
-               if (len != Z_STRLEN_P(zv)) {
+               if (len != Z_STRLEN_P(zv) || strpbrk(Z_STRVAL_P(zv), "()<>@,;:\"[]?={} ")) {
                        zval tmp = *zv;
                        int len = Z_STRLEN_P(zv) + 2;
                        char *str = emalloc(len + 1);
@@ -96,7 +98,7 @@ static inline void sanitize_urlencoded(zval *zv TSRMLS_DC)
 static inline void prepare_urlencoded(zval *zv TSRMLS_DC)
 {
        int len;
-       char *str =     php_url_encode(Z_STRVAL_P(zv), Z_STRLEN_P(zv), &len);
+       char *str =     php_raw_url_encode(Z_STRVAL_P(zv), Z_STRLEN_P(zv), &len);
 
        zval_dtor(zv);
        ZVAL_STRINGL(zv, str, len, 0);
@@ -212,13 +214,22 @@ static void prepare_dimension(php_http_buffer_t *buf, php_http_buffer_t *keybuf,
        --ht->nApplyCount;
 }
 
-static inline void sanitize_key(unsigned flags, char *str, size_t len, zval *zv TSRMLS_DC)
+static inline void sanitize_key(unsigned flags, char *str, size_t len, zval *zv, zend_bool *rfc5987 TSRMLS_DC)
 {
+       char *eos;
+
        zval_dtor(zv);
        php_trim(str, len, NULL, 0, zv, 3 TSRMLS_CC);
 
-       if (flags & PHP_HTTP_PARAMS_DEFAULT) {
-               sanitize_default(zv TSRMLS_CC);
+       if (flags & PHP_HTTP_PARAMS_ESCAPED) {
+               sanitize_escaped(zv TSRMLS_CC);
+       }
+
+       eos = &Z_STRVAL_P(zv)[Z_STRLEN_P(zv)-1];
+       if (*eos == '*') {
+               *eos = '\0';
+               *rfc5987 = 1;
+               Z_STRLEN_P(zv) -= 1;
        }
 
        if (flags & PHP_HTTP_PARAMS_URLENCODED) {
@@ -230,18 +241,110 @@ static inline void sanitize_key(unsigned flags, char *str, size_t len, zval *zv
        }
 }
 
-static inline void sanitize_value(unsigned flags, char *str, size_t len, zval *zv TSRMLS_DC)
+static inline void sanitize_rfc5987(zval *zv, char **language, zend_bool *latin1 TSRMLS_DC)
+{
+       char *ptr;
+
+       /* examples:
+        * iso-8850-1'de'bl%f6der%20schei%df%21
+        * utf-8'de-DE'bl%c3%b6der%20schei%c3%9f%21
+        */
+
+       switch (Z_STRVAL_P(zv)[0]) {
+       case 'I':
+       case 'i':
+               if (!strncasecmp(Z_STRVAL_P(zv), ZEND_STRL("iso-8859-1"))) {
+                       *latin1 = 1;
+                       ptr = Z_STRVAL_P(zv) + lenof("iso-8859-1");
+                       break;
+               }
+               /* no break */
+       case 'U':
+       case 'u':
+               if (!strncasecmp(Z_STRVAL_P(zv), ZEND_STRL("utf-8"))) {
+                       *latin1 = 0;
+                       ptr = Z_STRVAL_P(zv) + lenof("utf-8");
+                       break;
+               }
+               /* no break */
+       default:
+               return;
+       }
+
+       /* extract language */
+       if (*ptr == '\'') {
+               for (*language = ++ptr; *ptr && *ptr != '\''; ++ptr);
+               if (!*ptr) {
+                       *language = NULL;
+                       return;
+               }
+               *language = estrndup(*language, ptr - *language);
+
+               /* remainder */
+               ptr = estrdup(++ptr);
+               zval_dtor(zv);
+               ZVAL_STRING(zv, ptr, 0);
+       }
+}
+
+static void utf8encode(zval *zv)
+{
+       size_t pos, len = 0;
+       unsigned char *ptr = (unsigned char *) Z_STRVAL_P(zv);
+
+       while (*ptr) {
+               if (*ptr++ >= 0x80) {
+                       ++len;
+               }
+               ++len;
+       }
+
+       ptr = safe_emalloc(1, len, 1);
+       for (len = 0, pos = 0; len <= Z_STRLEN_P(zv); ++len, ++pos) {
+               ptr[pos] = Z_STRVAL_P(zv)[len];
+               if ((ptr[pos]) >= 0x80) {
+                       ptr[pos + 1] = 0x80 | (ptr[pos] & 0x3f);
+                       ptr[pos] = 0xc0 | ((ptr[pos] >> 6) & 0x1f);
+                       ++pos;
+               }
+       }
+       zval_dtor(zv);
+       ZVAL_STRINGL(zv, (char *) ptr, pos-1, 0);
+}
+
+static inline void sanitize_value(unsigned flags, char *str, size_t len, zval *zv, zend_bool rfc5987 TSRMLS_DC)
 {
+       char *language = NULL;
+       zend_bool latin1 = 0;
+
        zval_dtor(zv);
        php_trim(str, len, NULL, 0, zv, 3 TSRMLS_CC);
 
-       if (flags & PHP_HTTP_PARAMS_DEFAULT) {
-               sanitize_default(zv TSRMLS_CC);
+       if (rfc5987) {
+               sanitize_rfc5987(zv, &language, &latin1 TSRMLS_CC);
        }
 
-       if (flags & PHP_HTTP_PARAMS_URLENCODED) {
+       if (flags & PHP_HTTP_PARAMS_ESCAPED) {
+               sanitize_escaped(zv TSRMLS_CC);
+       }
+
+       if ((flags & PHP_HTTP_PARAMS_URLENCODED) || (rfc5987 && language)) {
                sanitize_urlencoded(zv TSRMLS_CC);
        }
+
+       if (rfc5987 && language) {
+               zval *tmp;
+
+               if (latin1) {
+                       utf8encode(zv);
+               }
+
+               MAKE_STD_ZVAL(tmp);
+               ZVAL_COPY_VALUE(tmp, zv);
+               array_init(zv);
+               add_assoc_zval(zv, language, tmp);
+               STR_FREE(language);
+       }
 }
 
 static inline void prepare_key(unsigned flags, char *old_key, size_t old_len, char **new_key, size_t *new_len TSRMLS_DC)
@@ -255,8 +358,8 @@ static inline void prepare_key(unsigned flags, char *old_key, size_t old_len, ch
                prepare_urlencoded(&zv TSRMLS_CC);
        }
 
-       if (flags & PHP_HTTP_PARAMS_DEFAULT) {
-               prepare_default(&zv TSRMLS_CC);
+       if (flags & PHP_HTTP_PARAMS_ESCAPED) {
+               prepare_escaped(&zv TSRMLS_CC);
        }
 
        *new_key = Z_STRVAL(zv);
@@ -269,8 +372,8 @@ static inline void prepare_value(unsigned flags, zval *zv TSRMLS_DC)
                prepare_urlencoded(zv TSRMLS_CC);
        }
 
-       if (flags & PHP_HTTP_PARAMS_DEFAULT) {
-               prepare_default(zv TSRMLS_CC);
+       if (flags & PHP_HTTP_PARAMS_ESCAPED) {
+               prepare_escaped(zv TSRMLS_CC);
        }
 }
 
@@ -392,34 +495,55 @@ static void push_param(HashTable *params, php_http_params_state_t *state, const
 {
        if (state->val.str) {
                if (0 < (state->val.len = state->input.str - state->val.str)) {
-                       sanitize_value(opts->flags, state->val.str, state->val.len, *(state->current.val) TSRMLS_CC);
+                       sanitize_value(opts->flags, state->val.str, state->val.len, *(state->current.val), state->rfc5987 TSRMLS_CC);
                }
+               state->rfc5987 = 0;
        } else if (state->arg.str) {
                if (0 < (state->arg.len = state->input.str - state->arg.str)) {
                        zval *val, key;
+                       zend_bool rfc5987 = 0;
 
                        INIT_PZVAL(&key);
                        ZVAL_NULL(&key);
-                       sanitize_key(opts->flags, state->arg.str, state->arg.len, &key TSRMLS_CC);
+                       sanitize_key(opts->flags, state->arg.str, state->arg.len, &key, &rfc5987 TSRMLS_CC);
+                       state->rfc5987 = rfc5987;
                        if (Z_TYPE(key) == IS_STRING && Z_STRLEN(key)) {
                                MAKE_STD_ZVAL(val);
                                ZVAL_TRUE(val);
-                               zend_symtable_update(Z_ARRVAL_PP(state->current.args), Z_STRVAL(key), Z_STRLEN(key) + 1, (void *) &val, sizeof(zval *), (void *) &state->current.val);
+
+                               if (rfc5987) {
+                                       zval **rfc;
+
+                                       if (SUCCESS == zend_hash_find(Z_ARRVAL_PP(state->current.args), ZEND_STRS("*rfc5987*"), (void *) &rfc)) {
+                                               zend_symtable_update(Z_ARRVAL_PP(rfc), Z_STRVAL(key), Z_STRLEN(key) + 1, (void *) &val, sizeof(zval *), (void *) &state->current.val);
+                                       } else {
+                                               zval *tmp;
+
+                                               MAKE_STD_ZVAL(tmp);
+                                               array_init_size(tmp, 1);
+                                               zend_symtable_update(Z_ARRVAL_P(tmp), Z_STRVAL(key), Z_STRLEN(key) + 1, (void *) &val, sizeof(zval *), (void *) &state->current.val);
+                                               zend_symtable_update(Z_ARRVAL_PP(state->current.args), ZEND_STRS("*rfc5987*"), (void *) &tmp, sizeof(zval *), NULL);
+                                       }
+                               } else {
+                                       zend_symtable_update(Z_ARRVAL_PP(state->current.args), Z_STRVAL(key), Z_STRLEN(key) + 1, (void *) &val, sizeof(zval *), (void *) &state->current.val);
+                               }
                        }
                        zval_dtor(&key);
                }
        } else if (state->param.str) {
                if (0 < (state->param.len = state->input.str - state->param.str)) {
                        zval *prm, *arg, *val, *key;
+                       zend_bool rfc5987 = 0;
 
                        MAKE_STD_ZVAL(key);
                        ZVAL_NULL(key);
-                       sanitize_key(opts->flags, state->param.str, state->param.len, key TSRMLS_CC);
+                       sanitize_key(opts->flags, state->param.str, state->param.len, key, &rfc5987 TSRMLS_CC);
+                       state->rfc5987 = rfc5987;
                        if (Z_TYPE_P(key) != IS_STRING) {
                                merge_param(params, key, &state->current.val, &state->current.args TSRMLS_CC);
                        } else if (Z_STRLEN_P(key)) {
                                MAKE_STD_ZVAL(prm);
-                               array_init(prm);
+                               array_init_size(prm, 2);
 
                                MAKE_STD_ZVAL(val);
                                if (opts->defval) {
@@ -428,10 +552,14 @@ static void push_param(HashTable *params, php_http_params_state_t *state, const
                                } else {
                                        ZVAL_TRUE(val);
                                }
-                               zend_hash_update(Z_ARRVAL_P(prm), "value", sizeof("value"), (void *) &val, sizeof(zval *), (void *) &state->current.val);
+                               if (rfc5987 && (opts->flags & PHP_HTTP_PARAMS_RFC5987)) {
+                                       zend_hash_update(Z_ARRVAL_P(prm), "*rfc5987*", sizeof("*rfc5987*"), (void *) &val, sizeof(zval *), (void *) &state->current.val);
+                               } else {
+                                       zend_hash_update(Z_ARRVAL_P(prm), "value", sizeof("value"), (void *) &val, sizeof(zval *), (void *) &state->current.val);
+                               }
 
                                MAKE_STD_ZVAL(arg);
-                               array_init(arg);
+                               array_init_size(arg, 3);
                                zend_hash_update(Z_ARRVAL_P(prm), "arguments", sizeof("arguments"), (void *) &arg, sizeof(zval *), (void *) &state->current.args);
 
                                zend_symtable_update(params, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, (void *) &prm, sizeof(zval *), (void *) &state->current.param);
@@ -442,7 +570,7 @@ static void push_param(HashTable *params, php_http_params_state_t *state, const
 }
 
 static inline zend_bool check_str(const char *chk_str, size_t chk_len, const char *sep_str, size_t sep_len) {
-       return 0 < sep_len && chk_len >= sep_len && !memcmp(chk_str, sep_str, sep_len);
+       return 0 < sep_len && chk_len >= sep_len && *chk_str == *sep_str && !memcmp(chk_str + 1, sep_str + 1, sep_len - 1);
 }
 
 static size_t check_sep(php_http_params_state_t *state, php_http_params_token_t **separators)
@@ -576,6 +704,28 @@ static inline void shift_key(php_http_buffer_t *buf, char *key_str, size_t key_l
        efree(str);
 }
 
+static inline void shift_rfc5987(php_http_buffer_t *buf, zval *zvalue, const char *vss, size_t vsl, unsigned flags TSRMLS_DC)
+{
+       HashTable *ht = HASH_OF(zvalue);
+       zval **zdata, *tmp;
+       php_http_array_hashkey_t key = php_http_array_hashkey_init(0);
+
+       if (SUCCESS == zend_hash_get_current_data(ht, (void *) &zdata)
+       &&      HASH_KEY_NON_EXISTENT != (key.type = zend_hash_get_current_key_ex(ht, &key.str, &key.len, &key.num, key.dup, NULL))
+       ) {
+               php_http_array_hashkey_stringify(&key);
+               php_http_buffer_appendf(buf, "*%.*sutf-8'%.*s'",
+                               (int) (vsl > INT_MAX ? INT_MAX : vsl), vss,
+                               (int) (key.len > INT_MAX ? INT_MAX : key.len), key.str);
+               php_http_array_hashkey_stringfree(&key);
+
+               tmp = php_http_zsep(1, IS_STRING, *zdata);
+               prepare_value(flags | PHP_HTTP_PARAMS_URLENCODED, tmp TSRMLS_CC);
+               php_http_buffer_append(buf, Z_STRVAL_P(tmp), Z_STRLEN_P(tmp));
+               zval_ptr_dtor(&tmp);
+       }
+}
+
 static inline void shift_val(php_http_buffer_t *buf, zval *zvalue, const char *vss, size_t vsl, unsigned flags TSRMLS_DC)
 {
        if (Z_TYPE_P(zvalue) != IS_BOOL) {
@@ -598,12 +748,20 @@ static void shift_arg(php_http_buffer_t *buf, char *key_str, size_t key_len, zva
                HashPosition pos;
                php_http_array_hashkey_t key = php_http_array_hashkey_init(0);
                zval **val;
+               zend_bool rfc5987 = !strcmp(key_str, "*rfc5987*");
 
-               shift_key(buf, key_str, key_len, ass, asl, flags TSRMLS_CC);
+               if (!rfc5987) {
+                       shift_key(buf, key_str, key_len, ass, asl, flags TSRMLS_CC);
+               }
                FOREACH_KEYVAL(pos, zvalue, key, val) {
                        /* did you mean recursion? */
                        php_http_array_hashkey_stringify(&key);
-                       shift_arg(buf, key.str, key.len-1, *val, ass, asl, vss, vsl, flags TSRMLS_CC);
+                       if (rfc5987 && (Z_TYPE_PP(val) == IS_ARRAY || Z_TYPE_PP(val) == IS_OBJECT)) {
+                               shift_key(buf, key.str, key.len-1, ass, asl, flags TSRMLS_CC);
+                               shift_rfc5987(buf, *val, vss, vsl, flags TSRMLS_CC);
+                       } else {
+                               shift_arg(buf, key.str, key.len-1, *val, ass, asl, vss, vsl, flags TSRMLS_CC);
+                       }
                        php_http_array_hashkey_stringfree(&key);
                }
        } else {
@@ -612,14 +770,17 @@ static void shift_arg(php_http_buffer_t *buf, char *key_str, size_t key_len, zva
        }
 }
 
-static void shift_param(php_http_buffer_t *buf, char *key_str, size_t key_len, zval *zvalue, const char *pss, size_t psl, const char *ass, size_t asl, const char *vss, size_t vsl, unsigned flags TSRMLS_DC)
+static void shift_param(php_http_buffer_t *buf, char *key_str, size_t key_len, zval *zvalue, const char *pss, size_t psl, const char *ass, size_t asl, const char *vss, size_t vsl, unsigned flags, zend_bool rfc5987 TSRMLS_DC)
 {
        if (Z_TYPE_P(zvalue) == IS_ARRAY || Z_TYPE_P(zvalue) == IS_OBJECT) {
-               /* treat as arguments, unless we care for dimensions */
+               /* treat as arguments, unless we care for dimensions or rfc5987 */
                if (flags & PHP_HTTP_PARAMS_DIMENSION) {
                        php_http_buffer_t *keybuf = php_http_buffer_from_string(key_str, key_len);
                        prepare_dimension(buf, keybuf, zvalue, pss, psl, vss, vsl, flags TSRMLS_CC);
                        php_http_buffer_free(&keybuf);
+               } else if (rfc5987) {
+                       shift_key(buf, key_str, key_len, pss, psl, flags TSRMLS_CC);
+                       shift_rfc5987(buf, zvalue, vss, vsl, flags TSRMLS_CC);
                } else {
                        shift_arg(buf, key_str, key_len, zvalue, ass, asl, vss, vsl, flags TSRMLS_CC);
                }
@@ -634,6 +795,7 @@ php_http_buffer_t *php_http_params_to_string(php_http_buffer_t *buf, HashTable *
        zval **zparam;
        HashPosition pos, pos1;
        php_http_array_hashkey_t key = php_http_array_hashkey_init(0), key1 = php_http_array_hashkey_init(0);
+       zend_bool rfc5987 = 0;
 
        if (!buf) {
                buf = php_http_buffer_init(NULL);
@@ -642,12 +804,20 @@ php_http_buffer_t *php_http_params_to_string(php_http_buffer_t *buf, HashTable *
        FOREACH_HASH_KEYVAL(pos, params, key, zparam) {
                zval **zvalue, **zargs;
 
-               if (Z_TYPE_PP(zparam) != IS_ARRAY || SUCCESS != zend_hash_find(Z_ARRVAL_PP(zparam), ZEND_STRS("value"), (void *) &zvalue)) {
+               if (Z_TYPE_PP(zparam) != IS_ARRAY) {
                        zvalue = zparam;
+               } else {
+                       if (SUCCESS != zend_hash_find(Z_ARRVAL_PP(zparam), ZEND_STRS("value"), (void *) &zvalue)) {
+                               if (SUCCESS != zend_hash_find(Z_ARRVAL_PP(zparam), ZEND_STRS("*rfc5987*"), (void *) &zvalue)) {
+                                       zvalue = zparam;
+                               } else {
+                                       rfc5987 = 1;
+                               }
+                       }
                }
 
                php_http_array_hashkey_stringify(&key);
-               shift_param(buf, key.str, key.len - 1, *zvalue, pss, psl, ass, asl, vss, vsl, flags TSRMLS_CC);
+               shift_param(buf, key.str, key.len - 1, *zvalue, pss, psl, ass, asl, vss, vsl, flags, rfc5987 TSRMLS_CC);
                php_http_array_hashkey_stringfree(&key);
 
                if (Z_TYPE_PP(zparam) == IS_ARRAY && SUCCESS != zend_hash_find(Z_ARRVAL_PP(zparam), ZEND_STRS("arguments"), (void *) &zvalue)) {
@@ -1002,9 +1172,11 @@ PHP_MINIT_FUNCTION(http_params)
        zend_declare_class_constant_stringl(php_http_params_class_entry, ZEND_STRL("COOKIE_PARAM_SEP"), ZEND_STRL("") TSRMLS_CC);
 
        zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_RAW"), PHP_HTTP_PARAMS_RAW TSRMLS_CC);
-       zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_DEFAULT"), PHP_HTTP_PARAMS_DEFAULT TSRMLS_CC);
+       zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_ESCAPED"), PHP_HTTP_PARAMS_ESCAPED TSRMLS_CC);
        zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_URLENCODED"), PHP_HTTP_PARAMS_URLENCODED TSRMLS_CC);
        zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_DIMENSION"), PHP_HTTP_PARAMS_DIMENSION TSRMLS_CC);
+       zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_RFC5987"), PHP_HTTP_PARAMS_RFC5987 TSRMLS_CC);
+       zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_DEFAULT"), PHP_HTTP_PARAMS_DEFAULT TSRMLS_CC);
        zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_QUERY"), PHP_HTTP_PARAMS_QUERY TSRMLS_CC);
 
        zend_declare_property_null(php_http_params_class_entry, ZEND_STRL("params"), ZEND_ACC_PUBLIC TSRMLS_CC);
index a9ac564..42f56f9 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
@@ -19,10 +19,12 @@ typedef struct php_http_params_token {
 } php_http_params_token_t;
 
 #define PHP_HTTP_PARAMS_RAW                    0x00
-#define PHP_HTTP_PARAMS_DEFAULT                0x01
+#define PHP_HTTP_PARAMS_ESCAPED                0x01
 #define PHP_HTTP_PARAMS_URLENCODED     0x04
 #define PHP_HTTP_PARAMS_DIMENSION      0x08
+#define PHP_HTTP_PARAMS_RFC5987                0x10
 #define PHP_HTTP_PARAMS_QUERY          (PHP_HTTP_PARAMS_URLENCODED|PHP_HTTP_PARAMS_DIMENSION)
+#define PHP_HTTP_PARAMS_DEFAULT                (PHP_HTTP_PARAMS_ESCAPED|PHP_HTTP_PARAMS_RFC5987)
 
 typedef struct php_http_params_opts {
        php_http_params_token_t input;
index 7304d69..933529f 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
index 6418f83..4ebdd77 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
index 4e316db..f457178 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
index 319113f..2685423 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
index eb1d2a3..c4eb90b 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
index 938cf07..5c61daa 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
index 4b80504..fbe9411 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
@@ -27,19 +27,37 @@ php_http_version_t *php_http_version_init(php_http_version_t *v, unsigned major,
 php_http_version_t *php_http_version_parse(php_http_version_t *v, const char *str TSRMLS_DC)
 {
        php_http_version_t tmp;
-       char separator = 0;
+       char separator = 0, *stop = NULL;
+       register const char *ptr = str;
 
-       if (3 != sscanf(str, "HTTP/%u%c%u", &tmp.major, &separator, &tmp.minor)
-       &&      3 != sscanf(str, "%u%c%u", &tmp.major, &separator, &tmp.minor)) {
-               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not parse HTTP protocol version '%s'", str);
-               return NULL;
+       switch (*ptr) {
+       case 'h':
+       case 'H':
+               ++ptr; if (*ptr != 't' && *ptr != 'T') break;
+               ++ptr; if (*ptr != 't' && *ptr != 'T') break;
+               ++ptr; if (*ptr != 'p' && *ptr != 'P') break;
+               ++ptr; if (*ptr != '/') break;
+               ++ptr;
+               /* no break */
+       default:
+               tmp.major = strtol(ptr, &stop, 10);
+               if (stop && stop != ptr && tmp.major != LONG_MIN && tmp.major != LONG_MAX) {
+                       separator = *stop;
+                       if (separator) {
+                               if (separator != '.' && separator != ',') {
+                                       php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Non-standard version separator '%c' in HTTP protocol version '%s'", separator, ptr);
+                               }
+                               ptr = stop + 1;
+                               tmp.minor = strtol(ptr, &stop, 10);
+                               if (tmp.minor != LONG_MIN && tmp.minor != LONG_MAX) {
+                                       return php_http_version_init(v, tmp.major, tmp.minor TSRMLS_CC);
+                               }
+                       }
+               }
        }
 
-       if (separator && separator != '.' && separator != ',') {
-               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Non-standard version separator '%c' in HTTP protocol version '%s'", separator, str);
-       }
-
-       return php_http_version_init(v, tmp.major, tmp.minor TSRMLS_CC);
+       php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not parse HTTP protocol version '%s'", str);
+       return NULL;
 }
 
 void php_http_version_to_string(php_http_version_t *v, char **str, size_t *len, const char *pre, const char *post TSRMLS_DC)
index 8053646..40b833e 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
diff --git a/phpunit.php b/phpunit.php
deleted file mode 100644 (file)
index 8a61937..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-<?php
-require_once "PHPUnit/Autoload.php";
-$c = new PHPUnit_TextUI_Command;
-$c->run(array_merge($argv, array(__DIR__."/phpunit/")));
diff --git a/phpunit/CookieTest.php b/phpunit/CookieTest.php
deleted file mode 100644 (file)
index d569c75..0000000
+++ /dev/null
@@ -1,204 +0,0 @@
-<?php
-
-ini_set("date.timezone", "Europe/Vienna");
-
-class CookieTest extends PHPUnit_Framework_TestCase {
-    function testEmpty() {
-        $c = new http\Cookie;
-        $o = clone $c;
-        $a = array(
-            "cookies" => array(),
-            "extras" => array(),
-            "flags" => 0,
-            "expires" => -1,
-            "path" => "",
-            "domain" => "",
-               "max-age" => -1,
-        );
-        $this->assertEquals($a, $c->toArray());
-        $this->assertEquals($a, $o->toArray());
-    }
-
-    function testExpiresAsDate() {
-        $d = new DateTime;
-        $c = new http\Cookie(array("expires" => $d->format(DateTime::RFC1123)));
-        $this->assertEquals($d->format("U"), $c->getExpires());
-    }
-
-    function testNumeric() {
-        $c = new http\Cookie("1=%20; 2=%22; 3=%5D", 0, array(2));
-        $this->assertEquals("1=%20; 3=%5D; 2=%22; ", (string) $c);
-    }
-
-    function testRaw() {
-        $c = new http\Cookie("1=%20; 2=%22; e3=%5D", http\Cookie::PARSE_RAW, array(2));
-        $this->assertEquals("1=%2520; e3=%255D; 2=%2522; ", (string) $c);
-    }
-
-    function testSimple() {
-        $orig = new http\Cookie("key=value");
-        $copy = clone $orig;
-        $same = new http\Cookie($copy);
-        $even = new http\Cookie($same->toArray());
-        foreach (array($orig, $copy) as $c) {
-            $this->assertEquals("value", $c->getCookie("key"));
-            $this->assertEquals(-1, $c->getExpires());
-            $this->assertEquals(-1, $c->getMaxAge());
-            $this->assertEquals(0, $c->getFlags());
-            $this->assertEquals(null, $c->getPath());
-            $this->assertEquals(null, $c->getDomain());
-            $this->assertEquals(array(), $c->getExtras());
-            $this->assertEquals(array("key" => "value"), $c->getCookies());
-            $this->assertEquals("key=value; ", $c->toString());
-            $this->assertEquals(
-                array (
-                    "cookies" => 
-                        array (
-                            "key" => "value",
-                        ),
-                    "extras" => 
-                        array (
-                        ),
-                    "flags" => 0,
-                    "expires" => -1,
-                    "path" => "",
-                    "domain" => "",
-                       "max-age" => -1,
-                ),
-                $c->toArray()
-            );
-        }
-    }
-
-    function testExpires() {
-        $c = new http\Cookie("this=expires; expires=Tue, 24 Jan 2012 10:35:32 +0100");
-        $this->assertEquals("expires", $c->getCookie("this"));
-        $this->assertEquals(1327397732, $c->getExpires());
-        $o = clone $c;
-        $t = time();
-        $o->setExpires();
-        $this->assertEquals(-1, $o->getExpires());
-        $this->assertNotEquals(-1, $c->getExpires());
-        $o->setExpires($t);
-        $this->assertEquals($t, $o->getExpires());
-        $this->assertNotEquals($t, $c->getExpires());
-        $this->assertEquals(
-            sprintf(
-                "this=expires; expires=%s; ", 
-                date_create("@$t")
-                       ->setTimezone(new DateTimezone("UTC"))
-                       ->format("D, d M Y H:i:s \\G\\M\\T")
-            ), 
-            $o->toString()
-        );
-    }
-
-    function testMaxAge() {
-        $c = new http\Cookie("this=max-age; max-age=12345");
-        $this->assertEquals("max-age", $c->getCookie("this"));
-        $this->assertEquals(12345, $c->getMaxAge());
-        $o = clone $c;
-        $t = 54321;
-        $o->setMaxAge();
-        $this->assertEquals(-1, $o->getMaxAge());
-        $this->assertNotEquals(-1, $c->getMaxAge());
-        $o->setMaxAge($t);
-        $this->assertEquals($t, $o->getMaxAge());
-        $this->assertNotEquals($t, $c->getMaxAge());
-        $this->assertEquals(
-               "this=max-age; max-age=$t; ",
-            $o->toString()
-        );
-    }
-
-    function testPath() {
-        $c = new http\Cookie("this=has a path; path=/down; ");
-        $this->assertEquals("has a path", $c->getCookie("this"));
-        $this->assertEquals("this=has%20a%20path; path=/down; ", (string)$c);
-        $this->assertEquals("/down", $c->getPath());
-        $o = clone $c;
-        $p = "/up";
-        $o->setPath();
-        $this->assertEquals(null, $o->getPath());
-        $this->assertNotEquals(null, $c->getPath());
-        $o->setPath($p);
-        $this->assertEquals($p, $o->getPath());
-        $this->assertNotEquals($p, $c->getPath());
-        $this->assertEquals("this=has%20a%20path; path=$p; ", $o->toString());
-    }
-
-    function testDomain() {
-        $c = new http\Cookie("this=has a domain; domain=.example.com; ");
-        $this->assertEquals("has a domain", $c->getCookie("this"));
-        $this->assertEquals("this=has%20a%20domain; domain=.example.com; ", (string)$c);
-        $this->assertEquals(".example.com", $c->getDomain());
-        $o = clone $c;
-        $d = "sub.example.com";
-        $o->setDomain();
-        $this->assertEquals(null, $o->getDomain());
-        $this->assertNotEquals(null, $c->getDomain());
-        $o->setDomain($d);
-        $this->assertEquals($d, $o->getDomain());
-        $this->assertNotEquals($d, $c->getDomain());
-        $this->assertEquals("this=has%20a%20domain; domain=$d; ", $o->toString());
-    }
-
-    function testFlags() {
-        $c = new http\Cookie("icanhas=flags; secure; httpOnly");
-        $this->assertEquals(http\Cookie::SECURE, $c->getFlags() & http\Cookie::SECURE, "secure");
-        $this->assertEquals(http\Cookie::HTTPONLY, $c->getFlags() & http\Cookie::HTTPONLY, "httpOnly");
-        $c->setFlags($c->getFlags() ^ http\Cookie::SECURE);
-        $this->assertEquals(0, $c->getFlags() & http\Cookie::SECURE, "secure");
-        $this->assertEquals(http\Cookie::HTTPONLY, $c->getFlags() & http\Cookie::HTTPONLY, "httpOnly");
-        $c->setFlags($c->getFlags() ^ http\Cookie::HTTPONLY);
-        $this->assertEquals(0, $c->getFlags() & http\Cookie::SECURE, "secure");
-        $this->assertEquals(0, $c->getFlags() & http\Cookie::HTTPONLY, "httpOnly");
-        $this->assertEquals("icanhas=flags; ", $c->toString());
-        $c->setFlags(http\Cookie::SECURE|http\Cookie::HTTPONLY);
-        $this->assertEquals("icanhas=flags; secure; httpOnly; ", $c->toString());
-    }
-
-    function testExtras() {
-        $c = new http\Cookie("c1=v1; e0=1; e2=2; c2=v2", 0, array("e0", "e1", "e2"));
-        $this->assertEquals(array("c1"=>"v1", "c2"=>"v2"), $c->getCookies());
-        $this->assertEquals(array("e0"=>"1", "e2"=>"2"), $c->getExtras());
-        $c->addExtra("e1", 1);
-        $c->setExtra("e0");
-        $c->setExtra("e3", 123);
-        $this->assertEquals(123, $c->getExtra("e3"));
-        $c->setExtra("e3");
-        $this->assertEquals(array("e2"=>"2", "e1"=>1), $c->getExtras());
-        $this->assertEquals("c1=v1; c2=v2; e2=2; e1=1; ", $c->toString());
-        $c->addExtras(array("e3"=>3, "e4"=>4));
-        $this->assertEquals(array("e2"=>"2", "e1"=>1, "e3"=>3, "e4"=>4), $c->getExtras());
-        $this->assertEquals("c1=v1; c2=v2; e2=2; e1=1; e3=3; e4=4; ", $c->toString());
-        $c->setExtras(array("e"=>"x"));
-        $this->assertEquals(array("e"=>"x"), $c->getExtras());
-        $this->assertEquals("c1=v1; c2=v2; e=x; ", $c->toString());
-        $c->setExtras();
-        $this->assertEquals(array(), $c->getExtras());
-        $this->assertEquals("c1=v1; c2=v2; ", $c->toString());
-    }
-
-    function testCookies() {
-        $c = new http\Cookie("e0=1; c1=v1; e2=2; c2=v2", 0, array("c0", "c1", "c2"));
-        $this->assertEquals(array("c1"=>"v1", "c2"=>"v2"), $c->getExtras());
-        $this->assertEquals(array("e0"=>"1", "e2"=>"2"), $c->getCookies());
-        $c->addCookie("e1", 1);
-        $c->setCookie("e0");
-        $c->setCookie("e3", 123);
-        $this->assertEquals(123, $c->getCookie("e3"));
-        $c->setCookie("e3");
-        $this->assertEquals(array("e2"=>"2", "e1"=>1), $c->getCookies());
-        $this->assertEquals("e2=2; e1=1; c1=v1; c2=v2; ", $c->toString());
-        $c->addCookies(array("e3"=>3, "e4"=>4));
-        $this->assertEquals(array("e2"=>"2", "e1"=>1, "e3"=>3, "e4"=>4), $c->getCookies());
-        $this->assertEquals("e2=2; e1=1; e3=3; e4=4; c1=v1; c2=v2; ", $c->toString());
-        $c->setCookies(array("e"=>"x"));
-        $this->assertEquals(array("e"=>"x"), $c->getCookies());
-        $this->assertEquals("e=x; c1=v1; c2=v2; ", $c->toString());
-        $c->setCookies();
-        $this->assertEquals(array(), $c->getCookies());
-        $this->assertEquals("c1=v1; c2=v2; ", $c->toString());
-    }
-}
diff --git a/phpunit/EncodingTest.php b/phpunit/EncodingTest.php
deleted file mode 100644 (file)
index 4642613..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-<?php
-
-class EncodingStreamTest extends PHPUnit_Framework_TestCase {
-    function testChunkStatic() {
-        $file = file(__FILE__);
-        $cenc = array_reduce(
-            $file,
-            function($data, $line) {
-                return $data . sprintf("%lx\r\n%s\r\n", strlen($line), $line);
-            }
-        ) . "0\r\n";
-
-        $this->assertEquals(implode("", $file), http\Encoding\Stream\Dechunk::decode($cenc));
-    }
-
-    function testChunkNoteEncoded() {
-        $s = "this is apparently not encodded\n";
-        $this->assertEquals($s, @http\Encoding\Stream\Dechunk::decode($s));
-    }
-
-    function testChunkNotEncodedNotice() {
-           error_reporting(E_ALL);
-        $this->setExpectedException("PHPUnit_Framework_Error_Notice", 
-            "Data does not seem to be chunked encoded");
-        $s = "this is apparently not encodded\n";
-        $this->assertEquals($s, http\Encoding\Stream\Dechunk::decode($s));
-    }
-
-    function testChunkNotEncodedFail() {
-        $s = "3\nis \nbetter than\n1\n";
-        $this->assertNotEquals($s, @http\Encoding\Stream\Dechunk::decode($s));
-    }
-
-    function testChunkNotEncodedWarning1() {
-        $this->setExpectedException("PHPUnit_Framework_Error_Warning", 
-            "Expected LF at pos 8 of 20 but got 0x74");
-        $s = "3\nis \nbetter than\n1\n";
-        http\Encoding\Stream\Dechunk::decode($s);
-    }
-
-    function testChunkNotEncodedWarning2() {
-        $this->setExpectedException("PHPUnit_Framework_Error_Warning", 
-            "Expected CRLF at pos 10 of 24 but got 0x74 0x74");
-        $s = "3\r\nis \r\nbetter than\r\n1\r\n";
-        http\Encoding\Stream\Dechunk::decode($s);
-    }
-
-    function testChunkNotEncodedWarning3() {
-        $this->setExpectedException("PHPUnit_Framework_Error_Warning", 
-            "Expected chunk size at pos 6 of 27 but got trash");
-        $s = "3\nis \nreally better than\n1\n";
-        http\Encoding\Stream\Dechunk::decode($s);
-    }
-
-    function testChunkFlush() {
-        $dech = new http\Encoding\Stream\Dechunk(http\Encoding\Stream::FLUSH_FULL);
-        $file = file(__FILE__);
-        $data = "";
-        foreach ($file as $i => $line) {
-            $dech = clone $dech;
-            if ($i % 2) {
-                $data .= $dech->update(sprintf("%lx\r\n%s\r\n", strlen($line), $line));
-            } else {
-                $data .= $dech->update(sprintf("%lx\r\n", strlen($line)));
-                $data .= $dech->flush();
-                $data .= $dech->update($line);
-                $data .= $dech->flush();
-                $data .= $dech->update("\r\n");
-            }
-            $dech->flush();
-            $this->assertFalse($dech->done());
-        }
-        $data .= $dech->update("0\r\n");
-        $this->assertTrue($dech->done());
-        $data .= $dech->finish();
-        $this->assertEquals(implode("", $file), $data);
-    }
-
-    function testZlibStatic() {
-        $file = file_get_contents(__FILE__);
-        $this->assertEquals($file, 
-            http\Encoding\Stream\Inflate::decode(
-                http\Encoding\Stream\Deflate::encode(
-                    $file, http\Encoding\Stream\Deflate::TYPE_GZIP
-                )
-            )
-        );
-        $this->assertEquals($file, 
-            http\Encoding\Stream\Inflate::decode(
-                http\Encoding\Stream\Deflate::encode(
-                    $file, http\Encoding\Stream\Deflate::TYPE_ZLIB
-                )
-            )
-        );
-        $this->assertEquals($file, 
-            http\Encoding\Stream\Inflate::decode(
-                http\Encoding\Stream\Deflate::encode(
-                    $file, http\Encoding\Stream\Deflate::TYPE_RAW
-                )
-            )
-        );
-    }
-
-    function testZlibAutoFlush() {
-        $defl = new http\Encoding\Stream\Deflate(http\Encoding\Stream::FLUSH_FULL);
-        $infl = new http\Encoding\Stream\Inflate;
-
-        for ($f = fopen(__FILE__, "rb"); !feof($f); $data = fread($f, 0x100)) {
-            $infl = clone $infl;
-            $defl = clone $defl;
-            if (isset($data)) {
-                $this->assertEquals($data, $infl->update($defl->update($data)));
-            }
-        }
-
-        echo $infl->update($defl->finish());
-        echo $infl->finish();
-    }
-
-    function testZlibWithoutFlush() {
-        $defl = new http\Encoding\Stream\Deflate;
-        $infl = new http\Encoding\Stream\Inflate;
-        $file = file(__FILE__);
-        $data = "";
-        foreach ($file as $line) {
-            $infl = clone $infl;
-            $defl = clone $defl;
-            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();
-        $this->assertEquals(implode("", $file), $data);
-    }
-
-    function testZlibWithExplicitFlush() {
-        $defl = new http\Encoding\Stream\Deflate;
-        $infl = new http\Encoding\Stream\Inflate;
-        $file = file(__FILE__);
-        $data = "";
-        foreach ($file as $line) {
-               $data .= $infl->flush();
-            if (strlen($temp = $defl->update($line))) {
-                $data .= $infl->update($temp);
-                       $data .= $infl->flush();
-            }
-            if (strlen($temp = $defl->flush())) {
-                $data .= $infl->update($temp);
-                       $data .= $infl->flush();
-            }
-            $this->assertTrue($defl->done());
-        }
-        if (strlen($temp = $defl->finish())) {
-            $data .= $infl->update($temp);
-        }
-        $this->assertTrue($defl->done());
-        $data .= $infl->finish();
-        $this->assertTrue($infl->done());
-        $this->assertEquals(implode("", $file), $data);
-    }
-
-    function testInflateError() {
-        $this->setExpectedException("PHPUnit_Framework_Error_Warning",
-            "Could not inflate data: data error");
-        http\Encoding\Stream\Inflate::decode("if this goes through, something's pretty wrong");
-    }
-}
diff --git a/phpunit/MessageBodyTest.php b/phpunit/MessageBodyTest.php
deleted file mode 100644 (file)
index 3aaf3eb..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-<?php
-
-class MessageBodyTest extends PHPUnit_Framework_TestCase {
-    protected $file, $temp;
-
-    function setUp() {
-        $this->file = new http\Message\Body(fopen(__FILE__, "r"));
-        $this->temp = new http\Message\Body();
-    }
-
-    function testStat() {
-        $this->assertEquals(filesize(__FILE__), $this->file->stat("size"));
-        $this->assertEquals(filemtime(__FILE__), $this->file->stat("mtime"));
-        $this->assertEquals(fileatime(__FILE__), $this->file->stat("atime"));
-        $this->assertEquals(filectime(__FILE__), $this->file->stat("ctime"));
-        $this->assertEquals(
-            (object) array(
-                "size" => 0,
-                "mtime" => 0,
-                "atime" => 0,
-                "ctime" => 0,
-            ),
-            $this->temp->stat()
-        );
-    }
-
-    function testAppendError() {
-       $this->setExpectedException("http\Exception\RuntimeException");
-        $this->file->append("nope");
-    }
-    function testAppend() {
-        $this->temp->append("yes");
-    }
-
-    function testAddForm() {
-        $this->temp->addForm(
-            array(
-                "foo" => "bar",
-                "more" => array(
-                    "bah", "baz", "fuz"
-                ),
-            ),
-            array(
-                array(
-                    "file" => __FILE__,
-                    "name" => "upload",
-                    "type" => "text/plain",
-                )
-            )
-        );
-
-        $file = str_replace("%", "%c", file_get_contents(__FILE__));
-        $this->assertStringMatchesFormat(
-            "--%x.%x\r\n".
-            "Content-Disposition: form-data; name=\"foo\"\r\n".
-            "\r\n".
-            "bar\r\n".
-            "--%x.%x\r\n".
-            "Content-Disposition: form-data; name=\"more[0]\"\r\n".
-            "\r\n".
-            "bah\r\n".
-            "--%x.%x\r\n".
-            "Content-Disposition: form-data; name=\"more[1]\"\r\n".
-            "\r\n".
-            "baz\r\n".
-            "--%x.%x\r\n".
-            "Content-Disposition: form-data; name=\"more[2]\"\r\n".
-            "\r\n".
-            "fuz\r\n".
-            "--%x.%x\r\n".
-            "Content-Disposition: form-data; name=\"upload\"; filename=\"MessageBodyTest.php\"\r\n".
-            "Content-Transfer-Encoding: binary\r\n".
-            "Content-Type: text/plain\r\n".
-            "\r\n".
-            "{$file}\r\n".
-            "--%x.%x--\r\n".
-            "",
-            str_replace("\r", "", $this->temp) // phpunit replaces \r\n with \n
-        );
-    }
-
-    function testAddPart() {
-        $this->temp->addPart(new http\Message("This: is a header\n\nand this is the data\n"));
-        $this->assertStringMatchesFormat(
-            "--%x.%x\r\n".
-            "This: is a header\r\n".
-            "Content-Length: 21\r\n".
-            "\r\n".
-            "and this is the data\n\r\n".
-            "--%x.%x--\r\n".
-            "",
-            str_replace("\r", "", $this->temp)
-        );
-    }
-
-    function testEtag() {
-        $s = stat(__FILE__);
-        $this->assertEquals(
-            sprintf(
-                "%lx-%lx-%lx", 
-                $s["ino"],$s["mtime"],$s["size"]
-            ),
-            $this->file->etag()
-        );
-        $this->assertEquals(crc32(""), $this->temp->etag());
-    }
-
-    function testToStream() {
-        $this->file->toStream($f = fopen("php://temp", "w")); 
-        fseek($f, 0, SEEK_SET);
-        $this->assertEquals(
-            file_get_contents(__FILE__), 
-            fread($f, filesize(__FILE__))
-        );
-    }
-
-    function testToCallback() {
-        $s = "";
-        $this->file->toCallback(
-            function($body, $string) use (&$s) { $s.=$string; }
-        );
-        $this->assertEquals($s, (string) $this->file);
-    }
-
-    function testClone() {
-        $this->assertEquals((string) $this->file, (string) clone $this->file);
-    }
-    
-    function testGetResource() {
-       $stream = $this->file->getResource();
-       $this->assertTrue(is_resource($stream));
-       $stat = fstat($stream);
-       $this->assertEquals(filesize(__FILE__), $stat["size"]);
-    }
-}
diff --git a/phpunit/ParamsTest.php b/phpunit/ParamsTest.php
deleted file mode 100644 (file)
index 71bfcf4..0000000
+++ /dev/null
@@ -1,186 +0,0 @@
-<?php
-
-class ParamsTest extends PHPUnit_Framework_TestCase {
-    function testDefault() {
-        $s = "foo, bar;arg=0;bla, gotit=0;now";
-        $this->runAssertions(
-            new http\Params($s),
-            str_replace(" ", "", $s)
-        );
-    }
-
-    function testCustom() {
-        $s = "foo bar.arg:0.bla gotit:0.now";
-        $this->runAssertions(
-            new http\Params($s, " ", ".", ":"),
-            $s
-        );
-    }
-
-    function testQuoted() {
-        $p = new http\Params("multipart/form-data; boundary=\"--123\"");
-        $this->assertEquals(
-            array(
-                "multipart/form-data" => array(
-                    "value" => true,
-                    "arguments" => array(
-                        "boundary" => "--123"
-                    )
-                )
-            ),
-            $p->params
-        );
-        $this->assertEquals("multipart/form-data;boundary=--123", (string) $p);
-    }
-
-    function testEscaped() {
-        $p = new http\Params("form-data; name=\"upload\"; filename=\"trick\\\"\0\\\"ed\"");
-        $this->assertEquals(
-            array(
-                "form-data" => array(
-                    "value" => true,
-                    "arguments" => array(
-                        "name" => "upload",
-                        "filename" => "trick\"\0\"ed"
-                    )
-                )
-            ),
-            $p->params
-        );
-        $this->assertEquals("form-data;name=upload;filename=\"trick\\\"\\0\\\"ed\"", (string) $p);
-    }
-
-    function testUrlencoded() {
-        $s = "foo=b%22r&bar=b%22z&a%5B%5D%5B%5D=1";
-        $p = new http\Params($s, "&", "", "=", http\Params::PARSE_URLENCODED);
-        $this->assertEquals(
-            array(
-                "foo" => array(
-                    "value" => "b\"r",
-                    "arguments" => array(),
-                ),
-                "bar" => array(
-                    "value" => "b\"z",
-                    "arguments" => array(),
-                ),
-                "a[][]" => array(
-                    "value" => "1",
-                    "arguments" => array(),
-                ),
-            ),
-            $p->params
-        );
-        $this->assertEquals("foo=b%22r&bar=b%22z&a%5B%5D%5B%5D=1", (string) $p);
-    }
-
-    function testQuery() {
-        $s = "foo=b%22r&bar=b%22z&a%5B%5D%5B%5D=1";
-        $p = new http\Params($s, "&", "", "=", http\Params::PARSE_QUERY);
-        $this->assertEquals(
-            array(
-                "foo" => array(
-                    "value" => "b\"r",
-                    "arguments" => array(),
-                ),
-                "bar" => array(
-                    "value" => "b\"z",
-                    "arguments" => array(),
-                ),
-                "a" => array(
-                    "value" => array(
-                        array("1")
-                    ),
-                    "arguments" => array(),
-                ),
-            ),
-            $p->params
-        );
-        $this->assertEquals("foo=b%22r&bar=b%22z&a%5B0%5D%5B0%5D=1", (string) $p);
-    }
-
-
-    function testEmpty() {
-        $p = new http\Params(NULL);
-        $this->assertEquals(array(), $p->params);
-    }
-
-    function testErrorOfToArrayWithArgs() {
-        $this->setExpectedException("PHPUnit_Framework_Error_Warning");
-        $p = new http\Params();
-        $p->toArray("dummy");
-    }
-
-    function testIntegerKeys() {
-        $p = new http\Params("0=nothing;1=yes");
-        $this->assertEquals(array("0" => array("value" => "nothing", "arguments" => array(1=>"yes"))), $p->params);
-        $this->assertEquals("0=nothing;1=yes", $p->toString());
-    }
-
-    function testBoolParamArguments() {
-        $p = new http\Params;
-        $container = array("value" => false, "arguments" => array("wrong" => false, "correct" => true));
-        $p["container"] = $container;
-        $this->assertEquals("container=0;wrong=0;correct", $p->toString());
-        $this->assertEquals(array("container" => $container), $p->toArray());
-    }
-
-    function testNoArgsForParam() {
-        $p = new http\Params;
-        $p["param"] = true;
-        $this->assertEquals("param", $p->toString());
-        $p["param"] = false;
-        $this->assertEquals("param=0", $p->toString());
-    }
-
-    protected function runAssertions($p, $s) {
-        $this->assertCount(3, $p->params);
-        $this->assertArrayHasKey("foo", $p->params);
-        $this->assertArrayHasKey("bar", $p->params);
-        $this->assertArrayHasKEy("gotit", $p->params);
-
-        $this->assertTrue($p["foo"]["value"]);
-        $this->assertTrue($p["bar"]["value"]);
-        $this->assertEmpty($p["gotit"]["value"]);
-
-        $this->assertEmpty($p["foo"]["arguments"]);
-        $this->assertCount(2, $p["bar"]["arguments"]);
-        $this->assertCount(1, $p["gotit"]["arguments"]);
-
-        $this->assertEmpty($p["bar"]["arguments"]["arg"]);
-        $this->assertTrue($p["bar"]["arguments"]["bla"]);
-        $this->assertTrue($p["gotit"]["arguments"]["now"]);
-
-        $this->assertEquals($s, (string) $p);
-
-        $comp = array (
-            'foo' => 
-            array (
-                'value' => true,
-                'arguments' => 
-                array (
-                ),
-            ),
-            'bar' => 
-            array (
-                'value' => true,
-                'arguments' => 
-                array (
-                    'arg' => '0',
-                    'bla' => true,
-                ),
-            ),
-            'gotit' => 
-            array (
-                'value' => '0',
-                'arguments' => 
-                array (
-                    'now' => true,
-                ),
-            ),
-        );
-
-        $this->assertEquals($comp, $p->params);
-        $a = new http\Params($p->params);
-        $this->assertEquals($comp, $a->toArray());
-       }
-}
diff --git a/phpunit/QueryStringTest.php b/phpunit/QueryStringTest.php
deleted file mode 100644 (file)
index fb2eb47..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-<?php
-
-class QueryStringTest extends PHPUnit_Framework_TestCase {
-    protected $q;
-    protected $s = "a=b&r[]=0&r[]=1&r[]=2&rr[][]=00&rr[][]=01&1=2";
-    protected $e = "a=b&r%5B0%5D=0&r%5B1%5D=1&r%5B2%5D=2&rr%5B0%5D%5B0%5D=00&rr%5B0%5D%5B1%5D=01&1=2";
-
-    function setUp() {
-        $this->q = new http\QueryString($this->s);
-    }
-
-    function testSimple() {
-        $this->assertEquals($this->e, (string) $this->q);
-        $this->assertEquals($this->e, $this->q->get());
-    }
-
-    function testGetDefval() {
-        $this->assertEquals("nonexistant", $this->q->get("unknown", "s", "nonexistant"));
-        $this->assertEquals(null, $this->q->get("unknown"));
-    }
-
-    function testGetA() {
-        $this->assertEquals("b", $this->q->get("a"));
-        $this->assertEquals(0, $this->q->get("a", "i"));
-        $this->assertEquals(array("b"), $this->q->get("a", "a"));
-        $this->assertEquals((object)array("scalar" => "b"), $this->q->get("a", "o"));
-    }
-
-    function testGetR() {
-        $this->assertEquals(array(0,1,2), $this->q->get("r"));
-    }
-
-    function testGetRR() {
-        $this->assertEquals(array(array("00","01")), $this->q->get("rr"));
-    }
-
-    function testGet1() {
-        $this->assertEquals(2, $this->q->get(1));
-        $this->assertEquals("2", $this->q->get(1, "s"));
-        $this->assertEquals(2.0, $this->q->get(1, "f"));
-        $this->assertTrue($this->q->get(1, "b"));
-    }
-
-    function testDelA() {
-        $this->assertEquals("b", $this->q->get("a", http\QueryString::TYPE_STRING, null, true));
-        $this->assertEquals(null, $this->q->get("a"));
-    }
-
-    function testDelAll() {
-        $this->q->set(array("a" => null, "r" => null, "rr" => null, 1 => null));
-        $this->assertEquals("", $this->q->toString());
-    }
-
-    function testQSO() {
-        $this->assertEquals($this->e, (string) new http\QueryString($this->q));
-        $this->assertEquals(http_build_query(array("e"=>$this->q->toArray())), (string) new http\QueryString(array("e" => $this->q)));
-    }
-
-    function testIterator() {
-        $this->assertEquals($this->q->toArray(), iterator_to_array($this->q));
-    }
-
-    function testSerialize() {
-        $this->assertEquals($this->e, (string) unserialize(serialize($this->q)));
-    }
-}
diff --git a/phpunit/UrlTest.php b/phpunit/UrlTest.php
deleted file mode 100644 (file)
index dcf3b4f..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-<?php
-
-class UrlTest extends PHPUnit_Framework_TestCase {
-       protected $url; 
-       function setUp() {
-               $this->url = "http://user:pass@www.example.com:8080/path/file.ext".
-                       "?foo=bar&more[]=1&more[]=2#hash";
-    }
-
-       function testStandard() {
-               $this->assertEquals($this->url, (string) new http\Url($this->url));
-               
-               $url = new http\Url($this->url, 
-                       array("path" => "changed", "query" => "foo=&added=this"), 
-                       http\Url::JOIN_PATH |
-                       http\Url::JOIN_QUERY |
-                       http\Url::STRIP_AUTH |
-                       http\Url::STRIP_FRAGMENT
-               );
-
-               $this->assertEquals("http", $url->scheme);
-               $this->assertEmpty($url->user);
-               $this->assertEmpty($url->pass);
-               $this->assertEquals("www.example.com", $url->host);
-               $this->assertEquals(8080, $url->port);
-               $this->assertEquals("/path/changed", $url->path);
-               $this->assertEquals("more%5B0%5D=1&more%5B1%5D=2&added=this", $url->query);
-        $this->assertEmpty($url->fragment);
-    }
-
-    function testMod() {
-        $tmp = new http\Url($this->url);
-        $mod = $tmp->mod(array("query" => "set=1"), http\Url::REPLACE);
-        $this->assertNotEquals($tmp->toArray(), $mod->toArray());
-        $this->assertEquals("set=1", $mod->query);
-        $this->assertEquals("new_fragment", $tmp->mod("#new_fragment")->fragment);
-    }
-
-    function testStrings() {
-        $url = new http\Url($this->url);
-        $this->assertEquals((string) $url, (string) new http\Url((string) $url));
-    }
-
-    function testArrays() {
-        $url = new http\Url($this->url);
-               $url2 = new http\Url($url->toArray());
-        $this->assertEquals($url->toArray(), $url2->toArray());
-    }
-}
diff --git a/tests/bug66388.phpt b/tests/bug66388.phpt
new file mode 100644 (file)
index 0000000..9f9c95e
--- /dev/null
@@ -0,0 +1,33 @@
+--TEST--
+Bug #66388 (Crash on POST with Content-Length:0 and untouched body)
+--SKIPIF--
+<?php
+include "skipif.inc";
+skip_online_test();
+?>
+--FILE--
+<?php
+
+use http\Client,
+       http\Client\Request;
+
+echo "Test\n";
+
+$client = new Client();
+$request = new Request(
+       'POST',
+       'https://api.twitter.com/oauth/request_token',
+       array(
+               'Content-Length' => 0
+       )
+);
+$client->enqueue($request);
+echo $client->send()->getResponse()->getResponseCode();
+
+?>
+
+===DONE===
+--EXPECT--
+Test
+401
+===DONE===
index 44ff3d1..89d4d65 100644 (file)
@@ -3,6 +3,7 @@ client observer
 --SKIPIF--
 <?php
 include "skipif.inc";
+skip_online_test();
 ?>
 --FILE--
 <?php
index b09c299..62d0bca 100644 (file)
@@ -3,6 +3,7 @@ client once & wait
 --SKIPIF--
 <?php
 include "skipif.inc";
+skip_online_test();
 ?>
 --FILE--
 <?php
index 22ad9fe..1342efa 100644 (file)
@@ -3,6 +3,7 @@ client reset
 --SKIPIF--
 <?php
 include "skipif.inc";
+skip_online_test();
 ?>
 --FILE--
 <?php
index 36a3f0a..4576f16 100644 (file)
@@ -3,6 +3,7 @@ client response callback
 --SKIPIF--
 <?php
 include "skipif.inc";
+skip_online_test();
 ?>
 --FILE--
 <?php
index 762e044..7b3986e 100644 (file)
@@ -3,6 +3,7 @@ client response callback + dequeue
 --SKIPIF--
 <?php
 include "skipif.inc";
+skip_online_test();
 ?>
 --FILE--
 <?php
index 8421b51..74cdbcd 100644 (file)
@@ -3,6 +3,7 @@ client response callback + requeue
 --SKIPIF--
 <?php
 include "skipif.inc";
+skip_online_test();
 ?>
 --FILE--
 <?php
index d7fe358..31584d3 100644 (file)
@@ -3,6 +3,7 @@ client features
 --SKIPIF--
 <?php
 include "skipif.inc";
+skip_online_test();
 ?>
 --FILE--
 <?php
index 937045d..e1553d6 100644 (file)
@@ -3,6 +3,7 @@ client static cookies
 --SKIPIF--
 <?php
 include "skipif.inc";
+skip_online_test();
 ?>
 --FILE--
 <?php
@@ -32,16 +33,4 @@ foreach (http\Client::getAvailableDrivers() as $driver) {
 Done
 --EXPECTREGEX--
 Test
-(?:string\(46\) "Array
-\(
-    \[test\] \=\> bar
-    \[foo\] \=\> test
-\)
-"
-string\(46\) "Array
-\(
-    \[test\] \=\> test
-    \[foo\] \=\> bar
-\)
-"
-)+Done
+(?:string\(46\) "Array\n\(\n    \[test\] \=\> bar\n    \[foo\] \=\> test\n\)\n"\nstring\(46\) "Array\n\(\n    \[test\] \=\> test\n    \[foo\] \=\> bar\n\)\n"\n)+Done
index 7563a77..055d585 100644 (file)
@@ -3,34 +3,38 @@ client upload
 --SKIPIF--
 <?php
 include "skipif.inc";
+skip_online_test();
 ?>
 --FILE--
 <?php
 echo "Test\n";
 
-$request = new http\Client\Request("POST", "http://dev.iworks.at/ext-http/.print_request.php");
-$request->getBody()->addForm(null, array("file"=>__FILE__, "name"=>"upload", "type"=>"text/plain"));
-
-foreach (http\Client::getAvailableDrivers() as $driver) {
-       $client = new http\Client($driver);
-       $client->enqueue($request)->send();
-       var_dump($client->getResponse()->getBody()->toString());
-}
-?>
-Done
---EXPECTREGEX--
-Test
-(?:string\(\d+\) "Array
+$RE =
+'/(Array
 \(
     \[upload\] \=\> Array
         \(
             \[name\] \=\> client010\.php
             \[type\] \=\> text\/plain
-            \[tmp_name\] \=\> .*
+            \[tmp_name\] \=\> .+
             \[error\] \=\> 0
             \[size\] \=\> \d+
         \)
 
 \)
-"
-)+Done
+)+/';
+$request = new http\Client\Request("POST", "http://dev.iworks.at/ext-http/.print_request.php");
+$request->getBody()->addForm(null, array("file"=>__FILE__, "name"=>"upload", "type"=>"text/plain"));
+
+foreach (http\Client::getAvailableDrivers() as $driver) {
+       $client = new http\Client($driver);
+       $client->enqueue($request)->send();
+       if (!preg_match($RE, $s = $client->getResponse()->getBody()->toString())) {
+               echo($s);
+       }
+}
+?>
+Done
+--EXPECT--
+Test
+Done
\ No newline at end of file
index 188b178..17c60ed 100644 (file)
@@ -3,6 +3,7 @@ client history
 --SKIPIF--
 <?php 
 include "skipif.inc";
+skip_online_test();
 ?>
 --FILE--
 <?php 
@@ -40,12 +41,12 @@ X-Original-Content-Length: 6
 
 foobar
 HTTP/1.1 200 OK
+Vary: %s
+Content-Type: text/html
 Date: %s
 Server: %s
-Vary: %s
+X-Original-Transfer-Encoding: chunked
 Content-Length: 19
-Content-Type: text/html
-X-Original-Content-Length: 19
 
 string(6) "foobar"
 
@@ -59,12 +60,12 @@ X-Original-Content-Length: 6
 
 foobar
 HTTP/1.1 200 OK
+Vary: %s
+Content-Type: text/html
 Date: %s
 Server: %s
-Vary: %s
+X-Original-Transfer-Encoding: chunked
 Content-Length: 19
-Content-Type: text/html
-X-Original-Content-Length: 19
 
 string(6) "foobar"
 
@@ -78,12 +79,12 @@ X-Original-Content-Length: 6
 
 foobar
 HTTP/1.1 200 OK
+Vary: %s
+Content-Type: text/html
 Date: %s
 Server: %s
-Vary: %s
+X-Original-Transfer-Encoding: chunked
 Content-Length: 19
-Content-Type: text/html
-X-Original-Content-Length: 19
 
 string(6) "foobar"
 
index 71e5081..ad6c2eb 100644 (file)
@@ -3,6 +3,7 @@ client ssl
 --SKIPIF--
 <?php 
 include "skipif.inc";
+skip_online_test();
 ?>
 --FILE--
 <?php 
index 0de0547..00bae4e 100644 (file)
@@ -3,6 +3,7 @@ client observers
 --SKIPIF--
 <?php 
 include "skipif.inc";
+skip_online_test();
 ?>
 --FILE--
 <?php 
@@ -50,7 +51,7 @@ $client->attach(
                )
 );
 
-$client->enqueue(new http\Client\Request("GET", "http://dev.iworks.at/ext-http/"))->send();
+$client->enqueue(new http\Client\Request("GET", "http://www.example.com/"))->send();
 var_dump(1 === preg_match("/(\.-)+/", $client->pi));
 var_dump(3 === count($client->getObservers()));
 $client->detach($o1);
diff --git a/tests/client014.phpt b/tests/client014.phpt
new file mode 100644 (file)
index 0000000..d0ff471
--- /dev/null
@@ -0,0 +1,26 @@
+--TEST--
+reset content length when resetting body
+--SKIPIF--
+<?php 
+include "skipif.inc";
+?>
+--FILE--
+<?php 
+
+echo "Test\n";
+
+$client = new http\Client;
+$request = new http\Client\Request("PUT", "put.php");
+$request->setBody(new http\Message\Body(fopen(__FILE__, "r")));
+$client->enqueue($request);
+var_dump($request->getHeader("Content-Length"));
+$request->setBody(new http\Message\Body);
+$client->requeue($request);
+var_dump($request->getHeader("Content-Length"));
+?>
+===DONE===
+--EXPECTF--
+Test
+int(379)
+bool(false)
+===DONE===
index 2f25291..270512b 100644 (file)
@@ -3,6 +3,7 @@ client response cookie
 --SKIPIF--
 <?php
 include "skipif.inc";
+skip_online_test();
 ?>
 --FILE--
 <?php
@@ -20,26 +21,4 @@ foreach (http\Client::getAvailableDrivers() as $driver) {
 Done
 --EXPECTREGEX--
 Test
-(?:array\(7\) \{
-  \["cookies"\]\=\>
-  array\(2\) \{
-    \["foo"\]\=\>
-    string\(3\) "bar"
-    \["bar"\]\=\>
-    string\(3\) "foo"
-  \}
-  \["extras"\]\=\>
-  array\(0\) \{
-  \}
-  \["flags"\]\=\>
-  int\(0\)
-  \["expires"\]\=\>
-  int\(\-1\)
-  \["max\-age"\]\=\>
-  int\(\-1\)
-  \["path"\]\=\>
-  string\(0\) ""
-  \["domain"\]\=\>
-  string\(0\) ""
-\}
-)+Done
+(?:array\(7\) \{\n  \["cookies"\]\=\>\n  array\(2\) \{\n    \["foo"\]\=\>\n    string\(3\) "bar"\n    \["bar"\]\=\>\n    string\(3\) "foo"\n  \}\n  \["extras"\]\=\>\n  array\(0\) \{\n  \}\n  \["flags"\]\=\>\n  int\(0\)\n  \["expires"\]\=\>\n  int\(\-1\)\n  \["max\-age"\]\=\>\n  int\(\-1\)\n  \["path"\]\=\>\n  string\(0\) ""\n  \["domain"\]\=\>\n  string\(0\) ""\n\}\n)+Done
index 3a0c50a..2379cc7 100644 (file)
@@ -3,6 +3,7 @@ client response cookies
 --SKIPIF--
 <?php
 include "skipif.inc";
+skip_online_test();
 ?>
 --FILE--
 <?php
@@ -20,44 +21,4 @@ foreach (http\Client::getAvailableDrivers() as $driver) {
 Done
 --EXPECTREGEX--
 Test
-(?:array\(7\) \{
-  \["cookies"\]\=\>
-  array\(1\) \{
-    \["temp"\]\=\>
-    string\(1[23]\) "\d+\.\d+"
-  \}
-  \["extras"\]\=\>
-  array\(0\) \{
-  \}
-  \["flags"\]\=\>
-  int\(0\)
-  \["expires"\]\=\>
-  int\(\-1\)
-  \["max\-age"\]\=\>
-  int\(\-1\)
-  \["path"\]\=\>
-  string\(0\) ""
-  \["domain"\]\=\>
-  string\(0\) ""
-\}
-array\(7\) \{
-  \["cookies"\]\=\>
-  array\(1\) \{
-    \["perm"\]\=\>
-    string\(1[23]\) "\d+\.\d+"
-  \}
-  \["extras"\]\=\>
-  array\(0\) \{
-  \}
-  \["flags"\]\=\>
-  int\(0\)
-  \["expires"\]\=\>
-  int\(\d+\)
-  \["max\-age"\]\=\>
-  int\(\-1\)
-  \["path"\]\=\>
-  string\(0\) ""
-  \["domain"\]\=\>
-  string\(0\) ""
-\}
-)+Done
+(?:array\(7\) \{\n  \["cookies"\]\=\>\n  array\(1\) \{\n    \["temp"\]\=\>\n    string\(1\d\) "\d+\.\d+"\n  \}\n  \["extras"\]\=\>\n  array\(0\) \{\n  \}\n  \["flags"\]\=\>\n  int\(0\)\n  \["expires"\]\=\>\n  int\(\-1\)\n  \["max\-age"\]\=\>\n  int\(\-1\)\n  \["path"\]\=\>\n  string\(0\) ""\n  \["domain"\]\=\>\n  string\(0\) ""\n\}\narray\(7\) \{\n  \["cookies"\]\=\>\n  array\(1\) \{\n    \["perm"\]\=\>\n    string\(1\d\) "\d+\.\d+"\n  \}\n  \["extras"\]\=\>\n  array\(0\) \{\n  \}\n  \["flags"\]\=\>\n  int\(0\)\n  \["expires"\]\=\>\n  int\(\d+\)\n  \["max\-age"\]\=\>\n  int\(\-1\)\n  \["path"\]\=\>\n  string\(0\) ""\n  \["domain"\]\=\>\n  string\(0\) ""\n\}\n)+Done
index 20dcef2..8ab936d 100644 (file)
@@ -3,6 +3,7 @@ client response transfer info
 --SKIPIF--
 <?php
 include "skipif.inc";
+skip_online_test();
 ?>
 --FILE--
 <?php
diff --git a/tests/cookie001.phpt b/tests/cookie001.phpt
new file mode 100644 (file)
index 0000000..3adf8d7
--- /dev/null
@@ -0,0 +1,31 @@
+--TEST--
+cookies empty state
+--SKIPIF--
+<?php
+include "skipif.inc";
+?>
+--FILE--
+<?php
+echo "Test\n";
+
+$c = new http\Cookie;
+$o = clone $c;
+$a = array(
+       "cookies" => array(),
+       "extras" => array(),
+       "flags" => 0,
+       "expires" => -1,
+       "path" => "",
+       "domain" => "",
+       "max-age" => -1,
+);
+var_dump($a == $c->toArray());
+var_dump($a == $o->toArray());
+
+?>
+DONE
+--EXPECT--
+Test
+bool(true)
+bool(true)
+DONE
diff --git a/tests/cookie002.phpt b/tests/cookie002.phpt
new file mode 100644 (file)
index 0000000..98c883b
--- /dev/null
@@ -0,0 +1,22 @@
+--TEST--
+cookies expire as date
+--SKIPIF--
+<?php
+include "skipif.inc";
+?>
+--INI--
+date.timezone=UTC
+--FILE--
+<?php
+echo "Test\n";
+
+$d = new DateTime;
+$c = new http\Cookie(array("expires" => $d->format(DateTime::RFC1123)));
+var_dump($d->format("U") == $c->getExpires());
+
+?>
+DONE
+--EXPECT--
+Test
+bool(true)
+DONE
diff --git a/tests/cookie003.phpt b/tests/cookie003.phpt
new file mode 100644 (file)
index 0000000..c546f52
--- /dev/null
@@ -0,0 +1,19 @@
+--TEST--
+cookies numeric keys
+--SKIPIF--
+<?php
+include "skipif.inc";
+?>
+--FILE--
+<?php
+echo "Test\n";
+
+$c = new http\Cookie("1=%20; 2=%22; 3=%5D", 0, array(2));
+var_dump("1=%20; 3=%5D; 2=%22; " === (string) $c);
+
+?>
+DONE
+--EXPECT--
+Test
+bool(true)
+DONE
diff --git a/tests/cookie004.phpt b/tests/cookie004.phpt
new file mode 100644 (file)
index 0000000..1c4ead4
--- /dev/null
@@ -0,0 +1,19 @@
+--TEST--
+cookies raw
+--SKIPIF--
+<?php
+include "skipif.inc";
+?>
+--FILE--
+<?php
+echo "Test\n";
+
+$c = new http\Cookie("1=%20; 2=%22; e3=%5D", http\Cookie::PARSE_RAW, array(2));
+var_dump("1=%2520; e3=%255D; 2=%2522; " === (string) $c);
+
+?>
+DONE
+--EXPECT--
+Test
+bool(true)
+DONE
diff --git a/tests/cookie005.phpt b/tests/cookie005.phpt
new file mode 100644 (file)
index 0000000..f210402
--- /dev/null
@@ -0,0 +1,75 @@
+--TEST--
+cookies simple data
+--SKIPIF--
+<?php
+include "skipif.inc";
+?>
+--FILE--
+<?php
+echo "Test\n";
+
+$orig = new http\Cookie("key=value");
+$copy = clone $orig;
+$same = new http\Cookie($copy);
+$even = new http\Cookie($same->toArray());
+foreach (array($orig, $copy) as $c) {
+       var_dump($c->getCookie("key"));
+       var_dump($c->getExpires());
+       var_dump($c->getMaxAge());
+       var_dump($c->getFlags());
+       var_dump($c->getPath());
+       var_dump($c->getDomain());
+       var_dump($c->getExtras());
+       var_dump($c->getCookies());
+       var_dump($c->toString());
+       var_dump(
+               array (
+                       "cookies" => 
+                               array (
+                                       "key" => "value",
+                               ),
+                       "extras" => 
+                               array (
+                               ),
+                       "flags" => 0,
+                       "expires" => -1,
+                       "path" => "",
+                       "domain" => "",
+                       "max-age" => -1,
+               ) == $c->toArray()
+       );
+}
+
+?>
+DONE
+--EXPECT--
+Test
+string(5) "value"
+int(-1)
+int(-1)
+int(0)
+NULL
+NULL
+array(0) {
+}
+array(1) {
+  ["key"]=>
+  string(5) "value"
+}
+string(11) "key=value; "
+bool(true)
+string(5) "value"
+int(-1)
+int(-1)
+int(0)
+NULL
+NULL
+array(0) {
+}
+array(1) {
+  ["key"]=>
+  string(5) "value"
+}
+string(11) "key=value; "
+bool(true)
+DONE
diff --git a/tests/cookie006.phpt b/tests/cookie006.phpt
new file mode 100644 (file)
index 0000000..d52f982
--- /dev/null
@@ -0,0 +1,47 @@
+--TEST--
+cookies expire
+--SKIPIF--
+<?php
+include "skipif.inc";
+?>
+--INI--
+date.timezone=UTC
+--FILE--
+<?php
+echo "Test\n";
+
+$c = new http\Cookie("this=expires; expires=Tue, 24 Jan 2012 10:35:32 +0100");
+var_dump($c->getCookie("this"));
+var_dump($c->getExpires());
+
+$o = clone $c;
+$t = time();
+
+$o->setExpires();
+var_dump(-1 === $o->getExpires());
+var_dump(-1 != $c->getExpires());
+
+$o->setExpires($t);
+var_dump($t === $o->getExpires());
+var_dump($t != $c->getExpires());
+var_dump(
+       sprintf(
+               "this=expires; expires=%s; ", 
+               date_create("@$t")
+                       ->setTimezone(new DateTimezone("UTC"))
+                       ->format("D, d M Y H:i:s \\G\\M\\T")
+       ) === $o->toString()
+);
+
+?>
+DONE
+--EXPECT--
+Test
+string(7) "expires"
+int(1327397732)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+DONE
diff --git a/tests/cookie007.phpt b/tests/cookie007.phpt
new file mode 100644 (file)
index 0000000..1a7a4c3
--- /dev/null
@@ -0,0 +1,37 @@
+--TEST--
+cookies max-age
+--SKIPIF--
+<?php
+include "skipif.inc";
+?>
+--INI--
+date.timezone=UTC
+--FILE--
+<?php
+echo "Test\n";
+
+$c = new http\Cookie("this=max-age; max-age=12345");
+var_dump($c->getCookie("this"));
+var_dump($c->getMaxAge());
+$o = clone $c;
+$t = 54321;
+$o->setMaxAge();
+var_dump($o->getMaxAge());
+var_dump(-1 != $c->getMaxAge());
+$o->setMaxAge($t);
+var_dump($o->getMaxAge());
+var_dump($t != $c->getMaxAge());
+var_dump($o->toString());
+
+?>
+DONE
+--EXPECT--
+Test
+string(7) "max-age"
+int(12345)
+int(-1)
+bool(true)
+int(54321)
+bool(true)
+string(29) "this=max-age; max-age=54321; "
+DONE
diff --git a/tests/cookie008.phpt b/tests/cookie008.phpt
new file mode 100644 (file)
index 0000000..5ec43dc
--- /dev/null
@@ -0,0 +1,37 @@
+--TEST--
+cookies path
+--SKIPIF--
+<?php
+include "skipif.inc";
+?>
+--FILE--
+<?php
+echo "Test\n";
+
+$c = new http\Cookie("this=has a path; path=/down; ");
+var_dump($c->getCookie("this"));
+var_dump((string)$c);
+var_dump($c->getPath());
+$o = clone $c;
+$p = "/up";
+$o->setPath();
+var_dump($o->getPath());
+var_dump($c->getPath());
+$o->setPath($p);
+var_dump($o->getPath());
+var_dump($c->getPath());
+var_dump($o->toString());
+
+?>
+DONE
+--EXPECT--
+Test
+string(10) "has a path"
+string(33) "this=has%20a%20path; path=/down; "
+string(5) "/down"
+NULL
+string(5) "/down"
+string(3) "/up"
+string(5) "/down"
+string(31) "this=has%20a%20path; path=/up; "
+DONE
diff --git a/tests/cookie009.phpt b/tests/cookie009.phpt
new file mode 100644 (file)
index 0000000..55aac94
--- /dev/null
@@ -0,0 +1,37 @@
+--TEST--
+cookies domain
+--SKIPIF--
+<?php
+include "skipif.inc";
+?>
+--FILE--
+<?php
+echo "Test\n";
+
+$c = new http\Cookie("this=has a domain; domain=.example.com; ");
+var_dump($c->getCookie("this"));
+var_dump((string)$c);
+var_dump($c->getDomain());
+$o = clone $c;
+$d = "sub.example.com";
+$o->setDomain();
+var_dump($o->getDomain());
+var_dump($c->getDomain());
+$o->setDomain($d);
+var_dump($o->getDomain());
+var_dump($c->getDomain());
+var_dump($o->toString());
+
+?>
+DONE
+--EXPECT--
+Test
+string(12) "has a domain"
+string(44) "this=has%20a%20domain; domain=.example.com; "
+string(12) ".example.com"
+NULL
+string(12) ".example.com"
+string(15) "sub.example.com"
+string(12) ".example.com"
+string(47) "this=has%20a%20domain; domain=sub.example.com; "
+DONE
diff --git a/tests/cookie010.phpt b/tests/cookie010.phpt
new file mode 100644 (file)
index 0000000..34d10f2
--- /dev/null
@@ -0,0 +1,35 @@
+--TEST--
+cookies flags
+--SKIPIF--
+<?php
+include "skipif.inc";
+?>
+--FILE--
+<?php
+echo "Test\n";
+
+$c = new http\Cookie("icanhas=flags; secure; httpOnly");
+var_dump(http\Cookie::SECURE === ($c->getFlags() & http\Cookie::SECURE));
+var_dump(http\Cookie::HTTPONLY === ($c->getFlags() & http\Cookie::HTTPONLY));
+$c->setFlags($c->getFlags() ^ http\Cookie::SECURE);
+var_dump(!($c->getFlags() & http\Cookie::SECURE));
+var_dump(http\Cookie::HTTPONLY === ($c->getFlags() & http\Cookie::HTTPONLY));
+$c->setFlags($c->getFlags() ^ http\Cookie::HTTPONLY);
+var_dump(!($c->getFlags() & http\Cookie::SECURE));
+var_dump(!($c->getFlags() & http\Cookie::HTTPONLY));
+var_dump("icanhas=flags; " === $c->toString());
+$c->setFlags(http\Cookie::SECURE|http\Cookie::HTTPONLY);
+var_dump("icanhas=flags; secure; httpOnly; " === $c->toString());
+?>
+DONE
+--EXPECT--
+Test
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+DONE
diff --git a/tests/cookie011.phpt b/tests/cookie011.phpt
new file mode 100644 (file)
index 0000000..03700ea
--- /dev/null
@@ -0,0 +1,45 @@
+--TEST--
+cookies extras
+--SKIPIF--
+<?php
+include "skipif.inc";
+?>
+--FILE--
+<?php
+echo "Test\n";
+$c = new http\Cookie("c1=v1; e0=1; e2=2; c2=v2", 0, array("e0", "e1", "e2"));
+var_dump(array("c1"=>"v1", "c2"=>"v2") === $c->getCookies());
+var_dump(array("e0"=>"1", "e2"=>"2") === $c->getExtras());
+$c->addExtra("e1", 1);
+$c->setExtra("e0");
+$c->setExtra("e3", 123);
+var_dump("123" === $c->getExtra("e3"));
+$c->setExtra("e3");
+var_dump(array("e2"=>"2", "e1"=>"1") === $c->getExtras());
+var_dump("c1=v1; c2=v2; e2=2; e1=1; " === $c->toString());
+$c->addExtras(array("e3"=>3, "e4"=>4));
+var_dump(array("e2"=>"2", "e1"=>"1", "e3"=>"3", "e4"=>"4") === $c->getExtras());
+var_dump("c1=v1; c2=v2; e2=2; e1=1; e3=3; e4=4; " === $c->toString());
+$c->setExtras(array("e"=>"x"));
+var_dump(array("e"=>"x") === $c->getExtras());
+var_dump("c1=v1; c2=v2; e=x; " === $c->toString());
+$c->setExtras();
+var_dump(array() === $c->getExtras());
+var_dump("c1=v1; c2=v2; " === $c->toString());
+
+?>
+DONE
+--EXPECT--
+Test
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+DONE
diff --git a/tests/cookie012.phpt b/tests/cookie012.phpt
new file mode 100644 (file)
index 0000000..a3898c7
--- /dev/null
@@ -0,0 +1,45 @@
+--TEST--
+cookies cookies
+--SKIPIF--
+<?php
+include "skipif.inc";
+?>
+--FILE--
+<?php
+echo "Test\n";
+$c = new http\Cookie("e0=1; c1=v1; e2=2; c2=v2", 0, array("c0", "c1", "c2"));
+var_dump(array("c1"=>"v1", "c2"=>"v2") === $c->getExtras());
+var_dump(array("e0"=>"1", "e2"=>"2") === $c->getCookies());
+$c->addCookie("e1", 1);
+$c->setCookie("e0");
+$c->setCookie("e3", 123);
+var_dump("123" === $c->getCookie("e3"));
+$c->setCookie("e3");
+var_dump(array("e2"=>"2", "e1"=>"1") === $c->getCookies());
+var_dump("e2=2; e1=1; c1=v1; c2=v2; " === $c->toString());
+$c->addCookies(array("e3"=>3, "e4"=>4));
+var_dump(array("e2"=>"2", "e1"=>"1", "e3"=>"3", "e4"=>"4") === $c->getCookies());
+var_dump("e2=2; e1=1; e3=3; e4=4; c1=v1; c2=v2; " === $c->toString());
+$c->setCookies(array("e"=>"x"));
+var_dump(array("e"=>"x") === $c->getCookies());
+var_dump("e=x; c1=v1; c2=v2; " === $c->toString());
+$c->setCookies();
+var_dump(array() === $c->getCookies());
+var_dump("c1=v1; c2=v2; " === $c->toString());
+
+?>
+DONE
+--EXPECT--
+Test
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+DONE
diff --git a/tests/encstream001.phpt b/tests/encstream001.phpt
new file mode 100644 (file)
index 0000000..5dc13d3
--- /dev/null
@@ -0,0 +1,27 @@
+--TEST--
+encoding stream chunked static
+--SKIPIF--
+<?php
+include "skipif.inc";
+?>
+--FILE--
+<?php
+echo "Test\n";
+
+$file = file(__FILE__);
+$cenc = array_reduce(
+       $file,
+       function($data, $line) {
+               return $data . sprintf("%lx\r\n%s\r\n", strlen($line), $line);
+       }
+) . "0\r\n";
+
+var_dump(implode("", $file) === http\Encoding\Stream\Dechunk::decode($cenc));
+
+?>
+DONE
+--EXPECT--
+Test
+bool(true)
+DONE
+
diff --git a/tests/encstream002.phpt b/tests/encstream002.phpt
new file mode 100644 (file)
index 0000000..3be0aca
--- /dev/null
@@ -0,0 +1,21 @@
+--TEST--
+encoding stream chunked not encoded
+--SKIPIF--
+<?php
+include "skipif.inc";
+?>
+--FILE--
+<?php
+echo "Test\n";
+
+$s = "this is apparently not encodded\n";
+var_dump($s === http\Encoding\Stream\Dechunk::decode($s));
+
+?>
+DONE
+--EXPECTF--
+Test
+
+Notice: http\Encoding\Stream\Dechunk::decode(): Data does not seem to be chunked encoded in %s on line %d
+bool(true)
+DONE
diff --git a/tests/encstream003.phpt b/tests/encstream003.phpt
new file mode 100644 (file)
index 0000000..ad8c737
--- /dev/null
@@ -0,0 +1,38 @@
+--TEST--
+encoding stream chunked error
+--SKIPIF--
+<?php
+include "skipif.inc";
+?>
+--FILE--
+<?php
+echo "Test\n";
+
+$s = "3\nis \nbetter than\n1\n";
+var_dump(http\Encoding\Stream\Dechunk::decode($s));
+$s = "3\r\nis \r\nbetter than\r\n1\r\n";
+var_dump(http\Encoding\Stream\Dechunk::decode($s));
+$s = "3\nis \nreally better than\n1\n";
+var_dump(http\Encoding\Stream\Dechunk::decode($s));
+?>
+DONE
+--EXPECTF--
+Test
+
+Warning: http\Encoding\Stream\Dechunk::decode(): Expected LF at pos 8 of 20 but got 0x74 in %s on line %d
+
+Warning: http\Encoding\Stream\Dechunk::decode(): Truncated message: chunk size 190 exceeds remaining data size 11 at pos 9 of 20 in %s on line %d
+string(14) "is ter than
+1
+"
+
+Warning: http\Encoding\Stream\Dechunk::decode(): Expected CRLF at pos 10 of 24 but got 0x74 0x74 in %s on line %d
+
+Warning: http\Encoding\Stream\Dechunk::decode(): Truncated message: chunk size 190 exceeds remaining data size 12 at pos 12 of 24 in %s on line %d
+string(15) "is er than
+1
+"
+
+Warning: http\Encoding\Stream\Dechunk::decode(): Expected chunk size at pos 6 of 27 but got trash in %s on line %d
+bool(false)
+DONE
diff --git a/tests/encstream004.phpt b/tests/encstream004.phpt
new file mode 100644 (file)
index 0000000..eb9da0f
--- /dev/null
@@ -0,0 +1,38 @@
+--TEST--
+encoding stream chunked flush
+--SKIPIF--
+<?php
+include "skipif.inc";
+?>
+--FILE--
+<?php
+echo "Test\n";
+
+$dech = new http\Encoding\Stream\Dechunk(http\Encoding\Stream::FLUSH_FULL);
+$file = file(__FILE__);
+$data = "";
+foreach ($file as $i => $line) {
+       $dech = clone $dech;
+       if ($i % 2) {
+               $data .= $dech->update(sprintf("%lx\r\n%s\r\n", strlen($line), $line));
+       } else {
+               $data .= $dech->update(sprintf("%lx\r\n", strlen($line)));
+               $data .= $dech->flush();
+               $data .= $dech->update($line);
+               $data .= $dech->flush();
+               $data .= $dech->update("\r\n");
+       }
+       $dech->flush();
+       $dech->done() and printf("uh-oh done() reported true!\n");
+}
+$data .= $dech->update("0\r\n");
+var_dump($dech->done());
+$data .= $dech->finish();
+var_dump(implode("", $file) === $data);
+?>
+DONE
+--EXPECT--
+Test
+bool(true)
+bool(true)
+DONE
diff --git a/tests/encstream005.phpt b/tests/encstream005.phpt
new file mode 100644 (file)
index 0000000..6455ed4
--- /dev/null
@@ -0,0 +1,41 @@
+--TEST--
+encoding stream zlib static
+--SKIPIF--
+<?php
+include "skipif.inc";
+?>
+--FILE--
+<?php
+echo "Test\n";
+
+$file = file_get_contents(__FILE__);
+var_dump($file ===
+       http\Encoding\Stream\Inflate::decode(
+               http\Encoding\Stream\Deflate::encode(
+                       $file, http\Encoding\Stream\Deflate::TYPE_GZIP
+               )
+       )
+);
+var_dump($file ===
+       http\Encoding\Stream\Inflate::decode(
+               http\Encoding\Stream\Deflate::encode(
+                       $file, http\Encoding\Stream\Deflate::TYPE_ZLIB
+               )
+       )
+);
+var_dump($file ===
+       http\Encoding\Stream\Inflate::decode(
+               http\Encoding\Stream\Deflate::encode(
+                       $file, http\Encoding\Stream\Deflate::TYPE_RAW
+               )
+       )
+);
+
+?>
+DONE
+--EXPECT--
+Test
+bool(true)
+bool(true)
+bool(true)
+DONE
diff --git a/tests/encstream006.phpt b/tests/encstream006.phpt
new file mode 100644 (file)
index 0000000..5430bfa
--- /dev/null
@@ -0,0 +1,30 @@
+--TEST--
+encoding stream zlib auto flush
+--SKIPIF--
+<?php
+include "skipif.inc";
+?>
+--FILE--
+<?php
+echo "Test\n";
+
+$defl = new http\Encoding\Stream\Deflate(http\Encoding\Stream::FLUSH_FULL);
+$infl = new http\Encoding\Stream\Inflate;
+
+for ($f = fopen(__FILE__, "rb"); !feof($f); $data = fread($f, 0x100)) {
+       $infl = clone $infl;
+       $defl = clone $defl;
+       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();
+?>
+DONE
+--EXPECT--
+Test
+DONE
diff --git a/tests/encstream007.phpt b/tests/encstream007.phpt
new file mode 100644 (file)
index 0000000..5fdeffe
--- /dev/null
@@ -0,0 +1,34 @@
+--TEST--
+encoding stream zlib without flush
+--SKIPIF--
+<?php
+include "skipif.inc";
+?>
+--FILE--
+<?php
+echo "Test\n";
+
+$defl = new http\Encoding\Stream\Deflate;
+$infl = new http\Encoding\Stream\Inflate;
+$file = file(__FILE__);
+$data = "";
+foreach ($file as $line) {
+       $infl = clone $infl;
+       $defl = clone $defl;
+       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/encstream008.phpt b/tests/encstream008.phpt
new file mode 100644 (file)
index 0000000..a46f9f0
--- /dev/null
@@ -0,0 +1,42 @@
+--TEST--
+encoding stream zlib with explicit flush
+--SKIPIF--
+<?php
+include "skipif.inc";
+?>
+--FILE--
+<?php
+echo "Test\n";
+
+$defl = new http\Encoding\Stream\Deflate;
+$infl = new http\Encoding\Stream\Inflate;
+$file = file(__FILE__);
+$data = "";
+foreach ($file as $line) {
+       $data .= $infl->flush();
+       if (strlen($temp = $defl->update($line))) {
+               $data .= $infl->update($temp);
+               $data .= $infl->flush();
+       }
+       if (strlen($temp = $defl->flush())) {
+               $data .= $infl->update($temp);
+               $data .= $infl->flush();
+       }
+       $defl->done() or printf("uh-oh stream's not done yet!\n");
+}
+if (strlen($temp = $defl->finish())) {
+       $data .= $infl->update($temp);
+}
+var_dump($defl->done());
+$data .= $infl->finish();
+var_dump($infl->done());
+var_dump(implode("", $file) === $data);
+
+?>
+DONE
+--EXPECT--
+Test
+bool(true)
+bool(true)
+bool(true)
+DONE
diff --git a/tests/encstream009.phpt b/tests/encstream009.phpt
new file mode 100644 (file)
index 0000000..fa51a8a
--- /dev/null
@@ -0,0 +1,20 @@
+--TEST--
+encoding stream zlib error
+--SKIPIF--
+<?php
+include "skipif.inc";
+?>
+--FILE--
+<?php
+echo "Test\n";
+
+var_dump(http\Encoding\Stream\Inflate::decode("if this goes through, something's pretty wrong"));
+
+?>
+DONE
+--EXPECTF--
+Test
+
+Warning: http\Encoding\Stream\Inflate::decode(): Could not inflate data: data error in %s on line %d
+bool(false)
+DONE
index 2351186..28f6a74 100644 (file)
@@ -1,12 +1,12 @@
 --TEST--
 env request body
 --SKIPIF--
-<? include "skipif.inc";
+<?php include "skipif.inc"; ?>
 --PUT--
 Content-Type: skip/me
 foo
 --FILE--
-<?
+<?php
 var_dump((string) \http\Env::getRequestBody());
 ?>
 DONE
index ec7d2d5..69c5988 100644 (file)
@@ -1,12 +1,12 @@
 --TEST--
 env request body
 --SKIPIF--
-<? include "skipif.inc";
+<?php include "skipif.inc"; ?>
 --PUT--
 Content-Type: application/x-www-form-urlencoded
 foo=bar&baz=buh
 --FILE--
-<?
+<?php
 var_dump($_POST);
 ?>
 DONE
index a22dbbd..c2bde83 100644 (file)
@@ -1,7 +1,7 @@
 --TEST--
 env request body
 --SKIPIF--
-<? include "skipif.inc";
+<?php include "skipif.inc"; ?>
 --PUT--
 Content-Type: multipart/form-data;boundary=123
 --123
@@ -18,7 +18,7 @@ Content-Disposition: form-data; name="up"; filename="up.txt"
 foo=bar&baz=buh
 --123--
 --FILE--
-<?
+<?php
 var_dump($_POST);
 var_dump($_FILES);
 ?>
@@ -38,7 +38,7 @@ array(1) {
     ["type"]=>
     string(0) ""
     ["tmp_name"]=>
-    string(14) "%s"
+    string(%d) "%s"
     ["error"]=>
     int(0)
     ["size"]=>
index b259ea5..bfc9ccb 100644 (file)
@@ -1,30 +1,33 @@
 --TEST--
 env request header
 --SKIPIF--
-<? include "skipif.inc";
+<?php include "skipif.inc"; ?>
 --POST--
 a=b
 --ENV--
 HTTP_HOST=foo.bar
 HTTP_ACCEPT=*/*
 --FILE--
-<?
+<?php
 
 var_dump(http\Env::getRequestHeader("nono"));
 var_dump(http\Env::getRequestHeader("Host"));
 var_dump(http\Env::getRequestHeader("content-type"));
-var_dump(http\Env::getRequestHeader());
+$hdr = http\Env::getRequestHeader();
+ksort($hdr);
+var_dump($hdr);
+?>
 --EXPECTF--
 NULL
 string(%d) "foo.bar"
 string(%d) "application/x-www-form-urlencoded"
 array(4) {
-  ["Host"]=>
-  string(7) "foo.bar"
   ["Accept"]=>
   string(3) "*/*"
   ["Content-Length"]=>
   string(1) "3"
   ["Content-Type"]=>
   string(33) "application/x-www-form-urlencoded"
+  ["Host"]=>
+  string(7) "foo.bar"
 }
index 3bbf760..7a02814 100644 (file)
@@ -18,7 +18,7 @@ $r->setBody(new http\Message\Body(fopen(__FILE__, "rb")));
 $r->send();
 
 ?>
---EXPECTHEADERS--
-Content-Type: text/plain
+--EXPECTHEADERSF--
+Content-Type: text/plain%s
 --EXPECTF--
 php
index f84c860..deee3f2 100644 (file)
@@ -1,5 +1,5 @@
 --TEST--
-env reponse callback
+env response callback
 --SKIPIF--
 <?php
 include "skipif.inc";
diff --git a/tests/envresponse015.phpt b/tests/envresponse015.phpt
new file mode 100644 (file)
index 0000000..abad2bb
--- /dev/null
@@ -0,0 +1,36 @@
+--TEST--
+env response send replaced body using multiple ob_start
+--SKIPIF--
+<?php
+include "skipif.inc";
+?>
+--FILE--
+<?php
+
+$r = new http\Env\Response;
+
+ob_start($r);
+echo "bar";
+ob_end_flush();
+
+$b = $r->getBody();
+$r->setBody(new http\Message\Body);
+
+ob_start($r);
+echo "foo: $b\n";
+ob_end_flush();
+
+$f = fopen("php://memory", "r+");
+
+$r->send($f);
+
+fseek($f, 0, SEEK_SET);
+echo stream_get_contents($f);
+
+?>
+--EXPECT--
+HTTP/1.1 200 OK
+Accept-Ranges: bytes
+ETag: "fc8305a1"
+
+foo: bar
diff --git a/tests/envresponse016.phpt b/tests/envresponse016.phpt
new file mode 100644 (file)
index 0000000..8d48c93
--- /dev/null
@@ -0,0 +1,35 @@
+--TEST--
+env response send failure
+--SKIPIF--
+<?php
+include "skipif.inc";
+?>
+--FILE--
+<?php
+
+echo "Test\n";
+
+class closer extends php_user_filter {
+       function filter ($in, $out, &$consumed, $closing) {
+               while ($bucket = stream_bucket_make_writeable($in)) {
+                       stream_bucket_append($out, $bucket);
+               }
+               return PSFS_ERR_FATAL;
+       }
+}
+
+stream_filter_register("closer", "closer");
+
+$r = new http\Env\Response;
+$r->getBody()->append(str_repeat("a", 16*1024*4));
+$s = fopen("php://temp", "w");
+stream_filter_append($s, "closer");
+var_dump($r->send($s));
+?>
+DONE
+--EXPECTF--
+Test
+
+Warning: http\Env\Response::send(): Failed to send response body in %s on line %d
+bool(false)
+DONE
index 194f7d7..3997cf8 100644 (file)
@@ -34,6 +34,6 @@ Array
             [2] => good
         )
 
-    [Content-Type] => text/html
+    [Content-Type] => %s
 )
 Created
index 8511fff..08c0f27 100644 (file)
@@ -1,7 +1,9 @@
 --TEST--
 ranges
 --SKIPIF--
-<? include "skipif.php";
+<?php
+include "skipif.inc";
+?>
 --GET--
 a=b
 --ENV--
index b3a2a53..c1e1e44 100644 (file)
@@ -11,7 +11,12 @@ version_compare(PHP_VERSION, "5.4.0", ">=") or die("skip PHP>=5.4 required");
 $body = new http\Message\Body;
 $body->append("Hello, my old fellow.");
 foreach (hash_algos() as $algo) {
-       if ($algo == "gost-crypto") continue;
+    switch ($algo) {
+    case "gost-crypto":
+    case "fnv1a32":
+    case "fnv1a64":
+        continue 2;
+    }
     ini_set("http.etag.mode", $algo);
     printf("%10s: %s\n", 
         $algo, 
index 06d9e1b..403fb26 100644 (file)
@@ -9,8 +9,10 @@ b=c
 HTTP_X_TEST=test
 --COOKIE--
 foo=bar
+--INI--
+always_populate_raw_post_data=-1
 --FILE--
-<?
+<?php
 echo "Test\n";
 
 use http\env\Request as HttpEnvRequest;
@@ -27,8 +29,8 @@ var_dump((string)$m->getBody());
 
 echo "stream\n";
 var_dump(file_get_contents("php://input"));
-
-echo "Done\n";
+?>
+Done
 --EXPECTF--
 Test
 object(%s)#%d (12) {
index 69be990..93f128a 100644 (file)
@@ -1,9 +1,11 @@
 --TEST--
 multipart message
 --SKIPIF--
-<? include "skipif.inc";
+<?php
+include "skipif.inc";
+?>
 --FILE--
-<?
+<?php
 $m = new http\Message(fopen(__DIR__."/data/message_r_multipart_put.txt","rb"));
 if ($m->isMultipart($boundary)) {
     var_dump($boundary);
index 914a8da..e1c9aa9 100644 (file)
@@ -2,7 +2,8 @@
 message reversal
 --SKIPIF--
 <?php
-include "skip.inc";
+include "skipif.inc";
+?>
 --FILE--
 <?php
 
diff --git a/tests/messagebody001.phpt b/tests/messagebody001.phpt
new file mode 100644 (file)
index 0000000..6f1e10a
--- /dev/null
@@ -0,0 +1,34 @@
+--TEST--
+message body stat
+--SKIPIF--
+<?php
+include "skipif.inc";
+?>
+--FILE--
+<?php
+echo "Test\n";
+
+$file = new http\Message\Body(fopen(__FILE__, "r"));
+$temp = new http\Message\Body();
+var_dump(filesize(__FILE__) === $file->stat("size"));
+var_dump(filemtime(__FILE__) === $file->stat("mtime"));
+var_dump(fileatime(__FILE__) === $file->stat("atime"));
+var_dump(filectime(__FILE__) === $file->stat("ctime"));
+var_dump(
+       (object) array(
+               "size" => 0,
+               "mtime" => 0,
+               "atime" => 0,
+               "ctime" => 0,
+       ) == $temp->stat()
+);
+?>
+DONE
+--EXPECT--
+Test
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+DONE
diff --git a/tests/messagebody002.phpt b/tests/messagebody002.phpt
new file mode 100644 (file)
index 0000000..fe28e28
--- /dev/null
@@ -0,0 +1,21 @@
+--TEST--
+message body append
+--SKIPIF--
+<?php
+include "skipif.inc";
+?>
+--FILE--
+<?php
+echo "Test\n";
+
+$temp = new http\Message\Body();
+$temp->append("yes");
+
+var_dump((string) $temp);
+
+?>
+DONE
+--EXPECT--
+Test
+string(3) "yes"
+DONE
diff --git a/tests/messagebody003.phpt b/tests/messagebody003.phpt
new file mode 100644 (file)
index 0000000..7b79e6a
--- /dev/null
@@ -0,0 +1,26 @@
+--TEST--
+message body append error
+--SKIPIF--
+<?php
+include "skipif.inc";
+?>
+--FILE--
+<?php
+echo "Test\n";
+
+$file = new http\Message\Body(fopen(__FILE__, "r"));
+try {
+       $file->append("nope");
+} catch (Exception $e) {
+       echo $e, "\n";
+}
+
+?>
+DONE
+--EXPECTF--
+Test
+exception 'http\Exception\RuntimeException' with message 'http\Message\Body::append(): Failed to append 4 bytes to body; wrote 0' in %s:%d
+Stack trace:
+#0 %s(%d): http\Message\Body->append('nope')
+#1 {main}
+DONE
diff --git a/tests/messagebody004.phpt b/tests/messagebody004.phpt
new file mode 100644 (file)
index 0000000..64254d4
--- /dev/null
@@ -0,0 +1,81 @@
+--TEST--
+message body add form
+--SKIPIF--
+<?php
+include "skipif.inc";
+?>
+--FILE--
+<?php
+echo "Test\n";
+
+$temp = new http\Message\Body;
+$temp->addForm(
+       array(
+               "foo" => "bar",
+               "more" => array(
+                       "bah", "baz", "fuz"
+               ),
+       ),
+       array(
+               array(
+                       "file" => __FILE__,
+                       "name" => "upload",
+                       "type" => "text/plain",
+               )
+       )
+);
+
+echo $temp;
+
+?>
+DONE
+--EXPECTF--
+Test
+--%x.%x
+Content-Disposition: form-data; name="foo"
+
+bar
+--%x.%x
+Content-Disposition: form-data; name="more[0]"
+
+bah
+--%x.%x
+Content-Disposition: form-data; name="more[1]"
+
+baz
+--%x.%x
+Content-Disposition: form-data; name="more[2]"
+
+fuz
+--%x.%x
+Content-Disposition: form-data; name="upload"; filename="%s"
+Content-Transfer-Encoding: binary
+Content-Type: text/plain
+
+<?php
+echo "Test\n";
+
+$temp = new http\Message\Body;
+$temp->addForm(
+       array(
+               "foo" => "bar",
+               "more" => array(
+                       "bah", "baz", "fuz"
+               ),
+       ),
+       array(
+               array(
+                       "file" => __FILE__,
+                       "name" => "upload",
+                       "type" => "text/plain",
+               )
+       )
+);
+
+echo $temp;
+
+?>
+DONE
+
+--%x.%x--
+DONE
diff --git a/tests/messagebody005.phpt b/tests/messagebody005.phpt
new file mode 100644 (file)
index 0000000..72f402d
--- /dev/null
@@ -0,0 +1,30 @@
+--TEST--
+message body add part
+--SKIPIF--
+<?php
+include "skipif.inc";
+?>
+--FILE--
+<?php
+echo "Test\n";
+
+$temp = new http\Message\Body;
+var_dump($temp->getBoundary());
+$temp->addPart(new http\Message("This: is a header\n\nand this is the data\n"));
+var_dump($temp->getBoundary());
+echo $temp;
+
+?>
+DONE
+--EXPECTF--
+Test
+NULL
+string(%d) "%x.%x"
+--%x.%x
+This: is a header
+Content-Length: 21
+
+and this is the data
+
+--%x.%x--
+DONE
diff --git a/tests/messagebody006.phpt b/tests/messagebody006.phpt
new file mode 100644 (file)
index 0000000..a02057e
--- /dev/null
@@ -0,0 +1,30 @@
+--TEST--
+message body etag
+--SKIPIF--
+<?php
+include "skipif.inc";
+?>
+--INI--
+http.etag.mode = crc32b
+--FILE--
+<?php
+echo "Test\n";
+
+$file = new http\Message\Body(fopen(__FILE__, "r"));
+$temp = new http\Message\Body;
+$s = stat(__FILE__);
+var_dump(
+       sprintf(
+               "%lx-%lx-%lx", 
+               $s["ino"],$s["mtime"],$s["size"]
+       ) === $file->etag()
+);
+var_dump($temp->etag());
+
+?>
+DONE
+--EXPECT--
+Test
+bool(true)
+string(8) "00000000"
+DONE
diff --git a/tests/messagebody007.phpt b/tests/messagebody007.phpt
new file mode 100644 (file)
index 0000000..dc010da
--- /dev/null
@@ -0,0 +1,21 @@
+--TEST--
+message body to stream
+--SKIPIF--
+<?php
+include "skipif.inc";
+?>
+--FILE--
+<?php
+echo "Test\n";
+
+$file = new http\Message\Body(fopen(__FILE__,"r"));
+$file->toStream($f = fopen("php://temp", "w")); 
+fseek($f, 0, SEEK_SET);
+var_dump(file_get_contents(__FILE__) === stream_get_contents($f));
+
+?>
+DONE
+--EXPECT--
+Test
+bool(true)
+DONE
diff --git a/tests/messagebody008.phpt b/tests/messagebody008.phpt
new file mode 100644 (file)
index 0000000..cb9612c
--- /dev/null
@@ -0,0 +1,23 @@
+--TEST--
+message body to callback
+--SKIPIF--
+<?php
+include "skipif.inc";
+?>
+--FILE--
+<?php
+echo "Test\n";
+
+$file = new http\Message\Body(fopen(__FILE__,"r"));
+$s = "";
+$file->toCallback(
+       function($body, $string) use (&$s) { $s.=$string; }
+);
+var_dump($s === (string) $file);
+
+?>
+DONE
+--EXPECT--
+Test
+bool(true)
+DONE
diff --git a/tests/messagebody009.phpt b/tests/messagebody009.phpt
new file mode 100644 (file)
index 0000000..a7a7f43
--- /dev/null
@@ -0,0 +1,19 @@
+--TEST--
+message body clone
+--SKIPIF--
+<?php
+include "skipif.inc";
+?>
+--FILE--
+<?php
+echo "Test\n";
+
+$file = new http\Message\Body(fopen(__FILE__,"r"));
+var_dump((string) $file === (string) clone $file);
+
+?>
+DONE
+--EXPECT--
+Test
+bool(true)
+DONE
diff --git a/tests/messagebody010.phpt b/tests/messagebody010.phpt
new file mode 100644 (file)
index 0000000..b50898d
--- /dev/null
@@ -0,0 +1,23 @@
+--TEST--
+message body resource
+--SKIPIF--
+<?php
+include "skipif.inc";
+?>
+--FILE--
+<?php
+echo "Test\n";
+
+$file = new http\Message\Body(fopen(__FILE__,"r"));
+for($i=0;$i<10;++$i) $stream = $file->getResource();
+var_dump(is_resource($stream));
+$stat = fstat($stream);
+var_dump(filesize(__FILE__) === $stat["size"]);
+
+?>
+DONE
+--EXPECT--
+Test
+bool(true)
+bool(true)
+DONE
index d384b87..f628cdf 100644 (file)
@@ -52,7 +52,7 @@ echo "$ln: "; print_r($lnr);
 
 CUSTOM
 
-<?
+<?php
 $cc = http\Env::negotiate("a, a.b;q=0.9, c.d;q=0, *.* ; q=0.1",
     array("a.x", "c.d", "c.e", "a.b"), ".", $ccr);
 echo "$cc: "; print_r($ccr);
index ac52bf7..5b28dee 100644 (file)
@@ -3,11 +3,12 @@ header params
 --SKIPIF--
 <?php
 include "skipif.inc";
+?>
 --FILE--
 <?php
 echo "Test\n";
 
-$ct = new http\Params("text/html; charset=utf-8");
+$ct = new http\Params("text/html; charset=utf-8", ",", ";", "=", 0);
 
 var_dump(
        isset($ct["text/html"]),
@@ -25,9 +26,10 @@ var_dump(
        $ct["text/json"]["arguments"]["charset"]
 );
 
-var_dump((string) $ct);
+var_dump((string) $ct,$ct);
 
-echo "Done\n";
+?>
+DONE
 --EXPECTF--
 Test
 bool(true)
@@ -37,4 +39,27 @@ bool(false)
 bool(true)
 string(10) "iso-8859-1"
 string(%d) "text/json;charset=iso-8859-1"
-Done
+object(http\Params)#%d (5) {
+  ["params"]=>
+  array(1) {
+    ["text/json"]=>
+    array(2) {
+      ["value"]=>
+      bool(true)
+      ["arguments"]=>
+      array(1) {
+        ["charset"]=>
+        string(10) "iso-8859-1"
+      }
+    }
+  }
+  ["param_sep"]=>
+  string(1) ","
+  ["arg_sep"]=>
+  string(1) ";"
+  ["val_sep"]=>
+  string(1) "="
+  ["flags"]=>
+  int(0)
+}
+DONE
diff --git a/tests/params003.phpt b/tests/params003.phpt
new file mode 100644 (file)
index 0000000..11e2759
--- /dev/null
@@ -0,0 +1,97 @@
+--TEST--
+default params
+--SKIPIF--
+<?php
+include "skipif.inc";
+?>
+--FILE--
+<?php
+echo "Test\n";
+
+$s = "foo, bar;arg=0;bla, gotit=0;now";
+$p = new http\Params($s);
+$c = str_replace(" ", "", $s);
+$k = array("foo", "bar", "gotit");
+$a = array("foo"=>"arg", "bar"=>"bla", "gotit"=>"now");
+$r = array (
+       'foo' => 
+       array (
+               'value' => true,
+               'arguments' => 
+               array (
+               ),
+       ),
+       'bar' => 
+       array (
+               'value' => true,
+               'arguments' => 
+               array (
+                       'arg' => '0',
+                       'bla' => true,
+               ),
+       ),
+       'gotit' => 
+       array (
+               'value' => '0',
+               'arguments' => 
+               array (
+                       'now' => true,
+               ),
+       ),
+);
+
+# ---
+
+var_dump(count($p->params));
+
+echo "key exists\n";
+foreach ($k as $key) {
+       var_dump(array_key_exists($key, $p->params));
+}
+
+echo "values\n";
+foreach ($k as $key) {
+       var_dump($p[$key]["value"]);
+}
+
+echo "args\n";
+foreach ($k as $key) {
+       var_dump(count($p[$key]["arguments"]));
+}
+
+echo "arg values\n";
+foreach ($k as $key) {
+       var_dump(@$p[$key]["arguments"][$a[$key]]);
+}
+
+echo "equals\n";
+var_dump($c === (string) $p);
+var_dump($r === $p->params);
+$x = new http\Params($p->params);
+var_dump($r === $x->toArray());
+?>
+DONE
+--EXPECT--
+Test
+int(3)
+key exists
+bool(true)
+bool(true)
+bool(true)
+values
+bool(true)
+bool(true)
+string(1) "0"
+args
+int(0)
+int(2)
+int(1)
+arg values
+NULL
+bool(true)
+bool(true)
+equals
+bool(true)
+bool(true)
+bool(true)
+DONE
diff --git a/tests/params004.phpt b/tests/params004.phpt
new file mode 100644 (file)
index 0000000..69075ea
--- /dev/null
@@ -0,0 +1,97 @@
+--TEST--
+custom params
+--SKIPIF--
+<?php
+include "skipif.inc";
+?>
+--FILE--
+<?php
+echo "Test\n";
+
+$s = "foo bar.arg:0.bla gotit:0.now";
+$p = new http\Params($s, " ", ".", ":");
+$c = $s;
+$k = array("foo", "bar", "gotit");
+$a = array("foo"=>"arg", "bar"=>"bla", "gotit"=>"now");
+$r = array (
+       'foo' => 
+       array (
+               'value' => true,
+               'arguments' => 
+               array (
+               ),
+       ),
+       'bar' => 
+       array (
+               'value' => true,
+               'arguments' => 
+               array (
+                       'arg' => '0',
+                       'bla' => true,
+               ),
+       ),
+       'gotit' => 
+       array (
+               'value' => '0',
+               'arguments' => 
+               array (
+                       'now' => true,
+               ),
+       ),
+);
+
+# ---
+
+var_dump(count($p->params));
+
+echo "key exists\n";
+foreach ($k as $key) {
+       var_dump(array_key_exists($key, $p->params));
+}
+
+echo "values\n";
+foreach ($k as $key) {
+       var_dump($p[$key]["value"]);
+}
+
+echo "args\n";
+foreach ($k as $key) {
+       var_dump(count($p[$key]["arguments"]));
+}