From: Michael Wallner Date: Tue, 5 Aug 2014 16:47:19 +0000 (+0200) Subject: Merge branch 'merge-DEV_2' X-Git-Tag: RELEASE_2_1_0_RC3~10 X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-http;a=commitdiff_plain;h=eaa046dc3e6496e523a17c3b786ef27067b9795c;hp=47be714b40e14b6b5cdc2f35a7994efd13c2076e Merge branch 'merge-DEV_2' --- diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..a55a7ae --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +package.xml merge=touch +php_http.h merge=touch diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..64b23b6 --- /dev/null +++ b/.gitignore @@ -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 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2013, Michael Wallner . +Copyright (c) 2004-2014, Michael Wallner . All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/TODO b/TODO index db7d39d..3981099 100644 --- 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 diff --git a/ThanksTo.txt b/ThanksTo.txt index 48003f9..67c5b32 100644 --- a/ThanksTo.txt +++ b/ThanksTo.txt @@ -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 index 0000000..4000054 --- /dev/null +++ b/check_package-xml.php @@ -0,0 +1,92 @@ +#!/usr/bin/env php + 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; + } +} diff --git a/config.w32 b/config.w32 index f74f152..497fb65 100644 --- a/config.w32 +++ b/config.w32 @@ -51,7 +51,7 @@ if (PHP_HTTP != "no") { "php_http_cookie.c php_http_curl.c php_http_client_curl.c " + "php_http_encoding.c php_http_env.c php_http_env_request.c " + "php_http_env_response.c php_http_etag.c php_http_exception.c php_http_filter.c php_http_header_parser.c " + - "php_http_headers.c php_http_info.c php_http_message.c php_http_message_body.c php_http_message_parser.c " + + "php_http_header.c php_http_info.c php_http_message.c php_http_message_body.c php_http_message_parser.c " + "php_http_misc.c php_http_negotiate.c php_http_object.c php_http_options.c php_http_params.c " + "php_http_querystring.c " + "php_http_strlist.c php_http_url.c php_http_version.c", diff --git a/config9.m4 b/config9.m4 index aff67ca..ba1b935 100644 --- a/config9.m4 +++ b/config9.m4 @@ -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 + 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], diff --git a/gen_curlinfo.php b/gen_curlinfo.php index fea14bb..0e8dfa1 100644 --- a/gen_curlinfo.php +++ b/gen_curlinfo.php @@ -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"))); ?> diff --git a/package.xml b/package.xml index 5467a83..bd7b579 100644 --- a/package.xml +++ b/package.xml @@ -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/ + ]]> Michael Wallner @@ -28,30 +37,24 @@ support. Parallel requests are available for PHP 5 and greater. mike@php.net yes - 2013-08-12 + 2014-08-05 - 2.0.0RC1 - 2.0.0 + 2.1.0dev + 2.1.0 beta - beta + stable BSD, revised + @@ -131,6 +134,7 @@ http://dev.iworks.at/ext-http/lcov/ext/http/ + @@ -144,6 +148,7 @@ http://dev.iworks.at/ext-http/lcov/ext/http/ + @@ -151,6 +156,27 @@ http://dev.iworks.at/ext-http/lcov/ext/http/ + + + + + + + + + + + + + + + + + + + + + @@ -175,6 +201,8 @@ http://dev.iworks.at/ext-http/lcov/ext/http/ + + @@ -209,24 +237,43 @@ http://dev.iworks.at/ext-http/lcov/ext/http/ + + + + + + + + + + - + + + + + + + + + + + + + - + + + + + + - - - - - - - - @@ -240,13 +287,13 @@ http://dev.iworks.at/ext-http/lcov/ext/http/ raphf pecl.php.net - 0.1.0 + 1.0.0 raphf propro pecl.php.net - 0.1.0 + 1.0.0 propro @@ -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" /> - - - diff --git a/php_http.c b/php_http.c index 2ed94c8..2101f0b 100644 --- a/php_http.c +++ b/php_http.c @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ @@ -20,7 +20,12 @@ #if PHP_HTTP_HAVE_CURL # include # if PHP_HTTP_HAVE_EVENT -# include +# if PHP_HTTP_HAVE_EVENT2 +# include +# include +# else +# include +# 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(); diff --git a/php_http.h b/php_http.h index 8e341ca..a911044 100644 --- a/php_http.h +++ b/php_http.h @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #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 diff --git a/php_http_api.h b/php_http_api.h index 42d34fc..9e0dc6c 100644 --- a/php_http_api.h +++ b/php_http_api.h @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ diff --git a/php_http_buffer.c b/php_http_buffer.c index 84272d0..8ccee08 100644 --- a/php_http_buffer.c +++ b/php_http_buffer.c @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ @@ -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) diff --git a/php_http_buffer.h b/php_http_buffer.h index 8ee4eae..cf9b458 100644 --- a/php_http_buffer.h +++ b/php_http_buffer.h @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ @@ -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); diff --git a/php_http_client.c b/php_http_client.c index 6dced66..f96164b 100644 --- a/php_http_client.c +++ b/php_http_client.c @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ @@ -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)); diff --git a/php_http_client.h b/php_http_client.h index 9bc5295..6c45516 100644 --- a/php_http_client.h +++ b/php_http_client.h @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ diff --git a/php_http_client_curl.c b/php_http_client_curl.c index fbb950a..baf99ce 100644 --- a/php_http_client_curl.c +++ b/php_http_client_curl.c @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ @@ -16,19 +16,33 @@ #if PHP_HTTP_HAVE_CURL #if PHP_HTTP_HAVE_EVENT -# include # if !PHP_HTTP_HAVE_EVENT2 && /* just be really sure */ !(LIBEVENT_VERSION_NUMBER >= 0x02000000) +# include # 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 +# include +# else +# error "libevent presence is unknown" +# endif # endif # ifndef DBG_EVENTS # define DBG_EVENTS 0 # endif #endif +#ifdef PHP_HTTP_HAVE_OPENSSL +# include +#endif +#ifdef PHP_HTTP_HAVE_GNUTLS +# include +#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; } diff --git a/php_http_client_curl.h b/php_http_client_curl.h index 6495568..03b9b6f 100644 --- a/php_http_client_curl.h +++ b/php_http_client_curl.h @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ diff --git a/php_http_client_request.c b/php_http_client_request.c index 12f2014..ea223be 100644 --- a/php_http_client_request.c +++ b/php_http_client_request.c @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ diff --git a/php_http_client_request.h b/php_http_client_request.h index 5f4da53..474114b 100644 --- a/php_http_client_request.h +++ b/php_http_client_request.h @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ diff --git a/php_http_client_response.c b/php_http_client_response.c index b269caf..8d512ec 100644 --- a/php_http_client_response.c +++ b/php_http_client_response.c @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ diff --git a/php_http_client_response.h b/php_http_client_response.h index 6cf677a..15d004e 100644 --- a/php_http_client_response.h +++ b/php_http_client_response.h @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ diff --git a/php_http_cookie.c b/php_http_cookie.c index 1234e38..4bd8d80 100644 --- a/php_http_cookie.c +++ b/php_http_cookie.c @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ @@ -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); } diff --git a/php_http_cookie.h b/php_http_cookie.h index 9d5b7c8..7cf00fe 100644 --- a/php_http_cookie.h +++ b/php_http_cookie.h @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ diff --git a/php_http_curl.c b/php_http_curl.c index 6607ca1..a995094 100644 --- a/php_http_curl.c +++ b/php_http_curl.c @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ @@ -25,11 +25,6 @@ # elif defined(PHP_HTTP_HAVE_GNUTLS) # define PHP_HTTP_NEED_GNUTLS_TSL # include -# 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 */ diff --git a/php_http_curl.h b/php_http_curl.h index 4621d5a..ab8b63c 100644 --- a/php_http_curl.h +++ b/php_http_curl.h @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ diff --git a/php_http_encoding.c b/php_http_encoding.c index 3c5393b..7f0462c 100644 --- a/php_http_encoding.c +++ b/php_http_encoding.c @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ @@ -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); diff --git a/php_http_encoding.h b/php_http_encoding.h index decc585..59bbd27 100644 --- a/php_http_encoding.h +++ b/php_http_encoding.h @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ diff --git a/php_http_env.c b/php_http_env.c index c98701b..10d54fe 100644 --- a/php_http_env.c +++ b/php_http_env.c @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ @@ -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) diff --git a/php_http_env.h b/php_http_env.h index dac10da..ee1afe9 100644 --- a/php_http_env.h +++ b/php_http_env.h @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ diff --git a/php_http_env_request.c b/php_http_env_request.c index 01c2f6d..6aff0c0 100644 --- a/php_http_env_request.c +++ b/php_http_env_request.c @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ @@ -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); + } } } diff --git a/php_http_env_request.h b/php_http_env_request.h index f6b8f40..a97836b 100644 --- a/php_http_env_request.h +++ b/php_http_env_request.h @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ diff --git a/php_http_env_response.c b/php_http_env_response.c index cb52752..4d6ef03 100644 --- a/php_http_env_response.c +++ b/php_http_env_response.c @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ @@ -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; } } diff --git a/php_http_env_response.h b/php_http_env_response.h index f79730f..3a702b2 100644 --- a/php_http_env_response.h +++ b/php_http_env_response.h @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ diff --git a/php_http_etag.c b/php_http_etag.c index 72a7927..4562324 100644 --- a/php_http_etag.c +++ b/php_http_etag.c @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ diff --git a/php_http_etag.h b/php_http_etag.h index dd0e3d1..bf6cf49 100644 --- a/php_http_etag.h +++ b/php_http_etag.h @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ diff --git a/php_http_exception.c b/php_http_exception.c index 00add62..25a33e6 100644 --- a/php_http_exception.c +++ b/php_http_exception.c @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ diff --git a/php_http_exception.h b/php_http_exception.h index 82a4b55..969a351 100644 --- a/php_http_exception.h +++ b/php_http_exception.h @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ diff --git a/php_http_filter.c b/php_http_filter.c index f0ba862..b6d967b 100644 --- a/php_http_filter.c +++ b/php_http_filter.c @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ diff --git a/php_http_filter.h b/php_http_filter.h index b2b8682..21fe4db 100644 --- a/php_http_filter.h +++ b/php_http_filter.h @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ diff --git a/php_http_header.c b/php_http_header.c index 08e643b..92a2de4 100644 --- a/php_http_header.c +++ b/php_http_header.c @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ diff --git a/php_http_header.h b/php_http_header.h index 2c0d2e8..d420e3f 100644 --- a/php_http_header.h +++ b/php_http_header.h @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ diff --git a/php_http_header_parser.c b/php_http_header_parser.c index e7fc886..ec41a24 100644 --- a/php_http_header_parser.c +++ b/php_http_header_parser.c @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ @@ -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); diff --git a/php_http_header_parser.h b/php_http_header_parser.h index 1c07da2..4c60f6e 100644 --- a/php_http_header_parser.h +++ b/php_http_header_parser.h @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ @@ -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; diff --git a/php_http_info.c b/php_http_info.c index dca784f..10ea0a3 100644 --- a/php_http_info.c +++ b/php_http_info.c @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ diff --git a/php_http_info.h b/php_http_info.h index 87aa791..afd747c 100644 --- a/php_http_info.h +++ b/php_http_info.h @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ diff --git a/php_http_message.c b/php_http_message.c index f3509a4..cc04edc 100644 --- a/php_http_message.c +++ b/php_http_message.c @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ @@ -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); diff --git a/php_http_message.h b/php_http_message.h index 32af834..6524a27 100644 --- a/php_http_message.h +++ b/php_http_message.h @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ @@ -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); diff --git a/php_http_message_body.c b/php_http_message_body.c index 2749fac..4be45ef 100644 --- a/php_http_message_body.c +++ b/php_http_message_body.c @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ @@ -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; } diff --git a/php_http_message_body.h b/php_http_message_body.h index 028ad62..860cd8a 100644 --- a/php_http_message_body.h +++ b/php_http_message_body.h @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ diff --git a/php_http_message_parser.c b/php_http_message_parser.c index b64eb00..20ef3ac 100644 --- a/php_http_message_parser.c +++ b/php_http_message_parser.c @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ @@ -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); } diff --git a/php_http_message_parser.h b/php_http_message_parser.h index 8ecf991..ebc2142 100644 --- a/php_http_message_parser.h +++ b/php_http_message_parser.h @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ @@ -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; diff --git a/php_http_misc.c b/php_http_misc.c index 0ba19f9..7afa006 100644 --- a/php_http_misc.c +++ b/php_http_misc.c @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ @@ -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); } } diff --git a/php_http_misc.h b/php_http_misc.h index 17cfec7..d47477c 100644 --- a/php_http_misc.h +++ b/php_http_misc.h @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ @@ -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); diff --git a/php_http_negotiate.c b/php_http_negotiate.c index ae10ddf..76106a8 100644 --- a/php_http_negotiate.c +++ b/php_http_negotiate.c @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ diff --git a/php_http_negotiate.h b/php_http_negotiate.h index f31226b..3a12ab7 100644 --- a/php_http_negotiate.h +++ b/php_http_negotiate.h @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ diff --git a/php_http_object.c b/php_http_object.c index d4785f1..abf7229 100644 --- a/php_http_object.c +++ b/php_http_object.c @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ diff --git a/php_http_object.h b/php_http_object.h index a3786bb..63730b4 100644 --- a/php_http_object.h +++ b/php_http_object.h @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ diff --git a/php_http_options.c b/php_http_options.c index ca455a7..1ba987a 100644 --- a/php_http_options.c +++ b/php_http_options.c @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ diff --git a/php_http_options.h b/php_http_options.h index 479b155..6726815 100644 --- a/php_http_options.h +++ b/php_http_options.h @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ diff --git a/php_http_params.c b/php_http_params.c index c64df95..65504ac 100644 --- a/php_http_params.c +++ b/php_http_params.c @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ @@ -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); diff --git a/php_http_params.h b/php_http_params.h index a9ac564..42f56f9 100644 --- a/php_http_params.h +++ b/php_http_params.h @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ @@ -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; diff --git a/php_http_querystring.c b/php_http_querystring.c index 7304d69..933529f 100644 --- a/php_http_querystring.c +++ b/php_http_querystring.c @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ diff --git a/php_http_querystring.h b/php_http_querystring.h index 6418f83..4ebdd77 100644 --- a/php_http_querystring.h +++ b/php_http_querystring.h @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ diff --git a/php_http_strlist.c b/php_http_strlist.c index 4e316db..f457178 100644 --- a/php_http_strlist.c +++ b/php_http_strlist.c @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ diff --git a/php_http_strlist.h b/php_http_strlist.h index 319113f..2685423 100644 --- a/php_http_strlist.h +++ b/php_http_strlist.h @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ diff --git a/php_http_url.c b/php_http_url.c index eb1d2a3..c4eb90b 100644 --- a/php_http_url.c +++ b/php_http_url.c @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ diff --git a/php_http_url.h b/php_http_url.h index 938cf07..5c61daa 100644 --- a/php_http_url.h +++ b/php_http_url.h @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ diff --git a/php_http_version.c b/php_http_version.c index 4b80504..fbe9411 100644 --- a/php_http_version.c +++ b/php_http_version.c @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ @@ -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) diff --git a/php_http_version.h b/php_http_version.h index 8053646..40b833e 100644 --- a/php_http_version.h +++ b/php_http_version.h @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ diff --git a/phpunit.php b/phpunit.php deleted file mode 100644 index 8a61937..0000000 --- a/phpunit.php +++ /dev/null @@ -1,4 +0,0 @@ -run(array_merge($argv, array(__DIR__."/phpunit/"))); diff --git a/phpunit/CookieTest.php b/phpunit/CookieTest.php deleted file mode 100644 index d569c75..0000000 --- a/phpunit/CookieTest.php +++ /dev/null @@ -1,204 +0,0 @@ - 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 index 4642613..0000000 --- a/phpunit/EncodingTest.php +++ /dev/null @@ -1,172 +0,0 @@ -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 index 3aaf3eb..0000000 --- a/phpunit/MessageBodyTest.php +++ /dev/null @@ -1,135 +0,0 @@ -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 index 71bfcf4..0000000 --- a/phpunit/ParamsTest.php +++ /dev/null @@ -1,186 +0,0 @@ -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 index fb2eb47..0000000 --- a/phpunit/QueryStringTest.php +++ /dev/null @@ -1,66 +0,0 @@ -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 index dcf3b4f..0000000 --- a/phpunit/UrlTest.php +++ /dev/null @@ -1,49 +0,0 @@ -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 index 0000000..9f9c95e --- /dev/null +++ b/tests/bug66388.phpt @@ -0,0 +1,33 @@ +--TEST-- +Bug #66388 (Crash on POST with Content-Length:0 and untouched body) +--SKIPIF-- + +--FILE-- + 0 + ) +); +$client->enqueue($request); +echo $client->send()->getResponse()->getResponseCode(); + +?> + +===DONE=== +--EXPECT-- +Test +401 +===DONE=== diff --git a/tests/client002.phpt b/tests/client002.phpt index 44ff3d1..89d4d65 100644 --- a/tests/client002.phpt +++ b/tests/client002.phpt @@ -3,6 +3,7 @@ client observer --SKIPIF-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- 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 diff --git a/tests/client010.phpt b/tests/client010.phpt index 7563a77..055d585 100644 --- a/tests/client010.phpt +++ b/tests/client010.phpt @@ -3,34 +3,38 @@ client upload --SKIPIF-- --FILE-- 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 diff --git a/tests/client011.phpt b/tests/client011.phpt index 188b178..17c60ed 100644 --- a/tests/client011.phpt +++ b/tests/client011.phpt @@ -3,6 +3,7 @@ client history --SKIPIF-- --FILE-- --FILE-- --FILE-- 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 index 0000000..d0ff471 --- /dev/null +++ b/tests/client014.phpt @@ -0,0 +1,26 @@ +--TEST-- +reset content length when resetting body +--SKIPIF-- + +--FILE-- +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=== diff --git a/tests/clientresponse001.phpt b/tests/clientresponse001.phpt index 2f25291..270512b 100644 --- a/tests/clientresponse001.phpt +++ b/tests/clientresponse001.phpt @@ -3,6 +3,7 @@ client response cookie --SKIPIF-- --FILE-- - 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 diff --git a/tests/clientresponse002.phpt b/tests/clientresponse002.phpt index 3a0c50a..2379cc7 100644 --- a/tests/clientresponse002.phpt +++ b/tests/clientresponse002.phpt @@ -3,6 +3,7 @@ client response cookies --SKIPIF-- --FILE-- - 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 diff --git a/tests/clientresponse003.phpt b/tests/clientresponse003.phpt index 20dcef2..8ab936d 100644 --- a/tests/clientresponse003.phpt +++ b/tests/clientresponse003.phpt @@ -3,6 +3,7 @@ client response transfer info --SKIPIF-- --FILE-- +--FILE-- + 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 index 0000000..98c883b --- /dev/null +++ b/tests/cookie002.phpt @@ -0,0 +1,22 @@ +--TEST-- +cookies expire as date +--SKIPIF-- + +--INI-- +date.timezone=UTC +--FILE-- + $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 index 0000000..c546f52 --- /dev/null +++ b/tests/cookie003.phpt @@ -0,0 +1,19 @@ +--TEST-- +cookies numeric keys +--SKIPIF-- + +--FILE-- + +DONE +--EXPECT-- +Test +bool(true) +DONE diff --git a/tests/cookie004.phpt b/tests/cookie004.phpt new file mode 100644 index 0000000..1c4ead4 --- /dev/null +++ b/tests/cookie004.phpt @@ -0,0 +1,19 @@ +--TEST-- +cookies raw +--SKIPIF-- + +--FILE-- + +DONE +--EXPECT-- +Test +bool(true) +DONE diff --git a/tests/cookie005.phpt b/tests/cookie005.phpt new file mode 100644 index 0000000..f210402 --- /dev/null +++ b/tests/cookie005.phpt @@ -0,0 +1,75 @@ +--TEST-- +cookies simple data +--SKIPIF-- + +--FILE-- +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 index 0000000..d52f982 --- /dev/null +++ b/tests/cookie006.phpt @@ -0,0 +1,47 @@ +--TEST-- +cookies expire +--SKIPIF-- + +--INI-- +date.timezone=UTC +--FILE-- +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 index 0000000..1a7a4c3 --- /dev/null +++ b/tests/cookie007.phpt @@ -0,0 +1,37 @@ +--TEST-- +cookies max-age +--SKIPIF-- + +--INI-- +date.timezone=UTC +--FILE-- +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 index 0000000..5ec43dc --- /dev/null +++ b/tests/cookie008.phpt @@ -0,0 +1,37 @@ +--TEST-- +cookies path +--SKIPIF-- + +--FILE-- +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 index 0000000..55aac94 --- /dev/null +++ b/tests/cookie009.phpt @@ -0,0 +1,37 @@ +--TEST-- +cookies domain +--SKIPIF-- + +--FILE-- +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 index 0000000..34d10f2 --- /dev/null +++ b/tests/cookie010.phpt @@ -0,0 +1,35 @@ +--TEST-- +cookies flags +--SKIPIF-- + +--FILE-- +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 index 0000000..03700ea --- /dev/null +++ b/tests/cookie011.phpt @@ -0,0 +1,45 @@ +--TEST-- +cookies extras +--SKIPIF-- + +--FILE-- +"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 index 0000000..a3898c7 --- /dev/null +++ b/tests/cookie012.phpt @@ -0,0 +1,45 @@ +--TEST-- +cookies cookies +--SKIPIF-- + +--FILE-- +"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 index 0000000..5dc13d3 --- /dev/null +++ b/tests/encstream001.phpt @@ -0,0 +1,27 @@ +--TEST-- +encoding stream chunked static +--SKIPIF-- + +--FILE-- + +DONE +--EXPECT-- +Test +bool(true) +DONE + diff --git a/tests/encstream002.phpt b/tests/encstream002.phpt new file mode 100644 index 0000000..3be0aca --- /dev/null +++ b/tests/encstream002.phpt @@ -0,0 +1,21 @@ +--TEST-- +encoding stream chunked not encoded +--SKIPIF-- + +--FILE-- + +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 index 0000000..ad8c737 --- /dev/null +++ b/tests/encstream003.phpt @@ -0,0 +1,38 @@ +--TEST-- +encoding stream chunked error +--SKIPIF-- + +--FILE-- + +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 index 0000000..eb9da0f --- /dev/null +++ b/tests/encstream004.phpt @@ -0,0 +1,38 @@ +--TEST-- +encoding stream chunked flush +--SKIPIF-- + +--FILE-- + $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 index 0000000..6455ed4 --- /dev/null +++ b/tests/encstream005.phpt @@ -0,0 +1,41 @@ +--TEST-- +encoding stream zlib static +--SKIPIF-- + +--FILE-- + +DONE +--EXPECT-- +Test +bool(true) +bool(true) +bool(true) +DONE diff --git a/tests/encstream006.phpt b/tests/encstream006.phpt new file mode 100644 index 0000000..5430bfa --- /dev/null +++ b/tests/encstream006.phpt @@ -0,0 +1,30 @@ +--TEST-- +encoding stream zlib auto flush +--SKIPIF-- + +--FILE-- +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 index 0000000..5fdeffe --- /dev/null +++ b/tests/encstream007.phpt @@ -0,0 +1,34 @@ +--TEST-- +encoding stream zlib without flush +--SKIPIF-- + +--FILE-- +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 index 0000000..a46f9f0 --- /dev/null +++ b/tests/encstream008.phpt @@ -0,0 +1,42 @@ +--TEST-- +encoding stream zlib with explicit flush +--SKIPIF-- + +--FILE-- +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 index 0000000..fa51a8a --- /dev/null +++ b/tests/encstream009.phpt @@ -0,0 +1,20 @@ +--TEST-- +encoding stream zlib error +--SKIPIF-- + +--FILE-- + +DONE +--EXPECTF-- +Test + +Warning: http\Encoding\Stream\Inflate::decode(): Could not inflate data: data error in %s on line %d +bool(false) +DONE diff --git a/tests/envrequestbody001.phpt b/tests/envrequestbody001.phpt index 2351186..28f6a74 100644 --- a/tests/envrequestbody001.phpt +++ b/tests/envrequestbody001.phpt @@ -1,12 +1,12 @@ --TEST-- env request body --SKIPIF-- - --PUT-- Content-Type: skip/me foo --FILE-- - DONE diff --git a/tests/envrequestbody002.phpt b/tests/envrequestbody002.phpt index ec7d2d5..69c5988 100644 --- a/tests/envrequestbody002.phpt +++ b/tests/envrequestbody002.phpt @@ -1,12 +1,12 @@ --TEST-- env request body --SKIPIF-- - --PUT-- Content-Type: application/x-www-form-urlencoded foo=bar&baz=buh --FILE-- - DONE diff --git a/tests/envrequestbody003.phpt b/tests/envrequestbody003.phpt index a22dbbd..c2bde83 100644 --- a/tests/envrequestbody003.phpt +++ b/tests/envrequestbody003.phpt @@ -1,7 +1,7 @@ --TEST-- env request body --SKIPIF-- - --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-- - @@ -38,7 +38,7 @@ array(1) { ["type"]=> string(0) "" ["tmp_name"]=> - string(14) "%s" + string(%d) "%s" ["error"]=> int(0) ["size"]=> diff --git a/tests/envrequestheader001.phpt b/tests/envrequestheader001.phpt index b259ea5..bfc9ccb 100644 --- a/tests/envrequestheader001.phpt +++ b/tests/envrequestheader001.phpt @@ -1,30 +1,33 @@ --TEST-- env request header --SKIPIF-- - --POST-- a=b --ENV-- HTTP_HOST=foo.bar HTTP_ACCEPT=*/* --FILE-- - --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" } diff --git a/tests/envresponse003.phpt b/tests/envresponse003.phpt index 3bbf760..7a02814 100644 --- a/tests/envresponse003.phpt +++ b/tests/envresponse003.phpt @@ -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 diff --git a/tests/envresponse004.phpt b/tests/envresponse004.phpt index f84c860..deee3f2 100644 --- a/tests/envresponse004.phpt +++ b/tests/envresponse004.phpt @@ -1,5 +1,5 @@ --TEST-- -env reponse callback +env response callback --SKIPIF-- +--FILE-- +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 index 0000000..8d48c93 --- /dev/null +++ b/tests/envresponse016.phpt @@ -0,0 +1,35 @@ +--TEST-- +env response send failure +--SKIPIF-- + +--FILE-- +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 diff --git a/tests/envresponseheader001.phpt b/tests/envresponseheader001.phpt index 194f7d7..3997cf8 100644 --- a/tests/envresponseheader001.phpt +++ b/tests/envresponseheader001.phpt @@ -34,6 +34,6 @@ Array [2] => good ) - [Content-Type] => text/html + [Content-Type] => %s ) Created diff --git a/tests/envresponseranges001.phpt b/tests/envresponseranges001.phpt index 8511fff..08c0f27 100644 --- a/tests/envresponseranges001.phpt +++ b/tests/envresponseranges001.phpt @@ -1,7 +1,9 @@ --TEST-- ranges --SKIPIF-- - --GET-- a=b --ENV-- diff --git a/tests/etag001.phpt b/tests/etag001.phpt index b3a2a53..c1e1e44 100644 --- a/tests/etag001.phpt +++ b/tests/etag001.phpt @@ -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, diff --git a/tests/message002.phpt b/tests/message002.phpt index 06d9e1b..403fb26 100644 --- a/tests/message002.phpt +++ b/tests/message002.phpt @@ -9,8 +9,10 @@ b=c HTTP_X_TEST=test --COOKIE-- foo=bar +--INI-- +always_populate_raw_post_data=-1 --FILE-- -getBody()); echo "stream\n"; var_dump(file_get_contents("php://input")); - -echo "Done\n"; +?> +Done --EXPECTF-- Test object(%s)#%d (12) { diff --git a/tests/message003.phpt b/tests/message003.phpt index 69be990..93f128a 100644 --- a/tests/message003.phpt +++ b/tests/message003.phpt @@ -1,9 +1,11 @@ --TEST-- multipart message --SKIPIF-- - --FILE-- -isMultipart($boundary)) { var_dump($boundary); diff --git a/tests/message004.phpt b/tests/message004.phpt index 914a8da..e1c9aa9 100644 --- a/tests/message004.phpt +++ b/tests/message004.phpt @@ -2,7 +2,8 @@ message reversal --SKIPIF-- --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 index 0000000..fe28e28 --- /dev/null +++ b/tests/messagebody002.phpt @@ -0,0 +1,21 @@ +--TEST-- +message body append +--SKIPIF-- + +--FILE-- +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 index 0000000..7b79e6a --- /dev/null +++ b/tests/messagebody003.phpt @@ -0,0 +1,26 @@ +--TEST-- +message body append error +--SKIPIF-- + +--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 index 0000000..64254d4 --- /dev/null +++ b/tests/messagebody004.phpt @@ -0,0 +1,81 @@ +--TEST-- +message body add form +--SKIPIF-- + +--FILE-- +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 + +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 index 0000000..72f402d --- /dev/null +++ b/tests/messagebody005.phpt @@ -0,0 +1,30 @@ +--TEST-- +message body add part +--SKIPIF-- + +--FILE-- +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 index 0000000..a02057e --- /dev/null +++ b/tests/messagebody006.phpt @@ -0,0 +1,30 @@ +--TEST-- +message body etag +--SKIPIF-- + +--INI-- +http.etag.mode = crc32b +--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 index 0000000..dc010da --- /dev/null +++ b/tests/messagebody007.phpt @@ -0,0 +1,21 @@ +--TEST-- +message body to stream +--SKIPIF-- + +--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 index 0000000..cb9612c --- /dev/null +++ b/tests/messagebody008.phpt @@ -0,0 +1,23 @@ +--TEST-- +message body to callback +--SKIPIF-- + +--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 index 0000000..a7a7f43 --- /dev/null +++ b/tests/messagebody009.phpt @@ -0,0 +1,19 @@ +--TEST-- +message body clone +--SKIPIF-- + +--FILE-- + +DONE +--EXPECT-- +Test +bool(true) +DONE diff --git a/tests/messagebody010.phpt b/tests/messagebody010.phpt new file mode 100644 index 0000000..b50898d --- /dev/null +++ b/tests/messagebody010.phpt @@ -0,0 +1,23 @@ +--TEST-- +message body resource +--SKIPIF-- + +--FILE-- +getResource(); +var_dump(is_resource($stream)); +$stat = fstat($stream); +var_dump(filesize(__FILE__) === $stat["size"]); + +?> +DONE +--EXPECT-- +Test +bool(true) +bool(true) +DONE diff --git a/tests/negotiate001.phpt b/tests/negotiate001.phpt index d384b87..f628cdf 100644 --- a/tests/negotiate001.phpt +++ b/tests/negotiate001.phpt @@ -52,7 +52,7 @@ echo "$ln: "; print_r($lnr); CUSTOM - --FILE-- +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 index 0000000..11e2759 --- /dev/null +++ b/tests/params003.phpt @@ -0,0 +1,97 @@ +--TEST-- +default params +--SKIPIF-- + +--FILE-- +"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 index 0000000..69075ea --- /dev/null +++ b/tests/params004.phpt @@ -0,0 +1,97 @@ +--TEST-- +custom params +--SKIPIF-- + +--FILE-- +"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/params005.phpt b/tests/params005.phpt new file mode 100644 index 0000000..7c64a31 --- /dev/null +++ b/tests/params005.phpt @@ -0,0 +1,28 @@ +--TEST-- +quoted params +--SKIPIF-- + +--FILE-- + array( + "value" => true, + "arguments" => array( + "boundary" => "--123" + ) + ) +); +var_dump($c === $p->params); +var_dump("multipart/form-data;boundary=--123" === (string) $p); +?> +DONE +--EXPECT-- +Test +bool(true) +bool(true) +DONE diff --git a/tests/params006.phpt b/tests/params006.phpt new file mode 100644 index 0000000..f0f0565 --- /dev/null +++ b/tests/params006.phpt @@ -0,0 +1,29 @@ +--TEST-- +escaped params +--SKIPIF-- + +--FILE-- + array( + "value" => true, + "arguments" => array( + "name" => "upload", + "filename" => "trick\"\0\"ed" + ) + ) +); +var_dump($c === $p->params); +var_dump("form-data;name=upload;filename=\"trick\\\"\\000\\\"ed\"" === (string) $p); +?> +DONE +--EXPECT-- +Test +bool(true) +bool(true) +DONE diff --git a/tests/params007.phpt b/tests/params007.phpt new file mode 100644 index 0000000..c56e2fa --- /dev/null +++ b/tests/params007.phpt @@ -0,0 +1,35 @@ +--TEST-- +urlencoded params +--SKIPIF-- + +--FILE-- + array( + "value" => "b\"r", + "arguments" => array(), + ), + "bar" => array( + "value" => "b\"z", + "arguments" => array(), + ), + "a[][]" => array( + "value" => "1", + "arguments" => array(), + ), +); +var_dump($c === $p->params); +var_dump("foo=b%22r&bar=b%22z&a%5B%5D%5B%5D=1" === (string) $p); +?> +DONE +--EXPECT-- +Test +bool(true) +bool(true) +DONE diff --git a/tests/params008.phpt b/tests/params008.phpt new file mode 100644 index 0000000..463a96c --- /dev/null +++ b/tests/params008.phpt @@ -0,0 +1,37 @@ +--TEST-- +querystring params +--SKIPIF-- + +--FILE-- + array( + "value" => "b\"r", + "arguments" => array(), + ), + "bar" => array( + "value" => "b\"z", + "arguments" => array(), + ), + "a" => array( + "value" => array( + array("1") + ), + "arguments" => array(), + ), +); +var_dump($c === $p->params); +var_dump("foo=b%22r&bar=b%22z&a%5B0%5D%5B0%5D=1" === (string) $p); +?> +DONE +--EXPECT-- +Test +bool(true) +bool(true) +DONE diff --git a/tests/params009.phpt b/tests/params009.phpt new file mode 100644 index 0000000..07c58c7 --- /dev/null +++ b/tests/params009.phpt @@ -0,0 +1,17 @@ +--TEST-- +empty params +--SKIPIF-- + +--FILE-- +params); +?> +DONE +--EXPECT-- +Test +bool(true) +DONE diff --git a/tests/params010.phpt b/tests/params010.phpt new file mode 100644 index 0000000..ced5e92 --- /dev/null +++ b/tests/params010.phpt @@ -0,0 +1,21 @@ +--TEST-- +int key params +--SKIPIF-- + +--FILE-- + array("value" => "nothing", "arguments" => array(1=>"yes"))) === $p->params); +var_dump("0=nothing;1=yes" === $p->toString()); + +?> +DONE +--EXPECT-- +Test +bool(true) +bool(true) +DONE diff --git a/tests/params011.phpt b/tests/params011.phpt new file mode 100644 index 0000000..1f9ecf7 --- /dev/null +++ b/tests/params011.phpt @@ -0,0 +1,23 @@ +--TEST-- +bool args params +--SKIPIF-- + +--FILE-- + false, "arguments" => array("wrong" => false, "correct" => true)); +$p["container"] = $container; +var_dump("container=0;wrong=0;correct" === $p->toString()); +var_dump(array("container" => $container) === $p->toArray()); + +?> +DONE +--EXPECT-- +Test +bool(true) +bool(true) +DONE diff --git a/tests/params012.phpt b/tests/params012.phpt new file mode 100644 index 0000000..f5a33ca --- /dev/null +++ b/tests/params012.phpt @@ -0,0 +1,22 @@ +--TEST-- +no args params +--SKIPIF-- + +--FILE-- +toString()); +$p["param"] = false; +var_dump("param=0" === $p->toString()); +?> +DONE +--EXPECT-- +Test +bool(true) +bool(true) +DONE diff --git a/tests/params013.phpt b/tests/params013.phpt new file mode 100644 index 0000000..d69782a --- /dev/null +++ b/tests/params013.phpt @@ -0,0 +1,79 @@ +--TEST-- +header params rfc5987 +--SKIPIF-- + +--FILE-- +params, (string) $p); +$p = new http\Params("bar; title*=iso-8859-1'en'%A3%20rates"); +var_dump($p->params, (string) $p); +$p = new http\Params("bar; title*=UTF-8''%c2%a3%20and%20%e2%82%ac%20rates"); +var_dump($p->params, (string) $p); + +?> +===DONE=== +--EXPECT-- +Test +array(1) { + ["attachment"]=> + array(2) { + ["value"]=> + bool(true) + ["arguments"]=> + array(1) { + ["*rfc5987*"]=> + array(1) { + ["filename"]=> + array(1) { + [""]=> + string(10) "döner.pdf" + } + } + } + } +} +string(42) "attachment;filename*=utf-8''d%C3%B6ner.pdf" +array(1) { + ["bar"]=> + array(2) { + ["value"]=> + bool(true) + ["arguments"]=> + array(1) { + ["*rfc5987*"]=> + array(1) { + ["title"]=> + array(1) { + ["en"]=> + string(8) "£ rates" + } + } + } + } +} +string(34) "bar;title*=utf-8'en'%C2%A3%20rates" +array(1) { + ["bar"]=> + array(2) { + ["value"]=> + bool(true) + ["arguments"]=> + array(1) { + ["*rfc5987*"]=> + array(1) { + ["title"]=> + array(1) { + [""]=> + string(16) "£ and € rates" + } + } + } + } +} +string(50) "bar;title*=utf-8''%C2%A3%20and%20%E2%82%AC%20rates" +===DONE=== diff --git a/tests/params014.phpt b/tests/params014.phpt new file mode 100644 index 0000000..b61953d --- /dev/null +++ b/tests/params014.phpt @@ -0,0 +1,70 @@ +--TEST-- +header params rfc5987 +--SKIPIF-- + +--FILE-- +params); +var_dump((string)$p === $t, (string)$p, $t); +?> +===DONE=== +--EXPECT-- +Test +array(3) { + ["p1"]=> + array(2) { + ["*rfc5987*"]=> + array(1) { + [""]=> + string(5) "süß" + } + ["arguments"]=> + array(0) { + } + } + ["p2"]=> + array(2) { + ["*rfc5987*"]=> + array(1) { + [""]=> + string(5) "heiß" + } + ["arguments"]=> + array(2) { + ["*rfc5987*"]=> + array(2) { + ["a1"]=> + array(1) { + [""]=> + string(3) "aß" + } + ["a2"]=> + array(1) { + [""]=> + string(3) "eß" + } + } + ["a3"]=> + string(2) "no" + } + } + ["p3"]=> + array(2) { + ["value"]=> + string(3) "not" + ["arguments"]=> + array(0) { + } + } +} +bool(true) +string(96) "p1*=utf-8''s%C3%BC%C3%9F,p2*=utf-8''hei%C3%9F;a1*=utf-8''a%C3%9F;a2*=utf-8''e%C3%9F;a3=no,p3=not" +string(96) "p1*=utf-8''s%C3%BC%C3%9F,p2*=utf-8''hei%C3%9F;a1*=utf-8''a%C3%9F;a2*=utf-8''e%C3%9F;a3=no,p3=not" +===DONE=== diff --git a/tests/params015.phpt b/tests/params015.phpt new file mode 100644 index 0000000..ad3948c --- /dev/null +++ b/tests/params015.phpt @@ -0,0 +1,25 @@ +--TEST-- +header params rfc5987 regression +--SKIPIF-- + +--FILE-- +["filename"=>"foo.bar"]]); +var_dump($p->params); +var_dump((string)$p); +?> +===DONE=== +--EXPECT-- +Test +array(1) { + ["attachment"]=> + array(1) { + ["filename"]=> + string(7) "foo.bar" + } +} +string(27) "attachment;filename=foo.bar" +===DONE=== diff --git a/tests/phpunit.phpt b/tests/phpunit.phpt deleted file mode 100644 index 087923e..0000000 --- a/tests/phpunit.phpt +++ /dev/null @@ -1,24 +0,0 @@ ---TEST-- -unit tests ---SKIPIF-- - ---INI-- -date.timezone=Europe/Vienna ---FILE-- -run(array("--process-isolation", __DIR__."/../phpunit/")); -?> ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -%a - -Time: %s, Memory: %s - -OK (%d tests, %d assertions) - diff --git a/tests/propertyproxy001.phpt b/tests/propertyproxy001.phpt index da17577..552a713 100644 --- a/tests/propertyproxy001.phpt +++ b/tests/propertyproxy001.phpt @@ -1,5 +1,9 @@ --TEST-- property proxy +--SKIPIF-- + --FILE-- +--GET-- +str=abc&num=-123&dec=123.123&bool=1&arr[]=1&arr[]=2&ma[l1][l2]=2&ma[l2][l3][l4]=3 +--FILE-- +getString("str")); +var_dump($q->getInt("num")); +var_dump($q->getFloat("dec")); +var_dump($q->getInt("dec")); +var_dump($q->getFloat("dec")); +var_dump($q->getBool("bool")); +var_dump($q->getInt("bool")); +var_dump($q->getBool("num")); +var_dump($q->getInt("num")); +var_dump($q->getArray("arr")); +var_dump($q->getArray("ma")); +var_dump($q->getObject("arr")); +var_dump($q->getObject("ma")); + +$s = $q->toString(); + +printf("\nClone modifications do not alter global instance:\n"); +$q->mod(array("arr" => array(3 => 3))); +printf("%s\n", $q); + +printf("\nClone modifications do not alter standard instance:\n"); +$q2 = new http\QueryString($s); +$q3 = $q2->mod(array("arr" => array(3 => 3))); +printf("%s\n%s\n", $q2, $q3); +#var_dump($q2, $q3); + +printf("\nIterator:\n"); +$it = new RecursiveIteratorIterator($q2, RecursiveIteratorIterator::SELF_FIRST); +foreach ($it as $k => $v) { + $i = $it->getDepth()*8; + @printf("%{$i}s: %s\n", $k, $v); +} + +printf("\nReplace a multi dimensional key:\n"); +printf("%s\n", $q2->mod(array("ma" => null))->set(array("ma" => array("l1" => false)))); + +printf("\nXlate:\n"); +$qu = new http\QueryString("ü=ö"); +printf("utf8: %s\n", $qu); +printf("latin1: %s\n", method_exists($qu, "xlate") ? $qu->xlate("utf-8", "latin1") : "%FC=%F6"); + +printf("\nOffsets:\n"); +var_dump($q2["ma"]); +$q2["ma"] = array("bye"); +var_dump($q2["ma"]); +var_dump(isset($q2["ma"])); +unset($q2["ma"]); +var_dump(isset($q2["ma"])); + +echo "Done\n"; +?> +--EXPECTF-- +Test + +Global instance: +str=abc&num=-123&dec=123.123&bool=1&arr%5B0%5D=1&arr%5B1%5D=2&ma%5Bl1%5D%5Bl2%5D=2&ma%5Bl2%5D%5Bl3%5D%5Bl4%5D=3 + +Standard getters: +string(3) "abc" +int(-123) +float(123.123) +int(123) +float(123.123) +bool(true) +int(1) +bool(true) +int(-123) +array(2) { + [0]=> + string(1) "1" + [1]=> + string(1) "2" +} +array(2) { + ["l1"]=> + array(1) { + ["l2"]=> + string(1) "2" + } + ["l2"]=> + array(1) { + ["l3"]=> + array(1) { + ["l4"]=> + string(1) "3" + } + } +} +object(stdClass)#%d (2) { + [0]=> + string(1) "1" + [1]=> + string(1) "2" +} +object(stdClass)#%d (2) { + ["l1"]=> + array(1) { + ["l2"]=> + string(1) "2" + } + ["l2"]=> + array(1) { + ["l3"]=> + array(1) { + ["l4"]=> + string(1) "3" + } + } +} + +Clone modifications do not alter global instance: +str=abc&num=-123&dec=123.123&bool=1&arr%5B0%5D=1&arr%5B1%5D=2&ma%5Bl1%5D%5Bl2%5D=2&ma%5Bl2%5D%5Bl3%5D%5Bl4%5D=3 + +Clone modifications do not alter standard instance: +str=abc&num=-123&dec=123.123&bool=1&arr%5B0%5D=1&arr%5B1%5D=2&ma%5Bl1%5D%5Bl2%5D=2&ma%5Bl2%5D%5Bl3%5D%5Bl4%5D=3 +str=abc&num=-123&dec=123.123&bool=1&arr%5B0%5D=1&arr%5B1%5D=2&arr%5B3%5D=3&ma%5Bl1%5D%5Bl2%5D=2&ma%5Bl2%5D%5Bl3%5D%5Bl4%5D=3 + +Iterator: +str: abc +num: -123 +dec: 123.123 +bool: 1 +arr: Array + 0: 1 + 1: 2 +ma: Array + l1: Array + l2: 2 + l2: Array + l3: Array + l4: 3 + +Replace a multi dimensional key: +str=abc&num=-123&dec=123.123&bool=1&arr%5B0%5D=1&arr%5B1%5D=2&ma%5Bl1%5D= + +Xlate: +utf8: %C3%BC=%C3%B6 +latin1: %FC=%F6 + +Offsets: +array(2) { + ["l1"]=> + array(1) { + ["l2"]=> + string(1) "2" + } + ["l2"]=> + array(1) { + ["l3"]=> + array(1) { + ["l4"]=> + string(1) "3" + } + } +} +array(1) { + [0]=> + string(3) "bye" +} +bool(true) +bool(false) +Done diff --git a/tests/querystring002.phpt b/tests/querystring002.phpt new file mode 100644 index 0000000..ab82672 --- /dev/null +++ b/tests/querystring002.phpt @@ -0,0 +1,95 @@ +--TEST-- +query string +--SKIPIF-- + +--FILE-- +get()); + +printf("Get defval\n"); +var_dump("nonexistant" === $q->get("unknown", "s", "nonexistant")); +var_dump(null === $q->get("unknown")); + +printf("Get 'a'\n"); +var_dump("b" === $q->get("a")); +var_dump(0 === $q->get("a", "i")); +var_dump(array("b") === $q->get("a", "a")); +var_dump((object)array("scalar" => "b") == $q->get("a", "o")); + +printf("Get 'r'\n"); +var_dump(array("0","1","2") === $q->get("r")); + +printf("Get 'rr'\n"); +var_dump(array(array("00","01")) === $q->get("rr")); + +printf("Get 1\n"); +var_dump(2 == $q->get(1)); +var_dump("2" === $q->get(1, "s")); +var_dump(2.0 === $q->get(1, "f")); +var_dump($q->get(1, "b")); + +printf("Del 'a'\n"); +var_dump("b" === $q->get("a", http\QueryString::TYPE_STRING, null, true)); +var_dump(null === $q->get("a")); + +printf("Del all\n"); +$q->set(array("a" => null, "r" => null, "rr" => null, 1 => null)); +var_dump("" === $q->toString()); + +$q = new http\QueryString($s); + +printf("QSO\n"); +var_dump($e === (string) new http\QueryString($q)); +var_dump(http_build_query(array("e"=>$q->toArray())) === (string) new http\QueryString(array("e" => $q))); + +printf("Iterator\n"); +var_dump($q->toArray() === iterator_to_array($q)); + +printf("Serialize\n"); +var_dump($e === (string) unserialize(serialize($q))); + +?> +DONE +--EXPECT-- +Test +bool(true) +bool(true) +Get defval +bool(true) +bool(true) +Get 'a' +bool(true) +bool(true) +bool(true) +bool(true) +Get 'r' +bool(true) +Get 'rr' +bool(true) +Get 1 +bool(true) +bool(true) +bool(true) +bool(true) +Del 'a' +bool(true) +bool(true) +Del all +bool(true) +QSO +bool(true) +bool(true) +Iterator +bool(true) +Serialize +bool(true) +DONE diff --git a/tests/querystring_001.phpt b/tests/querystring_001.phpt deleted file mode 100644 index 203be33..0000000 --- a/tests/querystring_001.phpt +++ /dev/null @@ -1,179 +0,0 @@ ---TEST-- -query string ---SKIPIF-- - ---GET-- -str=abc&num=-123&dec=123.123&bool=1&arr[]=1&arr[]=2&ma[l1][l2]=2&ma[l2][l3][l4]=3 ---FILE-- -getString("str")); -var_dump($q->getInt("num")); -var_dump($q->getFloat("dec")); -var_dump($q->getInt("dec")); -var_dump($q->getFloat("dec")); -var_dump($q->getBool("bool")); -var_dump($q->getInt("bool")); -var_dump($q->getBool("num")); -var_dump($q->getInt("num")); -var_dump($q->getArray("arr")); -var_dump($q->getArray("ma")); -var_dump($q->getObject("arr")); -var_dump($q->getObject("ma")); - -$s = $q->toString(); - -printf("\nClone modifications do not alter global instance:\n"); -$q->mod(array("arr" => array(3 => 3))); -printf("%s\n", $q); - -printf("\nClone modifications do not alter standard instance:\n"); -$q2 = new http\QueryString($s); -$q3 = $q2->mod(array("arr" => array(3 => 3))); -printf("%s\n%s\n", $q2, $q3); -#var_dump($q2, $q3); - -printf("\nIterator:\n"); -$it = new RecursiveIteratorIterator($q2, RecursiveIteratorIterator::SELF_FIRST); -foreach ($it as $k => $v) { - $i = $it->getDepth()*8; - @printf("%{$i}s: %s\n", $k, $v); -} - -printf("\nReplace a multi dimensional key:\n"); -printf("%s\n", $q2->mod(array("ma" => null))->set(array("ma" => array("l1" => false)))); - -printf("\nXlate:\n"); -$qu = new http\QueryString("ü=ö"); -printf("utf8: %s\n", $qu); -printf("latin1: %s\n", method_exists($qu, "xlate") ? $qu->xlate("utf-8", "latin1") : "%FC=%F6"); - -printf("\nOffsets:\n"); -var_dump($q2["ma"]); -$q2["ma"] = array("bye"); -var_dump($q2["ma"]); -var_dump(isset($q2["ma"])); -unset($q2["ma"]); -var_dump(isset($q2["ma"])); - -echo "Done\n"; -?> ---EXPECTF-- -Test - -Global instance: -str=abc&num=-123&dec=123.123&bool=1&arr%5B0%5D=1&arr%5B1%5D=2&ma%5Bl1%5D%5Bl2%5D=2&ma%5Bl2%5D%5Bl3%5D%5Bl4%5D=3 - -Standard getters: -string(3) "abc" -int(-123) -float(123.123) -int(123) -float(123.123) -bool(true) -int(1) -bool(true) -int(-123) -array(2) { - [0]=> - string(1) "1" - [1]=> - string(1) "2" -} -array(2) { - ["l1"]=> - array(1) { - ["l2"]=> - string(1) "2" - } - ["l2"]=> - array(1) { - ["l3"]=> - array(1) { - ["l4"]=> - string(1) "3" - } - } -} -object(stdClass)#%d (2) { - [0]=> - string(1) "1" - [1]=> - string(1) "2" -} -object(stdClass)#%d (2) { - ["l1"]=> - array(1) { - ["l2"]=> - string(1) "2" - } - ["l2"]=> - array(1) { - ["l3"]=> - array(1) { - ["l4"]=> - string(1) "3" - } - } -} - -Clone modifications do not alter global instance: -str=abc&num=-123&dec=123.123&bool=1&arr%5B0%5D=1&arr%5B1%5D=2&ma%5Bl1%5D%5Bl2%5D=2&ma%5Bl2%5D%5Bl3%5D%5Bl4%5D=3 - -Clone modifications do not alter standard instance: -str=abc&num=-123&dec=123.123&bool=1&arr%5B0%5D=1&arr%5B1%5D=2&ma%5Bl1%5D%5Bl2%5D=2&ma%5Bl2%5D%5Bl3%5D%5Bl4%5D=3 -str=abc&num=-123&dec=123.123&bool=1&arr%5B0%5D=1&arr%5B1%5D=2&arr%5B3%5D=3&ma%5Bl1%5D%5Bl2%5D=2&ma%5Bl2%5D%5Bl3%5D%5Bl4%5D=3 - -Iterator: -str: abc -num: -123 -dec: 123.123 -bool: 1 -arr: Array - 0: 1 - 1: 2 -ma: Array - l1: Array - l2: 2 - l2: Array - l3: Array - l4: 3 - -Replace a multi dimensional key: -str=abc&num=-123&dec=123.123&bool=1&arr%5B0%5D=1&arr%5B1%5D=2&ma%5Bl1%5D= - -Xlate: -utf8: %C3%BC=%C3%B6 -latin1: %FC=%F6 - -Offsets: -array(2) { - ["l1"]=> - array(1) { - ["l2"]=> - string(1) "2" - } - ["l2"]=> - array(1) { - ["l3"]=> - array(1) { - ["l4"]=> - string(1) "3" - } - } -} -array(1) { - [0]=> - string(3) "bye" -} -bool(true) -bool(false) -Done diff --git a/tests/skipif.inc b/tests/skipif.inc index 0f10264..28d9a13 100644 --- a/tests/skipif.inc +++ b/tests/skipif.inc @@ -1,3 +1,15 @@ + --ENV-- SERVER_PORT=55555 HTTP_HOST=example.com diff --git a/tests/url002.phpt b/tests/url002.phpt new file mode 100644 index 0000000..2b31ee9 --- /dev/null +++ b/tests/url002.phpt @@ -0,0 +1,45 @@ +--TEST-- +url properties +--SKIPIF-- + +--FILE-- + "changed", "query" => "foo=&added=this"), + http\Url::JOIN_PATH | + http\Url::JOIN_QUERY | + http\Url::STRIP_AUTH | + http\Url::STRIP_FRAGMENT +); + +var_dump($url->scheme); +var_dump($url->user); +var_dump($url->pass); +var_dump($url->host); +var_dump($url->port); +var_dump($url->path); +var_dump($url->query); +var_dump($url->fragment); + +?> +DONE +--EXPECT-- +Test +bool(true) +string(4) "http" +NULL +NULL +string(15) "www.example.com" +int(8080) +string(13) "/path/changed" +string(38) "more%5B0%5D=1&more%5B1%5D=2&added=this" +NULL +DONE diff --git a/tests/url003.phpt b/tests/url003.phpt new file mode 100644 index 0000000..b2def7f --- /dev/null +++ b/tests/url003.phpt @@ -0,0 +1,27 @@ +--TEST-- +url modification +--SKIPIF-- + +--FILE-- +mod(array("query" => "set=1"), http\Url::REPLACE); +var_dump($tmp->toArray() != $mod->toArray()); +var_dump("set=1" === $mod->query); +var_dump("new_fragment" === $tmp->mod("#new_fragment")->fragment); + +?> +DONE +--EXPECT-- +Test +bool(true) +bool(true) +bool(true) +DONE diff --git a/tests/url004.phpt b/tests/url004.phpt new file mode 100644 index 0000000..c3055da --- /dev/null +++ b/tests/url004.phpt @@ -0,0 +1,22 @@ +--TEST-- +url as string +--SKIPIF-- + +--FILE-- + +DONE +--EXPECT-- +Test +bool(true) +DONE diff --git a/tests/url005.phpt b/tests/url005.phpt new file mode 100644 index 0000000..f9b6965 --- /dev/null +++ b/tests/url005.phpt @@ -0,0 +1,22 @@ +--TEST-- +url as array +--SKIPIF-- + +--FILE-- +toArray()); +var_dump($url->toArray() === $url2->toArray()); +?> +DONE +--EXPECT-- +Test +bool(true) +DONE