--- /dev/null
+HTTP extension for PHP
+Michael Wallner
--- /dev/null
+Known Issues
+============
+$Id: KnownIssues.txt 292753 2009-12-29 12:30:43Z mike $
+
+Windows:
+ If you keep getting "SSL connect error" when trying to issue
+ requests, try another (newer) libeay32.dll/ssleay32.dll pair.
+
+Internals:
+ Inflating raw deflated data causes a re-initialization of the inflate
+ stream where the corresponding window bits are modified to tell libz
+ to not check for zlib header bytes. This is not preventable AFAICS.
+ LFS dependant parts of libcurl are left out because of off_t,
+ respectively off64_t confusion.
+ Persistent handles and "cookiestore" request option do interfere,
+ as libcurl saves the cookies to the file on curl_easy_destroy(),
+ cookies are not saved until the CURL handle will be recycled.
+ Thus one would either need to
+ * run PHP with http.persistent.handles.limit = 0
+ * call http_persistent_handles_clean() every request
+ * call $HttpRequest->flushCookies(), which is available
+ since libcurl v7.17.1 and does not work with the
+ procedural API
+ Anyway, none of these options is really perfect, so using
+ HttpRequestDatashare with cookies enabled is probably the
+ best thing to do.
+ HTTP and Proxy authentication information (username/password) can not be
+ unset with NULL prior libcurl v7.19.6 and separate options for setting
+ username and password--which work--are only available since v7.19.6.
--- /dev/null
+Copyright (c) 2004-2010, Michael Wallner <mike@iworks.at>.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
--- /dev/null
+Thanks To
+=========
+$Id: ThanksTo.txt 275653 2009-02-12 13:11:05Z mike $
+
+People who repeatedly reported issues with this extension in a manner
+so they could be fixed in a reasonable way, or suggested useful features
+to implement, in alphabetical order:
+
+ Ilia Alshanetsky (ilia at php dot net)
+ Petr Czaderna (petr at hroch dot info)
+ David James (james82 at gmail dot com)
+ Thomas Landro Johnsen (thomas dot l dot johnsen at gmail dot com)
+ Clay Loveless (clay at killersoft dot com)
+ Felipe Pena (felipe at php dot net)
+ David Sklar (sklar at sklar dot com)
+ Travis Swicegood (travis at mashery dot com)
+ Alexey Zakhlestin (indeyets at gmail dot com)
+ Alexander Zhuravlev (zaa at zaa dot pp dot ru)
+
+Thanks a lot!
--- /dev/null
+dnl phpize stub of config9.m4 for pecl/http
+dnl $Id: config.m4 214417 2006-06-07 21:05:34Z mike $
+dnl vim: noet ts=1 sw=1
+
+sinclude(config9.m4)
--- /dev/null
+dnl config.m4 for pecl/http
+dnl $Id: config9.m4 242664 2007-09-18 19:13:37Z mike $
+dnl vim: noet ts=1 sw=4
+
+PHP_ARG_WITH([http], [whether to enable extended HTTP support],
+[ --with-http Enable extended HTTP support])
+PHP_ARG_WITH([http-zlib-dir], [],
+[ --with-http-zlib-dir[=DIR] HTTP: where to find zlib], $PHP_HTTP, $PHP_HTTP)
+PHP_ARG_WITH([http-libcurl-dir], [],
+[ --with-http-libcurl-dir[=DIR] HTTP: where to find libcurl], $PHP_HTTP, $PHP_HTTP)
+PHP_ARG_WITH([http-libevent-dir], [],
+[ --with-http-libevent-dir[=DIR] HTTP: where to find libevent], $PHP_HTTP_LIBCURL_DIR, "")
+
+if test "$PHP_HTTP" != "no"; then
+
+ ifdef([AC_PROG_EGREP], [
+ AC_PROG_EGREP
+ ], [
+ AC_CHECK_PROG(EGREP, egrep, egrep)
+ ])
+ ifdef([AC_PROG_SED], [
+ AC_PROG_SED
+ ], [
+ ifdef([LT_AC_PROG_SED], [
+ LT_AC_PROG_SED
+ ], [
+ AC_CHECK_PROG(SED, sed, sed)
+ ])
+ ])
+
+ AC_PROG_CPP
+
+ if test "$PHP_HTTP_SHARED_DEPS" != "no"; then
+ AC_DEFINE([PHP_HTTP_SHARED_DEPS], [1], [ ])
+ else
+ AC_DEFINE([PHP_HTTP_SHARED_DEPS], [0], [ ])
+ fi
+
+ dnl
+ dnl HTTP_SHARED_DEP(name[, code-if-yes[, code-if-not]])
+ dnl
+ AC_DEFUN([HTTP_SHARED_DEP], [
+ extname=$1
+ haveext=$[PHP_HTTP_HAVE_EXT_]translit($1,a-z_-,A-Z__)
+
+ AC_MSG_CHECKING([whether to add a dependency on ext/$extname])
+ if test "$PHP_HTTP_SHARED_DEPS" = "no"; then
+ AC_MSG_RESULT([no])
+ $3
+ elif test "$haveext"; then
+ AC_MSG_RESULT([yes])
+ AC_DEFINE([PHP_HTTP_HAVE_EXT_]translit($1,a-z_-,A-Z__), [1], [ ])
+ ifdef([PHP_ADD_EXTENSION_DEP], [
+ PHP_ADD_EXTENSION_DEP([http], $1, true)
+ ])
+ $2
+ else
+ AC_MSG_RESULT([no])
+ $3
+ fi
+ ])
+
+ dnl
+ dnl HTTP_HAVE_PHP_EXT(name[, code-if-yes[, code-if-not]])
+ dnl
+ AC_DEFUN([HTTP_HAVE_PHP_EXT], [
+ extname=$1
+ haveext=$[PHP_]translit($1,a-z_-,A-Z__)
+
+ AC_MSG_CHECKING([for ext/$extname support])
+ if test -x "$PHP_EXECUTABLE"; then
+ grepext=`$PHP_EXECUTABLE -m | $EGREP ^$extname\$`
+ if test "$grepext" = "$extname"; then
+ [PHP_HTTP_HAVE_EXT_]translit($1,a-z_-,A-Z__)=1
+ AC_MSG_RESULT([yes])
+ $2
+ else
+ [PHP_HTTP_HAVE_EXT_]translit($1,a-z_-,A-Z__)=
+ AC_MSG_RESULT([no])
+ $3
+ fi
+ elif test "$haveext" != "no" && test "x$haveext" != "x"; then
+ [PHP_HTTP_HAVE_EXT_]translit($1,a-z_-,A-Z__)=1
+ AC_MSG_RESULT([yes])
+ $2
+ else
+ [PHP_HTTP_HAVE_EXT_]translit($1,a-z_-,A-Z__)=
+ AC_MSG_RESULT([no])
+ $3
+ fi
+ ])
+
+
+dnl ----
+dnl STDC
+dnl ----
+ AC_CHECK_HEADERS([netdb.h unistd.h])
+ PHP_CHECK_FUNC(gethostname, nsl)
+ PHP_CHECK_FUNC(getdomainname, nsl)
+ PHP_CHECK_FUNC(getservbyport, nsl)
+ PHP_CHECK_FUNC(getservbyname, nsl)
+
+dnl ----
+dnl ZLIB
+dnl ----
+ AC_MSG_CHECKING([for zlib.h])
+ ZLIB_DIR=
+ for i in "$PHP_HTTP_ZLIB_DIR" "$PHP_ZLIB_DIR" "$PHP_ZLIB" /usr/local /usr /opt; do
+ if test -f "$i/include/zlib.h"; then
+ ZLIB_DIR=$i
+ break;
+ fi
+ done
+ if test "x$ZLIB_DIR" = "x"; then
+ AC_MSG_RESULT([not found])
+ AC_MSG_ERROR([could not find zlib.h])
+ else
+ AC_MSG_RESULT([found in $ZLIB_DIR])
+ AC_MSG_CHECKING([for zlib version >= 1.2.0.4])
+ ZLIB_VERSION=`$EGREP "define ZLIB_VERSION" $ZLIB_DIR/include/zlib.h | $SED -e 's/[[^0-9\.]]//g'`
+ AC_MSG_RESULT([$ZLIB_VERSION])
+ if test `echo $ZLIB_VERSION | $SED -e 's/[[^0-9]]/ /g' | $AWK '{print $1*1000000 + $2*10000 + $3*100 + $4}'` -lt 1020004; then
+ AC_MSG_ERROR([zlib version greater or equal to 1.2.0.4 required])
+ else
+ PHP_ADD_INCLUDE($ZLIB_DIR/include)
+ PHP_ADD_LIBRARY_WITH_PATH(z, $ZLIB_DIR/$PHP_LIBDIR, HTTP_SHARED_LIBADD)
+ AC_DEFINE([PHP_HTTP_HAVE_ZLIB], [1], [Have zlib support])
+ fi
+ fi
+
+dnl ----
+dnl CURL
+dnl ----
+ AC_MSG_CHECKING([for curl/curl.h])
+ CURL_DIR=
+ for i in "$PHP_HTTP_LIBCURL_DIR" /usr/local /usr /opt; do
+ if test -f "$i/include/curl/curl.h"; then
+ CURL_DIR=$i
+ break
+ fi
+ done
+ if test "x$CURL_DIR" = "x"; then
+ AC_MSG_RESULT([not found])
+ AC_MSG_ERROR([could not find curl/curl.h])
+ else
+ AC_MSG_RESULT([found in $CURL_DIR])
+ fi
+
+ AC_MSG_CHECKING([for curl-config])
+ CURL_CONFIG=
+ for i in "$CURL_DIR/bin/curl-config" "$CURL_DIR/curl-config" `which curl-config`; do
+ if test -x "$i"; then
+ CURL_CONFIG=$i
+ break
+ fi
+ done
+ if test "x$CURL_CONFIG" = "x"; then
+ AC_MSG_RESULT([not found])
+ AC_MSG_ERROR([could not find curl-config])
+ else
+ AC_MSG_RESULT([found: $CURL_CONFIG])
+ fi
+
+ dnl Debian stable has currently 7.18.2
+ AC_MSG_CHECKING([for curl version >= 7.18.2])
+ CURL_VERSION=`$CURL_CONFIG --version | $SED -e 's/[[^0-9\.]]//g'`
+ AC_MSG_RESULT([$CURL_VERSION])
+ if test `echo $CURL_VERSION | $SED -e 's/[[^0-9]]/ /g' | $AWK '{print $1*10000 + $2*100 + $3}'` -lt 71802; then
+ AC_MSG_ERROR([libcurl version greater or equal to 7.18.2 required])
+ fi
+
+ dnl
+ dnl compile tests
+ dnl
+
+ save_INCLUDES="$INCLUDES"
+ INCLUDES=
+ save_LIBS="$LIBS"
+ LIBS=
+ save_CFLAGS="$CFLAGS"
+ CFLAGS=`$CURL_CONFIG --cflags`
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS=`$CURL_CONFIG --libs`
+ LDFLAGS="$LDFLAGS $ld_runpath_switch$CURL_DIR/$PHP_LIBDIR"
+
+ AC_MSG_CHECKING([for SSL support in libcurl])
+ CURL_SSL=`$CURL_CONFIG --feature | $EGREP SSL`
+ if test "$CURL_SSL" = "SSL"; then
+ AC_MSG_RESULT([yes])
+ AC_DEFINE([PHP_HTTP_HAVE_SSL], [1], [ ])
+
+ AC_MSG_CHECKING([for openssl support in libcurl])
+ AC_TRY_RUN([
+ #include <curl/curl.h>
+ int main(int argc, char *argv[]) {
+ curl_version_info_data *data = curl_version_info(CURLVERSION_NOW);
+ if (data && data->ssl_version && *data->ssl_version) {
+ const char *ptr = data->ssl_version;
+ while(*ptr == ' ') ++ptr;
+ return strncasecmp(ptr, "OpenSSL", sizeof("OpenSSL")-1);
+ }
+ return 1;
+ }
+ ], [
+ AC_MSG_RESULT([yes])
+ AC_CHECK_HEADER([openssl/crypto.h], [
+ AC_DEFINE([PHP_HTTP_HAVE_OPENSSL], [1], [ ])
+ ])
+ ], [
+ AC_MSG_RESULT([no])
+ ], [
+ AC_MSG_RESULT([no])
+ ])
+
+ AC_MSG_CHECKING([for gnutls support in libcurl])
+ AC_TRY_RUN([
+ #include <curl/curl.h>
+ int main(int argc, char *argv[]) {
+ curl_version_info_data *data = curl_version_info(CURLVERSION_NOW);
+ if (data && data->ssl_version && *data->ssl_version) {
+ const char *ptr = data->ssl_version;
+ while(*ptr == ' ') ++ptr;
+ return strncasecmp(ptr, "GnuTLS", sizeof("GnuTLS")-1);
+ }
+ return 1;
+ }
+ ], [
+ AC_MSG_RESULT([yes])
+ AC_CHECK_HEADER([gcrypt.h], [
+ AC_DEFINE([PHP_HTTP_HAVE_GNUTLS], [1], [ ])
+ ])
+ ], [
+ AC_MSG_RESULT([no])
+ ], [
+ AC_MSG_RESULT([no])
+ ])
+ else
+ AC_MSG_RESULT([no])
+ fi
+
+ INCLUDES="$save_INCLUDES"
+ LIBS="$save_LIBS"
+ CFLAGS="$save_CFLAGS"
+ LDFLAGS="$save_LDFLAGS"
+
+ 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
+ if test -f "$i"; then
+ CURL_CAINFO="$i"
+ break
+ fi
+ done
+ if test "x$CURL_CAINFO" = "x"; then
+ AC_MSG_RESULT([not found])
+ else
+ AC_MSG_RESULT([$CURL_CAINFO])
+ AC_DEFINE_UNQUOTED([PHP_HTTP_CURL_CAINFO], ["$CURL_CAINFO"], [path to bundled SSL CA info])
+ fi
+
+ 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)
+ AC_DEFINE([PHP_HTTP_HAVE_CURL], [1], [Have cURL support])
+
+ dnl ----
+ dnl EVENT
+ dnl ----
+
+ if test "$PHP_HTTP_LIBEVENT_DIR" != "no"; then
+ HTTP_HAVE_PHP_EXT([event], [
+ AC_MSG_WARN([event support is incompatible with pecl/event; continuing without libevent support])
+ ], [
+ AC_MSG_CHECKING([for 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])
+ else
+ AC_MSG_RESULT([found in $EVENT_DIR])
+
+ AC_MSG_CHECKING([for libevent version, roughly])
+ EVENT_VER="1.1b or lower"
+ 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
+ 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
+
+PHP_ARG_WITH([http-shared-deps], [whether to depend on extensions which have been built shared],
+[ --without-http-shared-deps HTTP: do not depend on extensions like hash
+ and iconv (when they're built shared)], $PHP_HTTP, $PHP_HTTP)
+dnl ----
+dnl HASH
+dnl ----
+ HTTP_HAVE_PHP_EXT([hash], [
+ AC_MSG_CHECKING([for php_hash.h])
+ HTTP_EXT_HASH_INCDIR=
+ for i in `echo $INCLUDES | $SED -e's/-I//g'` $abs_srcdir ../hash; do
+ if test -d $i; then
+ if test -f $i/php_hash.h; then
+ HTTP_EXT_HASH_INCDIR=$i
+ break
+ elif test -f $i/ext/hash/php_hash.h; then
+ HTTP_EXT_HASH_INCDIR=$i/ext/hash
+ break
+ fi
+ fi
+ done
+ if test "x$HTTP_EXT_HASH_INCDIR" = "x"; then
+ AC_MSG_RESULT([not found])
+ else
+ AC_MSG_RESULT([$HTTP_EXT_HASH_INCDIR])
+ AC_DEFINE([PHP_HTTP_HAVE_PHP_HASH_H], [1], [Have ext/hash support])
+ PHP_ADD_INCLUDE([$HTTP_EXT_HASH_INCDIR])
+ fi
+ ])
+
+dnl ----
+dnl ICONV
+dnl ----
+ HTTP_HAVE_PHP_EXT([iconv])
+
+dnl ----
+dnl DONE
+dnl ----
+ PHP_HTTP_SOURCES="\
+ php_http.c \
+ php_http_buffer.c \
+ php_http_cookie.c \
+ php_http_encoding.c \
+ php_http_env.c \
+ php_http_etag.c \
+ php_http_exception.c \
+ php_http_filter.c \
+ php_http_headers.c \
+ php_http_header_parser.c \
+ php_http_info.c \
+ php_http_message_body.c \
+ php_http_message.c \
+ php_http_message_parser.c \
+ php_http_misc.c \
+ php_http_negotiate.c \
+ php_http_object.c \
+ php_http_params.c \
+ php_http_persistent_handle.c \
+ php_http_property_proxy.c \
+ php_http_querystring.c \
+ php_http_request.c \
+ php_http_request_datashare.c \
+ php_http_request_info.c \
+ php_http_request_method.c \
+ php_http_request_pool.c \
+ php_http_strlist.c \
+ php_http_url.c \
+ php_http_version.c \
+ "
+ PHP_NEW_EXTENSION([http], $PHP_HTTP_SOURCES, $ext_shared)
+
+ dnl shared extension deps
+ HTTP_SHARED_DEP([hash])
+ HTTP_SHARED_DEP([iconv])
+
+ PHP_SUBST([HTTP_SHARED_LIBADD])
+
+ PHP_HTTP_HEADERS="
+ php_http.h \
+ php_http_buffer.h \
+ php_http_cookie.h \
+ php_http_encoding.h \
+ php_http_env.h \
+ php_http_etag.h \
+ php_http_exception.h \
+ php_http_filter.h \
+ php_http_headers.h \
+ php_http_header_parser.h \
+ php_http_info.h \
+ php_http_message_body.h \
+ php_http_message.h \
+ php_http_message_parser.h \
+ php_http_misc.h \
+ php_http_negotiate.h \
+ php_http_object.h \
+ php_http_params.h \
+ php_http_persistent_handle.h \
+ php_http_property_proxy.h \
+ php_http_querystring.h \
+ php_http_request_datashare.h \
+ php_http_request.h \
+ php_http_request_method.h \
+ php_http_request_pool.h \
+ php_http_strlist.h \
+ php_http_url.h \
+ php_http_version.h \
+ "
+ ifdef([PHP_INSTALL_HEADERS], [
+ PHP_INSTALL_HEADERS(ext/http, $PHP_HTTP_HEADERS)
+ ], [
+ PHP_SUBST([PHP_HTTP_HEADERS])
+ PHP_ADD_MAKEFILE_FRAGMENT
+ ])
+
+ AC_DEFINE([HAVE_HTTP], [1], [Have extended HTTP support])
+fi
--- /dev/null
+/*
+ +--------------------------------------------------------------------+
+ | PECL :: http |
+ +--------------------------------------------------------------------+
+ | Redistribution and use in source and binary forms, with or without |
+ | modification, are permitted provided that the conditions mentioned |
+ | in the accompanying LICENSE file are met. |
+ +--------------------------------------------------------------------+
+ | Copyright (c) 2004-2010, Michael Wallner <mike@php.net> |
+ +--------------------------------------------------------------------+
+*/
+
+/* $Id: http.c 300300 2010-06-09 07:29:35Z mike $ */
+
+#include "php_http.h"
+
+#include <main/php_ini.h>
+#include <ext/standard/info.h>
+#include <Zend/zend_extensions.h>
+
+ZEND_DECLARE_MODULE_GLOBALS(php_http);
+
+#ifdef COMPILE_DL_HTTP
+ZEND_GET_MODULE(http)
+#endif
+
+zend_function_entry http_functions[] = {
+ EMPTY_FUNCTION_ENTRY
+};
+
+PHP_MINIT_FUNCTION(http);
+PHP_MSHUTDOWN_FUNCTION(http);
+PHP_RINIT_FUNCTION(http);
+PHP_RSHUTDOWN_FUNCTION(http);
+PHP_MINFO_FUNCTION(http);
+
+static zend_module_dep http_module_deps[] = {
+ ZEND_MOD_REQUIRED("spl")
+#ifdef PHP_HTTP_HAVE_HASH
+ ZEND_MOD_REQUIRED("hash")
+#endif
+#ifdef PHP_HTTP_HAVE_ICONV
+ ZEND_MOD_REQUIRED("iconv")
+#endif
+#ifdef PHP_HTTP_HAVE_EVENT
+ ZEND_MOD_CONFLICTS("event")
+#endif
+ {NULL, NULL, NULL, 0}
+};
+
+zend_module_entry http_module_entry = {
+ STANDARD_MODULE_HEADER_EX,
+ NULL,
+ http_module_deps,
+ "http",
+ http_functions,
+ PHP_MINIT(http),
+ PHP_MSHUTDOWN(http),
+ PHP_RINIT(http),
+ PHP_RSHUTDOWN(http),
+ PHP_MINFO(http),
+ PHP_HTTP_EXT_VERSION,
+ STANDARD_MODULE_PROPERTIES
+};
+
+int http_module_number;
+
+static void php_http_globals_init_once(zend_php_http_globals *G)
+{
+ memset(G, 0, sizeof(*G));
+}
+
+static inline void php_http_globals_init(zend_php_http_globals *G TSRMLS_DC)
+{
+}
+
+static inline void php_http_globals_free(zend_php_http_globals *G TSRMLS_DC)
+{
+}
+
+#if defined(ZTS) && defined(PHP_DEBUG)
+#if ZTS && PHP_DEBUG
+zend_http_globals *php_http_globals(void)
+{
+ TSRMLS_FETCH();
+ return PHP_HTTP_G;
+}
+#endif
+#endif
+PHP_INI_MH(http_update_persistent_handle_ident)
+{
+ PHP_HTTP_G->persistent_handle.ident.h = zend_hash_func(new_value, PHP_HTTP_G->persistent_handle.ident.l = new_value_length+1);
+ return OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
+}
+
+PHP_INI_BEGIN()
+ PHP_HTTP_INI_ENTRY("http.etag.mode", "md5", PHP_INI_ALL, OnUpdateString, env.etag_mode)
+ PHP_HTTP_INI_ENTRY("http.request_datashare.cookie", "0", PHP_INI_SYSTEM, OnUpdateBool, request_datashare.cookie)
+ PHP_HTTP_INI_ENTRY("http.request_datashare.dns", "1", PHP_INI_SYSTEM, OnUpdateBool, request_datashare.dns)
+ PHP_HTTP_INI_ENTRY("http.request_datashare.ssl", "0", PHP_INI_SYSTEM, OnUpdateBool, request_datashare.ssl)
+ PHP_HTTP_INI_ENTRY("http.request_datashare.connect", "0", PHP_INI_SYSTEM, OnUpdateBool, request_datashare.connect)
+ PHP_HTTP_INI_ENTRY("http.persistent_handle.limit", "-1", PHP_INI_SYSTEM, OnUpdateLong, persistent_handle.limit)
+ PHP_HTTP_INI_ENTRY("http.persistent_handle.ident", "GLOBAL", PHP_INI_ALL, http_update_persistent_handle_ident, persistent_handle.ident.s)
+PHP_INI_END()
+
+PHP_MINIT_FUNCTION(http)
+{
+ http_module_number = module_number;
+ ZEND_INIT_MODULE_GLOBALS(php_http, php_http_globals_init_once, NULL);
+ REGISTER_INI_ENTRIES();
+
+ if (0
+ || SUCCESS != PHP_MINIT_CALL(http_object)
+ || SUCCESS != PHP_MINIT_CALL(http_exception)
+ || SUCCESS != PHP_MINIT_CALL(http_cookie)
+ || SUCCESS != PHP_MINIT_CALL(http_encoding)
+ || SUCCESS != PHP_MINIT_CALL(http_filter)
+ || SUCCESS != PHP_MINIT_CALL(http_message)
+ || SUCCESS != PHP_MINIT_CALL(http_message_body)
+ || SUCCESS != PHP_MINIT_CALL(http_persistent_handle)
+ || SUCCESS != PHP_MINIT_CALL(http_property_proxy)
+ || SUCCESS != PHP_MINIT_CALL(http_querystring)
+ || SUCCESS != PHP_MINIT_CALL(http_request)
+ || SUCCESS != PHP_MINIT_CALL(http_request_datashare)
+ || SUCCESS != PHP_MINIT_CALL(http_request_method)
+ || SUCCESS != PHP_MINIT_CALL(http_request_pool)
+ || SUCCESS != PHP_MINIT_CALL(http_url)
+ || SUCCESS != PHP_MINIT_CALL(http_env)
+ ) {
+ return FAILURE;
+ }
+
+ return SUCCESS;
+}
+
+
+
+PHP_MSHUTDOWN_FUNCTION(http)
+{
+ UNREGISTER_INI_ENTRIES();
+
+ if (0
+ || SUCCESS != PHP_MSHUTDOWN_CALL(http_message)
+ || SUCCESS != PHP_MSHUTDOWN_CALL(http_request)
+ || SUCCESS != PHP_MSHUTDOWN_CALL(http_request_datashare)
+ || SUCCESS != PHP_MSHUTDOWN_CALL(http_persistent_handle)
+ ) {
+ return FAILURE;
+ }
+
+ return SUCCESS;
+}
+
+PHP_RINIT_FUNCTION(http)
+{
+ if (0
+ || SUCCESS != PHP_RINIT_CALL(http_env)
+ || SUCCESS != PHP_RINIT_CALL(http_request_datashare)
+ || SUCCESS != PHP_RINIT_CALL(http_request_pool)
+ ) {
+ return FAILURE;
+ }
+
+ return SUCCESS;
+}
+
+PHP_RSHUTDOWN_FUNCTION(http)
+{
+ if (0
+ || SUCCESS != PHP_RSHUTDOWN_CALL(http_env)
+ || SUCCESS != PHP_RSHUTDOWN_CALL(http_request_datashare)
+ ) {
+ return FAILURE;
+ }
+
+ return SUCCESS;
+}
+
+
+
+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_end();
+
+ php_info_print_table_start();
+ php_info_print_table_header(3, "Used Library", "Compiled", "Linked");
+ {
+#ifdef PHP_HTTP_HAVE_CURL
+ curl_version_info_data *cv = curl_version_info(CURLVERSION_NOW);
+ php_info_print_table_row(3, "libcurl", LIBCURL_VERSION, cv->version);
+#else
+ php_info_print_table_row(3, "libcurl", "disabled", "disabled");
+#endif
+#ifdef PHP_HTTP_HAVE_EVENT
+ php_info_print_table_row(3, "libevent", PHP_HTTP_EVENT_VERSION, event_get_version());
+#else
+ php_info_print_table_row(3, "libevent", "disabled", "disabled");
+#endif
+#ifdef PHP_HTTP_HAVE_ZLIB
+ php_info_print_table_row(3, "libz", ZLIB_VERSION, zlibVersion());
+#else
+ php_info_print_table_row(3, "libz", "disabled", "disabled");
+#endif
+ }
+ php_info_print_table_end();
+
+ php_info_print_table_start();
+ php_info_print_table_colspan_header(4, "Persistent Handles");
+ php_info_print_table_header(4, "Provider", "Ident", "Used", "Free");
+ {
+ HashTable *ht;
+ HashPosition pos1, pos2;
+ php_http_array_hashkey_t provider = php_http_array_hashkey_init(0), ident = php_http_array_hashkey_init(0);
+ zval **val, **sub, **zused, **zfree;
+
+ if ((ht = php_http_persistent_handle_statall(NULL TSRMLS_CC)) && zend_hash_num_elements(ht)) {
+ FOREACH_HASH_KEYVAL(pos1, ht, provider, val) {
+ if (zend_hash_num_elements(Z_ARRVAL_PP(val))) {
+ FOREACH_KEYVAL(pos2, *val, ident, sub) {
+ if ( SUCCESS == zend_hash_find(Z_ARRVAL_PP(sub), ZEND_STRS("used"), (void *) &zused) &&
+ SUCCESS == zend_hash_find(Z_ARRVAL_PP(sub), ZEND_STRS("free"), (void *) &zfree)) {
+ zval *used = php_http_zsep(IS_STRING, *zused);
+ zval *free = php_http_zsep(IS_STRING, *zfree);
+ php_info_print_table_row(4, provider.str, ident.str, Z_STRVAL_P(used), Z_STRVAL_P(free));
+ zval_ptr_dtor(&used);
+ zval_ptr_dtor(&free);
+ } else {
+ php_info_print_table_row(4, provider.str, ident.str, "0", "0");
+ }
+ }
+ } else {
+ php_info_print_table_row(4, provider.str, "N/A", "0", "0");
+ }
+ }
+ } else {
+ php_info_print_table_row(4, "N/A", "N/A", "0", "0");
+ }
+ if (ht) {
+ zend_hash_destroy(ht);
+ FREE_HASHTABLE(ht);
+ }
+ }
+ php_info_print_table_end();
+
+ DISPLAY_INI_ENTRIES();
+}
+
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
+
--- /dev/null
+/*
+ +--------------------------------------------------------------------+
+ | PECL :: http |
+ +--------------------------------------------------------------------+
+ | Redistribution and use in source and binary forms, with or without |
+ | modification, are permitted provided that the conditions mentioned |
+ | in the accompanying LICENSE file are met. |
+ +--------------------------------------------------------------------+
+ | Copyright (c) 2004-2010, Michael Wallner <mike@php.net> |
+ +--------------------------------------------------------------------+
+*/
+
+/* $Id: php_http.h 300300 2010-06-09 07:29:35Z mike $ */
+
+#ifndef PHP_EXT_HTTP_H
+#define PHP_EXT_HTTP_H
+
+#define PHP_HTTP_EXT_VERSION "2.0.0dev"
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#else
+# ifndef PHP_WIN32
+# include "php_config.h"
+# endif
+#endif
+
+#include "php.h"
+#if defined(PHP_WIN32)
+# if defined(PHP_HTTP_EXPORTS)
+# define PHP_HTTP_API __declspec(dllexport)
+# elif defined(COMPILE_DL_HTTP)
+# define PHP_HTTP_API __declspec(dllimport)
+# else
+# define PHP_HTTP_API
+# endif
+#else
+# define PHP_HTTP_API
+#endif
+
+#include <main/SAPI.h>
+#include <main/fopen_wrappers.h>
+#include <main/php_streams.h>
+#include <main/php_variables.h>
+#include <Zend/zend_exceptions.h>
+#include <Zend/zend_interfaces.h>
+#include <ext/date/php_date.h>
+#include <ext/spl/spl_array.h>
+#include <ext/spl/spl_iterators.h>
+#include <ext/standard/php_lcg.h>
+#include <ext/standard/php_string.h>
+#include <ext/standard/url.h>
+
+/* make functions that return SUCCESS|FAILURE more obvious */
+typedef int STATUS;
+
+#include "php_http_buffer.h"
+#include "php_http_strlist.h"
+
+#if (defined(HAVE_ICONV) || defined(PHP_HTTP_HAVE_EXT_ICONV)) && (PHP_HTTP_SHARED_DEPS || !defined(COMPILE_DL_ICONV))
+# define PHP_HTTP_HAVE_ICONV
+# undef PHP_ATOM_INC
+# include <ext/iconv/php_iconv.h>
+#endif
+
+#if (defined(HAVE_HASH_EXT) || defined(PHP_HTTP_HAVE_EXT_HASH)) && (PHP_HTTP_SHARED_DEPS || !defined(COMPILE_DL_HASH)) && defined(PHP_HTTP_HAVE_PHP_HASH_H)
+# define PHP_HTTP_HAVE_HASH
+# include "php_hash.h"
+#endif
+
+#ifdef PHP_WIN32
+# define CURL_STATICLIB
+# define PHP_HTTP_HAVE_NETDB
+# include <winsock2.h>
+#elif defined(HAVE_NETDB_H)
+# define PHP_HTTP_HAVE_NETDB
+# include <netdb.h>
+# ifdef HAVE_UNISTD_H
+# include <unistd.h>
+# endif
+#endif
+
+#ifdef PHP_HTTP_HAVE_EVENT
+# include <event.h>
+#endif
+
+#include <curl/curl.h>
+#define PHP_HTTP_CURL_VERSION(x, y, z) (LIBCURL_VERSION_NUM >= (((x)<<16) + ((y)<<8) + (z)))
+
+#if defined(ZTS) && defined(PHP_HTTP_HAVE_SSL)
+# ifdef PHP_WIN32
+# define PHP_HTTP_NEED_OPENSSL_TSL
+# include <openssl/crypto.h>
+# else /* !PHP_WIN32 */
+# if defined(PHP_HTTP_HAVE_OPENSSL)
+# define PHP_HTTP_NEED_OPENSSL_TSL
+# include <openssl/crypto.h>
+# elif defined(PHP_HTTP_HAVE_GNUTLS)
+# define PHP_HTTP_NEED_GNUTLS_TSL
+# include <gcrypt.h>
+# else
+# warning \
+ "libcurl was compiled with SSL support, but configure could not determine which" \
+ "library was used; thus no SSL crypto locking callbacks will be set, which may " \
+ "cause random crashes on SSL requests"
+# endif /* PHP_HTTP_HAVE_OPENSSL || PHP_HTTP_HAVE_GNUTLS */
+# endif /* PHP_WIN32 */
+#endif /* ZTS && PHP_HTTP_HAVE_SSL */
+
+#include <zlib.h>
+#include <ctype.h>
+#define PHP_HTTP_IS_CTYPE(type, c) is##type((int) (unsigned char) (c))
+#define PHP_HTTP_TO_CTYPE(type, c) to##type((int) (unsigned char) (c))
+
+extern zend_module_entry http_module_entry;
+#define phpext_http_ptr &http_module_entry
+
+extern int http_module_number;
+
+#include "php_http_misc.h"
+
+#include "php_http_cookie.h"
+#include "php_http_encoding.h"
+#include "php_http_env.h"
+#include "php_http_etag.h"
+#include "php_http_exception.h"
+#include "php_http_filter.h"
+#include "php_http_headers.h"
+#include "php_http_info.h"
+#include "php_http_header_parser.h"
+#include "php_http_message_body.h"
+#include "php_http_message.h"
+#include "php_http_message_parser.h"
+#include "php_http_negotiate.h"
+#include "php_http_object.h"
+#include "php_http_params.h"
+#include "php_http_persistent_handle.h"
+#include "php_http_property_proxy.h"
+#include "php_http_querystring.h"
+#include "php_http_request_datashare.h"
+#include "php_http_request.h"
+#include "php_http_request_method.h"
+#include "php_http_request_pool.h"
+#include "php_http_url.h"
+#include "php_http_version.h"
+
+ZEND_BEGIN_MODULE_GLOBALS(php_http)
+ struct php_http_env_globals env;
+ struct php_http_persistent_handle_globals persistent_handle;
+ struct php_http_request_datashare_globals request_datashare;
+ struct php_http_request_pool_globals request_pool;
+ZEND_END_MODULE_GLOBALS(php_http)
+
+ZEND_EXTERN_MODULE_GLOBALS(php_http);
+
+#ifdef ZTS
+# include "TSRM/TSRM.h"
+# define PHP_HTTP_G ((zend_http_globals *) (*((void ***) tsrm_ls))[TSRM_UNSHUFFLE_RSRC_ID(php_http_globals_id)])
+#else
+# define PHP_HTTP_G (&php_http_globals)
+#endif
+
+
+#endif /* PHP_EXT_HTTP_H */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
+
--- /dev/null
+
+/* $Id: php_http_buffer.c 211942 2006-04-24 17:17:09Z mike $ */
+
+#include "php.h"
+#include "php_http_buffer.h"
+
+PHP_HTTP_BUFFER_API php_http_buffer *php_http_buffer_init_ex(php_http_buffer *buf, size_t chunk_size, int flags)
+{
+ if (!buf) {
+ buf = pemalloc(sizeof(php_http_buffer), flags & PHP_HTTP_BUFFER_INIT_PERSISTENT);
+ }
+
+ if (buf) {
+ buf->size = (chunk_size) ? chunk_size : PHP_HTTP_BUFFER_DEFAULT_SIZE;
+ buf->pmem = (flags & PHP_HTTP_BUFFER_INIT_PERSISTENT) ? 1 : 0;
+ buf->data = (flags & PHP_HTTP_BUFFER_INIT_PREALLOC) ? pemalloc(buf->size, buf->pmem) : NULL;
+ buf->free = (flags & PHP_HTTP_BUFFER_INIT_PREALLOC) ? buf->size : 0;
+ buf->used = 0;
+ }
+
+ return buf;
+}
+
+PHP_HTTP_BUFFER_API php_http_buffer *php_http_buffer_from_string_ex(php_http_buffer *buf, const char *string, size_t length)
+{
+ if ((buf = php_http_buffer_init(buf))) {
+ if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_append(buf, string, length)) {
+ pefree(buf, buf->pmem);
+ buf = NULL;
+ }
+ }
+ return buf;
+}
+
+PHP_HTTP_BUFFER_API size_t php_http_buffer_resize_ex(php_http_buffer *buf, size_t len, size_t override_size, int allow_error)
+{
+ char *ptr = NULL;
+#if 0
+ fprintf(stderr, "RESIZE: size=%lu, used=%lu, free=%lu\n", buf->size, buf->used, buf->free);
+#endif
+ if (buf->free < len) {
+ size_t size = override_size ? override_size : buf->size;
+
+ while ((size + buf->free) < len) {
+ size <<= 1;
+ }
+
+ if (allow_error) {
+ ptr = perealloc_recoverable(buf->data, buf->used + buf->free + size, buf->pmem);
+ } else {
+ ptr = perealloc(buf->data, buf->used + buf->free + size, buf->pmem);
+ }
+
+ if (ptr) {
+ buf->data = ptr;
+ } else {
+ return PHP_HTTP_BUFFER_NOMEM;
+ }
+
+ buf->free += size;
+ return size;
+ }
+ return 0;
+}
+
+PHP_HTTP_BUFFER_API size_t php_http_buffer_shrink(php_http_buffer *buf)
+{
+ /* avoid another realloc on fixation */
+ if (buf->free > 1) {
+ char *ptr = perealloc(buf->data, buf->used + 1, buf->pmem);
+
+ if (ptr) {
+ buf->data = ptr;
+ } else {
+ return PHP_HTTP_BUFFER_NOMEM;
+ }
+ buf->free = 1;
+ }
+ return buf->used;
+}
+
+PHP_HTTP_BUFFER_API size_t php_http_buffer_append(php_http_buffer *buf, const char *append, size_t append_len)
+{
+ if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_resize(buf, append_len)) {
+ return PHP_HTTP_BUFFER_NOMEM;
+ }
+ memcpy(buf->data + buf->used, append, append_len);
+ buf->used += append_len;
+ buf->free -= append_len;
+ return append_len;
+}
+
+PHP_HTTP_BUFFER_API size_t php_http_buffer_appendf(php_http_buffer *buf, const char *format, ...)
+{
+ va_list argv;
+ char *append;
+ size_t append_len, alloc;
+
+ va_start(argv, format);
+ append_len = vspprintf(&append, 0, format, argv);
+ va_end(argv);
+
+ alloc = php_http_buffer_append(buf, append, append_len);
+ efree(append);
+
+ if (PHP_HTTP_BUFFER_NOMEM == alloc) {
+ return PHP_HTTP_BUFFER_NOMEM;
+ }
+ return append_len;
+}
+
+PHP_HTTP_BUFFER_API size_t php_http_buffer_insert(php_http_buffer *buf, const char *insert, size_t insert_len, size_t offset)
+{
+ if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_resize(buf, insert_len)) {
+ return PHP_HTTP_BUFFER_NOMEM;
+ }
+ memmove(buf->data + offset + insert_len, buf->data + offset, insert_len);
+ memcpy(buf->data + offset, insert, insert_len);
+ buf->used += insert_len;
+ buf->free -= insert_len;
+ return insert_len;
+}
+
+PHP_HTTP_BUFFER_API size_t php_http_buffer_insertf(php_http_buffer *buf, size_t offset, const char *format, ...)
+{
+ va_list argv;
+ char *insert;
+ size_t insert_len, alloc;
+
+ va_start(argv, format);
+ insert_len = vspprintf(&insert, 0, format, argv);
+ va_end(argv);
+
+ alloc = php_http_buffer_insert(buf, insert, insert_len, offset);
+ efree(insert);
+
+ if (PHP_HTTP_BUFFER_NOMEM == alloc) {
+ return PHP_HTTP_BUFFER_NOMEM;
+ }
+ return insert_len;
+}
+
+PHP_HTTP_BUFFER_API size_t php_http_buffer_prepend(php_http_buffer *buf, const char *prepend, size_t prepend_len)
+{
+ if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_resize(buf, prepend_len)) {
+ return PHP_HTTP_BUFFER_NOMEM;
+ }
+ memmove(buf->data + prepend_len, buf->data, buf->used);
+ memcpy(buf->data, prepend, prepend_len);
+ buf->used += prepend_len;
+ buf->free -= prepend_len;
+ return prepend_len;
+}
+
+PHP_HTTP_BUFFER_API size_t php_http_buffer_prependf(php_http_buffer *buf, const char *format, ...)
+{
+ va_list argv;
+ char *prepend;
+ size_t prepend_len, alloc;
+
+ va_start(argv, format);
+ prepend_len = vspprintf(&prepend, 0, format, argv);
+ va_end(argv);
+
+ alloc = php_http_buffer_prepend(buf, prepend, prepend_len);
+ efree(prepend);
+
+ if (PHP_HTTP_BUFFER_NOMEM == alloc) {
+ return PHP_HTTP_BUFFER_NOMEM;
+ }
+ return prepend_len;
+}
+
+PHP_HTTP_BUFFER_API char *php_http_buffer_data(const php_http_buffer *buf, char **into, size_t *len)
+{
+ char *copy = ecalloc(1, buf->used + 1);
+ memcpy(copy, buf->data, buf->used);
+ if (into) {
+ *into = copy;
+ }
+ if (len) {
+ *len = buf->used;
+ }
+ return copy;
+}
+
+PHP_HTTP_BUFFER_API php_http_buffer *php_http_buffer_dup(const php_http_buffer *buf)
+{
+ php_http_buffer *dup = php_http_buffer_clone(buf);
+ if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_append(dup, buf->data, buf->used)) {
+ php_http_buffer_free(&dup);
+ }
+ return dup;
+}
+
+PHP_HTTP_BUFFER_API size_t php_http_buffer_cut(php_http_buffer *buf, size_t offset, size_t length)
+{
+ if (offset > buf->used) {
+ return 0;
+ }
+ if (offset + length > buf->used) {
+ length = buf->used - offset;
+ }
+ memmove(buf->data + offset, buf->data + offset + length, buf->used - length - offset);
+ buf->used -= length;
+ buf->free += length;
+ return length;
+}
+
+PHP_HTTP_BUFFER_API php_http_buffer *php_http_buffer_sub(const php_http_buffer *buf, size_t offset, size_t length)
+{
+ if (offset >= buf->used) {
+ return NULL;
+ } else {
+ size_t need = 1 + ((length + offset) > buf->used ? (buf->used - offset) : (length - offset));
+ php_http_buffer *sub = php_http_buffer_init_ex(NULL, need, PHP_HTTP_BUFFER_INIT_PREALLOC | (buf->pmem ? PHP_HTTP_BUFFER_INIT_PERSISTENT:0));
+ if (sub) {
+ if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_append(sub, buf->data + offset, need)) {
+ php_http_buffer_free(&sub);
+ } else {
+ sub->size = buf->size;
+ }
+ }
+ return sub;
+ }
+}
+
+PHP_HTTP_BUFFER_API php_http_buffer *php_http_buffer_right(const php_http_buffer *buf, size_t length)
+{
+ if (length < buf->used) {
+ return php_http_buffer_sub(buf, buf->used - length, length);
+ } else {
+ return php_http_buffer_sub(buf, 0, buf->used);
+ }
+}
+
+
+PHP_HTTP_BUFFER_API php_http_buffer *php_http_buffer_merge_va(php_http_buffer *buf, unsigned argc, va_list argv)
+{
+ unsigned i = 0;
+ buf = php_http_buffer_init(buf);
+
+ if (buf) {
+ while (argc > i++) {
+ php_http_buffer_free_t f = va_arg(argv, php_http_buffer_free_t);
+ php_http_buffer *current = va_arg(argv, php_http_buffer *);
+ php_http_buffer_append(buf, current->data, current->used);
+ FREE_PHP_HTTP_BUFFER(f, current);
+ }
+ }
+
+ return buf;
+}
+
+PHP_HTTP_BUFFER_API php_http_buffer *php_http_buffer_merge_ex(php_http_buffer *buf, unsigned argc, ...)
+{
+ va_list argv;
+ php_http_buffer *ret;
+
+ va_start(argv, argc);
+ ret = php_http_buffer_merge_va(buf, argc, argv);
+ va_end(argv);
+ return ret;
+}
+
+PHP_HTTP_BUFFER_API php_http_buffer *php_http_buffer_merge(unsigned argc, ...)
+{
+ va_list argv;
+ php_http_buffer *ret;
+
+ va_start(argv, argc);
+ ret = php_http_buffer_merge_va(NULL, argc, argv);
+ va_end(argv);
+ return ret;
+}
+
+PHP_HTTP_BUFFER_API php_http_buffer *php_http_buffer_fix(php_http_buffer *buf)
+{
+ if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_resize_ex(buf, 1, 1, 0)) {
+ return NULL;
+ }
+ buf->data[buf->used] = '\0';
+ return buf;
+}
+
+PHP_HTTP_BUFFER_API int php_http_buffer_cmp(php_http_buffer *left, php_http_buffer *right)
+{
+ if (left->used > right->used) {
+ return -1;
+ } else if (right->used > left->used) {
+ return 1;
+ } else {
+ return memcmp(left->data, right->data, left->used);
+ }
+}
+
+PHP_HTTP_BUFFER_API void php_http_buffer_reset(php_http_buffer *buf)
+{
+ buf->free += buf->used;
+ buf->used = 0;
+}
+
+PHP_HTTP_BUFFER_API void php_http_buffer_dtor(php_http_buffer *buf)
+{
+ if (buf->data) {
+ pefree(buf->data, buf->pmem);
+ buf->data = NULL;
+ }
+ buf->used = 0;
+ buf->free = 0;
+}
+
+PHP_HTTP_BUFFER_API void php_http_buffer_free(php_http_buffer **buf)
+{
+ if (*buf) {
+ php_http_buffer_dtor(*buf);
+ pefree(*buf, (*buf)->pmem);
+ *buf = NULL;
+ }
+}
+
+PHP_HTTP_BUFFER_API size_t php_http_buffer_chunk_buffer(php_http_buffer **s, const char *data, size_t data_len, char **chunk, size_t chunk_size)
+{
+ php_http_buffer *storage;
+
+ *chunk = NULL;
+
+ if (!*s) {
+ *s = php_http_buffer_init_ex(NULL, chunk_size << 1, chunk_size ? PHP_HTTP_BUFFER_INIT_PREALLOC : 0);
+ }
+ storage = *s;
+
+ if (data_len) {
+ php_http_buffer_append(storage, data, data_len);
+ }
+
+ if (!chunk_size) {
+ php_http_buffer_data(storage, chunk, &chunk_size);
+ php_http_buffer_free(s);
+ return chunk_size;
+ }
+
+ if (storage->used >= (chunk_size = storage->size >> 1)) {
+ *chunk = estrndup(storage->data, chunk_size);
+ php_http_buffer_cut(storage, 0, chunk_size);
+ return chunk_size;
+ }
+
+ return 0;
+}
+
+PHP_HTTP_BUFFER_API void php_http_buffer_chunked_output(php_http_buffer **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;
+
+ while ((got = php_http_buffer_chunk_buffer(s, data, data_len, &chunk, chunk_len))) {
+ passout(opaque, chunk, got TSRMLS_CC);
+ if (!chunk_len) {
+ /* we already got the last chunk,
+ and freed all resources */
+ break;
+ }
+ data = NULL;
+ data_len = 0;
+ STR_SET(chunk, NULL);
+ }
+ STR_FREE(chunk);
+}
+
+PHP_HTTP_BUFFER_API ssize_t php_http_buffer_passthru(php_http_buffer *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)
+{
+ size_t passed_on = 0, passed_in = php_http_buffer_chunked_input(&s, chunk_size, passin, passin_arg TSRMLS_CC);
+
+ if (passed_in == PHP_HTTP_BUFFER_PASS0) {
+ return passed_in;
+ }
+ if (passed_in) {
+ passed_on = passon(passon_arg, s->data, passed_in TSRMLS_CC);
+
+ if (passed_on == PHP_HTTP_BUFFER_PASS0) {
+ return passed_on;
+ }
+
+ if (passed_on) {
+ php_http_buffer_cut(s, 0, passed_on);
+ }
+ }
+
+ return passed_on - passed_in;
+}
+
+PHP_HTTP_BUFFER_API size_t php_http_buffer_chunked_input(php_http_buffer **s, size_t chunk_size, php_http_buffer_pass_func_t passin, void *opaque TSRMLS_DC)
+{
+ php_http_buffer *str;
+ size_t passed;
+
+ if (!*s) {
+ *s = php_http_buffer_init_ex(NULL, chunk_size, chunk_size ? PHP_HTTP_BUFFER_INIT_PREALLOC : 0);
+ }
+ str = *s;
+
+ php_http_buffer_resize(str, chunk_size);
+ passed = passin(opaque, str->data + str->used, chunk_size TSRMLS_CC);
+
+ if (passed != PHP_HTTP_BUFFER_PASS0) {
+ str->used += passed;
+ str->free -= passed;
+ }
+
+ php_http_buffer_fix(str);
+
+ return passed;
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */
+
--- /dev/null
+
+/* $Id: php_http_buffer.h 229282 2007-02-07 15:31:50Z mike $ */
+
+#ifndef _PHP_HTTP_BUFFER_H
+#define _PHP_HTTP_BUFFER_H
+
+#ifndef PHP_HTTP_BUFFER_DEFAULT_SIZE
+# define PHP_HTTP_BUFFER_DEFAULT_SIZE 256
+#endif
+
+#define PHP_HTTP_BUFFER_ERROR ((size_t) -1)
+#define PHP_HTTP_BUFFER_NOMEM PHP_HTTP_BUFFER_ERROR
+#define PHP_HTTP_BUFFER_PASS0 PHP_HTTP_BUFFER_ERROR
+
+#ifndef STR_FREE
+# define STR_FREE(STR) \
+ { \
+ if (STR) { \
+ efree(STR); \
+ } \
+ }
+#endif
+#ifndef STR_SET
+# define STR_SET(STR, SET) \
+ { \
+ STR_FREE(STR); \
+ STR = SET; \
+ }
+#endif
+#ifndef TSRMLS_D
+# define TSRMLS_D
+# define TSRMLS_DC
+# define TSRMLS_CC
+# define TSRMLS_C
+#endif
+#ifdef PHP_ATTRIBUTE_FORMAT
+# define PHP_HTTP_BUFFER_ATTRIBUTE_FORMAT(f, a, b) PHP_ATTRIBUTE_FORMAT(f, a, b)
+#else
+# define PHP_HTTP_BUFFER_ATTRIBUTE_FORMAT(f, a, b)
+#endif
+#ifndef pemalloc
+# define pemalloc(s,p) malloc(s)
+# define pefree(x,p) free(x)
+# define perealloc(x,s,p) realloc(x,s)
+# define perealloc_recoverable perealloc
+# define ecalloc calloc
+static inline void *estrndup(void *p, size_t s)
+{
+ char *r = (char *) malloc(s+1);
+ if (r) memcpy((void *) r, p, s), r[s] = '\0';
+ return (void *) r;
+}
+#endif
+
+#if defined(PHP_WIN32)
+# if defined(PHP_HTTP_BUFFER_EXPORTS)
+# define PHP_HTTP_BUFFER_API __declspec(dllexport)
+# elif defined(COMPILE_DL_PHP_HTTP_BUFFER)
+# define PHP_HTTP_BUFFER_API __declspec(dllimport)
+# else
+# define PHP_HTTP_BUFFER_API
+# endif
+#else
+# define PHP_HTTP_BUFFER_API
+#endif
+
+#define PHP_HTTP_BUFFER(p) ((php_http_buffer *) (p))
+#define PHP_HTTP_BUFFER_VAL(p) (PHP_HTTP_BUFFER(p))->data
+#define PHP_HTTP_BUFFER_LEN(p) (PHP_HTTP_BUFFER(p))->used
+
+#define FREE_PHP_HTTP_BUFFER_PTR(STR) pefree(STR, STR->pmem)
+#define FREE_PHP_HTTP_BUFFER_VAL(STR) php_http_buffer_dtor(STR)
+#define FREE_PHP_HTTP_BUFFER_ALL(STR) php_http_buffer_free(&(STR))
+#define FREE_PHP_HTTP_BUFFER(free, STR) \
+ switch (free) \
+ { \
+ case PHP_HTTP_BUFFER_FREE_NOT: break; \
+ case PHP_HTTP_BUFFER_FREE_PTR: pefree(STR, STR->pmem); break; \
+ case PHP_HTTP_BUFFER_FREE_VAL: php_http_buffer_dtor(STR); break; \
+ case PHP_HTTP_BUFFER_FREE_ALL: \
+ { \
+ php_http_buffer *PTR = (STR); \
+ php_http_buffer_free(&PTR); \
+ } \
+ break; \
+ default: break; \
+ }
+
+#define RETURN_PHP_HTTP_BUFFER_PTR(STR) RETURN_PHP_HTTP_BUFFER((STR), PHP_HTTP_BUFFER_FREE_PTR, 0)
+#define RETURN_PHP_HTTP_BUFFER_VAL(STR) RETURN_PHP_HTTP_BUFFER((STR), PHP_HTTP_BUFFER_FREE_NOT, 0)
+#define RETURN_PHP_HTTP_BUFFER_DUP(STR) RETURN_PHP_HTTP_BUFFER((STR), PHP_HTTP_BUFFER_FREE_NOT, 1)
+#define RETVAL_PHP_HTTP_BUFFER_PTR(STR) RETVAL_PHP_HTTP_BUFFER((STR), PHP_HTTP_BUFFER_FREE_PTR, 0)
+#define RETVAL_PHP_HTTP_BUFFER_VAL(STR) RETVAL_PHP_HTTP_BUFFER((STR), PHP_HTTP_BUFFER_FREE_NOT, 0)
+#define RETVAL_PHP_HTTP_BUFFER_DUP(STR) RETVAL_PHP_HTTP_BUFFER((STR), PHP_HTTP_BUFFER_FREE_NOT, 1)
+/* RETURN_PHP_HTTP_BUFFER(buf, PHP_HTTP_BUFFER_FREE_PTR, 0) */
+#define RETURN_PHP_HTTP_BUFFER(STR, free, dup) \
+ RETVAL_PHP_HTTP_BUFFER((STR), (free), (dup)); \
+ return;
+
+#define RETVAL_PHP_HTTP_BUFFER(STR, free, dup) \
+ php_http_buffer_fix(STR); \
+ RETVAL_STRINGL((STR)->data, (STR)->used, (dup)); \
+ FREE_PHP_HTTP_BUFFER((free), (STR));
+
+typedef struct _php_http_buffer_t {
+ char *data;
+ size_t used;
+ size_t free;
+ size_t size;
+ unsigned pmem:1;
+ unsigned reserved:31;
+} php_http_buffer;
+
+typedef enum _php_http_buffer_free_t {
+ PHP_HTTP_BUFFER_FREE_NOT = 0,
+ PHP_HTTP_BUFFER_FREE_PTR, /* pefree() */
+ PHP_HTTP_BUFFER_FREE_VAL, /* php_http_buffer_dtor() */
+ PHP_HTTP_BUFFER_FREE_ALL /* php_http_buffer_free() */
+} php_http_buffer_free_t;
+
+#define PHP_HTTP_BUFFER_ALL_FREE(STR) PHP_HTTP_BUFFER_FREE_ALL,(STR)
+#define PHP_HTTP_BUFFER_PTR_FREE(STR) PHP_HTTP_BUFFER_FREE_PTR,(STR)
+#define PHP_HTTP_BUFFER_VAL_FREE(STR) PHP_HTTP_BUFFER_FREE_VAL,(STR)
+#define PHP_HTTP_BUFFER_NOT_FREE(STR) PHP_HTTP_BUFFER_FREE_NOT,(STR)
+
+#define PHP_HTTP_BUFFER_INIT_PREALLOC 0x01
+#define PHP_HTTP_BUFFER_INIT_PERSISTENT 0x02
+
+/* create a new php_http_buffer */
+#define php_http_buffer_new() php_http_buffer_init(NULL)
+#define php_http_buffer_init(b) php_http_buffer_init_ex(b, PHP_HTTP_BUFFER_DEFAULT_SIZE, 0)
+#define php_http_buffer_clone(php_http_buffer_pointer) php_http_buffer_init_ex(NULL, (php_http_buffer_pointer)->size, (php_http_buffer_pointer)->pmem ? PHP_HTTP_BUFFER_INIT_PERSISTENT:0)
+PHP_HTTP_BUFFER_API php_http_buffer *php_http_buffer_init_ex(php_http_buffer *buf, size_t chunk_size, int flags);
+
+/* create a php_http_buffer from a zval or c-string */
+#define php_http_buffer_from_zval(z) php_http_buffer_from_string(Z_STRVAL(z), Z_STRLEN(z))
+#define php_http_buffer_from_zval_ex(b, z) php_http_buffer_from_string_ex(b, Z_STRVAL(z), Z_STRLEN(z))
+#define php_http_buffer_from_string(s, l) php_http_buffer_from_string_ex(NULL, (s), (l))
+PHP_HTTP_BUFFER_API php_http_buffer *php_http_buffer_from_string_ex(php_http_buffer *buf, const char *string, size_t length);
+
+/* usually only called from within the internal functions */
+#define php_http_buffer_resize(b, s) php_http_buffer_resize_ex((b), (s), 0, 0)
+PHP_HTTP_BUFFER_API size_t php_http_buffer_resize_ex(php_http_buffer *buf, size_t len, size_t override_size, int allow_error);
+
+/* shrink memory chunk to actually used size (+1) */
+PHP_HTTP_BUFFER_API size_t php_http_buffer_shrink(php_http_buffer *buf);
+
+/* append data to the php_http_buffer */
+#define php_http_buffer_appends(b, a) php_http_buffer_append((b), (a), sizeof(a)-1)
+#define php_http_buffer_appendl(b, a) php_http_buffer_append((b), (a), strlen(a))
+PHP_HTTP_BUFFER_API size_t php_http_buffer_append(php_http_buffer *buf, const char *append, size_t append_len);
+PHP_HTTP_BUFFER_API size_t php_http_buffer_appendf(php_http_buffer *buf, const char *format, ...) PHP_HTTP_BUFFER_ATTRIBUTE_FORMAT(printf, 2, 3);
+
+/* insert data at a specific position of the php_http_buffer */
+#define php_http_buffer_inserts(b, i, o) php_http_buffer_insert((b), (i), sizeof(i)-1, (o))
+#define php_http_buffer_insertl(b, i, o) php_http_buffer_insert((b), (i), strlen(i), (o))
+PHP_HTTP_BUFFER_API size_t php_http_buffer_insert(php_http_buffer *buf, const char *insert, size_t insert_len, size_t offset);
+PHP_HTTP_BUFFER_API size_t php_http_buffer_insertf(php_http_buffer *buf, size_t offset, const char *format, ...) PHP_HTTP_BUFFER_ATTRIBUTE_FORMAT(printf, 3, 4);
+
+/* prepend data */
+#define php_http_buffer_prepends(b, p) php_http_buffer_prepend((b), (p), sizeof(p)-1)
+#define php_http_buffer_prependl(b, p) php_http_buffer_prepend((b), (p), strlen(p))
+PHP_HTTP_BUFFER_API size_t php_http_buffer_prepend(php_http_buffer *buf, const char *prepend, size_t prepend_len);
+PHP_HTTP_BUFFER_API size_t php_http_buffer_prependf(php_http_buffer *buf, const char *format, ...) PHP_HTTP_BUFFER_ATTRIBUTE_FORMAT(printf, 2, 3);
+
+/* get a zero-terminated string */
+PHP_HTTP_BUFFER_API char *php_http_buffer_data(const php_http_buffer *buf, char **into, size_t *len);
+
+/* get a part of the php_http_buffer */
+#define php_http_buffer_mid(b, o, l) php_http_buffer_sub((b), (o), (l))
+#define php_http_buffer_left(b, l) php_http_buffer_sub((b), 0, (l))
+PHP_HTTP_BUFFER_API php_http_buffer *php_http_buffer_right(const php_http_buffer *buf, size_t length);
+PHP_HTTP_BUFFER_API php_http_buffer *php_http_buffer_sub(const php_http_buffer *buf, size_t offset, size_t len);
+
+/* remove a substring */
+PHP_HTTP_BUFFER_API size_t php_http_buffer_cut(php_http_buffer *buf, size_t offset, size_t length);
+
+/* get a complete php_http_buffer duplicate */
+PHP_HTTP_BUFFER_API php_http_buffer *php_http_buffer_dup(const php_http_buffer *buf);
+
+/* merge several php_http_buffer objects
+ use like:
+
+ php_http_buffer *final = php_http_buffer_merge(3,
+ PHP_HTTP_BUFFER_NOT_FREE(&keep),
+ PHP_HTTP_BUFFER_ALL_FREE(middle_ptr),
+ PHP_HTTP_BUFFER_VAL_FREE(&local);
+*/
+PHP_HTTP_BUFFER_API php_http_buffer *php_http_buffer_merge(unsigned argc, ...);
+PHP_HTTP_BUFFER_API php_http_buffer *php_http_buffer_merge_ex(php_http_buffer *buf, unsigned argc, ...);
+PHP_HTTP_BUFFER_API php_http_buffer *php_http_buffer_merge_va(php_http_buffer *buf, unsigned argc, va_list argv);
+
+/* sets a trailing NUL byte */
+PHP_HTTP_BUFFER_API php_http_buffer *php_http_buffer_fix(php_http_buffer *buf);
+
+/* memcmp for php_http_buffer objects */
+PHP_HTTP_BUFFER_API int php_http_buffer_cmp(php_http_buffer *left, php_http_buffer *right);
+
+/* reset php_http_buffer object */
+PHP_HTTP_BUFFER_API void php_http_buffer_reset(php_http_buffer *buf);
+
+/* free a php_http_buffer objects contents */
+PHP_HTTP_BUFFER_API void php_http_buffer_dtor(php_http_buffer *buf);
+
+/* free a php_http_buffer object completely */
+PHP_HTTP_BUFFER_API void php_http_buffer_free(php_http_buffer **buf);
+
+/* stores data in a php_http_buffer until it reaches chunk_size */
+PHP_HTTP_BUFFER_API size_t php_http_buffer_chunk_buffer(php_http_buffer **s, const char *data, size_t data_len, char **chunk, size_t chunk_size);
+
+typedef size_t (*php_http_buffer_pass_func_t)(void *opaque, const char *, size_t 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 **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 buffer */
+PHP_HTTP_BUFFER_API size_t php_http_buffer_chunked_input(php_http_buffer **s, size_t chunk_size, php_http_buffer_pass_func_t passin, void *opaque TSRMLS_DC);
+
+#endif
+
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */
--- /dev/null
+/*
+ +--------------------------------------------------------------------+
+ | PECL :: http |
+ +--------------------------------------------------------------------+
+ | Redistribution and use in source and binary forms, with or without |
+ | modification, are permitted provided that the conditions mentioned |
+ | in the accompanying LICENSE file are met. |
+ +--------------------------------------------------------------------+
+ | Copyright (c) 2004-2010, Michael Wallner <mike@php.net> |
+ +--------------------------------------------------------------------+
+*/
+
+/* $Id: http_cookie_api.c 298662 2010-04-27 13:42:32Z mike $ */
+
+#include "php_http.h"
+
+PHP_HTTP_API php_http_cookie_list_t *php_http_cookie_list_init(php_http_cookie_list_t *list TSRMLS_DC)
+{
+ if (!list) {
+ list = emalloc(sizeof(*list));
+ }
+
+ zend_hash_init(&list->cookies, 0, NULL, ZVAL_PTR_DTOR, 0);
+ zend_hash_init(&list->extras, 0, NULL, ZVAL_PTR_DTOR, 0);
+
+ list->path = NULL;
+ list->domain = NULL;
+ list->expires = 0;
+ list->flags = 0;
+
+ return list;
+}
+
+PHP_HTTP_API php_http_cookie_list_t *php_http_cookie_list_copy(php_http_cookie_list_t *from, php_http_cookie_list_t *to TSRMLS_DC)
+{
+ to = php_http_cookie_list_init(to TSRMLS_CC);
+
+ array_copy(&from->cookies, &to->cookies);
+ array_copy(&from->extras, &to->extras);
+
+ STR_SET(to->path, from->path ? estrdup(from->path) : NULL);
+ STR_SET(to->domain, from->domain ? estrdup(from->domain) : NULL);
+ to->expires = from->expires;
+ to->flags = from->flags;
+
+ return to;
+}
+
+PHP_HTTP_API void php_http_cookie_list_dtor(php_http_cookie_list_t *list TSRMLS_DC)
+{
+ if (list) {
+ zend_hash_destroy(&list->cookies);
+ zend_hash_destroy(&list->extras);
+
+ STR_SET(list->path, NULL);
+ STR_SET(list->domain, NULL);
+ }
+}
+
+
+
+PHP_HTTP_API void php_http_cookie_list_free(php_http_cookie_list_t **list TSRMLS_DC)
+{
+ if (*list) {
+ php_http_cookie_list_dtor(*list);
+ efree(*list);
+ *list = NULL;
+ }
+}
+
+
+
+PHP_HTTP_API const char *php_http_cookie_list_get_cookie(php_http_cookie_list_t *list, const char *name, size_t name_len TSRMLS_DC)
+{
+ zval **cookie = NULL;
+ if ((SUCCESS != zend_hash_find(&list->cookies, name, name_len + 1, (void *) &cookie)) || (Z_TYPE_PP(cookie) != IS_STRING)) {
+ return NULL;
+ }
+ return Z_STRVAL_PP(cookie);
+}
+
+
+
+PHP_HTTP_API const char *php_http_cookie_list_get_extra(php_http_cookie_list_t *list, const char *name, size_t name_len TSRMLS_DC)
+{
+ zval **extra = NULL;
+ if ((SUCCESS != zend_hash_find(&list->extras, name, name_len + 1, (void *) &extra)) || (Z_TYPE_PP(extra) != IS_STRING)) {
+ return NULL;
+ }
+ return Z_STRVAL_PP(extra);
+}
+
+
+
+PHP_HTTP_API void php_http_cookie_list_add_cookie(php_http_cookie_list_t *list, const char *name, size_t name_len, const char *value, size_t value_len TSRMLS_DC)
+{
+ zval *cookie_value;
+ char *key = estrndup(name, name_len);
+ MAKE_STD_ZVAL(cookie_value);
+ ZVAL_STRINGL(cookie_value, estrndup(value, value_len), value_len, 0);
+ zend_hash_update(&list->cookies, key, name_len + 1, (void *) &cookie_value, sizeof(zval *), NULL);
+ efree(key);
+}
+
+
+
+PHP_HTTP_API void php_http_cookie_list_add_extra(php_http_cookie_list_t *list, const char *name, size_t name_len, const char *value, size_t value_len TSRMLS_DC)
+{
+ zval *cookie_value;
+ char *key = estrndup(name, name_len);
+ MAKE_STD_ZVAL(cookie_value);
+ ZVAL_STRINGL(cookie_value, estrndup(value, value_len), value_len, 0);
+ zend_hash_update(&list->extras, key, name_len + 1, (void *) &cookie_value, sizeof(zval *), NULL);
+ efree(key);
+}
+
+
+typedef struct php_http_param_parse_cb_arg {
+ php_http_cookie_list_t *list;
+ long flags;
+ char **allowed_extras;
+} php_http_parse_param_cb_arg_t;
+
+
+static void php_http_cookie_parse_callback(void *ptr, const char *key, int keylen, const char *val, int vallen TSRMLS_DC)
+{
+ php_http_parse_param_cb_arg_t *arg = (php_http_parse_param_cb_arg_t *) ptr;
+
+#define _KEY_IS(s) (keylen == lenof(s) && !strncasecmp(key, (s), keylen))
+ if _KEY_IS("path") {
+ STR_SET(arg->list->path, estrndup(val, vallen));
+ } else if _KEY_IS("domain") {
+ STR_SET(arg->list->domain, estrndup(val, vallen));
+ } else if _KEY_IS("expires") {
+ char *date = estrndup(val, vallen);
+ arg->list->expires = php_parse_date(date, NULL TSRMLS_CC);
+ efree(date);
+ } else if _KEY_IS("secure") {
+ arg->list->flags |= PHP_HTTP_COOKIE_SECURE;
+ } else if _KEY_IS("httpOnly") {
+ arg->list->flags |= PHP_HTTP_COOKIE_HTTPONLY;
+ } else {
+ /* check for extra */
+ if (arg->allowed_extras) {
+ char **ae = arg->allowed_extras;
+
+ for (; *ae; ++ae) {
+ if ((size_t) keylen == strlen(*ae) && !strncasecmp(key, *ae, keylen)) {
+ if (arg->flags & PHP_HTTP_COOKIE_PARSE_RAW) {
+ php_http_cookie_list_add_extra(arg->list, key, keylen, val, vallen TSRMLS_CC);
+ } else {
+ char *dec = estrndup(val, vallen);
+ int declen = php_url_decode(dec, vallen);
+
+ php_http_cookie_list_add_extra(arg->list, key, keylen, dec, declen TSRMLS_CC);
+ efree(dec);
+ }
+ return;
+ }
+ }
+ }
+ /* new cookie */
+ if (arg->flags & PHP_HTTP_COOKIE_PARSE_RAW) {
+ php_http_cookie_list_add_cookie(arg->list, key, keylen, val, vallen TSRMLS_CC);
+ } else {
+ char *dec = estrndup(val, vallen);
+ int declen = php_url_decode(dec, vallen);
+
+ php_http_cookie_list_add_cookie(arg->list, key, keylen, dec, declen TSRMLS_CC);
+ efree(dec);
+ }
+ }
+}
+
+
+
+PHP_HTTP_API php_http_cookie_list_t *php_http_cookie_list_parse(php_http_cookie_list_t *list, const char *string, long flags, char **allowed_extras TSRMLS_DC)
+{
+ int free_list = !list;
+ php_http_parse_param_cb_arg_t arg;
+
+ list = php_http_cookie_list_init(list TSRMLS_CC);
+
+ arg.list = list;
+ arg.flags = flags;
+ arg.allowed_extras = allowed_extras;
+
+ if (SUCCESS != php_http_params_parse(string, PHP_HTTP_PARAMS_RAISE_ERROR, php_http_cookie_parse_callback, &arg TSRMLS_CC)) {
+ if (free_list) {
+ php_http_cookie_list_free(&list TSRMLS_CC);
+ } else {
+ php_http_cookie_list_dtor(list TSRMLS_CC);
+ }
+ list = NULL;
+ }
+
+ return list;
+}
+
+
+
+PHP_HTTP_API void php_http_cookie_list_to_struct(php_http_cookie_list_t *list, zval *strct TSRMLS_DC)
+{
+ zval array, *cookies, *extras;
+
+ INIT_PZVAL_ARRAY(&array, HASH_OF(strct));
+
+ MAKE_STD_ZVAL(cookies);
+ array_init(cookies);
+ zend_hash_copy(Z_ARRVAL_P(cookies), &list->cookies, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
+ add_assoc_zval(&array, "cookies", cookies);
+
+ MAKE_STD_ZVAL(extras);
+ array_init(extras);
+ zend_hash_copy(Z_ARRVAL_P(extras), &list->extras, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
+ add_assoc_zval(&array, "extras", extras);
+
+ add_assoc_long(&array, "flags", list->flags);
+ add_assoc_long(&array, "expires", (long) list->expires);
+ add_assoc_string(&array, "path", STR_PTR(list->path), 1);
+ add_assoc_string(&array, "domain", STR_PTR(list->domain), 1);
+}
+
+
+
+PHP_HTTP_API php_http_cookie_list_t *php_http_cookie_list_from_struct(php_http_cookie_list_t *list, zval *strct TSRMLS_DC)
+{
+ zval **tmp, *cpy;
+ HashTable *ht = HASH_OF(strct);
+
+ list = php_http_cookie_list_init(list TSRMLS_CC);
+
+ if (SUCCESS == zend_hash_find(ht, "cookies", sizeof("cookies"), (void *) &tmp) && Z_TYPE_PP(tmp) == IS_ARRAY) {
+ zend_hash_copy(&list->cookies, Z_ARRVAL_PP(tmp), (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
+ }
+ if (SUCCESS == zend_hash_find(ht, "extras", sizeof("extras"), (void *) &tmp) && Z_TYPE_PP(tmp) == IS_ARRAY) {
+ zend_hash_copy(&list->extras, Z_ARRVAL_PP(tmp), (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
+ }
+ if (SUCCESS == zend_hash_find(ht, "flags", sizeof("flags"), (void *) &tmp)) {
+ switch (Z_TYPE_PP(tmp)) {
+ case IS_LONG:
+ list->flags = Z_LVAL_PP(tmp);
+ break;
+ case IS_DOUBLE:
+ list->flags = (long) Z_DVAL_PP(tmp);
+ break;
+ case IS_STRING:
+ cpy = php_http_zsep(IS_LONG, *tmp);
+ list->flags = Z_LVAL_P(cpy);
+ zval_ptr_dtor(&cpy);
+ break;
+ default:
+ break;
+ }
+ }
+ if (SUCCESS == zend_hash_find(ht, "expires", sizeof("expires"), (void *) &tmp)) {
+ switch (Z_TYPE_PP(tmp)) {
+ case IS_LONG:
+ list->expires = Z_LVAL_PP(tmp);
+ break;
+ case IS_DOUBLE:
+ list->expires = (long) Z_DVAL_PP(tmp);
+ break;
+ case IS_STRING:
+ cpy = php_http_zsep(IS_LONG, *tmp);
+ if (Z_LVAL_P(cpy)) {
+ list->expires = Z_LVAL_P(cpy);
+ } else {
+ time_t expires = php_parse_date(Z_STRVAL_PP(tmp), NULL TSRMLS_CC);
+ if (expires > 0) {
+ list->expires = expires;
+ }
+ }
+ zval_ptr_dtor(&cpy);
+ break;
+ default:
+ break;
+ }
+ }
+ if (SUCCESS == zend_hash_find(ht, "path", sizeof("path"), (void *) &tmp) && Z_TYPE_PP(tmp) == IS_STRING) {
+ list->path = estrndup(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
+ }
+ if (SUCCESS == zend_hash_find(ht, "domain", sizeof("domain"), (void *) &tmp) && Z_TYPE_PP(tmp) == IS_STRING) {
+ list->domain = estrndup(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
+ }
+
+ return list;
+}
+
+
+
+static inline void append_encoded(php_http_buffer *buf, const char *key, size_t key_len, const char *val, size_t val_len)
+{
+ char *enc_str[2];
+ int enc_len[2];
+
+ enc_str[0] = php_url_encode(key, key_len, &enc_len[0]);
+ enc_str[1] = php_url_encode(val, val_len, &enc_len[1]);
+
+ php_http_buffer_append(buf, enc_str[0], enc_len[0]);
+ php_http_buffer_appends(buf, "=");
+ php_http_buffer_append(buf, enc_str[1], enc_len[1]);
+ php_http_buffer_appends(buf, "; ");
+
+ efree(enc_str[0]);
+ efree(enc_str[1]);
+}
+
+
+
+PHP_HTTP_API void php_http_cookie_list_to_string(php_http_cookie_list_t *list, char **str, size_t *len TSRMLS_DC)
+{
+ php_http_buffer buf;
+ zval **val;
+ php_http_array_hashkey_t key = php_http_array_hashkey_init(0);
+ HashPosition pos;
+
+ php_http_buffer_init(&buf);
+
+ FOREACH_HASH_KEYVAL(pos, &list->cookies, key, val) {
+ if (key.type == HASH_KEY_IS_STRING && key.len) {
+ zval *tmp = php_http_zsep(IS_STRING, *val);
+ append_encoded(&buf, key.str, key.len-1, Z_STRVAL_P(tmp), Z_STRLEN_P(tmp));
+ zval_ptr_dtor(&tmp);
+ }
+ }
+
+ if (list->domain && *list->domain) {
+ php_http_buffer_appendf(&buf, "domain=%s; ", list->domain);
+ }
+ if (list->path && *list->path) {
+ php_http_buffer_appendf(&buf, "path=%s; ", list->path);
+ }
+ if (list->expires) {
+ char *date = php_format_date(ZEND_STRL(PHP_HTTP_DATE_FORMAT), list->expires, 0 TSRMLS_CC);
+ php_http_buffer_appendf(&buf, "expires=%s; ", date);
+ efree(date);
+ }
+
+ FOREACH_HASH_KEYVAL(pos, &list->extras, key, val) {
+ if (key.type == HASH_KEY_IS_STRING && key.len) {
+ zval *tmp = php_http_zsep(IS_STRING, *val);
+ append_encoded(&buf, key.str, key.len-1, Z_STRVAL_P(tmp), Z_STRLEN_P(tmp));
+ }
+ }
+
+ if (list->flags & PHP_HTTP_COOKIE_SECURE) {
+ php_http_buffer_appends(&buf, "secure; ");
+ }
+ if (list->flags & PHP_HTTP_COOKIE_HTTPONLY) {
+ php_http_buffer_appends(&buf, "httpOnly; ");
+ }
+
+ php_http_buffer_fix(&buf);
+ *str = PHP_HTTP_BUFFER_VAL(&buf);
+ *len = PHP_HTTP_BUFFER_LEN(&buf);
+}
+
+#define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpCookie, method, 0, req_args)
+#define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpCookie, method, 0)
+#define PHP_HTTP_COOKIE_ME(method, visibility) PHP_ME(HttpCookie, method, PHP_HTTP_ARGS(HttpCookie, method), visibility)
+
+PHP_HTTP_BEGIN_ARGS(__construct, 0)
+ PHP_HTTP_ARG_VAL(cookie_string, 0)
+ PHP_HTTP_ARG_VAL(parser_flags, 0)
+ PHP_HTTP_ARG_VAL(allowed_extras, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_EMPTY_ARGS(toArray);
+PHP_HTTP_EMPTY_ARGS(getCookies);
+PHP_HTTP_EMPTY_ARGS(getExtras);
+PHP_HTTP_EMPTY_ARGS(getDomain);
+PHP_HTTP_EMPTY_ARGS(getPath);
+PHP_HTTP_EMPTY_ARGS(getExpires);
+PHP_HTTP_EMPTY_ARGS(getFlags);
+PHP_HTTP_EMPTY_ARGS(toString);
+
+PHP_HTTP_BEGIN_ARGS(setDomain, 0)
+ PHP_HTTP_ARG_VAL(value, 0)
+PHP_HTTP_END_ARGS;
+PHP_HTTP_BEGIN_ARGS(setPath, 0)
+ PHP_HTTP_ARG_VAL(value, 0)
+PHP_HTTP_END_ARGS;
+PHP_HTTP_BEGIN_ARGS(setExpires, 0)
+ PHP_HTTP_ARG_VAL(value, 0)
+PHP_HTTP_END_ARGS;
+PHP_HTTP_BEGIN_ARGS(setFlags, 0)
+ PHP_HTTP_ARG_VAL(value, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(setCookies, 0)
+ PHP_HTTP_ARG_VAL(cookies, 0)
+PHP_HTTP_END_ARGS;
+PHP_HTTP_BEGIN_ARGS(addCookies, 1)
+ PHP_HTTP_ARG_VAL(cookies, 0)
+PHP_HTTP_END_ARGS;
+PHP_HTTP_BEGIN_ARGS(setExtras, 0)
+ PHP_HTTP_ARG_VAL(extras, 0)
+PHP_HTTP_END_ARGS;
+PHP_HTTP_BEGIN_ARGS(addExtras, 1)
+ PHP_HTTP_ARG_VAL(extras, 0)
+PHP_HTTP_END_ARGS;
+PHP_HTTP_BEGIN_ARGS(setCookie, 1)
+ PHP_HTTP_ARG_VAL(cookie_name, 0)
+ PHP_HTTP_ARG_VAL(cookie_value, 0)
+PHP_HTTP_END_ARGS;
+PHP_HTTP_BEGIN_ARGS(addCookie, 1)
+ PHP_HTTP_ARG_VAL(cookie_name, 0)
+ PHP_HTTP_ARG_VAL(cookie_value, 0)
+PHP_HTTP_END_ARGS;
+PHP_HTTP_BEGIN_ARGS(getCookie, 1)
+ PHP_HTTP_ARG_VAL(name, 0)
+PHP_HTTP_END_ARGS;
+PHP_HTTP_BEGIN_ARGS(setExtra, 1)
+ PHP_HTTP_ARG_VAL(extra_name, 0)
+ PHP_HTTP_ARG_VAL(extra_value, 0)
+PHP_HTTP_END_ARGS;
+PHP_HTTP_BEGIN_ARGS(addExtra, 1)
+ PHP_HTTP_ARG_VAL(extra_name, 0)
+ PHP_HTTP_ARG_VAL(extra_value, 0)
+PHP_HTTP_END_ARGS;
+PHP_HTTP_BEGIN_ARGS(getExtra, 1)
+ PHP_HTTP_ARG_VAL(name, 0)
+PHP_HTTP_END_ARGS;
+
+zend_class_entry *php_http_cookie_class_entry;
+zend_function_entry php_http_cookie_method_entry[] = {
+ PHP_HTTP_COOKIE_ME(__construct, ZEND_ACC_PUBLIC)
+ PHP_HTTP_COOKIE_ME(getCookies, ZEND_ACC_PUBLIC)
+ PHP_HTTP_COOKIE_ME(setCookies, ZEND_ACC_PUBLIC)
+ PHP_HTTP_COOKIE_ME(addCookies, ZEND_ACC_PUBLIC)
+ PHP_HTTP_COOKIE_ME(getCookie, ZEND_ACC_PUBLIC)
+ PHP_HTTP_COOKIE_ME(setCookie, ZEND_ACC_PUBLIC)
+ PHP_HTTP_COOKIE_ME(addCookie, ZEND_ACC_PUBLIC)
+
+ PHP_HTTP_COOKIE_ME(getExtras, ZEND_ACC_PUBLIC)
+ PHP_HTTP_COOKIE_ME(setExtras, ZEND_ACC_PUBLIC)
+ PHP_HTTP_COOKIE_ME(addExtras, ZEND_ACC_PUBLIC)
+ PHP_HTTP_COOKIE_ME(getExtra, ZEND_ACC_PUBLIC)
+ PHP_HTTP_COOKIE_ME(setExtra, ZEND_ACC_PUBLIC)
+ PHP_HTTP_COOKIE_ME(addExtra, ZEND_ACC_PUBLIC)
+
+ PHP_HTTP_COOKIE_ME(getDomain, ZEND_ACC_PUBLIC)
+ PHP_HTTP_COOKIE_ME(setDomain, ZEND_ACC_PUBLIC)
+ PHP_HTTP_COOKIE_ME(getPath, ZEND_ACC_PUBLIC)
+ PHP_HTTP_COOKIE_ME(setPath, ZEND_ACC_PUBLIC)
+ PHP_HTTP_COOKIE_ME(getExpires, ZEND_ACC_PUBLIC)
+ PHP_HTTP_COOKIE_ME(setExpires, ZEND_ACC_PUBLIC)
+ PHP_HTTP_COOKIE_ME(getFlags, ZEND_ACC_PUBLIC)
+ PHP_HTTP_COOKIE_ME(setFlags, ZEND_ACC_PUBLIC)
+
+ PHP_HTTP_COOKIE_ME(toArray, ZEND_ACC_PUBLIC)
+ PHP_HTTP_COOKIE_ME(toString, ZEND_ACC_PUBLIC)
+ ZEND_MALIAS(HttpCookie, __toString, toString, PHP_HTTP_ARGS(HttpCookie, toString), ZEND_ACC_PUBLIC)
+
+ EMPTY_FUNCTION_ENTRY
+};
+static zend_object_handlers php_http_cookie_object_handlers;
+
+zend_object_value php_http_cookie_object_new(zend_class_entry *ce TSRMLS_DC)
+{
+ return php_http_cookie_object_new_ex(ce, NULL, NULL TSRMLS_CC);
+}
+
+zend_object_value php_http_cookie_object_new_ex(zend_class_entry *ce, php_http_cookie_list_t *list, php_http_cookie_object_t **ptr TSRMLS_DC)
+{
+ zend_object_value ov;
+ php_http_cookie_object_t *o;
+
+ o = ecalloc(sizeof(*o), 1);
+ zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
+ object_properties_init((zend_object *) o, ce);
+
+ if (list) {
+ o->list = list;
+ }
+
+ if (ptr) {
+ *ptr = o;
+ }
+
+ ov.handle = zend_objects_store_put(o, NULL, php_http_cookie_object_free, NULL TSRMLS_CC);
+ ov.handlers = &php_http_cookie_object_handlers;
+
+ return ov;
+}
+
+zend_object_value php_http_cookie_object_clone(zval *this_ptr TSRMLS_CC)
+{
+ php_http_cookie_object_t *new_obj, *old_obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+ zend_object_value ov;
+
+ ov = php_http_cookie_object_new_ex(old_obj->o.ce, php_http_cookie_list_copy(old_obj->list, NULL TSRMLS_CC), &new_obj TSRMLS_CC);
+ zend_objects_clone_members((zend_object *) new_obj, ov, (zend_object *) old_obj, Z_OBJ_HANDLE_P(getThis()) TSRMLS_CC);
+
+ return ov;
+}
+
+void php_http_cookie_object_free(void *object TSRMLS_CC)
+{
+ php_http_cookie_object_t *obj = object;
+
+ php_http_cookie_list_free(&obj->list TSRMLS_CC);
+ zend_object_std_dtor((zend_object *) obj TSRMLS_CC);
+ efree(obj);
+}
+
+PHP_METHOD(HttpCookie, __construct)
+{
+ with_error_handling(EH_THROW, PHP_HTTP_EX_CE(runtime)) {
+ zval *zcookie = NULL;
+ long flags = 0;
+ HashTable *allowed_extras = NULL;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z!lH", &zcookie, &flags, &allowed_extras)) {
+ if (zcookie) {
+ with_error_handling(EH_THROW, PHP_HTTP_EX_CE(cookie)) {
+ char **ae = NULL;
+ php_http_cookie_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (allowed_extras && zend_hash_num_elements(allowed_extras)) {
+ char **ae_ptr = safe_emalloc(zend_hash_num_elements(allowed_extras) + 1, sizeof(char *), 0);
+ HashPosition pos;
+ zval **val;
+
+ ae = ae_ptr;
+ FOREACH_HASH_VAL(pos, allowed_extras, val) {
+ zval *cpy = php_http_zsep(IS_STRING, *val);
+
+ *ae_ptr++ = estrndup(Z_STRVAL_P(cpy), Z_STRLEN_P(cpy));
+ zval_ptr_dtor(&cpy);
+ }
+ *ae_ptr = NULL;
+ }
+
+ switch (Z_TYPE_P(zcookie)) {
+ case IS_ARRAY:
+ case IS_OBJECT:
+ obj->list = php_http_cookie_list_from_struct(obj->list, zcookie TSRMLS_CC);
+ break;
+ default: {
+ zval *cpy = php_http_zsep(IS_STRING, zcookie);
+
+ obj->list = php_http_cookie_list_parse(obj->list, Z_STRVAL_P(cpy), flags, ae TSRMLS_CC);
+ zval_ptr_dtor(&cpy);
+ break;
+ }
+ }
+ } end_error_handling();
+ }
+ }
+ } end_error_handling();
+}
+
+PHP_METHOD(HttpCookie, getCookies)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ php_http_cookie_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ array_init(return_value);
+ array_copy(&obj->list->cookies, Z_ARRVAL_P(return_value));
+ return;
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpCookie, setCookies)
+{
+ HashTable *cookies = NULL;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|H", &cookies)) {
+ php_http_cookie_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ zend_hash_clean(&obj->list->cookies);
+ if (cookies) {
+ array_copy(cookies, &obj->list->cookies);
+ }
+ RETURN_TRUE;
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpCookie, addCookies)
+{
+ HashTable *cookies = NULL;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "H", &cookies)) {
+ php_http_cookie_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ array_join(cookies, &obj->list->cookies, 1, ARRAY_JOIN_STRONLY);
+ RETURN_TRUE;
+ }
+ RETURN_FALSE;
+}
+
+
+PHP_METHOD(HttpCookie, getExtras)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ php_http_cookie_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ array_init(return_value);
+ array_copy(&obj->list->extras, Z_ARRVAL_P(return_value));
+ return;
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpCookie, setExtras)
+{
+ HashTable *extras = NULL;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|H", &extras)) {
+ php_http_cookie_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ zend_hash_clean(&obj->list->extras);
+ if (extras) {
+ array_copy(extras, &obj->list->extras);
+ }
+ RETURN_TRUE;
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpCookie, addExtras)
+{
+ HashTable *extras = NULL;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "H", &extras)) {
+ php_http_cookie_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ array_join(extras, &obj->list->extras, 1, ARRAY_JOIN_STRONLY);
+ RETURN_TRUE;
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpCookie, getCookie)
+{
+ char *name_str;
+ int name_len;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name_str, &name_len)) {
+ php_http_cookie_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+ zval **zvalue;
+
+ if (SUCCESS == zend_hash_find(&obj->list->cookies, name_str, name_len + 1, (void *) &zvalue)) {
+ RETURN_ZVAL(*zvalue, 1, 0);
+ }
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpCookie, setCookie)
+{
+ char *name_str, *value_str;
+ int name_len, value_len;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s!", &name_str, &name_len, &value_str, &value_len)) {
+ php_http_cookie_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (!value_str) {
+ RETURN_SUCCESS(zend_hash_del(&obj->list->cookies, name_str, name_len + 1));
+ } else {
+ zval *zvalue;
+
+ MAKE_STD_ZVAL(zvalue);
+ ZVAL_STRINGL(zvalue, value_str, value_len, 1);
+ RETURN_SUCCESS(zend_hash_update(&obj->list->cookies, name_str, name_len + 1, &zvalue, sizeof(zval *), NULL));
+ }
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpCookie, addCookie)
+{
+ char *name_str, *value_str;
+ int name_len, value_len;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &name_str, &name_len, &value_str, &value_len)) {
+ php_http_cookie_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+ zval *zvalue;
+
+ MAKE_STD_ZVAL(zvalue);
+ ZVAL_STRINGL(zvalue, value_str, value_len, 1);
+ RETURN_SUCCESS(zend_hash_add(&obj->list->cookies, name_str, name_len + 1, &zvalue, sizeof(zval *), NULL));
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpCookie, getExtra)
+{
+ char *name_str;
+ int name_len;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name_str, &name_len)) {
+ php_http_cookie_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+ zval **zvalue;
+
+ if (SUCCESS == zend_hash_find(&obj->list->extras, name_str, name_len + 1, (void *) &zvalue)) {
+ RETURN_ZVAL(*zvalue, 1, 0);
+ }
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpCookie, setExtra)
+{
+ char *name_str, *value_str;
+ int name_len, value_len;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s!", &name_str, &name_len, &value_str, &value_len)) {
+ php_http_cookie_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (!value_str) {
+ RETURN_SUCCESS(zend_hash_del(&obj->list->extras, name_str, name_len + 1));
+ } else {
+ zval *zvalue;
+
+ MAKE_STD_ZVAL(zvalue);
+ ZVAL_STRINGL(zvalue, value_str, value_len, 1);
+ RETURN_SUCCESS(zend_hash_update(&obj->list->extras, name_str, name_len + 1, &zvalue, sizeof(zval *), NULL));
+ }
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpCookie, addExtra)
+{
+ char *name_str, *value_str;
+ int name_len, value_len;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &name_str, &name_len, &value_str, &value_len)) {
+ php_http_cookie_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+ zval *zvalue;
+
+ MAKE_STD_ZVAL(zvalue);
+ ZVAL_STRINGL(zvalue, value_str, value_len, 1);
+ RETURN_SUCCESS(zend_hash_add(&obj->list->extras, name_str, name_len + 1, &zvalue, sizeof(zval *), NULL));
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpCookie, getDomain)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ php_http_cookie_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (obj->list->domain) {
+ RETURN_STRING(obj->list->domain, 1);
+ }
+ RETURN_NULL();
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpCookie, setDomain)
+{
+ char *domain_str = NULL;
+ int domain_len = 0;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!", &domain_str, &domain_len)) {
+ php_http_cookie_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ STR_SET(obj->list->domain, domain_str ? estrndup(domain_str, domain_len) : NULL);
+ RETURN_TRUE;
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpCookie, getPath)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ php_http_cookie_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (obj->list->path) {
+ RETURN_STRING(obj->list->path, 1);
+ }
+ RETURN_NULL();
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpCookie, setPath)
+{
+ char *path_str = NULL;
+ int path_len = 0;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!", &path_str, &path_len)) {
+ php_http_cookie_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ STR_SET(obj->list->path, path_str ? estrndup(path_str, path_len) : NULL);
+ RETURN_TRUE;
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpCookie, getExpires)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ php_http_cookie_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ RETURN_LONG(obj->list->expires);
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpCookie, setExpires)
+{
+ long ts = 0;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &ts)) {
+ php_http_cookie_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ obj->list->expires = ts;
+ RETURN_TRUE;
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpCookie, getFlags)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ php_http_cookie_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ RETURN_LONG(obj->list->flags);
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpCookie, setFlags)
+{
+ long flags = 0;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &flags)) {
+ php_http_cookie_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ obj->list->flags = flags;
+ RETURN_TRUE;
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpCookie, toString)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ php_http_cookie_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+ char *str;
+ size_t len;
+
+ php_http_cookie_list_to_string(obj->list, &str, &len TSRMLS_CC);
+ RETURN_STRINGL(str, len, 0);
+ }
+ RETURN_EMPTY_STRING();
+}
+
+PHP_METHOD(HttpCookie, toArray)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ php_http_cookie_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ array_init(return_value);
+ php_http_cookie_list_to_struct(obj->list, return_value TSRMLS_CC);
+ }
+}
+
+PHP_MINIT_FUNCTION(http_cookie)
+{
+ PHP_HTTP_REGISTER_CLASS(http, Cookie, http_cookie, php_http_object_class_entry, 0);
+ php_http_cookie_class_entry->create_object = php_http_cookie_object_new;
+ memcpy(&php_http_cookie_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
+ php_http_cookie_object_handlers.clone_obj = php_http_cookie_object_clone;
+
+ zend_declare_class_constant_long(php_http_cookie_class_entry, ZEND_STRL("PARSE_RAW"), PHP_HTTP_COOKIE_PARSE_RAW TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_cookie_class_entry, ZEND_STRL("SECURE"), PHP_HTTP_COOKIE_SECURE TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_cookie_class_entry, ZEND_STRL("HTTPONLY"), PHP_HTTP_COOKIE_HTTPONLY TSRMLS_CC);
+
+ return SUCCESS;
+}
+
+
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
--- /dev/null
+/*
+ +--------------------------------------------------------------------+
+ | PECL :: http |
+ +--------------------------------------------------------------------+
+ | Redistribution and use in source and binary forms, with or without |
+ | modification, are permitted provided that the conditions mentioned |
+ | in the accompanying LICENSE file are met. |
+ +--------------------------------------------------------------------+
+ | Copyright (c) 2004-2010, Michael Wallner <mike@php.net> |
+ +--------------------------------------------------------------------+
+*/
+
+/* $Id: php_http_cookie_api.h 292841 2009-12-31 08:48:57Z mike $ */
+
+#ifndef PHP_HTTP_COOKIE_H
+#define PHP_HTTP_COOKIE_H
+
+#define PHP_HTTP_COOKIE_SECURE 0x10L
+#define PHP_HTTP_COOKIE_HTTPONLY 0x20L
+
+#define PHP_HTTP_COOKIE_PARSE_RAW 0x01L
+
+/*
+ generally a netscape cookie compliant struct, recognizing httpOnly attribute, too;
+ cookie params like those from rfc2109 and rfc2965 are just put into extras, if
+ one specifies them in allowed extras, else they're treated like cookies themself
+*/
+typedef struct php_http_cookie_list {
+ HashTable cookies;
+ HashTable extras;
+ long flags;
+ char *path;
+ char *domain;
+ time_t expires;
+} php_http_cookie_list_t;
+
+PHP_HTTP_API php_http_cookie_list_t *php_http_cookie_list_init(php_http_cookie_list_t *list TSRMLS_DC);
+PHP_HTTP_API php_http_cookie_list_t *php_http_cookie_list_parse(php_http_cookie_list_t * list, const char *string, long flags, char **allowed_extras TSRMLS_DC);
+PHP_HTTP_API void php_http_cookie_list_dtor(php_http_cookie_list_t *list TSRMLS_DC);
+PHP_HTTP_API void php_http_cookie_list_free(php_http_cookie_list_t **list TSRMLS_DC);
+
+#define php_http_cookie_list_has_cookie(list, name, name_len) zend_hash_exists(&(list)->cookies, (name), (name_len)+1)
+PHP_HTTP_API void php_http_cookie_list_add_cookie(php_http_cookie_list_t *list, const char *name, size_t name_len, const char *value, size_t value_len TSRMLS_DC);
+PHP_HTTP_API const char *php_http_cookie_list_get_cookie(php_http_cookie_list_t *list, const char *name, size_t name_len TSRMLS_DC);
+
+#define php_http_cookie_list_has_extra(list, name, name_len) zend_hash_exists(&(list)->extras, (name), (name_len)+1)
+PHP_HTTP_API void php_http_cookie_list_add_extra(php_http_cookie_list_t *list, const char *name, size_t name_len, const char *value, size_t value_len TSRMLS_DC);
+PHP_HTTP_API const char *php_http_cookie_list_get_extra(php_http_cookie_list_t *list, const char *name, size_t name_len TSRMLS_DC);
+
+PHP_HTTP_API void php_http_cookie_list_to_string(php_http_cookie_list_t *list, char **str, size_t *len TSRMLS_DC);
+PHP_HTTP_API php_http_cookie_list_t *php_http_cookie_list_from_struct(php_http_cookie_list_t *list, zval *strct TSRMLS_DC);
+PHP_HTTP_API void php_http_cookie_list_to_struct(php_http_cookie_list_t *list, zval *strct TSRMLS_DC);
+
+
+extern zend_class_entry *php_http_cookie_class_entry;
+extern zend_function_entry php_http_cookie_method_entry[];
+
+typedef struct php_http_cookie_object {
+ zend_object o;
+ php_http_cookie_list_t *list;
+} php_http_cookie_object_t;
+
+zend_object_value php_http_cookie_object_new(zend_class_entry *ce TSRMLS_DC);
+zend_object_value php_http_cookie_object_new_ex(zend_class_entry *ce, php_http_cookie_list_t *list, php_http_cookie_object_t **obj TSRMLS_DC);
+zend_object_value php_http_cookie_object_clone(zval *this_ptr TSRMLS_DC);
+void php_http_cookie_object_free(void *object TSRMLS_DC);
+
+PHP_METHOD(HttpCookie, __construct);
+PHP_METHOD(HttpCookie, getCookies);
+PHP_METHOD(HttpCookie, setCookies);
+PHP_METHOD(HttpCookie, addCookies);
+PHP_METHOD(HttpCookie, getExtras);
+PHP_METHOD(HttpCookie, setExtras);
+PHP_METHOD(HttpCookie, addExtras);
+PHP_METHOD(HttpCookie, getCookie);
+PHP_METHOD(HttpCookie, setCookie);
+PHP_METHOD(HttpCookie, addCookie);
+PHP_METHOD(HttpCookie, getExtra);
+PHP_METHOD(HttpCookie, setExtra);
+PHP_METHOD(HttpCookie, addExtra);
+PHP_METHOD(HttpCookie, getDomain);
+PHP_METHOD(HttpCookie, setDomain);
+PHP_METHOD(HttpCookie, getPath);
+PHP_METHOD(HttpCookie, setPath);
+PHP_METHOD(HttpCookie, getExpires);
+PHP_METHOD(HttpCookie, setExpires);
+PHP_METHOD(HttpCookie, getFlags);
+PHP_METHOD(HttpCookie, setFlags);
+PHP_METHOD(HttpCookie, toString);
+PHP_METHOD(HttpCookie, toArray);
+
+extern PHP_MINIT_FUNCTION(http_cookie);
+
+
+#endif
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
--- /dev/null
+/*
+ +--------------------------------------------------------------------+
+ | PECL :: http |
+ +--------------------------------------------------------------------+
+ | Redistribution and use in source and binary forms, with or without |
+ | modification, are permitted provided that the conditions mentioned |
+ | in the accompanying LICENSE file are met. |
+ +--------------------------------------------------------------------+
+ | Copyright (c) 2004-2010, Michael Wallner <mike@php.net> |
+ +--------------------------------------------------------------------+
+*/
+
+/* $Id: http_encoding_api.c 298592 2010-04-26 11:47:29Z mike $ */
+
+#include "php_http.h"
+
+static inline int eol_match(char **line, int *eol_len)
+{
+ char *ptr = *line;
+
+ while (' ' == *ptr) ++ptr;
+
+ if (ptr == php_http_locate_eol(*line, eol_len)) {
+ *line = ptr;
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+PHP_HTTP_API const char *php_http_encoding_dechunk(const char *encoded, size_t encoded_len, char **decoded, size_t *decoded_len TSRMLS_DC)
+{
+ int eol_len = 0;
+ char *n_ptr = NULL;
+ const char *e_ptr = encoded;
+
+ *decoded_len = 0;
+ *decoded = ecalloc(1, encoded_len);
+
+ while ((encoded + encoded_len - e_ptr) > 0) {
+ ulong chunk_len = 0, rest;
+
+ chunk_len = strtoul(e_ptr, &n_ptr, 16);
+
+ /* we could not read in chunk size */
+ if (n_ptr == e_ptr) {
+ /*
+ * if this is the first turn and there doesn't seem to be a chunk
+ * size at the begining of the body, do not fail on apparently
+ * not encoded data and return a copy
+ */
+ if (e_ptr == encoded) {
+ php_http_error(HE_NOTICE, PHP_HTTP_E_ENCODING, "Data does not seem to be chunked encoded");
+ memcpy(*decoded, encoded, encoded_len);
+ *decoded_len = encoded_len;
+ return encoded + encoded_len;
+ } else {
+ efree(*decoded);
+ php_http_error(HE_WARNING, PHP_HTTP_E_ENCODING, "Expected chunk size at pos %tu of %zu but got trash", n_ptr - encoded, encoded_len);
+ return NULL;
+ }
+ }
+
+ /* reached the end */
+ if (!chunk_len) {
+ /* move over '0' chunked encoding terminator and any new lines */
+ do {
+ switch (*e_ptr) {
+ case '0':
+ case '\r':
+ case '\n':
+ ++e_ptr;
+ continue;
+ }
+ } while (0);
+ break;
+ }
+
+ /* there should be CRLF after the chunk size, but we'll ignore SP+ too */
+ if (*n_ptr && !eol_match(&n_ptr, &eol_len)) {
+ if (eol_len == 2) {
+ php_http_error(HE_WARNING, PHP_HTTP_E_ENCODING, "Expected CRLF at pos %tu of %zu but got 0x%02X 0x%02X", n_ptr - encoded, encoded_len, *n_ptr, *(n_ptr + 1));
+ } else {
+ php_http_error(HE_WARNING, PHP_HTTP_E_ENCODING, "Expected LF at pos %tu of %zu but got 0x%02X", n_ptr - encoded, encoded_len, *n_ptr);
+ }
+ }
+ n_ptr += eol_len;
+
+ /* chunk size pretends more data than we actually got, so it's probably a truncated message */
+ if (chunk_len > (rest = encoded + encoded_len - n_ptr)) {
+ php_http_error(HE_WARNING, PHP_HTTP_E_ENCODING, "Truncated message: chunk size %lu exceeds remaining data size %lu at pos %tu of %zu", chunk_len, rest, n_ptr - encoded, encoded_len);
+ chunk_len = rest;
+ }
+
+ /* copy the chunk */
+ memcpy(*decoded + *decoded_len, n_ptr, chunk_len);
+ *decoded_len += chunk_len;
+
+ if (chunk_len == rest) {
+ e_ptr = n_ptr + chunk_len;
+ break;
+ } else {
+ /* advance to next chunk */
+ e_ptr = n_ptr + chunk_len + eol_len;
+ }
+ }
+
+ return e_ptr;
+}
+
+static inline int php_http_inflate_rounds(z_stream *Z, int flush, char **buf, size_t *len)
+{
+ int status = 0, round = 0;
+ php_http_buffer buffer;
+
+ *buf = NULL;
+ *len = 0;
+
+ php_http_buffer_init_ex(&buffer, Z->avail_in, PHP_HTTP_BUFFER_INIT_PREALLOC);
+
+ do {
+ if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_resize_ex(&buffer, buffer.size, 0, 1)) {
+ status = Z_MEM_ERROR;
+ } else {
+ Z->avail_out = buffer.free;
+ Z->next_out = (Bytef *) buffer.data + buffer.used;
+#if 0
+ fprintf(stderr, "\n%3d: %3d PRIOR: size=%7lu,\tfree=%7lu,\tused=%7lu,\tavail_in=%7lu,\tavail_out=%7lu\n", round, status, buffer.size, buffer.free, buffer.used, Z->avail_in, Z->avail_out);
+#endif
+ status = inflate(Z, flush);
+
+ buffer.used += buffer.free - Z->avail_out;
+ buffer.free = Z->avail_out;
+#if 0
+ fprintf(stderr, "%3d: %3d AFTER: size=%7lu,\tfree=%7lu,\tused=%7lu,\tavail_in=%7lu,\tavail_out=%7lu\n", round, status, buffer.size, buffer.free, buffer.used, Z->avail_in, Z->avail_out);
+#endif
+ PHP_HTTP_INFLATE_BUFFER_SIZE_ALIGN(buffer.size);
+ }
+ } while ((Z_BUF_ERROR == status || (Z_OK == status && Z->avail_in)) && ++round < PHP_HTTP_INFLATE_ROUNDS);
+
+ if (status == Z_OK || status == Z_STREAM_END) {
+ php_http_buffer_shrink(&buffer);
+ php_http_buffer_fix(&buffer);
+ *buf = buffer.data;
+ *len = buffer.used;
+ } else {
+ php_http_buffer_dtor(&buffer);
+ }
+
+ return status;
+}
+
+PHP_HTTP_API STATUS php_http_encoding_deflate(int flags, const char *data, size_t data_len, char **encoded, size_t *encoded_len TSRMLS_DC)
+{
+ int status, level, wbits, strategy;
+ z_stream Z;
+
+ PHP_HTTP_DEFLATE_LEVEL_SET(flags, level);
+ PHP_HTTP_DEFLATE_WBITS_SET(flags, wbits);
+ PHP_HTTP_DEFLATE_STRATEGY_SET(flags, strategy);
+
+ memset(&Z, 0, sizeof(z_stream));
+ *encoded = NULL;
+ *encoded_len = 0;
+
+ status = deflateInit2(&Z, level, Z_DEFLATED, wbits, MAX_MEM_LEVEL, strategy);
+ if (Z_OK == status) {
+ *encoded_len = PHP_HTTP_DEFLATE_BUFFER_SIZE_GUESS(data_len);
+ *encoded = emalloc(*encoded_len);
+
+ Z.next_in = (Bytef *) data;
+ Z.next_out = (Bytef *) *encoded;
+ Z.avail_in = data_len;
+ Z.avail_out = *encoded_len;
+
+ status = deflate(&Z, Z_FINISH);
+ deflateEnd(&Z);
+
+ if (Z_STREAM_END == status) {
+ /* size buffer down to actual length */
+ *encoded = erealloc(*encoded, Z.total_out + 1);
+ (*encoded)[*encoded_len = Z.total_out] = '\0';
+ return SUCCESS;
+ } else {
+ STR_SET(*encoded, NULL);
+ *encoded_len = 0;
+ }
+ }
+
+ php_http_error(HE_WARNING, PHP_HTTP_E_ENCODING, "Could not deflate data: %s", zError(status));
+ return FAILURE;
+}
+
+PHP_HTTP_API STATUS php_http_encoding_inflate(const char *data, size_t data_len, char **decoded, size_t *decoded_len TSRMLS_DC)
+{
+ z_stream Z;
+ int status, wbits = PHP_HTTP_WINDOW_BITS_ANY;
+
+ memset(&Z, 0, sizeof(z_stream));
+
+retry_raw_inflate:
+ status = inflateInit2(&Z, wbits);
+ if (Z_OK == status) {
+ Z.next_in = (Bytef *) data;
+ Z.avail_in = data_len;
+
+ switch (status = php_http_inflate_rounds(&Z, Z_NO_FLUSH, decoded, decoded_len)) {
+ case Z_STREAM_END:
+ inflateEnd(&Z);
+ return SUCCESS;
+
+ case Z_OK:
+ status = Z_DATA_ERROR;
+ break;
+
+ case Z_DATA_ERROR:
+ /* raw deflated data? */
+ if (PHP_HTTP_WINDOW_BITS_ANY == wbits) {
+ inflateEnd(&Z);
+ wbits = PHP_HTTP_WINDOW_BITS_RAW;
+ goto retry_raw_inflate;
+ }
+ }
+ inflateEnd(&Z);
+
+ if (decoded_len && *decoded) {
+ efree(*decoded);
+ }
+ }
+
+ php_http_error(HE_WARNING, PHP_HTTP_E_ENCODING, "Could not inflate data: %s", zError(status));
+ return FAILURE;
+}
+
+PHP_HTTP_API php_http_encoding_stream_t *php_http_encoding_stream_init(php_http_encoding_stream_t *s, php_http_encoding_stream_ops_t *ops, unsigned flags TSRMLS_DC)
+{
+ int freeme;
+
+ if ((freeme = !s)) {
+ s = pemalloc(sizeof(*s), (flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT));
+ }
+ memset(s, 0, sizeof(*s));
+
+ s->flags = flags;
+ TSRMLS_SET_CTX(s->ts);
+
+ if ((s->ops = ops)) {
+ php_http_encoding_stream_t *ss = s->ops->init(s);
+
+ if (ss) {
+ return ss;
+ }
+ } else {
+ return s;
+ }
+
+ if (freeme) {
+ pefree(s, (flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT));
+ }
+ return NULL;
+}
+
+PHP_HTTP_API php_http_encoding_stream_t *php_http_encoding_stream_copy(php_http_encoding_stream_t *from, php_http_encoding_stream_t *to)
+{
+ TSRMLS_FETCH_FROM_CTX(from->ts);
+
+ if (!from->ops->copy) {
+ return NULL;
+ }
+
+ return from->ops->copy(from, php_http_encoding_stream_init(to, from->ops, from->flags TSRMLS_CC));
+}
+
+PHP_HTTP_API STATUS php_http_encoding_stream_reset(php_http_encoding_stream_t **s)
+{
+ php_http_encoding_stream_t *ss;
+ if ((*s)->ops->dtor) {
+ (*s)->ops->dtor(*s);
+ }
+ if ((ss = (*s)->ops->init(*s))) {
+ *s = ss;
+ return SUCCESS;
+ }
+ return FAILURE;
+}
+
+PHP_HTTP_API STATUS php_http_encoding_stream_update(php_http_encoding_stream_t *s, const char *in_str, size_t in_len, char **out_str, size_t *out_len)
+{
+ if (!s->ops->update) {
+ return FAILURE;
+ }
+ return s->ops->update(s, in_str, in_len, out_str, out_len);
+}
+
+PHP_HTTP_API STATUS php_http_encoding_stream_flush(php_http_encoding_stream_t *s, char **out_str, size_t *out_len)
+{
+ if (!s->ops->flush) {
+ return SUCCESS;
+ }
+ return s->ops->flush(s, out_str, out_len);
+}
+
+PHP_HTTP_API zend_bool php_http_encoding_stream_done(php_http_encoding_stream_t *s)
+{
+ if (!s->ops->done) {
+ return 0;
+ }
+ return s->ops->done(s);
+}
+
+PHP_HTTP_API STATUS php_http_encoding_stream_finish(php_http_encoding_stream_t *s, char **out_str, size_t *out_len)
+{
+ if (!s->ops->finish) {
+ return SUCCESS;
+ }
+ return s->ops->finish(s, out_str, out_len);
+}
+
+PHP_HTTP_API void php_http_encoding_stream_dtor(php_http_encoding_stream_t *s)
+{
+ if (s->ops->dtor) {
+ s->ops->dtor(s);
+ }
+}
+
+PHP_HTTP_API void php_http_encoding_stream_free(php_http_encoding_stream_t **s)
+{
+ if (*s) {
+ if ((*s)->ops->dtor) {
+ (*s)->ops->dtor(*s);
+ }
+ pefree(*s, ((*s)->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT));
+ *s = NULL;
+ }
+}
+
+struct dechunk_ctx {
+ php_http_buffer buffer;
+ ulong hexlen;
+ unsigned zeroed:1;
+};
+
+static php_http_encoding_stream_t *deflate_init(php_http_encoding_stream_t *s)
+{
+ int status, level, wbits, strategy, p = (s->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT);
+ z_streamp ctx = pecalloc(1, sizeof(z_stream), p);
+ TSRMLS_FETCH_FROM_CTX(s->ts);
+
+ PHP_HTTP_DEFLATE_LEVEL_SET(s->flags, level);
+ PHP_HTTP_DEFLATE_WBITS_SET(s->flags, wbits);
+ PHP_HTTP_DEFLATE_STRATEGY_SET(s->flags, strategy);
+
+ if (Z_OK == (status = deflateInit2(ctx, level, Z_DEFLATED, wbits, MAX_MEM_LEVEL, strategy))) {
+ if ((ctx->opaque = php_http_buffer_init_ex(NULL, PHP_HTTP_DEFLATE_BUFFER_SIZE, p ? PHP_HTTP_BUFFER_INIT_PERSISTENT : 0))) {
+ s->ctx = ctx;
+ return s;
+ }
+ deflateEnd(ctx);
+ status = Z_MEM_ERROR;
+ }
+ pefree(ctx, p);
+ php_http_error(HE_WARNING, PHP_HTTP_E_ENCODING, "Failed to initialize deflate encoding stream: %s", zError(status));
+ return NULL;
+}
+
+static php_http_encoding_stream_t *inflate_init(php_http_encoding_stream_t *s)
+{
+ int status, wbits, p = (s->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT);
+ z_streamp ctx = pecalloc(1, sizeof(z_stream), p);
+ TSRMLS_FETCH_FROM_CTX(s->ts);
+
+ PHP_HTTP_INFLATE_WBITS_SET(s->flags, wbits);
+
+ if (Z_OK == (status = inflateInit2(ctx, wbits))) {
+ if ((ctx->opaque = php_http_buffer_init_ex(NULL, PHP_HTTP_DEFLATE_BUFFER_SIZE, p ? PHP_HTTP_BUFFER_INIT_PERSISTENT : 0))) {
+ s->ctx = ctx;
+ return s;
+ }
+ inflateEnd(ctx);
+ status = Z_MEM_ERROR;
+ }
+ pefree(ctx, p);
+ php_http_error(HE_WARNING, PHP_HTTP_E_ENCODING, "Failed to initialize inflate stream: %s", zError(status));
+ return NULL;
+}
+
+static php_http_encoding_stream_t *dechunk_init(php_http_encoding_stream_t *s)
+{
+ struct dechunk_ctx *ctx = pecalloc(1, sizeof(*ctx), (s->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT));
+ TSRMLS_FETCH_FROM_CTX(s->ts);
+
+ if (!php_http_buffer_init_ex(&ctx->buffer, PHP_HTTP_BUFFER_DEFAULT_SIZE, (s->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT) ? PHP_HTTP_BUFFER_INIT_PERSISTENT : 0)) {
+ return NULL;
+ }
+
+ ctx->hexlen = 0;
+ ctx->zeroed = 0;
+ s->ctx = ctx;
+
+ return s;
+}
+
+static php_http_encoding_stream_t *deflate_copy(php_http_encoding_stream_t *from, php_http_encoding_stream_t *to)
+{
+ z_streamp from_ctx = from->ctx, to_ctx = to->ctx;
+
+ deflateCopy(to_ctx, from_ctx);
+ php_http_buffer_append(to_ctx->opaque, PHP_HTTP_BUFFER_VAL(from_ctx->opaque), PHP_HTTP_BUFFER_LEN(from_ctx->opaque));
+
+ return to;
+}
+
+static php_http_encoding_stream_t *inflate_copy(php_http_encoding_stream_t *from, php_http_encoding_stream_t *to)
+{
+ z_streamp from_ctx = from->ctx, to_ctx = to->ctx;
+
+ inflateCopy(to_ctx, from_ctx);
+ php_http_buffer_append(to_ctx->opaque, PHP_HTTP_BUFFER_VAL(from_ctx->opaque), PHP_HTTP_BUFFER_LEN(from_ctx->opaque));
+
+ return to;
+}
+
+static php_http_encoding_stream_t *dechunk_copy(php_http_encoding_stream_t *from, php_http_encoding_stream_t *to)
+{
+ struct dechunk_ctx *from_ctx = from->ctx, *to_ctx = to->ctx;
+
+ to_ctx->hexlen = from_ctx->hexlen;
+ to_ctx->zeroed = from_ctx->zeroed;
+ php_http_buffer_append(&to_ctx->buffer, PHP_HTTP_BUFFER_VAL(&from_ctx->buffer), PHP_HTTP_BUFFER_LEN(&from_ctx->buffer));
+
+ return to;
+}
+
+static STATUS deflate_update(php_http_encoding_stream_t *s, const char *data, size_t data_len, char **encoded, size_t *encoded_len)
+{
+ int status;
+ z_streamp ctx = s->ctx;
+ TSRMLS_FETCH_FROM_CTX(s->ts);
+
+ /* append input to our buffer */
+ php_http_buffer_append(PHP_HTTP_BUFFER(ctx->opaque), data, data_len);
+
+ ctx->next_in = (Bytef *) PHP_HTTP_BUFFER_VAL(ctx->opaque);
+ ctx->avail_in = PHP_HTTP_BUFFER_LEN(ctx->opaque);
+
+ /* deflate */
+ *encoded_len = PHP_HTTP_DEFLATE_BUFFER_SIZE_GUESS(data_len);
+ *encoded = emalloc(*encoded_len);
+ ctx->avail_out = *encoded_len;
+ ctx->next_out = (Bytef *) *encoded;
+
+ switch (status = deflate(ctx, PHP_HTTP_ENCODING_STREAM_FLUSH_FLAG(s->flags))) {
+ case Z_OK:
+ case Z_STREAM_END:
+ /* cut processed chunk off the buffer */
+ if (ctx->avail_in) {
+ php_http_buffer_cut(PHP_HTTP_BUFFER(ctx->opaque), 0, PHP_HTTP_BUFFER_LEN(ctx->opaque) - ctx->avail_in);
+ } else {
+ php_http_buffer_reset(PHP_HTTP_BUFFER(ctx->opaque));
+ }
+
+ /* size buffer down to actual size */
+ *encoded_len -= ctx->avail_out;
+ *encoded = erealloc(*encoded, *encoded_len + 1);
+ (*encoded)[*encoded_len] = '\0';
+ return SUCCESS;
+ }
+
+ STR_SET(*encoded, NULL);
+ *encoded_len = 0;
+ php_http_error(HE_WARNING, PHP_HTTP_E_ENCODING, "Failed to update deflate stream: %s", zError(status));
+ return FAILURE;
+}
+
+static STATUS inflate_update(php_http_encoding_stream_t *s, const char *data, size_t data_len, char **decoded, size_t *decoded_len)
+{
+ int status;
+ z_streamp ctx = s->ctx;
+ TSRMLS_FETCH_FROM_CTX(s->ts);
+
+ /* append input to buffer */
+ php_http_buffer_append(PHP_HTTP_BUFFER(ctx->opaque), data, data_len);
+
+retry_raw_inflate:
+ ctx->next_in = (Bytef *) PHP_HTTP_BUFFER_VAL(ctx->opaque);
+ ctx->avail_in = PHP_HTTP_BUFFER_LEN(ctx->opaque);
+
+ switch (status = php_http_inflate_rounds(ctx, PHP_HTTP_ENCODING_STREAM_FLUSH_FLAG(s->flags), decoded, decoded_len)) {
+ case Z_OK:
+ case Z_STREAM_END:
+ /* cut off */
+ if (ctx->avail_in) {
+ php_http_buffer_cut(PHP_HTTP_BUFFER(ctx->opaque), 0, PHP_HTTP_BUFFER_LEN(ctx->opaque) - ctx->avail_in);
+ } else {
+ php_http_buffer_reset(PHP_HTTP_BUFFER(ctx->opaque));
+ }
+ return SUCCESS;
+
+ case Z_DATA_ERROR:
+ /* raw deflated data ? */
+ if (!(s->flags & PHP_HTTP_INFLATE_TYPE_RAW) && !ctx->total_out) {
+ inflateEnd(ctx);
+ s->flags |= PHP_HTTP_INFLATE_TYPE_RAW;
+ inflateInit2(ctx, PHP_HTTP_WINDOW_BITS_RAW);
+ goto retry_raw_inflate;
+ }
+ }
+
+ php_http_error(HE_WARNING, PHP_HTTP_E_ENCODING, "Failed to update inflate stream: %s", zError(status));
+ return FAILURE;
+}
+
+static STATUS dechunk_update(php_http_encoding_stream_t *s, const char *data, size_t data_len, char **decoded, size_t *decoded_len)
+{
+ php_http_buffer tmp;
+ struct dechunk_ctx *ctx = s->ctx;
+ TSRMLS_FETCH_FROM_CTX(s->ts);
+
+ if (ctx->zeroed) {
+ return FAILURE;
+ }
+ if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_append(&ctx->buffer, data, data_len)) {
+ return FAILURE;
+ }
+ if (!php_http_buffer_fix(&ctx->buffer)) {
+ return FAILURE;
+ }
+
+ *decoded = NULL;
+ *decoded_len = 0;
+
+ php_http_buffer_init(&tmp);
+
+ /* we have data in our buffer */
+ while (PHP_HTTP_BUFFER_LEN(&ctx->buffer)) {
+
+ /* we already know the size of the chunk and are waiting for data */
+ if (ctx->hexlen) {
+
+ /* not enough data buffered */
+ if (PHP_HTTP_BUFFER_LEN(&ctx->buffer) < ctx->hexlen) {
+
+ /* flush anyway? */
+ if (s->flags & PHP_HTTP_ENCODING_STREAM_FLUSH_FULL) {
+ /* flush all data (should only be chunk data) */
+ php_http_buffer_append(&tmp, PHP_HTTP_BUFFER_VAL(&ctx->buffer), PHP_HTTP_BUFFER_LEN(&ctx->buffer));
+ /* waiting for less data now */
+ ctx->hexlen -= PHP_HTTP_BUFFER_LEN(&ctx->buffer);
+ /* no more buffered data */
+ php_http_buffer_reset(&ctx->buffer);
+ /* break */
+ }
+
+ /* we have too less data and don't need to flush */
+ else {
+ break;
+ }
+ }
+
+ /* we seem to have all data of the chunk */
+ else {
+ php_http_buffer_append(&tmp, PHP_HTTP_BUFFER_VAL(&ctx->buffer), ctx->hexlen);
+ /* remove outgoing data from the buffer */
+ php_http_buffer_cut(PHP_HTTP_BUFFER(&ctx->buffer), 0, ctx->hexlen);
+ /* reset hexlen */
+ ctx->hexlen = 0;
+ /* continue */
+ }
+ }
+
+ /* we don't know the length of the chunk yet */
+ else {
+ size_t off = 0;
+
+ /* ignore preceeding CRLFs (too loose?) */
+ while (off < PHP_HTTP_BUFFER_LEN(&ctx->buffer) && (
+ PHP_HTTP_BUFFER_VAL(&ctx->buffer)[off] == '\n' ||
+ PHP_HTTP_BUFFER_VAL(&ctx->buffer)[off] == '\r')) {
+ ++off;
+ }
+ if (off) {
+ php_http_buffer_cut(PHP_HTTP_BUFFER(&ctx->buffer), 0, off);
+ }
+
+ /* still data there? */
+ if (PHP_HTTP_BUFFER_LEN(&ctx->buffer)) {
+ int eollen;
+ const char *eolstr;
+
+ /* we need eol, so we can be sure we have all hex digits */
+ php_http_buffer_fix(&ctx->buffer);
+ if ((eolstr = php_http_locate_bin_eol(PHP_HTTP_BUFFER_VAL(&ctx->buffer), PHP_HTTP_BUFFER_LEN(&ctx->buffer), &eollen))) {
+ char *stop = NULL;
+
+ /* read in chunk size */
+ ctx->hexlen = strtoul(PHP_HTTP_BUFFER_VAL(&ctx->buffer), &stop, 16);
+
+ /* if strtoul() stops at the beginning of the buffered data
+ there's domething oddly wrong, i.e. bad input */
+ if (stop == PHP_HTTP_BUFFER_VAL(&ctx->buffer)) {
+ php_http_buffer_dtor(&tmp);
+ return FAILURE;
+ }
+
+ /* cut out <chunk size hex><chunk extension><eol> */
+ php_http_buffer_cut(PHP_HTTP_BUFFER(&ctx->buffer), 0, eolstr + eollen - PHP_HTTP_BUFFER_VAL(&ctx->buffer));
+ /* buffer->hexlen is 0 now or contains the size of the next chunk */
+ if (!ctx->hexlen) {
+ size_t off = 0;
+
+ /* ignore following CRLFs (too loose?) */
+ while (off < PHP_HTTP_BUFFER_LEN(&ctx->buffer) && (
+ PHP_HTTP_BUFFER_VAL(&ctx->buffer)[off] == '\n' ||
+ PHP_HTTP_BUFFER_VAL(&ctx->buffer)[off] == '\r')) {
+ ++off;
+ }
+ if (off) {
+ php_http_buffer_cut(PHP_HTTP_BUFFER(&ctx->buffer), 0, off);
+ }
+
+ ctx->zeroed = 1;
+ break;
+ }
+ /* continue */
+ } else {
+ /* we have not enough data buffered to read in chunk size */
+ break;
+ }
+ }
+ /* break */
+ }
+ }
+
+ php_http_buffer_fix(&tmp);
+ *decoded = PHP_HTTP_BUFFER_VAL(&tmp);
+ *decoded_len = PHP_HTTP_BUFFER_LEN(&tmp);
+
+ return SUCCESS;
+}
+
+static STATUS deflate_flush(php_http_encoding_stream_t *s, char **encoded, size_t *encoded_len)
+{
+ int status;
+ z_streamp ctx = s->ctx;
+ TSRMLS_FETCH_FROM_CTX(s->ts);
+
+ *encoded_len = PHP_HTTP_DEFLATE_BUFFER_SIZE;
+ *encoded = emalloc(*encoded_len);
+
+ ctx->avail_in = 0;
+ ctx->next_in = NULL;
+ ctx->avail_out = *encoded_len;
+ ctx->next_out = (Bytef *) *encoded;
+
+ switch (status = deflate(ctx, Z_FULL_FLUSH)) {
+ case Z_OK:
+ case Z_STREAM_END:
+ *encoded_len = PHP_HTTP_DEFLATE_BUFFER_SIZE - ctx->avail_out;
+ *encoded = erealloc(*encoded, *encoded_len + 1);
+ (*encoded)[*encoded_len] = '\0';
+ return SUCCESS;
+ }
+
+ STR_SET(*encoded, NULL);
+ *encoded_len = 0;
+ php_http_error(HE_WARNING, PHP_HTTP_E_ENCODING, "Failed to flush deflate stream: %s", zError(status));
+ return FAILURE;
+}
+
+static STATUS dechunk_flush(php_http_encoding_stream_t *s, char **decoded, size_t *decoded_len)
+{
+ struct dechunk_ctx *ctx = s->ctx;
+
+ if (ctx->hexlen) {
+ /* flush all data (should only be chunk data) */
+ php_http_buffer_fix(&ctx->buffer);
+ php_http_buffer_data(&ctx->buffer, decoded, decoded_len);
+ /* waiting for less data now */
+ ctx->hexlen -= PHP_HTTP_BUFFER_LEN(&ctx->buffer);
+ /* no more buffered data */
+ php_http_buffer_reset(&ctx->buffer);
+ } else {
+ *decoded = NULL;
+ *decoded_len = 0;
+ }
+
+ return SUCCESS;
+}
+
+static STATUS deflate_finish(php_http_encoding_stream_t *s, char **encoded, size_t *encoded_len)
+{
+ int status;
+ z_streamp ctx = s->ctx;
+ TSRMLS_FETCH_FROM_CTX(s->ts);
+
+ *encoded_len = PHP_HTTP_DEFLATE_BUFFER_SIZE;
+ *encoded = emalloc(*encoded_len);
+
+ /* deflate remaining input */
+ ctx->next_in = (Bytef *) PHP_HTTP_BUFFER_VAL(ctx->opaque);
+ ctx->avail_in = PHP_HTTP_BUFFER_LEN(ctx->opaque);
+
+ ctx->avail_out = *encoded_len;
+ ctx->next_out = (Bytef *) *encoded;
+
+ do {
+ status = deflate(ctx, Z_FINISH);
+ } while (Z_OK == status);
+
+ if (Z_STREAM_END == status) {
+ /* cut processed intp off */
+ php_http_buffer_cut(PHP_HTTP_BUFFER(ctx->opaque), 0, PHP_HTTP_BUFFER_LEN(ctx->opaque) - ctx->avail_in);
+
+ /* size down */
+ *encoded_len -= ctx->avail_out;
+ *encoded = erealloc(*encoded, *encoded_len + 1);
+ (*encoded)[*encoded_len] = '\0';
+ return SUCCESS;
+ }
+
+ STR_SET(*encoded, NULL);
+ *encoded_len = 0;
+ php_http_error(HE_WARNING, PHP_HTTP_E_ENCODING, "Failed to finish deflate stream: %s", zError(status));
+ return FAILURE;
+}
+
+static STATUS inflate_finish(php_http_encoding_stream_t *s, char **decoded, size_t *decoded_len)
+{
+ int status;
+ z_streamp ctx = s->ctx;
+ TSRMLS_FETCH_FROM_CTX(s->ts);
+
+ if (!PHP_HTTP_BUFFER_LEN(ctx->opaque)) {
+ *decoded = NULL;
+ *decoded_len = 0;
+ return SUCCESS;
+ }
+
+ *decoded_len = (PHP_HTTP_BUFFER_LEN(ctx->opaque) + 1) * PHP_HTTP_INFLATE_ROUNDS;
+ *decoded = emalloc(*decoded_len);
+
+ /* inflate remaining input */
+ ctx->next_in = (Bytef *) PHP_HTTP_BUFFER_VAL(ctx->opaque);
+ ctx->avail_in = PHP_HTTP_BUFFER_LEN(ctx->opaque);
+
+ ctx->avail_out = *decoded_len;
+ ctx->next_out = (Bytef *) *decoded;
+
+ if (Z_STREAM_END == (status = inflate(ctx, Z_FINISH))) {
+ /* cut processed input off */
+ php_http_buffer_cut(PHP_HTTP_BUFFER(ctx->opaque), 0, PHP_HTTP_BUFFER_LEN(ctx->opaque) - ctx->avail_in);
+
+ /* size down */
+ *decoded_len -= ctx->avail_out;
+ *decoded = erealloc(*decoded, *decoded_len + 1);
+ (*decoded)[*decoded_len] = '\0';
+ return SUCCESS;
+ }
+
+ STR_SET(*decoded, NULL);
+ *decoded_len = 0;
+ php_http_error(HE_WARNING, PHP_HTTP_E_ENCODING, "Failed to finish inflate stream: %s", zError(status));
+ return FAILURE;
+}
+
+static zend_bool deflate_done(php_http_encoding_stream_t *s)
+{
+ z_streamp ctx = s->ctx;
+ return !ctx->avail_in && !PHP_HTTP_BUFFER_LEN(ctx->opaque);
+}
+
+static zend_bool inflate_done(php_http_encoding_stream_t *s)
+{
+ z_streamp ctx = s->ctx;
+ return !ctx->avail_in && !PHP_HTTP_BUFFER_LEN(ctx->opaque);
+}
+
+static zend_bool dechunk_done(php_http_encoding_stream_t *s)
+{
+ return ((struct dechunk_ctx *) s->ctx)->zeroed;
+}
+
+static void deflate_dtor(php_http_encoding_stream_t *s)
+{
+ if (s->ctx) {
+ z_streamp ctx = s->ctx;
+
+ if (ctx->opaque) {
+ php_http_buffer_free((php_http_buffer **) &ctx->opaque);
+ }
+ deflateEnd(ctx);
+ pefree(ctx, (s->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT));
+ s->ctx = NULL;
+ }
+}
+
+static void inflate_dtor(php_http_encoding_stream_t *s)
+{
+ if (s->ctx) {
+ z_streamp ctx = s->ctx;
+
+ if (ctx->opaque) {
+ php_http_buffer_free((php_http_buffer **) &ctx->opaque);
+ }
+ inflateEnd(ctx);
+ pefree(ctx, (s->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT));
+ s->ctx = NULL;
+ }
+}
+
+static void dechunk_dtor(php_http_encoding_stream_t *s)
+{
+ if (s->ctx) {
+ struct dechunk_ctx *ctx = s->ctx;
+
+ php_http_buffer_dtor(&ctx->buffer);
+ pefree(ctx, (s->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT));
+ s->ctx = NULL;
+ }
+}
+
+static php_http_encoding_stream_ops_t php_http_encoding_deflate_ops = {
+ deflate_init,
+ deflate_copy,
+ deflate_update,
+ deflate_flush,
+ deflate_done,
+ deflate_finish,
+ deflate_dtor
+};
+
+PHP_HTTP_API php_http_encoding_stream_ops_t *php_http_encoding_stream_get_deflate_ops(void)
+{
+ return &php_http_encoding_deflate_ops;
+}
+
+static php_http_encoding_stream_ops_t php_http_encoding_inflate_ops = {
+ inflate_init,
+ inflate_copy,
+ inflate_update,
+ NULL,
+ inflate_done,
+ inflate_finish,
+ inflate_dtor
+};
+
+PHP_HTTP_API php_http_encoding_stream_ops_t *php_http_encoding_stream_get_inflate_ops(void)
+{
+ return &php_http_encoding_inflate_ops;
+}
+
+static php_http_encoding_stream_ops_t php_http_encoding_dechunk_ops = {
+ dechunk_init,
+ dechunk_copy,
+ dechunk_update,
+ dechunk_flush,
+ dechunk_done,
+ NULL,
+ dechunk_dtor
+};
+
+PHP_HTTP_API php_http_encoding_stream_ops_t *php_http_encoding_stream_get_dechunk_ops(void)
+{
+ return &php_http_encoding_dechunk_ops;
+}
+
+#define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpEncodingStream, method, 0, req_args)
+#define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpEncodingStream, method, 0)
+#define PHP_HTTP_ENCSTREAM_ME(method, visibility) PHP_ME(HttpEncodingStream, method, PHP_HTTP_ARGS(HttpEncodingStream, method), visibility)
+
+PHP_HTTP_BEGIN_ARGS(__construct, 0)
+ PHP_HTTP_ARG_VAL(flags, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(update, 1)
+ PHP_HTTP_ARG_VAL(data, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_EMPTY_ARGS(flush);
+PHP_HTTP_EMPTY_ARGS(done);
+PHP_HTTP_EMPTY_ARGS(finish);
+
+zend_class_entry *php_http_encoding_stream_class_entry;
+zend_function_entry php_http_encoding_stream_method_entry[] = {
+ PHP_HTTP_ENCSTREAM_ME(__construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
+ PHP_HTTP_ENCSTREAM_ME(update, ZEND_ACC_PUBLIC)
+ PHP_HTTP_ENCSTREAM_ME(flush, ZEND_ACC_PUBLIC)
+ PHP_HTTP_ENCSTREAM_ME(done, ZEND_ACC_PUBLIC)
+ PHP_HTTP_ENCSTREAM_ME(finish, ZEND_ACC_PUBLIC)
+
+ EMPTY_FUNCTION_ENTRY
+};
+static zend_object_handlers php_http_encoding_stream_object_handlers;
+
+zend_object_value php_http_encoding_stream_object_new(zend_class_entry *ce TSRMLS_DC)
+{
+ return php_http_encoding_stream_object_new_ex(ce, NULL, NULL TSRMLS_CC);
+}
+
+zend_object_value php_http_encoding_stream_object_new_ex(zend_class_entry *ce, php_http_encoding_stream_t *s, php_http_encoding_stream_object_t **ptr TSRMLS_DC)
+{
+ zend_object_value ov;
+ php_http_encoding_stream_object_t *o;
+
+ o = ecalloc(1, sizeof(*o));
+ zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
+ object_properties_init((zend_object *) o, ce);
+
+ if (ptr) {
+ *ptr = o;
+ }
+
+ if (s) {
+ o->stream = s;
+ }
+
+ ov.handle = zend_objects_store_put((zend_object *) o, NULL, php_http_encoding_stream_object_free, NULL TSRMLS_CC);
+ ov.handlers = &php_http_encoding_stream_object_handlers;
+
+ return ov;
+}
+
+zend_object_value php_http_encoding_stream_object_clone(zval *this_ptr TSRMLS_DC)
+{
+ zend_object_value new_ov;
+ php_http_encoding_stream_object_t *new_obj = NULL, *old_obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ new_ov = php_http_encoding_stream_object_new_ex(old_obj->zo.ce, php_http_encoding_stream_copy(old_obj->stream, NULL), &new_obj TSRMLS_CC);
+ zend_objects_clone_members(&new_obj->zo, new_ov, &old_obj->zo, Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC);
+
+ return new_ov;
+}
+
+void php_http_encoding_stream_object_free(void *object TSRMLS_DC)
+{
+ php_http_encoding_stream_object_t *o = (php_http_encoding_stream_object_t *) object;
+
+ if (o->stream) {
+ php_http_encoding_stream_free(&o->stream TSRMLS_CC);
+ }
+ zend_object_std_dtor((zend_object *) o TSRMLS_CC);
+ efree(o);
+}
+
+PHP_METHOD(HttpEncodingStream, __construct)
+{
+ with_error_handling(EH_THROW, PHP_HTTP_EX_CE(runtime)) {
+ long flags = 0;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &flags)) {
+ with_error_handling(EH_THROW, PHP_HTTP_EX_CE(encoding)) {
+ php_http_encoding_stream_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (!obj->stream) {
+ php_http_encoding_stream_ops_t *ops = NULL;
+
+ if (instanceof_function(obj->zo.ce, php_http_deflate_stream_class_entry TSRMLS_CC)) {
+ ops = &php_http_encoding_deflate_ops;
+ } else if (instanceof_function(obj->zo.ce, php_http_inflate_stream_class_entry TSRMLS_CC)) {
+ ops = &php_http_encoding_inflate_ops;
+ } else if (instanceof_function(obj->zo.ce, php_http_dechunk_stream_class_entry TSRMLS_CC)) {
+ ops = &php_http_encoding_dechunk_ops;
+ }
+
+ if (ops) {
+ obj->stream = php_http_encoding_stream_init(obj->stream, ops, flags TSRMLS_CC);
+ } else {
+ php_http_error(HE_WARNING, PHP_HTTP_E_ENCODING, "Unknown HttpEncodingStream class %s", obj->zo.ce->name);
+ }
+
+ } else {
+ php_http_error(HE_WARNING, PHP_HTTP_E_ENCODING, "HttpEncodingStream cannot be initialized twice");
+ }
+ } end_error_handling();
+ }
+ } end_error_handling();
+}
+
+PHP_METHOD(HttpEncodingStream, update)
+{
+ int data_len;
+ char *data_str;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data_str, &data_len)) {
+ php_http_encoding_stream_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (obj->stream) {
+ size_t encoded_len;
+ char *encoded_str;
+
+ if (SUCCESS == php_http_encoding_stream_update(obj->stream, data_str, data_len, &encoded_str, &encoded_len TSRMLS_CC)) {
+ RETURN_STRINGL(encoded_str, encoded_len, 0);
+ }
+ }
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpEncodingStream, flush)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ php_http_encoding_stream_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (obj->stream) {
+ char *encoded_str;
+ size_t encoded_len;
+
+ if (SUCCESS == php_http_encoding_stream_flush(obj->stream, &encoded_str, &encoded_len TSRMLS_CC)) {
+ RETURN_STRINGL(encoded_str, encoded_len, 0);
+ }
+ }
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpEncodingStream, done)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ php_http_encoding_stream_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (obj->stream) {
+ RETURN_BOOL(php_http_encoding_stream_done(obj->stream));
+ }
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpEncodingStream, finish)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ php_http_encoding_stream_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (obj->stream) {
+ char *encoded_str;
+ size_t encoded_len;
+
+ if (SUCCESS == php_http_encoding_stream_finish(obj->stream, &encoded_str, &encoded_len TSRMLS_CC)) {
+ if (SUCCESS == php_http_encoding_stream_reset(&obj->stream)) {
+ RETURN_STRINGL(encoded_str, encoded_len, 0);
+ } else {
+ STR_FREE(encoded_str);
+ }
+ }
+ }
+ }
+ RETURN_FALSE;
+}
+
+#undef PHP_HTTP_BEGIN_ARGS
+#undef PHP_HTTP_EMPTY_ARGS
+#define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpDeflateStream, method, 0, req_args)
+#define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpDeflateStream, method, 0)
+#define PHP_HTTP_DEFLATE_ME(method, visibility) PHP_ME(HttpDeflateStream, method, PHP_HTTP_ARGS(HttpDeflateStream, method), visibility)
+
+PHP_HTTP_BEGIN_ARGS(encode, 1)
+ PHP_HTTP_ARG_VAL(data, 0)
+ PHP_HTTP_ARG_VAL(flags, 0)
+PHP_HTTP_END_ARGS;
+
+zend_class_entry *php_http_deflate_stream_class_entry;
+zend_function_entry php_http_deflate_stream_method_entry[] = {
+ PHP_HTTP_DEFLATE_ME(encode, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
+
+ EMPTY_FUNCTION_ENTRY
+};
+
+PHP_METHOD(HttpDeflateStream, encode)
+{
+ char *str;
+ int len;
+ long flags = 0;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &str, &len, &flags)) {
+ char *enc_str;
+ size_t enc_len;
+
+ if (SUCCESS == php_http_encoding_deflate(flags, str, len, &enc_str, &enc_len TSRMLS_CC)) {
+ RETURN_STRINGL(enc_str, enc_len, 0);
+ }
+ }
+ RETURN_FALSE;
+}
+
+#undef PHP_HTTP_BEGIN_ARGS
+#undef PHP_HTTP_EMPTY_ARGS
+#define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpInflateStream, method, 0, req_args)
+#define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpInflateStream, method, 0)
+#define PHP_HTTP_INFLATE_ME(method, visibility) PHP_ME(HttpInflateStream, method, PHP_HTTP_ARGS(HttpInflateStream, method), visibility)
+
+PHP_HTTP_BEGIN_ARGS(decode, 1)
+ PHP_HTTP_ARG_VAL(data, 0)
+PHP_HTTP_END_ARGS;
+
+zend_class_entry *php_http_inflate_stream_class_entry;
+zend_function_entry php_http_inflate_stream_method_entry[] = {
+ PHP_HTTP_INFLATE_ME(decode, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
+
+ EMPTY_FUNCTION_ENTRY
+};
+
+PHP_METHOD(HttpInflateStream, decode)
+{
+ char *str;
+ int len;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len)) {
+ char *enc_str;
+ size_t enc_len;
+
+ if (SUCCESS == php_http_encoding_inflate(str, len, &enc_str, &enc_len TSRMLS_CC)) {
+ RETURN_STRINGL(enc_str, enc_len, 0);
+ }
+ }
+ RETURN_FALSE;
+}
+
+#undef PHP_HTTP_BEGIN_ARGS
+#undef PHP_HTTP_EMPTY_ARGS
+#define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpDechunkStream, method, 0, req_args)
+#define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpDechunkStream, method, 0)
+#define PHP_HTTP_DECHUNK_ME(method, visibility) PHP_ME(HttpDechunkStream, method, PHP_HTTP_ARGS(HttpDechunkStream, method), visibility)
+
+PHP_HTTP_BEGIN_ARGS(decode, 1)
+ PHP_HTTP_ARG_VAL(data, 0)
+ PHP_HTTP_ARG_VAL(decoded_len, 1)
+PHP_HTTP_END_ARGS;
+
+zend_class_entry *php_http_dechunk_stream_class_entry;
+zend_function_entry php_http_dechunk_stream_method_entry[] = {
+ PHP_HTTP_DECHUNK_ME(decode, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
+
+ EMPTY_FUNCTION_ENTRY
+};
+
+PHP_METHOD(HttpDechunkStream, decode)
+{
+ char *str;
+ int len;
+ zval *zlen;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z!", &str, &len, &zlen)) {
+ const char *end_ptr;
+ char *enc_str;
+ size_t enc_len;
+
+ if ((end_ptr = php_http_encoding_dechunk(str, len, &enc_str, &enc_len TSRMLS_CC))) {
+ if (zlen) {
+ zval_dtor(zlen);
+ ZVAL_LONG(zlen, str + len - end_ptr);
+ }
+ RETURN_STRINGL(enc_str, enc_len, 0);
+ }
+ }
+ RETURN_FALSE;
+}
+
+PHP_MINIT_FUNCTION(http_encoding)
+{
+ PHP_HTTP_REGISTER_CLASS(http\\encoding, Stream, http_encoding_stream, php_http_object_class_entry, ZEND_ACC_EXPLICIT_ABSTRACT_CLASS);
+ php_http_encoding_stream_class_entry->create_object = php_http_encoding_stream_object_new;
+ memcpy(&php_http_encoding_stream_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
+ php_http_encoding_stream_object_handlers.clone_obj = php_http_encoding_stream_object_clone;
+
+ zend_declare_class_constant_long(php_http_encoding_stream_class_entry, ZEND_STRL("FLUSH_NONE"), PHP_HTTP_ENCODING_STREAM_FLUSH_NONE TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_encoding_stream_class_entry, ZEND_STRL("FLUSH_SYNC"), PHP_HTTP_ENCODING_STREAM_FLUSH_SYNC TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_encoding_stream_class_entry, ZEND_STRL("FLUSH_FULL"), PHP_HTTP_ENCODING_STREAM_FLUSH_FULL TSRMLS_CC);
+
+ PHP_HTTP_REGISTER_CLASS(http\\encoding\\stream, Deflate, http_deflate_stream, php_http_encoding_stream_class_entry, 0);
+
+ zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("TYPE_GZIP"), PHP_HTTP_DEFLATE_TYPE_GZIP TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("TYPE_ZLIB"), PHP_HTTP_DEFLATE_TYPE_ZLIB TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("TYPE_RAW"), PHP_HTTP_DEFLATE_TYPE_RAW TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("LEVEL_DEF"), PHP_HTTP_DEFLATE_LEVEL_DEF TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("LEVEL_MIN"), PHP_HTTP_DEFLATE_LEVEL_MIN TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("LEVEL_MAX"), PHP_HTTP_DEFLATE_LEVEL_MAX TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("STRATEGY_DEF"), PHP_HTTP_DEFLATE_STRATEGY_DEF TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("STRATEGY_FILT"), PHP_HTTP_DEFLATE_STRATEGY_FILT TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("STRATEGY_HUFF"), PHP_HTTP_DEFLATE_STRATEGY_HUFF TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("STRATEGY_RLE"), PHP_HTTP_DEFLATE_STRATEGY_RLE TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("STRATEGY_FIXED"), PHP_HTTP_DEFLATE_STRATEGY_FIXED TSRMLS_CC);
+
+ PHP_HTTP_REGISTER_CLASS(http\\encoding\\stream, Inflate, http_inflate_stream, php_http_encoding_stream_class_entry, 0);
+ PHP_HTTP_REGISTER_CLASS(http\\encoding\\stream, Dechunk, http_dechunk_stream, php_http_encoding_stream_class_entry, 0);
+
+ return SUCCESS;
+}
+
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
+
--- /dev/null
+/*
+ +--------------------------------------------------------------------+
+ | PECL :: http |
+ +--------------------------------------------------------------------+
+ | Redistribution and use in source and binary forms, with or without |
+ | modification, are permitted provided that the conditions mentioned |
+ | in the accompanying LICENSE file are met. |
+ +--------------------------------------------------------------------+
+ | Copyright (c) 2004-2010, Michael Wallner <mike@php.net> |
+ +--------------------------------------------------------------------+
+*/
+
+/* $Id: php_http_encoding_api.h 292841 2009-12-31 08:48:57Z mike $ */
+
+#ifndef PHP_HTTP_ENCODING_H
+#define PHP_HTTP_ENCODING_H
+
+PHP_HTTP_API int php_http_encoding_response_start(size_t content_length, zend_bool ignore_http_ohandler TSRMLS_DC);
+
+extern PHP_MINIT_FUNCTION(http_encoding);
+extern PHP_RINIT_FUNCTION(http_encoding);
+extern PHP_RSHUTDOWN_FUNCTION(http_encoding);
+
+typedef enum php_http_encoding_type {
+ PHP_HTTP_ENCODING_NONE,
+ PHP_HTTP_ENCODING_GZIP,
+ PHP_HTTP_ENCODING_DEFLATE,
+} php_http_encoding_type_t;
+
+#define PHP_HTTP_INFLATE_ROUNDS 100
+
+#define PHP_HTTP_DEFLATE_BUFFER_SIZE_GUESS(S) \
+ (((size_t) ((double) S * (double) 1.015)) + 10 + 8 + 4 + 1)
+#define PHP_HTTP_INFLATE_BUFFER_SIZE_GUESS(S) \
+ (((S) + 1) << 3)
+#define PHP_HTTP_INFLATE_BUFFER_SIZE_ALIGN(S) \
+ ((S) += (S) >> (3))
+
+#define PHP_HTTP_DEFLATE_BUFFER_SIZE 0x8000
+#define PHP_HTTP_INFLATE_BUFFER_SIZE 0x1000
+
+#define PHP_HTTP_DEFLATE_LEVEL_DEF 0x00000000
+#define PHP_HTTP_DEFLATE_LEVEL_MIN 0x00000001
+#define PHP_HTTP_DEFLATE_LEVEL_MAX 0x00000009
+#define PHP_HTTP_DEFLATE_TYPE_ZLIB 0x00000000
+#define PHP_HTTP_DEFLATE_TYPE_GZIP 0x00000010
+#define PHP_HTTP_DEFLATE_TYPE_RAW 0x00000020
+#define PHP_HTTP_DEFLATE_STRATEGY_DEF 0x00000000
+#define PHP_HTTP_DEFLATE_STRATEGY_FILT 0x00000100
+#define PHP_HTTP_DEFLATE_STRATEGY_HUFF 0x00000200
+#define PHP_HTTP_DEFLATE_STRATEGY_RLE 0x00000300
+#define PHP_HTTP_DEFLATE_STRATEGY_FIXED 0x00000400
+
+#define PHP_HTTP_DEFLATE_LEVEL_SET(flags, level) \
+ switch (flags & 0xf) \
+ { \
+ default: \
+ if ((flags & 0xf) < 10) { \
+ level = flags & 0xf; \
+ break; \
+ } \
+ case PHP_HTTP_DEFLATE_LEVEL_DEF: \
+ level = Z_DEFAULT_COMPRESSION; \
+ break; \
+ }
+
+#define PHP_HTTP_DEFLATE_WBITS_SET(flags, wbits) \
+ switch (flags & 0xf0) \
+ { \
+ case PHP_HTTP_DEFLATE_TYPE_GZIP: \
+ wbits = PHP_HTTP_WINDOW_BITS_GZIP; \
+ break; \
+ case PHP_HTTP_DEFLATE_TYPE_RAW: \
+ wbits = PHP_HTTP_WINDOW_BITS_RAW; \
+ break; \
+ default: \
+ wbits = PHP_HTTP_WINDOW_BITS_ZLIB; \
+ break; \
+ }
+
+#define PHP_HTTP_INFLATE_WBITS_SET(flags, wbits) \
+ if (flags & PHP_HTTP_INFLATE_TYPE_RAW) { \
+ wbits = PHP_HTTP_WINDOW_BITS_RAW; \
+} else { \
+ wbits = PHP_HTTP_WINDOW_BITS_ANY; \
+}
+
+#define PHP_HTTP_DEFLATE_STRATEGY_SET(flags, strategy) \
+ switch (flags & 0xf00) \
+ { \
+ case PHP_HTTP_DEFLATE_STRATEGY_FILT: \
+ strategy = Z_FILTERED; \
+ break; \
+ case PHP_HTTP_DEFLATE_STRATEGY_HUFF: \
+ strategy = Z_HUFFMAN_ONLY; \
+ break; \
+ case PHP_HTTP_DEFLATE_STRATEGY_RLE: \
+ strategy = Z_RLE; \
+ break; \
+ case PHP_HTTP_DEFLATE_STRATEGY_FIXED: \
+ strategy = Z_FIXED; \
+ break; \
+ default: \
+ strategy = Z_DEFAULT_STRATEGY; \
+ break; \
+ }
+
+#define PHP_HTTP_WINDOW_BITS_ZLIB 0x0000000f
+#define PHP_HTTP_WINDOW_BITS_GZIP 0x0000001f
+#define PHP_HTTP_WINDOW_BITS_ANY 0x0000002f
+#define PHP_HTTP_WINDOW_BITS_RAW -0x000000f
+
+#ifndef Z_FIXED
+/* Z_FIXED does not exist prior 1.2.2.2 */
+# define Z_FIXED 0
+#endif
+
+#define PHP_HTTP_INFLATE_TYPE_ZLIB 0x00000000
+#define PHP_HTTP_INFLATE_TYPE_GZIP 0x00000000
+#define PHP_HTTP_INFLATE_TYPE_RAW 0x00000001
+
+#define PHP_HTTP_ENCODING_STREAM_FLUSH_NONE 0x00000000
+#define PHP_HTTP_ENCODING_STREAM_FLUSH_SYNC 0x00100000
+#define PHP_HTTP_ENCODING_STREAM_FLUSH_FULL 0x00200000
+
+#define PHP_HTTP_ENCODING_STREAM_FLUSH_FLAG(f) \
+ (((f) & PHP_HTTP_ENCODING_STREAM_FLUSH_FULL) ? Z_FULL_FLUSH : \
+ (((f) & PHP_HTTP_ENCODING_STREAM_FLUSH_SYNC) ? Z_SYNC_FLUSH : Z_NO_FLUSH))
+
+#define PHP_HTTP_ENCODING_STREAM_PERSISTENT 0x01000000
+
+typedef struct php_http_encoding_stream php_http_encoding_stream_t;
+
+typedef php_http_encoding_stream_t *(*php_http_encoding_stream_init_func_t)(php_http_encoding_stream_t *s);
+typedef php_http_encoding_stream_t *(*php_http_encoding_stream_copy_func_t)(php_http_encoding_stream_t *from, php_http_encoding_stream_t *to);
+typedef STATUS (*php_http_encoding_stream_update_func_t)(php_http_encoding_stream_t *s, const char *in_str, size_t in_len, char **out_str, size_t *out_len);
+typedef STATUS (*php_http_encoding_stream_flush_func_t)(php_http_encoding_stream_t *s, char **out_str, size_t *out_len);
+typedef zend_bool (*php_http_encoding_stream_done_func_t)(php_http_encoding_stream_t *s);
+typedef STATUS (*php_http_encoding_stream_finish_func_t)(php_http_encoding_stream_t *s, char **out_str, size_t *out_len);
+typedef void (*php_http_encoding_stream_dtor_func_t)(php_http_encoding_stream_t *s);
+
+typedef struct php_http_encoding_stream_ops {
+ php_http_encoding_stream_init_func_t init;
+ php_http_encoding_stream_copy_func_t copy;
+ php_http_encoding_stream_update_func_t update;
+ php_http_encoding_stream_flush_func_t flush;
+ php_http_encoding_stream_done_func_t done;
+ php_http_encoding_stream_finish_func_t finish;
+ php_http_encoding_stream_dtor_func_t dtor;
+} php_http_encoding_stream_ops_t;
+
+struct php_http_encoding_stream {
+ unsigned flags;
+ void *ctx;
+ php_http_encoding_stream_ops_t *ops;
+#ifdef ZTS
+ void ***ts;
+#endif
+};
+
+extern php_http_encoding_stream_ops_t *php_http_encoding_stream_get_deflate_ops(void);
+extern php_http_encoding_stream_ops_t *php_http_encoding_stream_get_inflate_ops(void);
+extern php_http_encoding_stream_ops_t *php_http_encoding_stream_get_dechunk_ops(void);
+
+PHP_HTTP_API php_http_encoding_stream_t *php_http_encoding_stream_init(php_http_encoding_stream_t *s, php_http_encoding_stream_ops_t *ops, unsigned flags TSRMLS_DC);
+PHP_HTTP_API php_http_encoding_stream_t *php_http_encoding_stream_copy(php_http_encoding_stream_t *from, php_http_encoding_stream_t *to);
+PHP_HTTP_API STATUS php_http_encoding_stream_reset(php_http_encoding_stream_t **s);
+PHP_HTTP_API STATUS php_http_encoding_stream_update(php_http_encoding_stream_t *s, const char *in_str, size_t in_len, char **out_str, size_t *out_len);
+PHP_HTTP_API STATUS php_http_encoding_stream_flush(php_http_encoding_stream_t *s, char **out_str, size_t *len);
+PHP_HTTP_API zend_bool php_http_encoding_stream_done(php_http_encoding_stream_t *s);
+PHP_HTTP_API STATUS php_http_encoding_stream_finish(php_http_encoding_stream_t *s, char **out_str, size_t *len);
+PHP_HTTP_API void php_http_encoding_stream_dtor(php_http_encoding_stream_t *s);
+PHP_HTTP_API void php_http_encoding_stream_free(php_http_encoding_stream_t **s);
+
+PHP_HTTP_API const char *php_http_encoding_dechunk(const char *encoded, size_t encoded_len, char **decoded, size_t *decoded_len TSRMLS_DC);
+PHP_HTTP_API STATUS php_http_encoding_deflate(int flags, const char *data, size_t data_len, char **encoded, size_t *encoded_len TSRMLS_DC);
+PHP_HTTP_API STATUS php_http_encoding_inflate(const char *data, size_t data_len, char **decoded, size_t *decoded_len TSRMLS_DC);
+
+typedef struct php_http_encoding_stream_object {
+ zend_object zo;
+ php_http_encoding_stream_t *stream;
+} php_http_encoding_stream_object_t;
+
+extern zend_class_entry *php_http_encoding_stream_class_entry;
+extern zend_function_entry php_http_encoding_stream_method_entry[];
+
+extern zend_object_value php_http_encoding_stream_object_new(zend_class_entry *ce TSRMLS_DC);
+extern zend_object_value php_http_encoding_stream_object_new_ex(zend_class_entry *ce, php_http_encoding_stream_t *s, php_http_encoding_stream_object_t **ptr TSRMLS_DC);
+extern zend_object_value php_http_encoding_stream_object_clone(zval *object TSRMLS_DC);
+extern void php_http_encoding_stream_object_free(void *object TSRMLS_DC);
+
+extern zend_class_entry *php_http_deflate_stream_class_entry;
+extern zend_function_entry php_http_deflate_stream_method_entry[];
+extern zend_class_entry *php_http_inflate_stream_class_entry;
+extern zend_function_entry php_http_inflate_stream_method_entry[];
+extern zend_class_entry *php_http_dechunk_stream_class_entry;
+extern zend_function_entry php_http_dechunk_stream_method_entry[];
+
+PHP_METHOD(HttpEncodingStream, __construct);
+PHP_METHOD(HttpEncodingStream, update);
+PHP_METHOD(HttpEncodingStream, flush);
+PHP_METHOD(HttpEncodingStream, done);
+PHP_METHOD(HttpEncodingStream, finish);
+
+PHP_METHOD(HttpDeflateStream, encode);
+PHP_METHOD(HttpInflateStream, decode);
+PHP_METHOD(HttpDechunkStream, decode);
+
+/*
+typedef struct php_http_inflatestream_object {
+ zend_object zo;
+ php_http_encoding_stream_t *stream;
+} php_http_inflatestream_object_t;
+
+extern zend_class_entry *php_http_inflatestream_class_entry;
+extern zend_function_entry php_http_inflatestream_method_entry[];
+
+extern zend_object_value php_http_inflatestream_object_new(zend_class_entry *ce TSRMLS_DC);
+extern zend_object_value php_http_inflatestream_object_new_ex(zend_class_entry *ce, php_http_encoding_stream_t *s, php_http_inflatestream_object_t **ptr TSRMLS_DC);
+extern zend_object_value php_http_inflatestream_object_clone(zval *object TSRMLS_DC);
+extern void php_http_inflatestream_object_free(void *object TSRMLS_DC);
+
+PHP_METHOD(HttpInflateStream, __construct);
+PHP_METHOD(HttpInflateStream, factory);
+PHP_METHOD(HttpInflateStream, update);
+PHP_METHOD(HttpInflateStream, flush);
+PHP_METHOD(HttpInflateStream, finish);
+*/
+#endif
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
--- /dev/null
+/*
+ +--------------------------------------------------------------------+
+ | PECL :: http |
+ +--------------------------------------------------------------------+
+ | Redistribution and use in source and binary forms, with or without |
+ | modification, are permitted provided that the conditions mentioned |
+ | in the accompanying LICENSE file are met. |
+ +--------------------------------------------------------------------+
+ | Copyright (c) 2004-2010, Michael Wallner <mike@php.net> |
+ +--------------------------------------------------------------------+
+*/
+
+/* $Id $ */
+
+#include "php_http.h"
+
+PHP_RINIT_FUNCTION(http_env)
+{
+ PHP_HTTP_G->env.response.last_modified = 0;
+ PHP_HTTP_G->env.response.throttle_chunk = 0;
+ PHP_HTTP_G->env.response.throttle_delay = 0;
+ PHP_HTTP_G->env.request.time = sapi_get_request_time(TSRMLS_C);
+
+ return SUCCESS;
+}
+
+PHP_RSHUTDOWN_FUNCTION(http_env)
+{
+ if (PHP_HTTP_G->env.request.headers) {
+ zend_hash_destroy(PHP_HTTP_G->env.request.headers);
+ FREE_HASHTABLE(PHP_HTTP_G->env.request.headers);
+ PHP_HTTP_G->env.request.headers = NULL;
+ }
+ if (PHP_HTTP_G->env.request.body) {
+ php_http_message_body_free(&PHP_HTTP_G->env.request.body);
+ }
+ if (PHP_HTTP_G->env.response.body) {
+ php_http_message_body_free(&PHP_HTTP_G->env.response.body);
+ }
+ STR_SET(PHP_HTTP_G->env.response.content_type, NULL);
+ STR_SET(PHP_HTTP_G->env.response.etag, NULL);
+
+ if (PHP_HTTP_G->env.server_var) {
+ zval_ptr_dtor(&PHP_HTTP_G->env.server_var);
+ PHP_HTTP_G->env.server_var = NULL;
+ }
+
+ return SUCCESS;
+}
+
+PHP_HTTP_API void php_http_env_get_request_headers(HashTable *headers TSRMLS_DC)
+{
+ php_http_array_hashkey_t key = php_http_array_hashkey_init(0);
+ zval **hsv, **header;
+ HashPosition pos;
+
+ if (!PHP_HTTP_G->env.request.headers) {
+ ALLOC_HASHTABLE(PHP_HTTP_G->env.request.headers);
+ zend_hash_init(PHP_HTTP_G->env.request.headers, 0, NULL, ZVAL_PTR_DTOR, 0);
+
+ zend_is_auto_global("_SERVER", lenof("_SERVER") TSRMLS_CC);
+
+ if (SUCCESS == zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void *) &hsv) && Z_TYPE_PP(hsv) == IS_ARRAY) {
+ FOREACH_KEY(pos, *hsv, key) {
+ if (key.type == HASH_KEY_IS_STRING && key.len > 6 && !strncmp(key.str, "HTTP_", 5)) {
+ key.len -= 5;
+ key.str = php_http_pretty_key(estrndup(key.str + 5, key.len - 1), key.len - 1, 1, 1);
+
+ zend_hash_get_current_data_ex(Z_ARRVAL_PP(hsv), (void *) &header, &pos);
+ Z_ADDREF_P(*header);
+ zend_hash_add(PHP_HTTP_G->env.request.headers, key.str, key.len, (void *) header, sizeof(zval *), NULL);
+
+ efree(key.str);
+ }
+ }
+ }
+ }
+
+ if (headers) {
+ zend_hash_copy(headers, PHP_HTTP_G->env.request.headers, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
+ }
+}
+
+PHP_HTTP_API char *php_http_env_get_request_header(const char *name_str, size_t name_len TSRMLS_DC)
+{
+ zval **zvalue;
+ char *val = NULL, *key = php_http_pretty_key(estrndup(name_str, name_len), name_len, 1, 1);
+
+ php_http_env_get_request_headers(NULL TSRMLS_CC);
+
+ if (SUCCESS == zend_hash_find(PHP_HTTP_G->env.request.headers, key, name_len + 1, (void *) &zvalue)) {
+ zval *zcopy = php_http_zsep(IS_STRING, *zvalue);
+
+ val = estrndup(Z_STRVAL_P(zcopy), Z_STRLEN_P(zcopy));
+ zval_ptr_dtor(&zcopy);
+ }
+
+ efree(key);
+
+ return val;
+}
+
+PHP_HTTP_API int php_http_env_got_request_header(const char *name_str, size_t name_len TSRMLS_DC)
+{
+ char *key = php_http_pretty_key(estrndup(name_str, name_len), name_len, 1, 1);
+ int got;
+
+ php_http_env_get_request_headers(NULL TSRMLS_CC);
+ got = zend_hash_exists(PHP_HTTP_G->env.request.headers, key, name_len + 1);
+ efree(key);
+
+ return got;
+}
+
+PHP_HTTP_API zval *php_http_env_get_server_var(const char *key, size_t key_len, zend_bool check TSRMLS_DC)
+{
+ zval **hsv, **var;
+ char *env;
+
+ /* if available, this is a lot faster than accessing $_SERVER */
+ if (sapi_module.getenv) {
+ if ((!(env = sapi_module.getenv((char *) key, key_len TSRMLS_CC))) || (check && !*env)) {
+ return NULL;
+ }
+ if (PHP_HTTP_G->env.server_var) {
+ zval_ptr_dtor(&PHP_HTTP_G->env.server_var);
+ }
+ MAKE_STD_ZVAL(PHP_HTTP_G->env.server_var);
+ ZVAL_STRING(PHP_HTTP_G->env.server_var, env, 1);
+ return PHP_HTTP_G->env.server_var;
+ }
+
+ zend_is_auto_global(ZEND_STRL("_SERVER") TSRMLS_CC);
+
+ if ((SUCCESS != zend_hash_find(&EG(symbol_table), ZEND_STRS("_SERVER"), (void *) &hsv)) || (Z_TYPE_PP(hsv) != IS_ARRAY)) {
+ return NULL;
+ }
+ if ((SUCCESS != zend_hash_find(Z_ARRVAL_PP(hsv), key, key_len + 1, (void *) &var))) {
+ return NULL;
+ }
+ if (check && !((Z_TYPE_PP(var) == IS_STRING) && Z_STRVAL_PP(var) && Z_STRLEN_PP(var))) {
+ return NULL;
+ }
+ return *var;
+}
+
+PHP_HTTP_API php_http_message_body_t *php_http_env_get_request_body(TSRMLS_D)
+{
+ if (!PHP_HTTP_G->env.request.body) {
+ php_stream *s = NULL;
+
+ if (SG(request_info).post_data || SG(request_info).raw_post_data) {
+ if ((s = php_stream_temp_new())) {
+ /* php://input does not support seek() */
+ if (SG(request_info).raw_post_data) {
+ php_stream_write(s, SG(request_info).raw_post_data, SG(request_info).raw_post_data_length);
+ } else {
+ php_stream_write(s, SG(request_info).post_data, SG(request_info).post_data_length);
+ }
+ php_stream_rewind(s);
+ }
+ } else if (sapi_module.read_post) {
+ if ((s = php_stream_temp_new())) {
+ char *buf = emalloc(4096);
+ int len;
+
+ while (0 < (len = sapi_module.read_post(buf, 4096 TSRMLS_CC))) {
+ php_stream_write(s, buf, len);
+
+ if (len < 4096) {
+ break;
+ }
+ }
+ efree(buf);
+
+ php_stream_rewind(s);
+ }
+ }
+ PHP_HTTP_G->env.request.body = php_http_message_body_init(NULL, s TSRMLS_CC);
+ }
+
+ return PHP_HTTP_G->env.request.body;
+}
+
+PHP_HTTP_API php_http_range_status_t php_http_env_get_request_ranges(HashTable *ranges, size_t length TSRMLS_DC)
+{
+ zval *zentry;
+ char *range, *rp, c;
+ long begin = -1, end = -1, *ptr;
+
+ if (!(range = php_http_env_get_request_header(ZEND_STRL("Range") TSRMLS_CC))) {
+ return PHP_HTTP_RANGE_NO;
+ }
+ if (strncmp(range, "bytes=", lenof("bytes="))) {
+ STR_FREE(range);
+ return PHP_HTTP_RANGE_NO;
+ }
+
+ rp = range + lenof("bytes=");
+ ptr = &begin;
+
+ do {
+ switch (c = *(rp++)) {
+ case '0':
+ /* allow 000... - shall we? */
+ if (*ptr != -10) {
+ *ptr *= 10;
+ }
+ break;
+
+ case '1': case '2': case '3':
+ case '4': case '5': case '6':
+ case '7': case '8': case '9':
+ /*
+ * If the value of the pointer is already set (non-negative)
+ * then multiply its value by ten and add the current value,
+ * else initialise the pointers value with the current value
+ * --
+ * This let us recognize empty fields when validating the
+ * ranges, i.e. a "-10" for begin and "12345" for the end
+ * was the following range request: "Range: bytes=0-12345";
+ * While a "-1" for begin and "12345" for the end would
+ * have been: "Range: bytes=-12345".
+ */
+ if (*ptr > 0) {
+ *ptr *= 10;
+ *ptr += c - '0';
+ } else {
+ *ptr = c - '0';
+ }
+ break;
+
+ case '-':
+ ptr = &end;
+ break;
+
+ case ' ':
+ break;
+
+ case 0:
+ case ',':
+
+ if (length) {
+ /* validate ranges */
+ switch (begin) {
+ /* "0-12345" */
+ case -10:
+ switch (end) {
+ /* "0-" */
+ case -1:
+ STR_FREE(range);
+ return PHP_HTTP_RANGE_NO;
+
+ /* "0-0" */
+ case -10:
+ end = 0;
+ break;
+
+ default:
+ if (length <= (size_t) end) {
+ end = length - 1;
+ }
+ break;
+ }
+ begin = 0;
+ break;
+
+ /* "-12345" */
+ case -1:
+ /* "-", "-0" */
+ if (end == -1 || end == -10) {
+ STR_FREE(range);
+ return PHP_HTTP_RANGE_ERR;
+ }
+ begin = length - end;
+ end = length - 1;
+ break;
+
+ /* "12345-(NNN)" */
+ default:
+ if (length <= (size_t) begin) {
+ STR_FREE(range);
+ return PHP_HTTP_RANGE_ERR;
+ }
+ switch (end) {
+ /* "12345-0" */
+ case -10:
+ STR_FREE(range);
+ return PHP_HTTP_RANGE_ERR;
+
+ /* "12345-" */
+ case -1:
+ end = length - 1;
+ break;
+
+ /* "12345-67890" */
+ default:
+ if (length <= (size_t) end) {
+ end = length - 1;
+ } else if (end < begin) {
+ STR_FREE(range);
+ return PHP_HTTP_RANGE_ERR;
+ }
+ break;
+ }
+ break;
+ }
+ }
+
+ MAKE_STD_ZVAL(zentry);
+ array_init(zentry);
+ add_index_long(zentry, 0, begin);
+ add_index_long(zentry, 1, end);
+ zend_hash_next_index_insert(ranges, &zentry, sizeof(zval *), NULL);
+
+ begin = -1;
+ end = -1;
+ ptr = &begin;
+
+ break;
+
+ default:
+ STR_FREE(range);
+ return PHP_HTTP_RANGE_NO;
+ }
+ } while (c != 0);
+
+ STR_FREE(range);
+ return PHP_HTTP_RANGE_OK;
+}
+
+static void grab_headers(void *data, void *arg TSRMLS_DC)
+{
+ php_http_buffer_appendl(PHP_HTTP_BUFFER(arg), ((sapi_header_struct *)data)->header);
+ php_http_buffer_appends(PHP_HTTP_BUFFER(arg), PHP_HTTP_CRLF);
+}
+
+PHP_HTTP_API STATUS php_http_env_get_response_headers(HashTable *headers_ht TSRMLS_DC)
+{
+ STATUS status;
+ php_http_buffer headers;
+
+ php_http_buffer_init(&headers);
+ zend_llist_apply_with_argument(&SG(sapi_headers).headers, grab_headers, &headers TSRMLS_CC);
+ php_http_buffer_fix(&headers);
+
+ status = php_http_headers_parse(PHP_HTTP_BUFFER_VAL(&headers), PHP_HTTP_BUFFER_LEN(&headers), headers_ht, NULL, NULL TSRMLS_CC);
+ php_http_buffer_dtor(&headers);
+
+ return status;
+}
+
+PHP_HTTP_API char *php_http_env_get_response_header(const char *name_str, size_t name_len TSRMLS_DC)
+{
+ char *val = NULL;
+ HashTable headers;
+
+ zend_hash_init(&headers, 0, NULL, NULL, 0);
+ if (SUCCESS == php_http_env_get_response_headers(&headers TSRMLS_CC)) {
+ zval **zvalue;
+ char *key = php_http_pretty_key(estrndup(name_str, name_len), name_len, 1, 1);
+
+ if (SUCCESS == zend_hash_find(&headers, key, name_len + 1, (void *) &zvalue)) {
+ zval *zcopy = php_http_zsep(IS_STRING, *zvalue);
+
+ val = estrndup(Z_STRVAL_P(zcopy), Z_STRLEN_P(zcopy));
+ zval_ptr_dtor(&zcopy);
+ }
+
+ efree(key);
+ }
+ zend_hash_destroy(&headers);
+
+ return val;
+}
+
+PHP_HTTP_API long php_http_env_get_response_code(TSRMLS_D)
+{
+ long code = SG(sapi_headers).http_response_code;
+ return code ? code : 200;
+}
+
+PHP_HTTP_API STATUS php_http_env_set_response_code(long http_code TSRMLS_DC)
+{
+ return sapi_header_op(SAPI_HEADER_SET_STATUS, (void *) http_code TSRMLS_CC);
+}
+
+PHP_HTTP_API STATUS php_http_env_set_response_status_line(long code, php_http_version_t *v TSRMLS_DC)
+{
+ sapi_header_line h = {0};
+ STATUS ret;
+
+ h.line_len = spprintf(&h.line, 0, "HTTP/%u.%u %ld %s", v->major, v->minor, code, php_http_env_get_response_status_for_code(code));
+ ret = sapi_header_op(SAPI_HEADER_REPLACE, (void *) &h TSRMLS_CC);
+ efree(h.line);
+
+ return ret;
+}
+
+PHP_HTTP_API STATUS php_http_env_set_response_protocol_version(php_http_version_t *v TSRMLS_DC)
+{
+ return php_http_env_set_response_status_line(php_http_env_get_response_code(TSRMLS_C), v TSRMLS_CC);
+}
+
+PHP_HTTP_API STATUS php_http_env_set_response_header(long http_code, const char *header_str, size_t header_len, zend_bool replace TSRMLS_DC)
+{
+ sapi_header_line h = {estrndup(header_str, header_len), header_len, http_code};
+ STATUS ret = sapi_header_op(replace ? SAPI_HEADER_REPLACE : SAPI_HEADER_ADD, (void *) &h TSRMLS_CC);
+ efree(h.line);
+ return ret;
+}
+
+PHP_HTTP_API STATUS php_http_env_set_response_header_value(long http_code, const char *name_str, size_t name_len, zval *value, zend_bool replace TSRMLS_DC)
+{
+ if (!value) {
+ sapi_header_line h = {(char *) name_str, name_len, http_code};
+
+ return sapi_header_op(SAPI_HEADER_DELETE, (void *) &h TSRMLS_CC);
+ }
+
+ if(Z_TYPE_P(value) == IS_ARRAY || Z_TYPE_P(value) == IS_OBJECT) {
+ HashPosition pos;
+ int first = replace;
+ zval **data_ptr;
+
+ FOREACH_HASH_VAL(pos, HASH_OF(value), data_ptr) {
+ if (SUCCESS != php_http_env_set_response_header_value(http_code, name_str, name_len, *data_ptr, first TSRMLS_CC)) {
+ return FAILURE;
+ }
+ first = 0;
+ }
+
+ return SUCCESS;
+ } else {
+ zval *data = php_http_zsep(IS_STRING, value);
+
+ if (!Z_STRLEN_P(data)) {
+ zval_ptr_dtor(&data);
+ return php_http_env_set_response_header_value(http_code, name_str, name_len, NULL, replace TSRMLS_CC);
+ } else {
+ sapi_header_line h;
+ STATUS ret;
+
+ if (name_len > INT_MAX) {
+ name_len = INT_MAX;
+ }
+ h.response_code = http_code;
+ h.line_len = spprintf(&h.line, 0, "%.*s: %.*s", (int) name_len, name_str, Z_STRLEN_P(data), Z_STRVAL_P(data));
+
+ ret = sapi_header_op(replace ? SAPI_HEADER_REPLACE : SAPI_HEADER_ADD, (void *) &h TSRMLS_CC);
+
+ zval_ptr_dtor(&data);
+ STR_FREE(h.line);
+
+ return ret;
+ }
+ }
+}
+
+PHP_HTTP_API void php_http_env_set_response_throttle_rate(zval *container, size_t chunk_size, double delay TSRMLS_CC)
+{
+ if (Z_TYPE_P(container) == IS_OBJECT) {
+ zend_update_property_double(Z_OBJCE_P(container), container, ZEND_STRL("throttleDelay"), delay TSRMLS_CC);
+ zend_update_property_long(Z_OBJCE_P(container), container, ZEND_STRL("throttleChunk"), chunk_size TSRMLS_CC);
+ } else {
+ convert_to_array(container);
+ add_assoc_double_ex(container, ZEND_STRS("throttleDelay"), delay);
+ add_assoc_long_ex(container, ZEND_STRS("throttleChunk"), chunk_size);
+ }
+}
+
+static void set_container_value(zval *container, const char *name_str, size_t name_len, int type, const void *value_ptr, size_t value_len TSRMLS_DC)
+{
+ if (Z_TYPE_P(container) == IS_OBJECT) {
+ /* stupid non-const api */
+ char *name = estrndup(name_str, name_len);
+ switch (type) {
+ case IS_LONG:
+ zend_update_property_long(Z_OBJCE_P(container), container, name, name_len, *(long *)value_ptr TSRMLS_CC);
+ break;
+ case IS_STRING:
+ zend_update_property_stringl(Z_OBJCE_P(container), container, name, name_len, value_ptr, value_len TSRMLS_CC);
+ break;
+ }
+ efree(name);
+ } else {
+ convert_to_array(container);
+ switch (type) {
+ case IS_LONG:
+ add_assoc_long_ex(container, name_str, name_len + 1, *(long *)value_ptr);
+ break;
+ case IS_STRING: {
+ char *value = estrndup(value_ptr, value_len);
+ add_assoc_stringl_ex(container, name_str, name_len + 1, value, value_len, 0);
+ break;
+ }
+ }
+ }
+}
+
+PHP_HTTP_API STATUS php_http_env_set_response_last_modified(zval *container, time_t t, char **sent_header TSRMLS_DC)
+{
+ STATUS ret;
+ char *lm_header_str, *date;
+ size_t lm_header_len;
+
+ if (t) {
+ if (!(date = php_format_date(ZEND_STRL(PHP_HTTP_DATE_FORMAT), t, 0 TSRMLS_CC))) {
+ return FAILURE;
+ }
+
+ lm_header_len = spprintf(&lm_header_str, 0, "Last-Modified: %s", date);
+ STR_FREE(date);
+ } else {
+ lm_header_str = "Last-Modified:";
+ lm_header_len = lenof("Last-Modified:");
+ }
+
+ if (SUCCESS == (ret = php_http_env_set_response_header(0, lm_header_str, lm_header_len, 1 TSRMLS_CC))) {
+ set_container_value(container, ZEND_STRL("lastModified"), IS_LONG, &t, 0 TSRMLS_CC);
+ }
+
+ if (sent_header) {
+ *sent_header = lm_header_str;
+ } else if (t) {
+ STR_FREE(lm_header_str);
+ }
+
+ return ret;
+}
+
+PHP_HTTP_API STATUS php_http_env_set_response_etag(zval *container, const char *etag_str, size_t etag_len, char **sent_header TSRMLS_DC)
+{
+ STATUS ret;
+ char *etag = NULL, *etag_header_str;
+ size_t etag_header_len;
+
+ if (etag_len){
+ etag_header_len = spprintf(&etag_header_str, 0, "ETag: \"%s\"", etag_str);
+ } else {
+ etag_header_str = "ETag:";
+ etag_header_len = lenof("ETag:");
+ }
+
+ if (SUCCESS == (ret = php_http_env_set_response_header(0, etag_header_str, etag_header_len, 1 TSRMLS_CC))) {
+ set_container_value(container, ZEND_STRL(etag), IS_STRING, etag_str, etag_len TSRMLS_CC);
+ }
+
+ if (sent_header) {
+ *sent_header = etag_header_str;
+ } else if (etag_len) {
+ STR_FREE(etag_header_str);
+ }
+
+ return ret;
+}
+
+PHP_HTTP_API STATUS php_http_env_set_response_content_type(zval *container, const char *ct_str, size_t ct_len, char **sent_header TSRMLS_DC)
+{
+ STATUS ret;
+ char *ct_header_str;
+ size_t ct_header_len;
+
+ if (ct_len) {
+ PHP_HTTP_CHECK_CONTENT_TYPE(ct_str, return FAILURE);
+ ct_header_len = spprintf(&ct_header_str, 0, "Content-Type: %s", ct_str);
+ } else {
+ ct_header_str = "Content-Type:";
+ ct_header_len = lenof("Content-Type:");
+ }
+
+ if (SUCCESS == (ret = php_http_env_set_response_header(0, ct_header_str, ct_header_len, 1 TSRMLS_CC))) {
+ set_container_value(container, ZEND_STRL("contentType"), IS_STRING, ct_str, ct_len TSRMLS_CC);
+ }
+
+ if (sent_header) {
+ *sent_header = ct_header_str;
+ } else if (ct_len) {
+ STR_FREE(ct_header_str);
+ }
+
+ return ret;
+}
+
+PHP_HTTP_API STATUS php_http_env_set_response_content_disposition(zval *container, php_http_content_disposition_t d, const char *f_str, size_t f_len, char **sent_header TSRMLS_DC)
+{
+ STATUS ret;
+ char *tmp, *cd_header_str, *new_f_str;
+ int new_f_len;
+ size_t cd_header_len;
+
+ switch (d) {
+ case PHP_HTTP_CONTENT_DISPOSITION_NONE:
+ break;
+ case PHP_HTTP_CONTENT_DISPOSITION_INLINE:
+ tmp = "inline";
+ break;
+ case PHP_HTTP_CONTENT_DISPOSITION_ATTACHMENT:
+ tmp = "attachment";
+ break;
+ default:
+ php_http_error(HE_WARNING, PHP_HTTP_E_INVALID_PARAM, "Unknown content disposition (%d)", (int) d);
+ return FAILURE;
+ }
+
+ if (f_len) {
+ new_f_str = php_addslashes(estrndup(f_str, f_len), f_len, &new_f_len, 0 TSRMLS_CC);
+ cd_header_len = spprintf(&cd_header_str, 0, "Content-Disposition: %s; filename=\"%.*s\"", tmp, new_f_len, new_f_str);
+ STR_FREE(new_f_str);
+ } else if (d) {
+ cd_header_len = spprintf(&cd_header_str, 0, "Content-Disposition: %s", tmp);
+ } else {
+ cd_header_str = "Content-Disposition:";
+ cd_header_len = lenof("Content-Disposition:");
+ }
+
+ ret = php_http_env_set_response_header(0, cd_header_str, cd_header_len, 1 TSRMLS_CC);
+
+ if (sent_header) {
+ *sent_header = cd_header_str;
+ } else if (f_len || d){
+ STR_FREE(cd_header_str);
+ }
+
+ return ret;
+}
+
+PHP_HTTP_API STATUS php_http_env_set_response_cache_control(zval *container, const char *cc_str, size_t cc_len, char **sent_header TSRMLS_DC)
+{
+ STATUS ret;
+ char *cc_header_str;
+ size_t cc_header_len;
+
+ if (cc_len) {
+ cc_header_len = spprintf(&cc_header_str, 0, "Cache-Control: %s", cc_str);
+ } else {
+ cc_header_str = "Content-Disposition:";
+ cc_header_len = lenof("Content-Disposition:");
+ }
+
+ ret = php_http_env_set_response_header(0, cc_header_str, cc_header_len, 1 TSRMLS_CC);
+
+ if (sent_header) {
+ *sent_header = cc_header_str;
+ } else if (cc_len) {
+ STR_FREE(cc_header_str);
+ }
+
+ return ret;
+}
+
+static zval *get_container_value(zval *container, const char *name_str, size_t name_len TSRMLS_CC)
+{
+ zval *val, **valptr;
+
+ if (Z_TYPE_P(container) == IS_OBJECT) {
+ char *name = estrndup(name_str, name_len);
+ val = zend_read_property(Z_OBJCE_P(container), container, name, name_len, 0 TSRMLS_CC);
+ efree(name);
+ } else {
+ if (SUCCESS == zend_hash_find(Z_ARRVAL_P(container), name_str, name_len + 1, (void *) &valptr)) {
+ val = *valptr;
+ } else {
+ val = NULL;
+ }
+ }
+ if (val) {
+ Z_ADDREF_P(val);
+ }
+ return val;
+}
+
+PHP_HTTP_API php_http_cache_status_t php_http_env_is_response_cached_by_etag(zval *container, const char *header_str, size_t header_len TSRMLS_DC)
+{
+ int ret, free_etag = 0;
+ char *header, *etag;
+ zval *zetag, *zbody = NULL;
+
+ if ( !(header = php_http_env_get_request_header(header_str, header_len TSRMLS_CC))
+ || !(zbody = get_container_value(container, ZEND_STRL("body") TSRMLS_CC))
+ || !(Z_TYPE_P(zbody) == IS_OBJECT)
+ || !instanceof_function(Z_OBJCE_P(zbody), php_http_message_body_class_entry TSRMLS_CC)
+ ) {
+ STR_FREE(header);
+ if (zbody) {
+ zval_ptr_dtor(&zbody);
+ }
+ return PHP_HTTP_CACHE_NO;
+ }
+
+ if ((zetag = get_container_value(container, ZEND_STRL("etag") TSRMLS_CC))) {
+ zval *zetag_copy = php_http_zsep(IS_STRING, zetag);
+ zval_ptr_dtor(&zetag);
+ zetag = zetag_copy;
+ }
+
+ if (zetag && Z_STRLEN_P(zetag)) {
+ etag = Z_STRVAL_P(zetag);
+ } else {
+ etag = php_http_message_body_etag(((php_http_message_body_object_t *) zend_object_store_get_object(zbody TSRMLS_CC))->body);
+ php_http_env_set_response_etag(container, etag, strlen(etag), NULL TSRMLS_CC);
+ free_etag = 1;
+ }
+
+ if (zetag) {
+ zval_ptr_dtor(&zetag);
+ }
+
+ ret = php_http_match(header, etag, PHP_HTTP_MATCH_WORD);
+
+ if (free_etag) {
+ efree(etag);
+ }
+ efree(header);
+
+ return ret ? PHP_HTTP_CACHE_HIT : PHP_HTTP_CACHE_MISS;
+}
+
+PHP_HTTP_API php_http_cache_status_t php_http_env_is_response_cached_by_last_modified(zval *container, const char *header_str, size_t header_len TSRMLS_DC)
+{
+ char *header;
+ time_t ums, lm = 0;
+ zval *zbody = NULL, *zlm;
+
+ if ( !(header = php_http_env_get_request_header(header_str, header_len TSRMLS_CC))
+ || !(zbody = get_container_value(container, ZEND_STRL("body") TSRMLS_CC))
+ || !(Z_TYPE_P(zbody) == IS_OBJECT)
+ || !instanceof_function(Z_OBJCE_P(zbody), php_http_message_body_class_entry TSRMLS_CC)
+ ) {
+ STR_FREE(header);
+ if (zbody) {
+ zval_ptr_dtor(&zbody);
+ }
+ return PHP_HTTP_CACHE_NO;
+ }
+
+ if ((zlm = get_container_value(container, ZEND_STRL("lastModified") TSRMLS_CC))) {
+ zval *zlm_copy = php_http_zsep(IS_LONG, zlm);
+ zval_ptr_dtor(&zlm);
+ zlm = zlm_copy;
+ }
+
+ if (zlm && Z_LVAL_P(zlm) > 0) {
+ lm = Z_LVAL_P(zlm);
+ } else {
+ lm = php_http_message_body_mtime(((php_http_message_body_object_t *) zend_object_store_get_object(zbody TSRMLS_CC))->body);
+ php_http_env_set_response_last_modified(container, lm, NULL TSRMLS_CC);
+ }
+
+ if (zlm) {
+ zval_ptr_dtor(&zlm);
+ }
+
+ ums = php_parse_date(header, NULL TSRMLS_CC);
+ efree(header);
+
+ if (ums > 0 && ums <= lm) {
+ return PHP_HTTP_CACHE_HIT;
+ } else {
+ return PHP_HTTP_CACHE_MISS;
+ }
+}
+
+PHP_HTTP_API void php_http_env_set_response_body(zval *container, php_http_message_body_t *body)
+{
+ TSRMLS_FETCH_FROM_CTX(body->ts);
+ zend_object_value ov = php_http_message_body_object_new_ex(php_http_message_body_class_entry, php_http_message_body_copy(body, NULL, 0), NULL TSRMLS_CC);
+
+ set_container_value(container, ZEND_STRL("body"), IS_OBJECT, &ov, 0 TSRMLS_CC);
+}
+
+struct output_ctx {
+ php_http_buffer *buf;
+ zval *container;
+};
+
+static size_t output(void *context, const char *buf, size_t len TSRMLS_DC)
+{
+ struct output_ctx *ctx = context;
+
+ if (ctx->buf) {
+ zval *zcs;
+ size_t chunk_size = PHP_HTTP_SENDBUF_SIZE;
+
+ if ((zcs = get_container_value(ctx->container, ZEND_STRL("throttleChunk") TSRMLS_CC))) {
+ zval *zcs_copy = php_http_zsep(IS_LONG, zcs);
+
+ zval_ptr_dtor(&zcs);
+ chunk_size = Z_LVAL_P(zcs_copy);
+ zval_ptr_dtor(&zcs_copy);
+ }
+ php_http_buffer_chunked_output(&ctx->buf, buf, len, buf ? chunk_size : 0, output, NULL TSRMLS_CC);
+ } else {
+ zval *ztd;
+
+
+ PHPWRITE(buf, len);
+
+ /* we really only need to flush when throttling is enabled,
+ because we push the data as fast as possible anyway if not */
+ if ((ztd = get_container_value(ctx->container, ZEND_STRL("throttleDelay") TSRMLS_CC))) {
+ double delay;
+ zval *ztd_copy = php_http_zsep(IS_DOUBLE, ztd);
+
+ zval_ptr_dtor(&ztd);
+ delay = Z_DVAL_P(ztd_copy);
+ zval_ptr_dtor(&ztd_copy);
+
+ if (delay >= PHP_HTTP_DIFFSEC) {
+ if (php_output_get_level(TSRMLS_C)) {
+ php_output_flush_all(TSRMLS_C);
+ }
+ if (!(php_output_get_status(TSRMLS_C) & PHP_OUTPUT_IMPLICITFLUSH)) {
+ sapi_flush(TSRMLS_C);
+ }
+ php_http_sleep(delay);
+ }
+ }
+ }
+ return len;
+}
+
+PHP_HTTP_API STATUS php_http_env_send_response(zval *container TSRMLS_DC)
+{
+ struct output_ctx ctx = {NULL, container};
+ zval *zbody, *zheader, *zrcode, *zversion;
+ HashTable ranges;
+ php_http_range_status_t range_status;
+ php_http_message_body_t *body;
+ size_t body_size;
+
+ if ( !(zbody = get_container_value(container, ZEND_STRL("body") TSRMLS_CC))
+ || !(Z_TYPE_P(zbody) == IS_OBJECT)
+ || !instanceof_function(Z_OBJCE_P(zbody), php_http_message_body_class_entry TSRMLS_CC)
+ ) {
+ if (zbody) {
+ zval_ptr_dtor(&zbody);
+ }
+ return FAILURE;
+ }
+
+ if ((zrcode = get_container_value(container, ZEND_STRL("responseCode") TSRMLS_CC))) {
+ zval *zrcode_copy = php_http_zsep(IS_LONG, zrcode);
+
+ zval_ptr_dtor(&zrcode);
+ if (Z_LVAL_P(zrcode_copy) > 0) {
+ php_http_env_set_response_code(Z_LVAL_P(zrcode_copy) TSRMLS_CC);
+ }
+ zval_ptr_dtor(&zrcode_copy);
+ }
+
+ if ((zversion = get_container_value(container, ZEND_STRL("httpVersion") TSRMLS_CC))) {
+ php_http_version_t v;
+ zval *zversion_copy = php_http_zsep(IS_STRING, zversion);
+
+ zval_ptr_dtor(&zversion);
+ if (Z_STRLEN_P(zversion_copy) && php_http_version_parse(&v, Z_STRVAL_P(zversion_copy) TSRMLS_CC)) {
+ php_http_env_set_response_protocol_version(&v TSRMLS_CC);
+ php_http_version_dtor(&v);
+ }
+ zval_ptr_dtor(&zversion_copy);
+ }
+
+ if ((zheader = get_container_value(container, ZEND_STRL("headers") TSRMLS_CC))) {
+ if (Z_TYPE_P(zheader) == IS_ARRAY) {
+ zval **val;
+ HashPosition pos;
+ php_http_array_hashkey_t key = php_http_array_hashkey_init(0);
+
+ FOREACH_KEYVAL(pos, zheader, key, val) {
+ if (key.type == HASH_KEY_IS_STRING) {
+ php_http_env_set_response_header_value(0, key.str, key.len - 1, *val, 1 TSRMLS_CC);
+ }
+ }
+ }
+ zval_ptr_dtor(&zheader);
+ }
+
+ body = ((php_http_message_body_object_t *) zend_object_store_get_object(zbody TSRMLS_CC))->body;
+ body_size = php_http_message_body_size(body);
+ php_http_env_set_response_header(0, ZEND_STRL("Accept-Ranges: bytes"), 1 TSRMLS_CC);
+ zend_hash_init(&ranges, 0, NULL, ZVAL_PTR_DTOR, 0);
+ range_status = php_http_env_get_request_ranges(&ranges, body_size TSRMLS_CC);
+
+ switch (range_status) {
+ case PHP_HTTP_RANGE_ERR:
+ zend_hash_destroy(&ranges);
+ if (!php_http_env_got_request_header(ZEND_STRL("If-Range") TSRMLS_CC)) {
+ char *cr_header_str;
+ size_t cr_header_len;
+
+ cr_header_len = spprintf(&cr_header_str, 0, "Content-Range: bytes */%zu", body_size);
+ php_http_env_set_response_header(416, cr_header_str, cr_header_len, 1 TSRMLS_CC);
+ efree(cr_header_str);
+ if (zbody) {
+ zval_ptr_dtor(&zbody);
+ }
+ return SUCCESS;
+ }
+ break;
+
+ case PHP_HTTP_RANGE_NO:
+ /* send full entity */
+ zend_hash_destroy(&ranges);
+ break;
+
+ case PHP_HTTP_RANGE_OK:
+ /* send content-range response */
+ if (PHP_HTTP_CACHE_MISS == php_http_env_is_response_cached_by_etag(container, ZEND_STRL("If-Range") TSRMLS_CC)
+ || PHP_HTTP_CACHE_MISS == php_http_env_is_response_cached_by_last_modified(container, ZEND_STRL("If-Range") TSRMLS_CC)
+ ) {
+ /* send full entity */
+ zend_hash_destroy(&ranges);
+ break;
+ }
+ if (PHP_HTTP_CACHE_MISS == php_http_env_is_response_cached_by_etag(container, ZEND_STRL("If-Match") TSRMLS_CC)
+ || PHP_HTTP_CACHE_MISS == php_http_env_is_response_cached_by_last_modified(container, ZEND_STRL("If-Unmodified-Since") TSRMLS_CC)
+ || PHP_HTTP_CACHE_MISS == php_http_env_is_response_cached_by_last_modified(container, ZEND_STRL("Unless-Modified-Since") TSRMLS_CC)
+ ) {
+ zend_hash_destroy(&ranges);
+ php_http_env_set_response_code(412 TSRMLS_CC);
+ if (zbody) {
+ zval_ptr_dtor(&zbody);
+ }
+ return SUCCESS;
+ }
+ if (zend_hash_num_elements(&ranges) == 1) {
+ /* single range */
+ zval **range, **begin, **end;
+
+ if (SUCCESS != zend_hash_index_find(&ranges, 0, (void *) &range)
+ || SUCCESS != zend_hash_index_find(Z_ARRVAL_PP(range), 0, (void *) &begin)
+ || SUCCESS != zend_hash_index_find(Z_ARRVAL_PP(range), 1, (void *) &end)
+ ) {
+ /* this should never happen */
+ zend_hash_destroy(&ranges);
+ php_http_env_set_response_code(500 TSRMLS_CC);
+ if (zbody) {
+ zval_ptr_dtor(&zbody);
+ }
+ return FAILURE;
+ } else {
+ char *cr_header_str;
+ size_t cr_header_len;
+
+ cr_header_len = spprintf(&cr_header_str, 0, "Content-Range: bytes %ld-%ld/%zu", Z_LVAL_PP(begin), Z_LVAL_PP(end), body_size);
+ php_http_env_set_response_header(206, cr_header_str, cr_header_len, 1 TSRMLS_CC);
+ efree(cr_header_str);
+
+ /* send chunk */
+ php_http_message_body_to_callback(body, output, &ctx, Z_LVAL_PP(begin), Z_LVAL_PP(end) - Z_LVAL_PP(begin) + 1);
+ output(&ctx, NULL, 0 TSRMLS_CC);
+ if (zbody) {
+ zval_ptr_dtor(&zbody);
+ }
+ return SUCCESS;
+ }
+ } else {
+ /* send multipart/byte-ranges message */
+ HashPosition pos;
+ zval **chunk, *zct;
+ php_http_buffer preface;
+ int free_ct = 0;
+ char *content_type = "application/octet-stream";
+ char boundary[32], *ct_header_str = "Content-Type: multipart/byteranges; boundary= ";
+
+ if ((zct = get_container_value(container, ZEND_STRL("contentType") TSRMLS_CC))) {
+ zval *zct_copy = php_http_zsep(IS_STRING, zct);
+
+ zval_ptr_dtor(&zct);
+ if (Z_STRLEN_P(zct_copy)) {
+ content_type = estrndup(Z_STRVAL_P(zct_copy), Z_STRLEN_P(zct_copy));
+ free_ct = 1;
+ }
+
+ zval_ptr_dtor(&zct);
+ }
+
+ php_http_boundary(boundary, sizeof(boundary));
+ strlcpy(&ct_header_str[45], boundary, 32);
+
+ php_http_env_set_response_header(206, ct_header_str, strlen(ct_header_str), 1 TSRMLS_CC);
+
+ php_http_buffer_init(&preface);
+ FOREACH_HASH_VAL(pos, &ranges, chunk) {
+ zval **begin, **end;
+
+ if (IS_ARRAY == Z_TYPE_PP(chunk)
+ && SUCCESS == zend_hash_index_find(Z_ARRVAL_PP(chunk), 0, (void *) &begin)
+ && IS_LONG == Z_TYPE_PP(begin)
+ && SUCCESS == zend_hash_index_find(Z_ARRVAL_PP(chunk), 1, (void *) &end)
+ && IS_LONG == Z_TYPE_PP(end)
+ ) {
+ php_http_buffer_appendf(&preface,
+ PHP_HTTP_CRLF
+ "--%s" PHP_HTTP_CRLF
+ "Content-Type: %s" PHP_HTTP_CRLF
+ "Content-Range: bytes %ld-%ld/%zu" PHP_HTTP_CRLF,
+ /* - */
+ boundary,
+ content_type,
+ Z_LVAL_PP(begin),
+ Z_LVAL_PP(end),
+ body_size
+ );
+ php_http_buffer_fix(&preface);
+ output(&ctx, PHP_HTTP_BUFFER_VAL(&preface), PHP_HTTP_BUFFER_LEN(&preface) TSRMLS_CC);
+ php_http_buffer_reset(&preface);
+
+ php_http_message_body_to_callback(body, output, &ctx, Z_LVAL_PP(begin), Z_LVAL_PP(end) - Z_LVAL_PP(begin) + 1);
+ }
+ }
+ php_http_buffer_appendf(&preface, PHP_HTTP_CRLF "--%s--", boundary);
+ php_http_buffer_fix(&preface);
+ output(&ctx, PHP_HTTP_BUFFER_VAL(&preface), PHP_HTTP_BUFFER_LEN(&preface) TSRMLS_CC);
+ php_http_buffer_dtor(&preface);
+ output(&ctx, NULL, 0 TSRMLS_CC);
+ if (zbody) {
+ zval_ptr_dtor(&zbody);
+ }
+ return SUCCESS;
+ }
+ break;
+ }
+
+ switch (php_http_env_is_response_cached_by_etag(container, ZEND_STRL("If-None-Match"))) {
+ case PHP_HTTP_CACHE_MISS:
+ break;
+
+ case PHP_HTTP_CACHE_NO:
+ if (PHP_HTTP_CACHE_HIT != php_http_env_is_response_cached_by_last_modified(container, ZEND_STRL("If-Modified-Since"))) {
+ break;
+ }
+
+ case PHP_HTTP_CACHE_HIT:
+ php_http_env_set_response_code(304 TSRMLS_CC);
+ if (zbody) {
+ zval_ptr_dtor(&zbody);
+ }
+ return SUCCESS;
+ }
+
+ php_http_message_body_to_callback(body, output, &ctx, 0, 0);
+ output(&ctx, NULL, 0 TSRMLS_CC);
+
+ if (zbody) {
+ zval_ptr_dtor(&zbody);
+ }
+ return SUCCESS;
+}
+
+static PHP_HTTP_STRLIST(php_http_env_response_status) =
+ PHP_HTTP_STRLIST_ITEM("Continue")
+ PHP_HTTP_STRLIST_ITEM("Switching Protocols")
+ PHP_HTTP_STRLIST_NEXT
+ PHP_HTTP_STRLIST_ITEM("OK")
+ PHP_HTTP_STRLIST_ITEM("Created")
+ PHP_HTTP_STRLIST_ITEM("Accepted")
+ PHP_HTTP_STRLIST_ITEM("Non-Authoritative Information")
+ PHP_HTTP_STRLIST_ITEM("No Content")
+ PHP_HTTP_STRLIST_ITEM("Reset Content")
+ PHP_HTTP_STRLIST_ITEM("Partial Content")
+ PHP_HTTP_STRLIST_NEXT
+ PHP_HTTP_STRLIST_ITEM("Multiple Choices")
+ PHP_HTTP_STRLIST_ITEM("Moved Permanently")
+ PHP_HTTP_STRLIST_ITEM("Found")
+ PHP_HTTP_STRLIST_ITEM("See Other")
+ PHP_HTTP_STRLIST_ITEM("Not Modified")
+ PHP_HTTP_STRLIST_ITEM("Use Proxy")
+ PHP_HTTP_STRLIST_ITEM("(Unused)")
+ PHP_HTTP_STRLIST_ITEM("Temporary Redirect")
+ PHP_HTTP_STRLIST_NEXT
+ PHP_HTTP_STRLIST_ITEM("Bad Request")
+ PHP_HTTP_STRLIST_ITEM("Unauthorized")
+ PHP_HTTP_STRLIST_ITEM("Payment Required")
+ PHP_HTTP_STRLIST_ITEM("Forbidden")
+ PHP_HTTP_STRLIST_ITEM("Not Found")
+ PHP_HTTP_STRLIST_ITEM("Method Not Allowed")
+ PHP_HTTP_STRLIST_ITEM("Not Acceptable")
+ PHP_HTTP_STRLIST_ITEM("Proxy Authentication Required")
+ PHP_HTTP_STRLIST_ITEM("Request Timeout")
+ PHP_HTTP_STRLIST_ITEM("Conflict")
+ PHP_HTTP_STRLIST_ITEM("Gone")
+ PHP_HTTP_STRLIST_ITEM("Length Required")
+ PHP_HTTP_STRLIST_ITEM("Precondition Failed")
+ PHP_HTTP_STRLIST_ITEM("Request Entity Too Large")
+ PHP_HTTP_STRLIST_ITEM("Request URI Too Long")
+ PHP_HTTP_STRLIST_ITEM("Unsupported Media Type")
+ PHP_HTTP_STRLIST_ITEM("Requested Range Not Satisfiable")
+ PHP_HTTP_STRLIST_ITEM("Expectation Failed")
+ PHP_HTTP_STRLIST_NEXT
+ PHP_HTTP_STRLIST_ITEM("Internal Server Error")
+ PHP_HTTP_STRLIST_ITEM("Not Implemented")
+ PHP_HTTP_STRLIST_ITEM("Bad Gateway")
+ PHP_HTTP_STRLIST_ITEM("Service Unavailable")
+ PHP_HTTP_STRLIST_ITEM("Gateway Timeout")
+ PHP_HTTP_STRLIST_ITEM("HTTP Version Not Supported")
+ PHP_HTTP_STRLIST_STOP
+;
+
+PHP_HTTP_API const char *php_http_env_get_response_status_for_code(unsigned code)
+{
+ return php_http_strlist_find(php_http_env_response_status, 100, code);
+}
+
+zend_class_entry *php_http_env_class_entry;
+
+#define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpEnv, method, 0, req_args)
+#define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpEnv, method, 0)
+#define PHP_HTTP_ENV_ME(method) PHP_ME(HttpEnv, method, PHP_HTTP_ARGS(HttpEnv, method), ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
+
+PHP_HTTP_BEGIN_ARGS(getRequestHeader, 0)
+ PHP_HTTP_ARG_VAL(header_name, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(getRequestBody, 0)
+ PHP_HTTP_ARG_VAL(body_class_name, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(getResponseStatusForCode, 1)
+ PHP_HTTP_ARG_VAL(code, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(getResponseHeader, 0)
+ PHP_HTTP_ARG_VAL(header_name, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_EMPTY_ARGS(getResponseCode);
+
+PHP_HTTP_BEGIN_ARGS(setResponseHeader, 1)
+ PHP_HTTP_ARG_VAL(header_name, 0)
+ PHP_HTTP_ARG_VAL(header_value, 0)
+ PHP_HTTP_ARG_VAL(response_code, 0)
+ PHP_HTTP_ARG_VAL(replace_header, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(setResponseCode, 1)
+ PHP_HTTP_ARG_VAL(code, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(negotiateLanguage, 0)
+ PHP_HTTP_ARG_VAL(supported, 0)
+ PHP_HTTP_ARG_VAL(result_array, 1)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(negotiateContentType, 0)
+ PHP_HTTP_ARG_VAL(supported, 0)
+ PHP_HTTP_ARG_VAL(result_array, 1)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(negotiateCharset, 0)
+ PHP_HTTP_ARG_VAL(supported, 0)
+ PHP_HTTP_ARG_VAL(result_array, 1)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(negotiate, 0)
+ PHP_HTTP_ARG_VAL(value, 0)
+ PHP_HTTP_ARG_VAL(supported, 0)
+ PHP_HTTP_ARG_VAL(result_array, 1)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_EMPTY_ARGS(persistentHandlesStat);
+
+PHP_HTTP_BEGIN_ARGS(persistentHandlesClean, 0)
+ PHP_HTTP_ARG_VAL(name, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(persistentHandlesIdent, 0)
+ PHP_HTTP_ARG_VAL(name, 0)
+PHP_HTTP_END_ARGS;
+
+zend_function_entry php_http_env_method_entry[] = {
+ PHP_HTTP_ENV_ME(getRequestHeader)
+ PHP_HTTP_ENV_ME(getRequestBody)
+
+ PHP_HTTP_ENV_ME(getResponseStatusForCode)
+
+ PHP_HTTP_ENV_ME(getResponseHeader)
+ PHP_HTTP_ENV_ME(getResponseCode)
+ PHP_HTTP_ENV_ME(setResponseHeader)
+ PHP_HTTP_ENV_ME(setResponseCode)
+
+ PHP_HTTP_ENV_ME(negotiateLanguage)
+ PHP_HTTP_ENV_ME(negotiateContentType)
+ PHP_HTTP_ENV_ME(negotiateCharset)
+ PHP_HTTP_ENV_ME(negotiate)
+
+ PHP_HTTP_ENV_ME(persistentHandlesStat)
+ PHP_HTTP_ENV_ME(persistentHandlesClean)
+ PHP_HTTP_ENV_ME(persistentHandlesIdent)
+
+ EMPTY_FUNCTION_ENTRY
+};
+
+PHP_METHOD(HttpEnv, getRequestHeader)
+{
+ char *header_name_str;
+ int header_name_len;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!", &header_name_str, &header_name_len)) {
+ if (header_name_str && header_name_len) {
+ char *header_value = php_http_env_get_request_header(header_name_str, header_name_len TSRMLS_CC);
+
+ if (header_value) {
+ RETURN_STRING(header_value, 0);
+ }
+ RETURN_NULL();
+ } else {
+ array_init(return_value);
+ php_http_env_get_request_headers(Z_ARRVAL_P(return_value) TSRMLS_CC);
+ return;
+ }
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpEnv, getRequestBody)
+{
+ with_error_handling(EH_THROW, PHP_HTTP_EX_CE(runtime)) {
+ zend_class_entry *class_entry = php_http_message_body_class_entry;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|C", &class_entry)) {
+ zend_object_value ov;
+ php_http_message_body_t *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)) {
+ RETURN_OBJVAL(ov, 0);
+ }
+ }
+ } end_error_handling();
+}
+
+PHP_METHOD(HttpEnv, getResponseStatusForCode)
+{
+ long code;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &code)) {
+ RETURN_STRING(php_http_env_get_response_status_for_code(code), 1);
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpEnv, getResponseHeader)
+{
+ char *header_name_str;
+ int header_name_len;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!", &header_name_str, &header_name_len)) {
+ if (header_name_str && header_name_len) {
+ char *header_value = php_http_env_get_response_header(header_name_str, header_name_len TSRMLS_CC);
+
+ if (header_value) {
+ RETURN_STRING(header_value, 0);
+ }
+ RETURN_NULL();
+ } else {
+ array_init(return_value);
+ php_http_env_get_response_headers(Z_ARRVAL_P(return_value) TSRMLS_CC);
+ return;
+ }
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpEnv, getResponseCode)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ RETURN_LONG(php_http_env_get_response_code(TSRMLS_C));
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpEnv, setResponseHeader)
+{
+ char *header_name_str;
+ int header_name_len;
+ zval *header_value;
+ long code = 0;
+ zend_bool replace_header = 1;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z!lb", &header_name_str, &header_name_len, &header_value, &code, &replace_header)) {
+ RETURN_SUCCESS(php_http_env_set_response_header_value(code, header_name_str, header_name_len, header_value, replace_header TSRMLS_CC));
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpEnv, setResponseCode)
+{
+ long code;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &code)) {
+ RETURN_SUCCESS(php_http_env_set_response_code(code TSRMLS_CC));
+ }
+ RETURN_FALSE;
+}
+
+
+#define PHP_HTTP_DO_NEGOTIATE_DEFAULT(supported) \
+ { \
+ zval **value; \
+ \
+ zend_hash_internal_pointer_reset((supported)); \
+ if (SUCCESS == zend_hash_get_current_data((supported), (void *) &value)) { \
+ RETVAL_ZVAL(*value, 1, 0); \
+ } else { \
+ RETVAL_NULL(); \
+ } \
+ }
+
+#define PHP_HTTP_DO_NEGOTIATE_HANDLE_DEFAULT(supported, rs_array) \
+ PHP_HTTP_DO_NEGOTIATE_DEFAULT(supported); \
+ if (rs_array) { \
+ HashPosition pos; \
+ zval **value_ptr; \
+ \
+ FOREACH_HASH_VAL(pos, supported, value_ptr) { \
+ zval *value = php_http_zsep(IS_STRING, *value_ptr); \
+ add_assoc_double(rs_array, Z_STRVAL_P(value), 1.0); \
+ zval_ptr_dtor(&value); \
+ } \
+ }
+
+#define PHP_HTTP_DO_NEGOTIATE_HANDLE_RESULT(result, supported, rs_array) \
+ { \
+ char *key; \
+ uint key_len; \
+ ulong idx; \
+ \
+ if (zend_hash_num_elements(result) && HASH_KEY_IS_STRING == zend_hash_get_current_key_ex(result, &key, &key_len, &idx, 1, NULL)) { \
+ RETVAL_STRINGL(key, key_len-1, 0); \
+ } else { \
+ PHP_HTTP_DO_NEGOTIATE_DEFAULT(supported); \
+ } \
+ \
+ if (rs_array) { \
+ zend_hash_copy(Z_ARRVAL_P(rs_array), result, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); \
+ } \
+ \
+ zend_hash_destroy(result); \
+ FREE_HASHTABLE(result); \
+ }
+
+#define PHP_HTTP_DO_NEGOTIATE(type, supported, rs_array) \
+ { \
+ HashTable *result; \
+ if ((result = php_http_negotiate_ ##type(supported))) { \
+ PHP_HTTP_DO_NEGOTIATE_HANDLE_RESULT(result, supported, rs_array); \
+ } else { \
+ PHP_HTTP_DO_NEGOTIATE_HANDLE_DEFAULT(supported, rs_array); \
+ } \
+ }
+
+PHP_METHOD(HttpEnv, negotiateLanguage)
+{
+ HashTable *supported;
+ zval *rs_array = NULL;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "H|z", &supported, &rs_array)) {
+ if (rs_array) {
+ zval_dtor(rs_array);
+ array_init(rs_array);
+ }
+
+ PHP_HTTP_DO_NEGOTIATE(language, supported, rs_array);
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpEnv, negotiateCharset)
+{
+ HashTable *supported;
+ zval *rs_array = NULL;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "H|z", &supported, &rs_array)) {
+ if (rs_array) {
+ zval_dtor(rs_array);
+ array_init(rs_array);
+ }
+ PHP_HTTP_DO_NEGOTIATE(charset, supported, rs_array);
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpEnv, negotiateContentType)
+{
+ HashTable *supported;
+ zval *rs_array = NULL;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "H|z", &supported, &rs_array)) {
+ if (rs_array) {
+ zval_dtor(rs_array);
+ array_init(rs_array);
+ }
+ PHP_HTTP_DO_NEGOTIATE(content_type, supported, rs_array);
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpEnv, negotiate)
+{
+ HashTable *supported;
+ zval *rs_array = NULL;
+ char *value_str;
+ int value_len;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sH|z", &value_str, &value_len, &supported, &rs_array)) {
+ HashTable *rs;
+
+ if (rs_array) {
+ zval_dtor(rs_array);
+ array_init(rs_array);
+ }
+
+ if ((rs = php_http_negotiate(value_str, supported, php_http_negotiate_default_func))) {
+ PHP_HTTP_DO_NEGOTIATE_HANDLE_RESULT(rs, supported, rs_array);
+ } else {
+ PHP_HTTP_DO_NEGOTIATE_HANDLE_DEFAULT(supported, rs_array);
+ }
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpEnv, persistentHandlesStat)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ object_init(return_value);
+ if (php_http_persistent_handle_statall(HASH_OF(return_value))) {
+ return;
+ }
+ zval_dtor(return_value);
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpEnv, persistentHandlesClean)
+{
+ char *name_str = NULL;
+ int name_len = 0;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &name_str, &name_len)) {
+ php_http_persistent_handle_cleanup(name_str, name_len, 1 TSRMLS_CC);
+ }
+}
+
+PHP_METHOD(HttpEnv, persistentHandlesIdent)
+{
+ char *ident_str = NULL;
+ int ident_len = 0;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &ident_str, &ident_len)) {
+ RETVAL_STRING(zend_ini_string(ZEND_STRS("http.persistent.handles.ident"), 0), 1);
+ if (ident_str && ident_len) {
+ zend_alter_ini_entry(ZEND_STRS("http.persistent.handles.ident"), ident_str, ident_len, ZEND_INI_USER, PHP_INI_STAGE_RUNTIME);
+ }
+ return;
+ }
+ RETURN_FALSE;
+}
+
+zend_class_entry *php_http_env_request_class_entry;
+
+#undef PHP_HTTP_BEGIN_ARGS
+#undef PHP_HTTP_EMPTY_ARGS
+#define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpEnvRequest, method, 0, req_args)
+#define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpEnvRequest, method, 0)
+#define PHP_HTTP_ENV_REQUEST_ME(method, visibility) PHP_ME(HttpEnvRequest, method, PHP_HTTP_ARGS(HttpEnvRequest, method), visibility)
+
+PHP_HTTP_EMPTY_ARGS(__construct);
+
+zend_function_entry php_http_env_request_method_entry[] = {
+ PHP_HTTP_ENV_REQUEST_ME(__construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
+
+ EMPTY_FUNCTION_ENTRY
+};
+
+PHP_METHOD(HttpEnvRequest, __construct)
+{
+ with_error_handling(EH_THROW, PHP_HTTP_EX_CE(runtime)) {
+ if (SUCCESS == zend_parse_parameters_none()) {
+ php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ with_error_handling(EH_THROW, PHP_HTTP_EX_CE(message)) {
+ obj->message = php_http_message_init_env(obj->message, PHP_HTTP_REQUEST TSRMLS_CC);
+ } end_error_handling();
+ }
+ } end_error_handling();
+}
+
+
+zend_class_entry *php_http_env_response_class_entry;
+
+#undef PHP_HTTP_BEGIN_ARGS
+#undef PHP_HTTP_EMPTY_ARGS
+#define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpEnvResponse, method, 0, req_args)
+#define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpEnvResponse, method, 0)
+#define PHP_HTTP_ENV_RESPONSE_ME(method, visibility) PHP_ME(HttpEnvResponse, method, PHP_HTTP_ARGS(HttpEnvResponse, method), visibility)
+
+PHP_HTTP_EMPTY_ARGS(__construct);
+
+PHP_HTTP_BEGIN_ARGS(setContentType, 1)
+ PHP_HTTP_ARG_VAL(content_type, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(setContentDisposition, 1)
+ PHP_HTTP_ARG_VAL(content_disposition, 0)
+ PHP_HTTP_ARG_VAL(filename, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(setCacheControl, 1)
+ PHP_HTTP_ARG_VAL(cache_control, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(setLastModified, 1)
+ PHP_HTTP_ARG_VAL(last_modified, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(isCachedByLastModified, 0)
+ PHP_HTTP_ARG_VAL(header_name, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(setEtag, 1)
+ PHP_HTTP_ARG_VAL(etag, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(isCachedByEtag, 0)
+ PHP_HTTP_ARG_VAL(header_name, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(setThrottleRate, 1)
+ PHP_HTTP_ARG_VAL(chunk_size, 0)
+ PHP_HTTP_ARG_VAL(delay, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_EMPTY_ARGS(send);
+
+
+zend_function_entry php_http_env_response_method_entry[] = {
+ PHP_HTTP_ENV_RESPONSE_ME(__construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
+ PHP_HTTP_ENV_RESPONSE_ME(setContentType, ZEND_ACC_PUBLIC)
+ PHP_HTTP_ENV_RESPONSE_ME(setContentDisposition, ZEND_ACC_PUBLIC)
+ PHP_HTTP_ENV_RESPONSE_ME(setCacheControl, ZEND_ACC_PUBLIC)
+ PHP_HTTP_ENV_RESPONSE_ME(setLastModified, ZEND_ACC_PUBLIC)
+ PHP_HTTP_ENV_RESPONSE_ME(isCachedByLastModified, ZEND_ACC_PUBLIC)
+ PHP_HTTP_ENV_RESPONSE_ME(setEtag, ZEND_ACC_PUBLIC)
+ PHP_HTTP_ENV_RESPONSE_ME(isCachedByEtag, ZEND_ACC_PUBLIC)
+ PHP_HTTP_ENV_RESPONSE_ME(setThrottleRate, ZEND_ACC_PUBLIC)
+
+ PHP_HTTP_ENV_RESPONSE_ME(send, ZEND_ACC_PUBLIC)
+
+ EMPTY_FUNCTION_ENTRY
+};
+
+
+PHP_METHOD(HttpEnvResponse, __construct)
+{
+ with_error_handling(EH_THROW, PHP_HTTP_EX_CE(runtime)) {
+ if (SUCCESS == zend_parse_parameters_none()) {
+ php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ with_error_handling(EH_THROW, PHP_HTTP_EX_CE(message)) {
+ obj->message = php_http_message_init_env(obj->message, PHP_HTTP_RESPONSE TSRMLS_CC);
+ } end_error_handling();
+ }
+ } end_error_handling();
+
+}
+
+PHP_METHOD(HttpEnvResponse, setContentType)
+{
+ char *ct_str;
+ int ct_len;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &ct_str, &ct_len)) {
+ RETURN_SUCCESS(php_http_env_set_response_content_type(getThis(), ct_str, ct_len, NULL TSRMLS_CC));
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpEnvResponse, setContentDisposition)
+{
+ long cd;
+ char *file_str = NULL;
+ int file_len = 0;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|s!", &cd, &file_str, &file_len)) {
+ RETURN_SUCCESS(php_http_env_set_response_content_disposition(getThis(), cd, file_str, file_len, NULL TSRMLS_CC));
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpEnvResponse, setCacheControl)
+{
+ char *cc_str;
+ int cc_len;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &cc_str, &cc_len)) {
+ RETURN_SUCCESS(php_http_env_set_response_cache_control(getThis(), cc_str, cc_len, NULL TSRMLS_CC));
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpEnvResponse, setLastModified)
+{
+ long last_modified;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &last_modified)) {
+ RETURN_SUCCESS(php_http_env_set_response_last_modified(getThis(), last_modified, NULL TSRMLS_CC));
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpEnvResponse, isCachedByLastModified)
+{
+ char *header_name_str = NULL;
+ int header_name_len = 0;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!", &header_name_str, &header_name_len)) {
+ if (!header_name_str || !header_name_len) {
+ header_name_str = "If-Modified-Since";
+ header_name_len = lenof("If-Modified-Since");
+ }
+ RETURN_LONG(php_http_env_is_response_cached_by_last_modified(getThis(), header_name_str, header_name_len TSRMLS_CC));
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpEnvResponse, setEtag)
+{
+ char *etag_str;
+ int etag_len;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s!", &etag_str, &etag_len)) {
+ RETURN_SUCCESS(php_http_env_set_response_etag(getThis(), etag_str, etag_len, NULL TSRMLS_CC));
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpEnvResponse, isCachedByEtag)
+{
+ char *header_name_str = NULL;
+ int header_name_len = 0;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &header_name_str, &header_name_len)) {
+ if (!header_name_str || !header_name_len) {
+ header_name_str = "If-None-Match";
+ header_name_len = lenof("If-None-Match");
+ }
+ RETURN_LONG(php_http_env_is_response_cached_by_etag(getThis(), header_name_str, header_name_len TSRMLS_CC));
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpEnvResponse, setThrottleRate)
+{
+ long chunk_size;
+ double delay = 1;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|d", &chunk_size, &delay)) {
+ php_http_env_set_response_throttle_rate(getThis(), chunk_size, delay TSRMLS_CC);
+ RETURN_TRUE;
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpEnvResponse, send)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ RETURN_SUCCESS(php_http_env_send_response(getThis() TSRMLS_CC));
+ }
+ RETURN_FALSE;
+}
+
+
+PHP_MINIT_FUNCTION(http_env)
+{
+ PHP_HTTP_REGISTER_CLASS(http, Env, http_env, NULL, 0);
+ PHP_HTTP_REGISTER_CLASS(http\\env, Request, http_env_request, php_http_message_class_entry, 0);
+ PHP_HTTP_REGISTER_CLASS(http\\env, Response, http_env_response, php_http_message_class_entry, 0);
+
+ zend_declare_class_constant_long(php_http_env_response_class_entry, ZEND_STRL("CONTENT_DISPOSITION_INLINE"), PHP_HTTP_CONTENT_DISPOSITION_INLINE TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_env_response_class_entry, ZEND_STRL("CONTENT_DISPOSITION_ATTACHMENT"), PHP_HTTP_CONTENT_DISPOSITION_ATTACHMENT TSRMLS_CC);
+
+ zend_declare_class_constant_long(php_http_env_response_class_entry, ZEND_STRL("CACHE_NO"), PHP_HTTP_CACHE_NO TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_env_response_class_entry, ZEND_STRL("CACHE_HIT"), PHP_HTTP_CACHE_HIT TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_env_response_class_entry, ZEND_STRL("CACHE_MISS"), PHP_HTTP_CACHE_MISS TSRMLS_CC);
+
+ zend_declare_property_null(php_http_env_response_class_entry, ZEND_STRL("contentType"), ZEND_ACC_PROTECTED TSRMLS_CC);
+ zend_declare_property_null(php_http_env_response_class_entry, ZEND_STRL("etag"), ZEND_ACC_PROTECTED TSRMLS_CC);
+ zend_declare_property_null(php_http_env_response_class_entry, ZEND_STRL("lastModified"), ZEND_ACC_PROTECTED TSRMLS_CC);
+ zend_declare_property_null(php_http_env_response_class_entry, ZEND_STRL("throttleDelay"), ZEND_ACC_PROTECTED TSRMLS_CC);
+ zend_declare_property_null(php_http_env_response_class_entry, ZEND_STRL("throttleChunk"), ZEND_ACC_PROTECTED TSRMLS_CC);
+
+ return SUCCESS;
+}
+
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
--- /dev/null
+/*
+ +--------------------------------------------------------------------+
+ | PECL :: http |
+ +--------------------------------------------------------------------+
+ | Redistribution and use in source and binary forms, with or without |
+ | modification, are permitted provided that the conditions mentioned |
+ | in the accompanying LICENSE file are met. |
+ +--------------------------------------------------------------------+
+ | Copyright (c) 2004-2010, Michael Wallner <mike@php.net> |
+ +--------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifndef PHP_HTTP_ENV_H
+#define PHP_HTTP_ENV_H
+
+#include "php_http_message_body.h"
+#include "php_http_encoding.h"
+#include "php_http_version.h"
+
+struct php_http_env_globals {
+ zval *server_var;
+ char *etag_mode;
+
+ struct {
+ char *content_type;
+ php_http_message_body_t *body;
+ char *etag;
+ time_t last_modified;
+ double throttle_delay;
+ size_t throttle_chunk;
+ php_http_encoding_stream_t *deflate;
+ } response;
+
+ struct {
+ time_t time;
+ HashTable *headers;
+ php_http_message_body_t *body;
+ } request;
+};
+
+typedef enum php_http_range_status {
+ PHP_HTTP_RANGE_NO,
+ PHP_HTTP_RANGE_OK,
+ PHP_HTTP_RANGE_ERR
+} php_http_range_status_t;
+
+PHP_HTTP_API php_http_range_status_t php_http_env_get_request_ranges(HashTable *ranges, size_t entity_length TSRMLS_DC);
+PHP_HTTP_API void php_http_env_get_request_headers(HashTable *headers TSRMLS_DC);
+PHP_HTTP_API char *php_http_env_get_request_header(const char *name_str, size_t name_len TSRMLS_DC);
+PHP_HTTP_API int php_http_env_got_request_header(const char *name_str, size_t name_len TSRMLS_DC);
+PHP_HTTP_API php_http_message_body_t *php_http_env_get_request_body(TSRMLS_D);
+
+typedef enum php_http_content_disposition {
+ PHP_HTTP_CONTENT_DISPOSITION_NONE,
+ PHP_HTTP_CONTENT_DISPOSITION_INLINE,
+ PHP_HTTP_CONTENT_DISPOSITION_ATTACHMENT
+} php_http_content_disposition_t;
+
+typedef enum php_http_cache_status {
+ PHP_HTTP_CACHE_NO,
+ PHP_HTTP_CACHE_HIT,
+ PHP_HTTP_CACHE_MISS
+} php_http_cache_status_t;
+
+PHP_HTTP_API long php_http_env_get_response_code(TSRMLS_D);
+PHP_HTTP_API const char *php_http_env_get_response_status_for_code(unsigned code);
+PHP_HTTP_API STATUS php_http_env_get_response_headers(HashTable *headers_ht TSRMLS_DC);
+PHP_HTTP_API char *php_http_env_get_response_header(const char *name_str, size_t name_len TSRMLS_DC);
+PHP_HTTP_API STATUS php_http_env_set_response_code(long http_code TSRMLS_DC);
+PHP_HTTP_API STATUS php_http_env_set_response_protocol_version(php_http_version_t *v TSRMLS_DC);
+PHP_HTTP_API STATUS php_http_env_set_response_header(long http_code, const char *header_str, size_t header_len, zend_bool replace TSRMLS_DC);
+PHP_HTTP_API STATUS php_http_env_set_response_header_value(long http_code, const char *name_str, size_t name_len, zval *value, zend_bool replace TSRMLS_DC);
+
+PHP_HTTP_API zval *php_http_env_get_server_var(const char *key_str, size_t key_len, zend_bool check TSRMLS_DC);
+#define php_http_env_got_server_var(v) (NULL != php_http_env_get_server_var((v), strlen(v), 1 TSRMLS_CC))
+
+PHP_HTTP_API STATUS php_http_env_set_response_last_modified(zval *container, time_t lm, char **sent_header TSRMLS_DC);
+PHP_HTTP_API STATUS php_http_env_set_response_etag(zval *container, const char *etag_str, size_t etag_len, char **sent_header TSRMLS_DC);
+PHP_HTTP_API STATUS php_http_env_set_response_content_type(zval *container, const char *ct_str, size_t ct_len, char **sent_header TSRMLS_DC);
+PHP_HTTP_API STATUS php_http_env_set_response_content_disposition(zval *container, php_http_content_disposition_t d, const char *f_str, size_t f_len, char **sent_header TSRMLS_DC);
+PHP_HTTP_API STATUS php_http_env_set_response_cache_control(zval *container, const char *cc_str, size_t cc_len, char **sent_header TSRMLS_DC);
+PHP_HTTP_API void php_http_env_set_response_throttle_rate(zval *container, size_t chunk_size, double delay TSRMLS_CC);
+PHP_HTTP_API void php_http_env_set_response_body(zval *container, php_http_message_body_t *body);
+PHP_HTTP_API STATUS php_http_env_send_response(zval *container TSRMLS_DC);
+PHP_HTTP_API php_http_cache_status_t php_http_env_is_response_cached_by_etag(zval *container, const char *header_str, size_t header_len TSRMLS_DC);
+PHP_HTTP_API php_http_cache_status_t php_http_env_is_response_cached_by_last_modified(zval *container, const char *header_str, size_t header_len TSRMLS_DC);
+
+extern zend_class_entry *php_http_env_class_entry;
+extern zend_function_entry php_http_env_method_entry[];
+
+PHP_METHOD(HttpEnv, getRequestHeader);
+PHP_METHOD(HttpEnv, getRequestBody);
+PHP_METHOD(HttpEnv, getResponseStatusForCode);
+PHP_METHOD(HttpEnv, getResponseHeader);
+PHP_METHOD(HttpEnv, getResponseCode);
+PHP_METHOD(HttpEnv, setResponseHeader);
+PHP_METHOD(HttpEnv, setResponseCode);
+PHP_METHOD(HttpEnv, negotiateLanguage);
+PHP_METHOD(HttpEnv, negotiateCharset);
+PHP_METHOD(HttpEnv, negotiateContentType);
+PHP_METHOD(HttpEnv, negotiate);
+PHP_METHOD(HttpEnv, persistentHandlesStat);
+PHP_METHOD(HttpEnv, persistentHandlesClean);
+PHP_METHOD(HttpEnv, persistentHandlesIdent);
+
+extern zend_class_entry *php_http_env_request_class_entry;
+extern zend_function_entry php_http_env_request_method_entry[];
+
+PHP_METHOD(HttpEnvRequest, __construct);
+
+extern zend_class_entry *php_http_env_response_class_entry;
+extern zend_function_entry php_http_env_response_method_entry[];
+
+PHP_METHOD(HttpEnvResponse, __construct);
+PHP_METHOD(HttpEnvResponse, setContentType);
+PHP_METHOD(HttpEnvResponse, setContentDisposition);
+PHP_METHOD(HttpEnvResponse, setCacheControl);
+PHP_METHOD(HttpEnvResponse, setLastModified);
+PHP_METHOD(HttpEnvResponse, isCachedByLastModified);
+PHP_METHOD(HttpEnvResponse, setEtag);
+PHP_METHOD(HttpEnvResponse, isCachedByEtag);
+PHP_METHOD(HttpEnvResponse, setThrottleRate);
+PHP_METHOD(HttpEnvResponse, send);
+
+PHP_MINIT_FUNCTION(http_env);
+PHP_RINIT_FUNCTION(http_env);
+PHP_RSHUTDOWN_FUNCTION(http_env);
+
+#endif
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
+
--- /dev/null
+#include "php_http.h"
+
+#include <ext/standard/crc32.h>
+#include <ext/standard/sha1.h>
+#include <ext/standard/md5.h>
+
+PHP_HTTP_API void *php_http_etag_init(TSRMLS_D)
+{
+ void *ctx = NULL;
+ char *mode = PHP_HTTP_G->env.etag_mode;
+
+#ifdef PHP_HTTP_HAVE_HASH
+ const php_hash_ops *eho = NULL;
+
+ if (mode && (eho = php_hash_fetch_ops(mode, strlen(mode)))) {
+ ctx = emalloc(eho->context_size);
+ eho->hash_init(ctx);
+ } else
+#endif
+ if (mode && ((!strcasecmp(mode, "crc32")) || (!strcasecmp(mode, "crc32b")))) {
+ ctx = emalloc(sizeof(uint));
+ *((uint *) ctx) = ~0;
+ } else if (mode && !strcasecmp(mode, "sha1")) {
+ PHP_SHA1Init(ctx = emalloc(sizeof(PHP_SHA1_CTX)));
+ } else {
+ PHP_MD5Init(ctx = emalloc(sizeof(PHP_MD5_CTX)));
+ }
+
+ return ctx;
+}
+
+PHP_HTTP_API char *php_http_etag_finish(void *ctx TSRMLS_DC)
+{
+ unsigned char digest[128] = {0};
+ char *etag = NULL, *mode = PHP_HTTP_G->env.etag_mode;
+
+#ifdef PHP_HTTP_HAVE_HASH
+ const php_hash_ops *eho = NULL;
+
+ if (mode && (eho = php_hash_fetch_ops(mode, strlen(mode)))) {
+ eho->hash_final(digest, ctx);
+ etag = php_http_etag_digest(digest, eho->digest_size);
+ } else
+#endif
+ if (mode && ((!strcasecmp(mode, "crc32")) || (!strcasecmp(mode, "crc32b")))) {
+ *((uint *) ctx) = ~*((uint *) ctx);
+ etag = php_http_etag_digest((const unsigned char *) ctx, sizeof(uint));
+ } else if (mode && (!strcasecmp(mode, "sha1"))) {
+ PHP_SHA1Final(digest, ctx);
+ etag = php_http_etag_digest(digest, 20);
+ } else {
+ PHP_MD5Final(digest, ctx);
+ etag = php_http_etag_digest(digest, 16);
+ }
+ efree(ctx);
+
+ return etag;
+}
+
+PHP_HTTP_API size_t php_http_etag_update(void *ctx, const char *data_ptr, size_t data_len TSRMLS_DC)
+{
+ char *mode = PHP_HTTP_G->env.etag_mode;
+#ifdef PHP_HTTP_HAVE_HASH
+ const php_hash_ops *eho = NULL;
+
+ if (mode && (eho = php_hash_fetch_ops(mode, strlen(mode)))) {
+ eho->hash_update(ctx, (const unsigned char *) data_ptr, data_len);
+ } else
+#endif
+ if (mode && ((!strcasecmp(mode, "crc32")) || (!strcasecmp(mode, "crc32b")))) {
+ uint i, c = *((uint *) ctx);
+ for (i = 0; i < data_len; ++i) {
+ CRC32(c, data_ptr[i]);
+ }
+ *((uint *)ctx) = c;
+ } else if (mode && (!strcasecmp(mode, "sha1"))) {
+ PHP_SHA1Update(ctx, (const unsigned char *) data_ptr, data_len);
+ } else {
+ PHP_MD5Update(ctx, (const unsigned char *) data_ptr, data_len);
+ }
+
+ return data_len;
+}
+
--- /dev/null
+#ifndef PHP_HTTP_ETAG_H
+#define PHP_HTTP_ETAG_H
+
+PHP_HTTP_API void *php_http_etag_init(TSRMLS_D);
+PHP_HTTP_API size_t php_http_etag_update(void *ctx, const char *data_ptr, size_t data_len TSRMLS_DC);
+PHP_HTTP_API char *php_http_etag_finish(void *ctx TSRMLS_DC);
+
+static inline char *php_http_etag_digest(const unsigned char *digest, int len)
+{
+ static const char hexdigits[17] = "0123456789abcdef";
+ int i;
+ char *hex = emalloc(len * 2 + 1);
+ char *ptr = hex;
+
+ for (i = 0; i < len; ++i) {
+ *ptr++ = hexdigits[digest[i] >> 4];
+ *ptr++ = hexdigits[digest[i] & 0xF];
+ }
+ *ptr = '\0';
+
+ return hex;
+}
+
+#endif /* PHP_HTTP_ETAG_H */
--- /dev/null
+/*
+ +--------------------------------------------------------------------+
+ | PECL :: http |
+ +--------------------------------------------------------------------+
+ | Redistribution and use in source and binary forms, with or without |
+ | modification, are permitted provided that the conditions mentioned |
+ | in the accompanying LICENSE file are met. |
+ +--------------------------------------------------------------------+
+ | Copyright (c) 2004-2010, Michael Wallner <mike@php.net> |
+ +--------------------------------------------------------------------+
+*/
+
+/* $Id: http_exception_object.c 292841 2009-12-31 08:48:57Z mike $ */
+
+#include "php_http.h"
+
+
+#ifndef PHP_HTTP_DBG_EXCEPTIONS
+# define PHP_HTTP_DBG_EXCEPTIONS 0
+#endif
+
+zend_class_entry *PHP_HTTP_EX_DEF_CE;
+zend_class_entry *PHP_HTTP_EX_CE(runtime);
+zend_class_entry *PHP_HTTP_EX_CE(header);
+zend_class_entry *PHP_HTTP_EX_CE(malformed_headers);
+zend_class_entry *PHP_HTTP_EX_CE(request_method);
+zend_class_entry *PHP_HTTP_EX_CE(message);
+zend_class_entry *PHP_HTTP_EX_CE(message_type);
+zend_class_entry *PHP_HTTP_EX_CE(invalid_param);
+zend_class_entry *PHP_HTTP_EX_CE(encoding);
+zend_class_entry *PHP_HTTP_EX_CE(request);
+zend_class_entry *PHP_HTTP_EX_CE(request_pool);
+zend_class_entry *PHP_HTTP_EX_CE(socket);
+zend_class_entry *PHP_HTTP_EX_CE(response);
+zend_class_entry *PHP_HTTP_EX_CE(url);
+zend_class_entry *PHP_HTTP_EX_CE(querystring);
+zend_class_entry *PHP_HTTP_EX_CE(cookie);
+
+zend_function_entry php_http_exception_method_entry[] = {
+ EMPTY_FUNCTION_ENTRY
+};
+
+#if PHP_HTTP_DBG_EXCEPTIONS
+static void php_http_exception_hook(zval *ex TSRMLS_DC)
+{
+ if (ex) {
+ zval *m = zend_read_property(Z_OBJCE_P(ex), ex, "message", lenof("message"), 0 TSRMLS_CC);
+ fprintf(stderr, "*** Threw exception '%s'\n", Z_STRVAL_P(m));
+ } else {
+ fprintf(stderr, "*** Threw NULL exception\n");
+ }
+}
+#endif
+
+PHP_MINIT_FUNCTION(http_exception)
+{
+ PHP_HTTP_REGISTER_EXCEPTION(Exception, PHP_HTTP_EX_DEF_CE, zend_exception_get_default(TSRMLS_C));
+
+ PHP_HTTP_REGISTER_EXCEPTION(RuntimeException, PHP_HTTP_EX_CE(runtime), PHP_HTTP_EX_DEF_CE);
+ PHP_HTTP_REGISTER_EXCEPTION(InvalidParamException, PHP_HTTP_EX_CE(invalid_param), PHP_HTTP_EX_DEF_CE);
+ PHP_HTTP_REGISTER_EXCEPTION(HeaderException, PHP_HTTP_EX_CE(header), PHP_HTTP_EX_DEF_CE);
+ PHP_HTTP_REGISTER_EXCEPTION(MalformedHeadersException, PHP_HTTP_EX_CE(malformed_headers), PHP_HTTP_EX_DEF_CE);
+ PHP_HTTP_REGISTER_EXCEPTION(RequestMethodException, PHP_HTTP_EX_CE(request_method), PHP_HTTP_EX_DEF_CE);
+ PHP_HTTP_REGISTER_EXCEPTION(MessageException, PHP_HTTP_EX_CE(message), PHP_HTTP_EX_DEF_CE);
+ PHP_HTTP_REGISTER_EXCEPTION(MessageTypeException, PHP_HTTP_EX_CE(message_type), PHP_HTTP_EX_DEF_CE);
+ PHP_HTTP_REGISTER_EXCEPTION(EncodingException, PHP_HTTP_EX_CE(encoding), PHP_HTTP_EX_DEF_CE);
+ PHP_HTTP_REGISTER_EXCEPTION(RequestException, PHP_HTTP_EX_CE(request), PHP_HTTP_EX_DEF_CE);
+
+ zend_declare_property_long(PHP_HTTP_EX_CE(request), "curlCode", lenof("curlCode"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
+
+ PHP_HTTP_REGISTER_EXCEPTION(RequestPoolException, PHP_HTTP_EX_CE(request_pool), PHP_HTTP_EX_DEF_CE);
+ PHP_HTTP_REGISTER_EXCEPTION(SocketException, PHP_HTTP_EX_CE(socket), PHP_HTTP_EX_DEF_CE);
+ PHP_HTTP_REGISTER_EXCEPTION(ResponseException, PHP_HTTP_EX_CE(response), PHP_HTTP_EX_DEF_CE);
+ PHP_HTTP_REGISTER_EXCEPTION(UrlException, PHP_HTTP_EX_CE(url), PHP_HTTP_EX_DEF_CE);
+ PHP_HTTP_REGISTER_EXCEPTION(QueryStringException, PHP_HTTP_EX_CE(querystring), PHP_HTTP_EX_DEF_CE);
+ PHP_HTTP_REGISTER_EXCEPTION(CookieException, PHP_HTTP_EX_CE(cookie), PHP_HTTP_EX_DEF_CE);
+
+#if PHP_HTTP_DBG_EXCEPTIONS
+ zend_throw_exception_hook = php_http_exception_hook;
+#endif
+
+ return SUCCESS;
+}
+
+zend_class_entry *php_http_exception_get_default(void)
+{
+ return PHP_HTTP_EX_DEF_CE;
+}
+
+zend_class_entry *php_http_exception_get_for_code(long code)
+{
+ zend_class_entry *ex = PHP_HTTP_EX_DEF_CE;
+
+ switch (code) {
+ case PHP_HTTP_E_RUNTIME: ex = PHP_HTTP_EX_CE(runtime); break;
+ case PHP_HTTP_E_INVALID_PARAM: ex = PHP_HTTP_EX_CE(invalid_param); break;
+ case PHP_HTTP_E_HEADER: ex = PHP_HTTP_EX_CE(header); break;
+ case PHP_HTTP_E_MALFORMED_HEADERS: ex = PHP_HTTP_EX_CE(malformed_headers); break;
+ case PHP_HTTP_E_REQUEST_METHOD: ex = PHP_HTTP_EX_CE(request_method); break;
+ case PHP_HTTP_E_MESSAGE: ex = PHP_HTTP_EX_CE(message); break;
+ case PHP_HTTP_E_MESSAGE_TYPE: ex = PHP_HTTP_EX_CE(message_type); break;
+ case PHP_HTTP_E_ENCODING: ex = PHP_HTTP_EX_CE(encoding); break;
+ case PHP_HTTP_E_REQUEST: ex = PHP_HTTP_EX_CE(request); break;
+ case PHP_HTTP_E_REQUEST_POOL: ex = PHP_HTTP_EX_CE(request_pool); break;
+ case PHP_HTTP_E_SOCKET: ex = PHP_HTTP_EX_CE(socket); break;
+ case PHP_HTTP_E_RESPONSE: ex = PHP_HTTP_EX_CE(response); break;
+ case PHP_HTTP_E_URL: ex = PHP_HTTP_EX_CE(url); break;
+ case PHP_HTTP_E_QUERYSTRING: ex = PHP_HTTP_EX_CE(querystring); break;
+ case PHP_HTTP_E_COOKIE: ex = PHP_HTTP_EX_CE(cookie); break;
+ }
+
+ return ex;
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
+
--- /dev/null
+/*
+ +--------------------------------------------------------------------+
+ | PECL :: http |
+ +--------------------------------------------------------------------+
+ | Redistribution and use in source and binary forms, with or without |
+ | modification, are permitted provided that the conditions mentioned |
+ | in the accompanying LICENSE file are met. |
+ +--------------------------------------------------------------------+
+ | Copyright (c) 2004-2010, Michael Wallner <mike@php.net> |
+ +--------------------------------------------------------------------+
+*/
+
+/* $Id: php_http_exception_object.h 292841 2009-12-31 08:48:57Z mike $ */
+
+#ifndef PHP_HTTP_EXCEPTION_H
+#define PHP_HTTP_EXCEPTION_H
+
+PHP_MINIT_FUNCTION(http_exception_object);
+
+#define PHP_HTTP_EX_DEF_CE php_http_exception_class_entry
+#define PHP_HTTP_EX_CE(name) php_http_ ##name## _exception_class_entry
+
+extern zend_class_entry *PHP_HTTP_EX_DEF_CE;
+extern zend_class_entry *PHP_HTTP_EX_CE(runtime);
+extern zend_class_entry *PHP_HTTP_EX_CE(header);
+extern zend_class_entry *PHP_HTTP_EX_CE(malformed_headers);
+extern zend_class_entry *PHP_HTTP_EX_CE(request_method);
+extern zend_class_entry *PHP_HTTP_EX_CE(message);
+extern zend_class_entry *PHP_HTTP_EX_CE(message_type);
+extern zend_class_entry *PHP_HTTP_EX_CE(invalid_param);
+extern zend_class_entry *PHP_HTTP_EX_CE(encoding);
+extern zend_class_entry *PHP_HTTP_EX_CE(request);
+extern zend_class_entry *PHP_HTTP_EX_CE(request_pool);
+extern zend_class_entry *PHP_HTTP_EX_CE(socket);
+extern zend_class_entry *PHP_HTTP_EX_CE(response);
+extern zend_class_entry *PHP_HTTP_EX_CE(url);
+extern zend_class_entry *PHP_HTTP_EX_CE(querystring);
+extern zend_class_entry *PHP_HTTP_EX_CE(cookie);
+extern zend_function_entry php_http_exception_method_entry[];
+
+PHP_HTTP_API zend_class_entry *php_http_exception_get_default(void);
+PHP_HTTP_API zend_class_entry *php_http_exception_get_for_code(long code);
+
+PHP_MINIT_FUNCTION(http_exception);
+
+#endif
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
+
--- /dev/null
+/*
+ +--------------------------------------------------------------------+
+ | PECL :: http |
+ +--------------------------------------------------------------------+
+ | Redistribution and use in source and binary forms, with or without |
+ | modification, are permitted provided that the conditions mentioned |
+ | in the accompanying LICENSE file are met. |
+ +--------------------------------------------------------------------+
+ | Copyright (c) 2004-2010, Michael Wallner <mike@php.net> |
+ +--------------------------------------------------------------------+
+*/
+
+/* $Id: http_filter_api.c 292841 2009-12-31 08:48:57Z mike $ */
+
+#include "php_http.h"
+
+PHP_MINIT_FUNCTION(http_filter)
+{
+ php_stream_filter_register_factory("http.*", &php_http_filter_factory TSRMLS_CC);
+ return SUCCESS;
+}
+
+#define PHP_HTTP_FILTER_PARAMS \
+ php_stream *stream, \
+ php_stream_filter *this, \
+ php_stream_bucket_brigade *buckets_in, \
+ php_stream_bucket_brigade *buckets_out, \
+ size_t *bytes_consumed, int flags \
+ TSRMLS_DC
+#define PHP_HTTP_FILTER_OP(filter) \
+ http_filter_op_ ##filter
+#define PHP_HTTP_FILTER_OPS(filter) \
+ php_stream_filter_ops PHP_HTTP_FILTER_OP(filter)
+#define PHP_HTTP_FILTER_DTOR(filter) \
+ http_filter_ ##filter## _dtor
+#define PHP_HTTP_FILTER_DESTRUCTOR(filter) \
+ void PHP_HTTP_FILTER_DTOR(filter)(php_stream_filter *this TSRMLS_DC)
+#define PHP_HTTP_FILTER_FUNC(filter) \
+ http_filter_ ##filter
+#define PHP_HTTP_FILTER_FUNCTION(filter) \
+ php_stream_filter_status_t PHP_HTTP_FILTER_FUNC(filter)(PHP_HTTP_FILTER_PARAMS)
+#define PHP_HTTP_FILTER_BUFFER(filter) \
+ http_filter_ ##filter## _buffer
+
+#define NEW_BUCKET(data, length) \
+ { \
+ char *__data; \
+ php_stream_bucket *__buck; \
+ \
+ __data = pemalloc(length, this->is_persistent); \
+ if (!__data) { \
+ return PSFS_ERR_FATAL; \
+ } \
+ memcpy(__data, data, length); \
+ \
+ __buck = php_stream_bucket_new(stream, __data, length, 1, this->is_persistent TSRMLS_CC); \
+ if (!__buck) { \
+ pefree(__data, this->is_persistent); \
+ return PSFS_ERR_FATAL; \
+ } \
+ \
+ php_stream_bucket_append(buckets_out, __buck TSRMLS_CC); \
+ }
+
+typedef struct _http_chunked_decode_filter_buffer_t {
+ php_http_buffer buffer;
+ ulong hexlen;
+} PHP_HTTP_FILTER_BUFFER(chunked_decode);
+
+typedef php_http_encoding_stream_t PHP_HTTP_FILTER_BUFFER(zlib);
+
+static PHP_HTTP_FILTER_FUNCTION(chunked_decode)
+{
+ int out_avail = 0;
+ php_stream_bucket *ptr, *nxt;
+ PHP_HTTP_FILTER_BUFFER(chunked_decode) *buffer = (PHP_HTTP_FILTER_BUFFER(chunked_decode) *) (this->abstract);
+
+ if (bytes_consumed) {
+ *bytes_consumed = 0;
+ }
+
+ /* new data available? */
+ if (buckets_in->head) {
+
+ /* fetch available bucket data */
+ for (ptr = buckets_in->head; ptr; ptr = nxt) {
+ nxt = ptr->next;
+ if (bytes_consumed) {
+ *bytes_consumed += ptr->buflen;
+ }
+
+ if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_append(PHP_HTTP_BUFFER(buffer), ptr->buf, ptr->buflen)) {
+ return PSFS_ERR_FATAL;
+ }
+
+ php_stream_bucket_unlink(ptr TSRMLS_CC);
+ php_stream_bucket_delref(ptr TSRMLS_CC);
+ }
+ }
+ if (!php_http_buffer_fix(PHP_HTTP_BUFFER(buffer))) {
+ return PSFS_ERR_FATAL;
+ }
+
+ /* we have data in our buffer */
+ while (PHP_HTTP_BUFFER_LEN(buffer)) {
+
+ /* we already know the size of the chunk and are waiting for data */
+ if (buffer->hexlen) {
+
+ /* not enough data buffered */
+ if (PHP_HTTP_BUFFER_LEN(buffer) < buffer->hexlen) {
+
+ /* flush anyway? */
+ if (flags & PSFS_FLAG_FLUSH_INC) {
+
+ /* flush all data (should only be chunk data) */
+ out_avail = 1;
+ NEW_BUCKET(PHP_HTTP_BUFFER_VAL(buffer), PHP_HTTP_BUFFER_LEN(buffer));
+
+ /* waiting for less data now */
+ buffer->hexlen -= PHP_HTTP_BUFFER_LEN(buffer);
+ /* no more buffered data */
+ php_http_buffer_reset(PHP_HTTP_BUFFER(buffer));
+ /* break */
+ }
+
+ /* we have too less data and don't need to flush */
+ else {
+ break;
+ }
+ }
+
+ /* we seem to have all data of the chunk */
+ else {
+ out_avail = 1;
+ NEW_BUCKET(PHP_HTTP_BUFFER_VAL(buffer), buffer->hexlen);
+
+ /* remove outgoing data from the buffer */
+ php_http_buffer_cut(PHP_HTTP_BUFFER(buffer), 0, buffer->hexlen);
+ /* reset hexlen */
+ buffer->hexlen = 0;
+ /* continue */
+ }
+ }
+
+ /* we don't know the length of the chunk yet */
+ else {
+ size_t off = 0;
+
+ /* ignore preceeding CRLFs (too loose?) */
+ while (off < PHP_HTTP_BUFFER_LEN(buffer) && (
+ PHP_HTTP_BUFFER_VAL(buffer)[off] == '\n' ||
+ PHP_HTTP_BUFFER_VAL(buffer)[off] == '\r')) {
+ ++off;
+ }
+ if (off) {
+ php_http_buffer_cut(PHP_HTTP_BUFFER(buffer), 0, off);
+ }
+
+ /* still data there? */
+ if (PHP_HTTP_BUFFER_LEN(buffer)) {
+ int eollen;
+ const char *eolstr;
+
+ /* we need eol, so we can be sure we have all hex digits */
+ php_http_buffer_fix(PHP_HTTP_BUFFER(buffer));
+ if ((eolstr = php_http_locate_bin_eol(PHP_HTTP_BUFFER_VAL(buffer), PHP_HTTP_BUFFER_LEN(buffer), &eollen))) {
+ char *stop = NULL;
+
+ /* read in chunk size */
+ buffer->hexlen = strtoul(PHP_HTTP_BUFFER_VAL(buffer), &stop, 16);
+
+ /* if strtoul() stops at the beginning of the buffered data
+ there's domething oddly wrong, i.e. bad input */
+ if (stop == PHP_HTTP_BUFFER_VAL(buffer)) {
+ return PSFS_ERR_FATAL;
+ }
+
+ /* cut out <chunk size hex><chunk extension><eol> */
+ php_http_buffer_cut(PHP_HTTP_BUFFER(buffer), 0, eolstr + eollen - PHP_HTTP_BUFFER_VAL(buffer));
+ /* buffer->hexlen is 0 now or contains the size of the next chunk */
+ if (!buffer->hexlen) {
+ php_stream_notify_info(stream->context, PHP_STREAM_NOTIFY_COMPLETED, NULL, 0);
+ break;
+ }
+ /* continue */
+ } else {
+ /* we have not enough data buffered to read in chunk size */
+ break;
+ }
+ }
+ /* break */
+ }
+ }
+
+ /* flush before close, but only if we are already waiting for more data */
+ if ((flags & PSFS_FLAG_FLUSH_CLOSE) && buffer->hexlen && PHP_HTTP_BUFFER_LEN(buffer)) {
+ out_avail = 1;
+ NEW_BUCKET(PHP_HTTP_BUFFER_VAL(buffer), PHP_HTTP_BUFFER_LEN(buffer));
+ php_http_buffer_reset(PHP_HTTP_BUFFER(buffer));
+ buffer->hexlen = 0;
+ }
+
+ return out_avail ? PSFS_PASS_ON : PSFS_FEED_ME;
+}
+
+static PHP_HTTP_FILTER_DESTRUCTOR(chunked_decode)
+{
+ PHP_HTTP_FILTER_BUFFER(chunked_decode) *b = (PHP_HTTP_FILTER_BUFFER(chunked_decode) *) (this->abstract);
+
+ php_http_buffer_dtor(PHP_HTTP_BUFFER(b));
+ pefree(b, this->is_persistent);
+}
+
+static PHP_HTTP_FILTER_FUNCTION(chunked_encode)
+{
+ int out_avail = 0;
+ php_stream_bucket *ptr, *nxt;
+
+ if (bytes_consumed) {
+ *bytes_consumed = 0;
+ }
+
+ /* new data available? */
+ if (buckets_in->head) {
+ php_http_buffer buf;
+ out_avail = 1;
+
+ php_http_buffer_init(&buf);
+
+ /* fetch available bucket data */
+ for (ptr = buckets_in->head; ptr; ptr = nxt) {
+ nxt = ptr->next;
+ if (bytes_consumed) {
+ *bytes_consumed += ptr->buflen;
+ }
+
+ php_http_buffer_appendf(&buf, "%lx" PHP_HTTP_CRLF, ptr->buflen);
+ php_http_buffer_append(&buf, ptr->buf, ptr->buflen);
+ php_http_buffer_appends(&buf, PHP_HTTP_CRLF);
+
+ /* pass through */
+ NEW_BUCKET(PHP_HTTP_BUFFER_VAL(&buf), PHP_HTTP_BUFFER_LEN(&buf));
+ /* reset */
+ php_http_buffer_reset(&buf);
+
+ php_stream_bucket_unlink(ptr TSRMLS_CC);
+ php_stream_bucket_delref(ptr TSRMLS_CC);
+ }
+
+ /* free buffer */
+ php_http_buffer_dtor(&buf);
+ }
+
+ /* terminate with "0" */
+ if (flags & PSFS_FLAG_FLUSH_CLOSE) {
+ out_avail = 1;
+ NEW_BUCKET("0" PHP_HTTP_CRLF, lenof("0" PHP_HTTP_CRLF));
+ }
+
+ return out_avail ? PSFS_PASS_ON : PSFS_FEED_ME;
+}
+
+static PHP_HTTP_FILTER_OPS(chunked_decode) = {
+ PHP_HTTP_FILTER_FUNC(chunked_decode),
+ PHP_HTTP_FILTER_DTOR(chunked_decode),
+ "http.chunked_decode"
+};
+
+static PHP_HTTP_FILTER_OPS(chunked_encode) = {
+ PHP_HTTP_FILTER_FUNC(chunked_encode),
+ NULL,
+ "http.chunked_encode"
+};
+
+static PHP_HTTP_FILTER_FUNCTION(zlib)
+{
+ int out_avail = 0;
+ php_stream_bucket *ptr, *nxt;
+ PHP_HTTP_FILTER_BUFFER(zlib) *buffer = (PHP_HTTP_FILTER_BUFFER(zlib) *) this->abstract;
+
+ if (bytes_consumed) {
+ *bytes_consumed = 0;
+ }
+
+ /* new data available? */
+ if (buckets_in->head) {
+
+ /* fetch available bucket data */
+ for (ptr = buckets_in->head; ptr; ptr = nxt) {
+ char *encoded = NULL;
+ size_t encoded_len = 0;
+
+ nxt = ptr->next;
+ if (bytes_consumed) {
+ *bytes_consumed += ptr->buflen;
+ }
+
+ if (ptr->buflen) {
+ php_http_encoding_stream_update(buffer, ptr->buf, ptr->buflen, &encoded, &encoded_len TSRMLS_CC);
+ if (encoded) {
+ if (encoded_len) {
+ out_avail = 1;
+ NEW_BUCKET(encoded, encoded_len);
+ }
+ efree(encoded);
+ }
+ }
+
+ php_stream_bucket_unlink(ptr TSRMLS_CC);
+ php_stream_bucket_delref(ptr TSRMLS_CC);
+ }
+ }
+
+ /* flush & close */
+ if (flags & PSFS_FLAG_FLUSH_INC) {
+ char *encoded = NULL;
+ size_t encoded_len = 0;
+
+ php_http_encoding_stream_flush(buffer, &encoded, &encoded_len TSRMLS_CC);
+ if (encoded) {
+ if (encoded_len) {
+ out_avail = 1;
+ NEW_BUCKET(encoded, encoded_len);
+ }
+ efree(encoded);
+ }
+ }
+
+ if (flags & PSFS_FLAG_FLUSH_CLOSE) {
+ char *encoded = NULL;
+ size_t encoded_len = 0;
+
+ php_http_encoding_stream_finish(buffer, &encoded, &encoded_len TSRMLS_CC);
+ if (encoded) {
+ if (encoded_len) {
+ out_avail = 1;
+ NEW_BUCKET(encoded, encoded_len);
+ }
+ efree(encoded);
+ }
+ }
+
+ return out_avail ? PSFS_PASS_ON : PSFS_FEED_ME;
+}
+static PHP_HTTP_FILTER_DESTRUCTOR(zlib)
+{
+ PHP_HTTP_FILTER_BUFFER(zlib) *buffer = (PHP_HTTP_FILTER_BUFFER(zlib) *) this->abstract;
+ php_http_encoding_stream_free(&buffer TSRMLS_CC);
+}
+
+static PHP_HTTP_FILTER_OPS(deflate) = {
+ PHP_HTTP_FILTER_FUNC(zlib),
+ PHP_HTTP_FILTER_DTOR(zlib),
+ "http.deflate"
+};
+
+static PHP_HTTP_FILTER_OPS(inflate) = {
+ PHP_HTTP_FILTER_FUNC(zlib),
+ PHP_HTTP_FILTER_DTOR(zlib),
+ "http.inflate"
+};
+
+static php_stream_filter *http_filter_create(const char *name, zval *params, int p TSRMLS_DC)
+{
+ zval **tmp = ¶ms;
+ php_stream_filter *f = NULL;
+
+ if (!strcasecmp(name, "http.chunked_decode")) {
+ PHP_HTTP_FILTER_BUFFER(chunked_decode) *b = NULL;
+
+ if ((b = pecalloc(1, sizeof(PHP_HTTP_FILTER_BUFFER(chunked_decode)), p))) {
+ php_http_buffer_init_ex(PHP_HTTP_BUFFER(b), 4096, p ? PHP_HTTP_BUFFER_INIT_PERSISTENT : 0);
+ if (!(f = php_stream_filter_alloc(&PHP_HTTP_FILTER_OP(chunked_decode), b, p))) {
+ pefree(b, p);
+ }
+ }
+ } else
+
+ if (!strcasecmp(name, "http.chunked_encode")) {
+ f = php_stream_filter_alloc(&PHP_HTTP_FILTER_OP(chunked_encode), NULL, p);
+ } else
+
+ if (!strcasecmp(name, "http.inflate")) {
+ int flags = p ? PHP_HTTP_ENCODING_STREAM_PERSISTENT : 0;
+ PHP_HTTP_FILTER_BUFFER(zlib) *b = NULL;
+
+ if ((b = php_http_encoding_stream_init(NULL, php_http_encoding_stream_get_inflate_ops(), flags TSRMLS_CC))) {
+ if (!(f = php_stream_filter_alloc(&PHP_HTTP_FILTER_OP(inflate), b, p))) {
+ php_http_encoding_stream_free(&b TSRMLS_CC);
+ }
+ }
+ } else
+
+ if (!strcasecmp(name, "http.deflate")) {
+ int flags = p ? PHP_HTTP_ENCODING_STREAM_PERSISTENT : 0;
+ PHP_HTTP_FILTER_BUFFER(zlib) *b = NULL;
+
+ if (params) {
+ switch (Z_TYPE_P(params)) {
+ case IS_ARRAY:
+ case IS_OBJECT:
+ if (SUCCESS != zend_hash_find(HASH_OF(params), "flags", sizeof("flags"), (void *) &tmp)) {
+ break;
+ }
+ default:
+ {
+ zval *num = php_http_zsep(IS_LONG, *tmp);
+
+ flags |= (Z_LVAL_P(num) & 0x0fffffff);
+ zval_ptr_dtor(&num);
+ }
+ }
+ }
+ if ((b = php_http_encoding_stream_init(NULL, php_http_encoding_stream_get_deflate_ops(), flags TSRMLS_CC))) {
+ if (!(f = php_stream_filter_alloc(&PHP_HTTP_FILTER_OP(deflate), b, p))) {
+ php_http_encoding_stream_free(&b TSRMLS_CC);
+ }
+ }
+ }
+
+ return f;
+}
+
+php_stream_filter_factory php_http_filter_factory = {
+ http_filter_create
+};
+
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
--- /dev/null
+/*
+ +--------------------------------------------------------------------+
+ | PECL :: http |
+ +--------------------------------------------------------------------+
+ | Redistribution and use in source and binary forms, with or without |
+ | modification, are permitted provided that the conditions mentioned |
+ | in the accompanying LICENSE file are met. |
+ +--------------------------------------------------------------------+
+ | Copyright (c) 2004-2010, Michael Wallner <mike@php.net> |
+ +--------------------------------------------------------------------+
+*/
+
+/* $Id: php_http_filter_api.h 292841 2009-12-31 08:48:57Z mike $ */
+
+#ifndef PHP_HTTP_FILTER_H
+#define PHP_HTTP_FILTER_H
+
+extern php_stream_filter_factory php_http_filter_factory;
+PHP_MINIT_FUNCTION(http_filter);
+
+#endif
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
+
--- /dev/null
+
+#include "php_http.h"
+
+typedef struct php_http_header_parser_state_spec {
+ php_http_header_parser_state_t state;
+ unsigned need_data:1;
+} php_http_header_parser_state_spec_t;
+
+static const php_http_header_parser_state_spec_t php_http_header_parser_states[] = {
+ {PHP_HTTP_HEADER_PARSER_STATE_START, 1},
+ {PHP_HTTP_HEADER_PARSER_STATE_KEY, 1},
+ {PHP_HTTP_HEADER_PARSER_STATE_VALUE, 1},
+ {PHP_HTTP_HEADER_PARSER_STATE_HEADER_DONE, 0},
+ {PHP_HTTP_HEADER_PARSER_STATE_DONE, 0}
+};
+
+
+PHP_HTTP_API php_http_header_parser_t *php_http_header_parser_init(php_http_header_parser_t *parser TSRMLS_CC)
+{
+ if (!parser) {
+ parser = emalloc(sizeof(*parser));
+ }
+ memset(parser, 0, sizeof(*parser));
+
+ TSRMLS_SET_CTX(parser->ts);
+
+ return parser;
+}
+
+
+PHP_HTTP_API php_http_header_parser_state_t php_http_header_parser_state_push(php_http_header_parser_t *parser, unsigned argc, ...)
+{
+ va_list va_args;
+ unsigned i;
+ php_http_header_parser_state_t state = 0;
+
+ 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));
+ }
+ va_end(va_args);
+
+ return state;
+}
+
+PHP_HTTP_API 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;
+
+ if (SUCCESS == zend_stack_top(&parser->stack, (void *) &state)) {
+ return *state;
+ }
+ return PHP_HTTP_HEADER_PARSER_STATE_START;
+}
+
+PHP_HTTP_API 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;
+ }
+ return PHP_HTTP_HEADER_PARSER_STATE_START;
+}
+
+PHP_HTTP_API void php_http_header_parser_dtor(php_http_header_parser_t *parser)
+{
+ zend_stack_destroy(&parser->stack);
+ php_http_info_dtor(&parser->info);
+ STR_FREE(parser->_key.str);
+ STR_FREE(parser->_val.str);
+}
+
+PHP_HTTP_API void php_http_header_parser_free(php_http_header_parser_t **parser)
+{
+ if (*parser) {
+ php_http_header_parser_dtor(*parser);
+ efree(*parser);
+ *parser = NULL;
+ }
+}
+
+PHP_HTTP_API STATUS php_http_header_parser_parse(php_http_header_parser_t *parser, php_http_buffer *buffer, unsigned flags, HashTable *headers, php_http_info_callback_t callback_func, void *callback_arg)
+{
+ TSRMLS_FETCH_FROM_CTX(parser->ts);
+
+ while (buffer->used || !php_http_header_parser_states[php_http_header_parser_state_is(parser)].need_data) {
+#if 0
+ const char *state[] = {"START", "KEY", "VALUE", "HEADER_DONE", "DONE"};
+ fprintf(stderr, "#HP: %s (%d) %zu\n",
+ state[php_http_header_parser_state_is(parser)], zend_hash_num_elements(headers), buffer->used);
+#endif
+ switch (php_http_header_parser_state_pop(parser)) {
+ case PHP_HTTP_HEADER_PARSER_STATE_FAILURE:
+ return php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_FAILURE);
+
+ case PHP_HTTP_HEADER_PARSER_STATE_START: {
+ char *ptr = buffer->data;
+
+ while (ptr - buffer->data < buffer->used && PHP_HTTP_IS_CTYPE(space, *ptr)) {
+ ++ptr;
+ }
+
+ php_http_buffer_cut(buffer, 0, ptr - buffer->data);
+ php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_KEY);
+ break;
+ }
+
+ case PHP_HTTP_HEADER_PARSER_STATE_KEY: {
+ const char *colon, *eol_str;
+ int eol_len;
+
+ if (buffer->data == (eol_str = php_http_locate_bin_eol(buffer->data, buffer->used, &eol_len))) {
+ /* end of headers */
+ php_http_buffer_cut(buffer, 0, eol_len);
+ php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_DONE);
+ } else if (php_http_info_parse(&parser->info, php_http_buffer_fix(buffer)->data TSRMLS_CC)) {
+ /* new message starting with request/response line */
+ if (callback_func) {
+ callback_func(callback_arg, &headers, &parser->info TSRMLS_CC);
+ }
+ php_http_info_dtor(&parser->info);
+ php_http_buffer_cut(buffer, 0, eol_str + eol_len - buffer->data);
+ php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_HEADER_DONE);
+ } else if ((colon = memchr(buffer->data, ':', buffer->used)) && (!eol_str || eol_str > colon)) {
+ /* header: string */
+ parser->_key.str = estrndup(buffer->data, parser->_key.len = colon - buffer->data);
+ while (PHP_HTTP_IS_CTYPE(space, *++colon));
+ php_http_buffer_cut(buffer, 0, colon - buffer->data);
+ php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_VALUE);
+ } else {
+ /* neither reqeust/response line nor header: string */
+ return php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_FAILURE);
+ }
+ break;
+ /*
+ if (colon && (!eol_str || colon < eol_str)) {
+ parser->_key.str = estrndup(buffer->data, parser->_key.len = colon - buffer->data);
+ while (PHP_HTTP_IS_CTYPE(space, *++colon));
+ php_http_buffer_cut(buffer, 0, colon - buffer->data);
+ php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_VALUE);
+ } else if (eol_str) {
+ if (eol_str == buffer->data) {
+ php_http_buffer_cut(buffer, 0, eol_len);
+ php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_DONE);
+ } else if (php_http_info_parse(&parser->info, php_http_buffer_fix(buffer)->data TSRMLS_CC)) {
+ if (callback_func) {
+ callback_func(callback_arg, &headers, &parser->info TSRMLS_CC);
+ }
+ php_http_info_dtor(&parser->info);
+ php_http_buffer_cut(buffer, 0, eol_str + eol_len - buffer->data);
+ php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_HEADER_DONE);
+ } else {
+ return PHP_HTTP_HEADER_PARSER_STATE_FAILURE;
+ }
+ } else {
+ php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_KEY);
+ return PHP_HTTP_HEADER_PARSER_STATE_KEY;
+ }
+ break;
+ */
+ }
+
+ case PHP_HTTP_HEADER_PARSER_STATE_VALUE: {
+ const char *eol_str;
+ int eol_len;
+
+ do {
+ if ((eol_str = php_http_locate_bin_eol(buffer->data, buffer->used, &eol_len))) {
+ if (eol_str + eol_len - buffer->data < buffer->used) {
+ char nextline = *(eol_str + eol_len);
+
+ if (nextline == '\t' || nextline == ' ') {
+ php_http_buffer_cut(buffer, eol_str - buffer->data, eol_len);
+ continue;
+ }
+ }
+
+ parser->_val.str = estrndup(buffer->data, parser->_val.len = eol_str - buffer->data);
+ php_http_buffer_cut(buffer, 0, eol_str + eol_len - buffer->data);
+ php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_HEADER_DONE);
+ } else if (flags & PHP_HTTP_HEADER_PARSER_CLEANUP) {
+ if (buffer->used) {
+ parser->_val.str = estrndup(buffer->data, parser->_val.len = buffer->used);
+ php_http_buffer_reset(buffer);
+ }
+ php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_HEADER_DONE);
+ } else {
+ return php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_VALUE);
+ }
+ } while (0);
+
+ break;
+ }
+
+ case PHP_HTTP_HEADER_PARSER_STATE_HEADER_DONE:
+ if (parser->_key.str && parser->_val.str) {
+ zval array, **exist;
+
+ INIT_PZVAL_ARRAY(&array, headers);
+ php_http_pretty_key(parser->_key.str, parser->_key.len, 1, 1);
+ if (SUCCESS == zend_hash_find(headers, parser->_key.str, parser->_key.len + 1, (void *) &exist)) {
+ convert_to_array(*exist);
+ add_next_index_stringl(&array, parser->_val.str, parser->_val.len, 0);
+ } else {
+ add_assoc_stringl_ex(&array, parser->_key.str, parser->_key.len + 1, parser->_val.str, parser->_val.len, 0);
+ }
+ parser->_val.str = NULL;
+ }
+
+ STR_SET(parser->_key.str, NULL);
+ STR_SET(parser->_val.str, NULL);
+
+ php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_KEY);
+ break;
+
+ case PHP_HTTP_HEADER_PARSER_STATE_DONE:
+ return PHP_HTTP_HEADER_PARSER_STATE_DONE;
+ }
+ }
+
+ return php_http_header_parser_state_is(parser);
+}
--- /dev/null
+#ifndef PHP_HTTP_HEADER_PARSER_H
+#define PHP_HTTP_HEADER_PARSER_H
+
+typedef enum php_http_header_parser_state {
+ PHP_HTTP_HEADER_PARSER_STATE_FAILURE = FAILURE,
+ PHP_HTTP_HEADER_PARSER_STATE_START = 0,
+ PHP_HTTP_HEADER_PARSER_STATE_KEY,
+ PHP_HTTP_HEADER_PARSER_STATE_VALUE,
+ PHP_HTTP_HEADER_PARSER_STATE_HEADER_DONE,
+ PHP_HTTP_HEADER_PARSER_STATE_DONE
+} php_http_header_parser_state_t;
+
+#define PHP_HTTP_HEADER_PARSER_CLEANUP 0x1
+
+typedef struct php_http_header_parser {
+ zend_stack stack;
+ php_http_info_t info;
+ struct {
+ char *str;
+ size_t len;
+ } _key;
+ struct {
+ char *str;
+ size_t len;
+ } _val;
+#ifdef ZTS
+ void ***ts;
+#endif
+} php_http_header_parser_t;
+
+PHP_HTTP_API php_http_header_parser_t *php_http_header_parser_init(php_http_header_parser_t *parser TSRMLS_DC);
+PHP_HTTP_API php_http_header_parser_state_t php_http_header_parser_state_push(php_http_header_parser_t *parser, unsigned argc, ...);
+PHP_HTTP_API php_http_header_parser_state_t php_http_header_parser_state_is(php_http_header_parser_t *parser);
+PHP_HTTP_API php_http_header_parser_state_t php_http_header_parser_state_pop(php_http_header_parser_t *parser);
+PHP_HTTP_API void php_http_header_parser_dtor(php_http_header_parser_t *parser);
+PHP_HTTP_API void php_http_header_parser_free(php_http_header_parser_t **parser);
+PHP_HTTP_API STATUS php_http_header_parser_parse(php_http_header_parser_t *parser, php_http_buffer *buffer, unsigned flags, HashTable *headers, php_http_info_callback_t callback_func, void *callback_arg);
+
+#endif /* PHP_HTTP_HEADER_PARSER_H */
--- /dev/null
+/*
+ +--------------------------------------------------------------------+
+ | PECL :: http |
+ +--------------------------------------------------------------------+
+ | Redistribution and use in source and binary forms, with or without |
+ | modification, are permitted provided that the conditions mentioned |
+ | in the accompanying LICENSE file are met. |
+ +--------------------------------------------------------------------+
+ | Copyright (c) 2004-2010, Michael Wallner <mike@php.net> |
+ +--------------------------------------------------------------------+
+*/
+
+/* $Id: http_headers_api.c 300300 2010-06-09 07:29:35Z mike $ */
+
+#include "php_http.h"
+
+PHP_HTTP_API STATUS php_http_headers_parse(const char *header, size_t length, HashTable *headers, php_http_info_callback_t callback_func, void **callback_data TSRMLS_DC)
+{
+ php_http_header_parser_t ctx;
+ php_http_buffer buf;
+
+ php_http_buffer_from_string_ex(&buf, header, length);
+ php_http_header_parser_init(&ctx TSRMLS_CC);
+ php_http_header_parser_parse(&ctx, &buf, PHP_HTTP_HEADER_PARSER_CLEANUP, headers, callback_func, callback_data);
+ php_http_header_parser_dtor(&ctx);
+ php_http_buffer_dtor(&buf);
+ /* FIXME */
+ return SUCCESS;
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
+
--- /dev/null
+/*
+ +--------------------------------------------------------------------+
+ | PECL :: http |
+ +--------------------------------------------------------------------+
+ | Redistribution and use in source and binary forms, with or without |
+ | modification, are permitted provided that the conditions mentioned |
+ | in the accompanying LICENSE file are met. |
+ +--------------------------------------------------------------------+
+ | Copyright (c) 2004-2010, Michael Wallner <mike@php.net> |
+ +--------------------------------------------------------------------+
+*/
+
+/* $Id: php_http_headers_api.h 300300 2010-06-09 07:29:35Z mike $ */
+
+#ifndef PHP_HTTP_HEADERS_H
+#define PHP_HTTP_HEADERS_H
+
+#include "php_http_info.h"
+
+PHP_HTTP_API STATUS php_http_headers_parse(const char *header, size_t length, HashTable *headers, php_http_info_callback_t callback_func, void **callback_data TSRMLS_DC);
+
+#endif
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
+
--- /dev/null
+/*
+ +--------------------------------------------------------------------+
+ | PECL :: http |
+ +--------------------------------------------------------------------+
+ | Redistribution and use in source and binary forms, with or without |
+ | modification, are permitted provided that the conditions mentioned |
+ | in the accompanying LICENSE file are met. |
+ +--------------------------------------------------------------------+
+ | Copyright (c) 2004-2010, Michael Wallner <mike@php.net> |
+ +--------------------------------------------------------------------+
+*/
+
+/* $Id: http_info_api.c 292841 2009-12-31 08:48:57Z mike $ */
+
+#include "php_http.h"
+
+PHP_HTTP_API void php_http_info_default_callback(void **nothing, HashTable **headers, php_http_info_t *info TSRMLS_DC)
+{
+ zval array;
+ (void) nothing;
+
+ INIT_PZVAL_ARRAY(&array, *headers);
+
+ switch (info->type) {
+ case PHP_HTTP_REQUEST:
+ add_assoc_string(&array, "Request Method", PHP_HTTP_INFO(info).request.method, 1);
+ add_assoc_string(&array, "Request Url", PHP_HTTP_INFO(info).request.url, 1);
+ break;
+
+ case PHP_HTTP_RESPONSE:
+ add_assoc_long(&array, "Response Code", (long) PHP_HTTP_INFO(info).response.code);
+ add_assoc_string(&array, "Response Status", PHP_HTTP_INFO(info).response.status, 1);
+ break;
+
+ case PHP_HTTP_NONE:
+ break;
+ }
+}
+
+PHP_HTTP_API php_http_info_t *php_http_info_init(php_http_info_t *i TSRMLS_DC)
+{
+ if (!i) {
+ i = emalloc(sizeof(*i));
+ }
+
+ memset(i, 0, sizeof(*i));
+
+ return i;
+}
+
+PHP_HTTP_API void php_http_info_dtor(php_http_info_t *i)
+{
+ switch (i->type) {
+ case PHP_HTTP_REQUEST:
+ STR_SET(PHP_HTTP_INFO(i).request.method, NULL);
+ STR_SET(PHP_HTTP_INFO(i).request.url, NULL);
+ break;
+
+ case PHP_HTTP_RESPONSE:
+ STR_SET(PHP_HTTP_INFO(i).response.status, NULL);
+ break;
+
+ default:
+ break;
+ }
+}
+
+PHP_HTTP_API void php_http_info_free(php_http_info_t **i)
+{
+ if (*i) {
+ php_http_info_dtor(*i);
+ efree(*i);
+ *i = NULL;
+ }
+}
+
+PHP_HTTP_API php_http_info_t *php_http_info_parse(php_http_info_t *info, const char *pre_header TSRMLS_DC)
+{
+ const char *end, *http;
+ zend_bool free_info = !info;
+
+ /* sane parameter */
+ if ((!pre_header) || (!*pre_header)) {
+ return NULL;
+ }
+
+ /* where's the end of the line */
+ if (!(end = php_http_locate_eol(pre_header, NULL))) {
+ end = pre_header + strlen(pre_header);
+ }
+
+ /* there must be HTTP/1.x in the line */
+ if (!(http = php_http_locate_str(pre_header, end - pre_header, "HTTP/1.", lenof("HTTP/1.")))) {
+ return NULL;
+ }
+
+ info = php_http_info_init(info TSRMLS_CC);
+
+ /* and nothing than SPACE or NUL after HTTP/1.x */
+ if (!php_http_version_parse(&info->http.version, http TSRMLS_CC)
+ || (http[lenof("HTTP/1.1")] && (!PHP_HTTP_IS_CTYPE(space, http[lenof("HTTP/1.1")])))) {
+ if (free_info) {
+ php_http_info_free(&info);
+ }
+ return NULL;
+ }
+
+#if 0
+ {
+ char *line = estrndup(pre_header, end - pre_header);
+ fprintf(stderr, "http_parse_info('%s')\n", line);
+ efree(line);
+ }
+#endif
+
+ /* is response */
+ if (pre_header == http) {
+ char *status = NULL;
+ const char *code = http + sizeof("HTTP/1.1");
+
+ info->type = PHP_HTTP_RESPONSE;
+ while (' ' == *code) ++code;
+ if (code && end > code) {
+ PHP_HTTP_INFO(info).response.code = strtol(code, &status, 10);
+ } else {
+ PHP_HTTP_INFO(info).response.code = 0;
+ }
+ if (status && end > status) {
+ while (' ' == *status) ++status;
+ PHP_HTTP_INFO(info).response.status = estrndup(status, end - status);
+ } else {
+ PHP_HTTP_INFO(info).response.status = NULL;
+ }
+
+ return info;
+ }
+
+ /* is request */
+ else if (!http[lenof("HTTP/1.x")] || http[lenof("HTTP/1.x")] == '\r' || http[lenof("HTTP/1.x")] == '\n') {
+ const char *url = strchr(pre_header, ' ');
+
+ info->type = PHP_HTTP_REQUEST;
+ if (url && http > url) {
+ PHP_HTTP_INFO(info).request.method = estrndup(pre_header, url - pre_header);
+ while (' ' == *url) ++url;
+ while (' ' == *(http-1)) --http;
+ if (http > url) {
+ PHP_HTTP_INFO(info).request.url = estrndup(url, http - url);
+ } else {
+ efree(PHP_HTTP_INFO(info).request.method);
+ return NULL;
+ }
+ } else {
+ PHP_HTTP_INFO(info).request.method = NULL;
+ PHP_HTTP_INFO(info).request.url = NULL;
+ }
+
+ return info;
+ }
+
+ /* some darn header containing HTTP/1.x */
+ else {
+ if (free_info) {
+ php_http_info_free(&info);
+ }
+ return NULL;
+ }
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
+
--- /dev/null
+/*
+ +--------------------------------------------------------------------+
+ | PECL :: http |
+ +--------------------------------------------------------------------+
+ | Redistribution and use in source and binary forms, with or without |
+ | modification, are permitted provided that the conditions mentioned |
+ | in the accompanying LICENSE file are met. |
+ +--------------------------------------------------------------------+
+ | Copyright (c) 2004-2010, Michael Wallner <mike@php.net> |
+ +--------------------------------------------------------------------+
+*/
+
+/* $Id: php_http_info_api.h 292841 2009-12-31 08:48:57Z mike $ */
+
+#ifndef PHP_HTTP_INFO_H
+#define PHP_HTTP_INFO_H
+
+#include "php_http_version.h"
+
+#define PHP_HTTP_INFO_REQUEST_FMT_ARGS(_http_ptr, eol) "%s %s HTTP/%u.%u" eol, \
+ (_http_ptr)->info.request.method?(_http_ptr)->info.request.method:"UNKNOWN", \
+ (_http_ptr)->info.request.url?(_http_ptr)->info.request.url:"/", \
+ (_http_ptr)->version.major||(_http_ptr)->version.major?(_http_ptr)->version.major:1, \
+ (_http_ptr)->version.major||(_http_ptr)->version.minor?(_http_ptr)->version.minor:1
+
+#define PHP_HTTP_INFO_RESPONSE_FMT_ARGS(_http_ptr, eol) "HTTP/%u.%u %d%s%s" eol, \
+ (_http_ptr)->version.major||(_http_ptr)->version.major?(_http_ptr)->version.major:1, \
+ (_http_ptr)->version.major||(_http_ptr)->version.minor?(_http_ptr)->version.minor:1, \
+ (_http_ptr)->info.response.code?(_http_ptr)->info.response.code:200, \
+ (_http_ptr)->info.response.status&&*(_http_ptr)->info.response.status ? " ":"", \
+ STR_PTR((_http_ptr)->info.response.status)
+
+typedef struct php_http_info_data {
+ union {
+ /* GET /foo/bar */
+ struct { char *method; char *url; } request;
+ /* 200 Ok */
+ struct { unsigned code; char *status; } response;
+ } info;
+ php_http_version_t version;
+} php_http_info_data_t;
+
+typedef enum php_http_info_type {
+ PHP_HTTP_NONE = 0,
+ PHP_HTTP_REQUEST,
+ PHP_HTTP_RESPONSE
+} php_http_info_type_t;
+
+#define PHP_HTTP_INFO(ptr) (ptr)->http.info
+#define PHP_HTTP_INFO_IMPL(_http, _type) \
+ php_http_info_data_t _http; \
+ php_http_info_type_t _type;
+
+typedef struct php_http_info {
+ PHP_HTTP_INFO_IMPL(http, type)
+} php_http_info_t;
+
+typedef zend_bool (*php_http_info_callback_t)(void **callback_data, HashTable **headers, php_http_info_t *info TSRMLS_DC);
+
+PHP_HTTP_API void php_http_info_default_callback(void **nothing, HashTable **headers, php_http_info_t *info TSRMLS_DC);
+
+PHP_HTTP_API php_http_info_t *php_http_info_init(php_http_info_t *info TSRMLS_DC);
+PHP_HTTP_API php_http_info_t *php_http_info_parse(php_http_info_t *info, const char *pre_header TSRMLS_DC);
+PHP_HTTP_API void php_http_info_dtor(php_http_info_t *info);
+PHP_HTTP_API void php_http_info_free(php_http_info_t **info);
+
+#endif
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
+
--- /dev/null
+/*
+ +--------------------------------------------------------------------+
+ | PECL :: http |
+ +--------------------------------------------------------------------+
+ | Redistribution and use in source and binary forms, with or without |
+ | modification, are permitted provided that the conditions mentioned |
+ | in the accompanying LICENSE file are met. |
+ +--------------------------------------------------------------------+
+ | Copyright (c) 2004-2010, Michael Wallner <mike@php.net> |
+ +--------------------------------------------------------------------+
+*/
+
+/* $Id: http_message_api.c 298689 2010-04-28 06:50:06Z mike $ */
+
+#include "php_http.h"
+
+/* API */
+
+PHP_HTTP_API zend_bool php_http_message_info_callback(php_http_message_t **message, HashTable **headers, php_http_info_t *info TSRMLS_DC)
+{
+ php_http_message_t *old = *message;
+
+ /* advance message */
+ if (old->type || zend_hash_num_elements(&old->hdrs) || PHP_HTTP_BUFFER_LEN(old)) {
+ (*message) = php_http_message_init(NULL, 0);
+ (*message)->parent = old;
+ (*headers) = &((*message)->hdrs);
+ }
+
+ php_http_message_set_info(*message, info);
+
+ return old != *message;
+}
+
+PHP_HTTP_API php_http_message_t *php_http_message_init(php_http_message_t *message, php_http_message_type_t type TSRMLS_DC)
+{
+ if (!message) {
+ message = emalloc(sizeof(*message));
+ }
+ memset(message, 0, sizeof(*message));
+ TSRMLS_SET_CTX(message->ts);
+
+ php_http_message_set_type(message, type);
+ zend_hash_init(&message->hdrs, 0, NULL, ZVAL_PTR_DTOR, 0);
+ php_http_message_body_init(&message->body, NULL TSRMLS_CC);
+
+ return message;
+}
+
+PHP_HTTP_API php_http_message_t *php_http_message_init_env(php_http_message_t *message, php_http_message_type_t type TSRMLS_DC)
+{
+ int free_msg = !message;
+ zval *sval, tval;
+ php_http_message_body_t *mbody;
+
+ message = php_http_message_init(message, type TSRMLS_CC);
+
+ switch (type) {
+ case PHP_HTTP_REQUEST:
+ if ((sval = php_http_env_get_server_var(ZEND_STRL("SERVER_PROTOCOL"), 1 TSRMLS_CC)) && !strncmp(Z_STRVAL_P(sval), "HTTP/", lenof("HTTP/"))) {
+ php_http_version_parse(&message->http.version, Z_STRVAL_P(sval));
+ } else {
+ message->http.version.major = 1;
+ message->http.version.minor = 1;
+ }
+ if ((sval = php_http_env_get_server_var(ZEND_STRL("REQUEST_METHOD"), 1 TSRMLS_CC))) {
+ message->http.info.request.method = estrdup(Z_STRVAL_P(sval));
+ }
+ if ((sval = php_http_env_get_server_var(ZEND_STRL("REQUEST_URI"), 1 TSRMLS_CC))) {
+ message->http.info.request.url = estrdup(Z_STRVAL_P(sval));
+ }
+
+ php_http_env_get_request_headers(&message->hdrs TSRMLS_CC);
+
+ if ((mbody = php_http_env_get_request_body(TSRMLS_C))) {
+ php_http_message_body_dtor(&message->body);
+ php_http_message_body_copy(mbody, &message->body, 0 TSRMLS_CC);
+ }
+ break;
+
+ case PHP_HTTP_RESPONSE:
+ if (!SG(sapi_headers).http_status_line || !php_http_info_parse((php_http_info_t *) &message->http, SG(sapi_headers).http_status_line TSRMLS_CC)) {
+ message->http.version.major = 1;
+ message->http.version.minor = 1;
+ switch ((message->http.info.response.code = SG(sapi_headers).http_response_code)) {
+ case 0:
+ message->http.info.response.code = 200;
+ case 200:
+ message->http.info.response.status = estrdup("Ok");
+ break;
+ default:
+ message->http.info.response.status = estrdup("");
+ break;
+ }
+
+ }
+
+ php_http_env_get_response_headers(&message->hdrs TSRMLS_CC);
+
+ if (php_output_get_level()) {
+ if (php_output_get_status(TSRMLS_C) & PHP_OUTPUT_SENT) {
+ php_http_error(HE_WARNING, PHP_HTTP_E_RUNTIME, "Could not fetch response body, output has already been sent at %s:%d", php_output_get_start_filename(TSRMLS_C), php_output_get_start_lineno(TSRMLS_C));
+ goto error;
+ } else if (SUCCESS != php_output_get_contents(&tval TSRMLS_CC)) {
+ php_http_error(HE_WARNING, PHP_HTTP_E_RUNTIME, "Could not fetch response body");
+ goto error;
+ } else {
+ php_http_message_body_append(&message->body, Z_STRVAL(tval), Z_STRLEN(tval));
+ zval_dtor(&tval);
+ }
+ }
+ break;
+
+ default:
+ error:
+ if (free_msg) {
+ php_http_message_free(&message);
+ } else {
+ message = NULL;
+ }
+ break;
+ }
+
+ return message;
+}
+
+PHP_HTTP_API php_http_message_t *php_http_message_parse(php_http_message_t *msg, const char *str, size_t len TSRMLS_DC)
+{
+ php_http_message_parser_t p;
+ php_http_buffer buf;
+
+ if (!msg) {
+ msg = php_http_message_init(NULL, 0 TSRMLS_CC);
+ }
+ php_http_buffer_from_string_ex(&buf, str, len);
+ php_http_message_parser_init(&p TSRMLS_CC);
+ php_http_message_parser_parse(&p, &buf, PHP_HTTP_MESSAGE_PARSER_CLEANUP, &msg);
+ php_http_message_parser_dtor(&p);
+ php_http_buffer_dtor(&buf);
+
+ /* FIXME */
+ return msg;
+}
+
+PHP_HTTP_API zval *php_http_message_header(php_http_message_t *msg, 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);
+
+ if (SUCCESS == zend_hash_find(&msg->hdrs, key, key_len + 1, (void *) &header)) {
+ if (join && Z_TYPE_PP(header) == IS_ARRAY) {
+ zval *header_str, **val;
+ HashPosition pos;
+ php_http_buffer str;
+
+ php_http_buffer_init(&str);
+ MAKE_STD_ZVAL(header_str);
+ FOREACH_VAL(pos, *header, val) {
+ php_http_buffer_appendf(&str, PHP_HTTP_BUFFER_LEN(&str) ? ", %s":"%s", Z_STRVAL_PP(val));
+ }
+ php_http_buffer_fix(&str);
+ ZVAL_STRINGL(header_str, PHP_HTTP_BUFFER_VAL(&str), PHP_HTTP_BUFFER_LEN(&str), 0);
+ ret = header_str;
+ } else {
+ ret = php_http_zsep(IS_STRING, *header);
+ }
+ }
+
+ efree(key);
+
+ return ret;
+}
+
+
+/* */
+PHP_HTTP_API void php_http_message_set_type(php_http_message_t *message, php_http_message_type_t type)
+{
+ /* just act if different */
+ if (type != message->type) {
+
+ /* free request info */
+ switch (message->type = type) {
+ case PHP_HTTP_REQUEST:
+ STR_FREE(message->http.info.request.method);
+ STR_FREE(message->http.info.request.url);
+ break;
+
+ case PHP_HTTP_RESPONSE:
+ STR_FREE(message->http.info.response.status);
+ break;
+
+ default:
+ break;
+ }
+
+ memset(&message->http, 0, sizeof(message->http));
+ }
+}
+
+PHP_HTTP_API void php_http_message_set_info(php_http_message_t *message, php_http_info_t *info)
+{
+ php_http_message_set_type(message, info->type);
+ message->http.version = info->http.version;
+ switch (message->type) {
+ case PHP_HTTP_REQUEST:
+ STR_SET(PHP_HTTP_INFO(message).request.url, PHP_HTTP_INFO(info).request.url ? estrdup(PHP_HTTP_INFO(info).request.url) : NULL);
+ STR_SET(PHP_HTTP_INFO(message).request.method, PHP_HTTP_INFO(info).request.method ? estrdup(PHP_HTTP_INFO(info).request.method) : NULL);
+ break;
+
+ case PHP_HTTP_RESPONSE:
+ PHP_HTTP_INFO(message).response.code = PHP_HTTP_INFO(info).response.code;
+ STR_SET(PHP_HTTP_INFO(message).response.status, PHP_HTTP_INFO(info).response.status ? estrdup(PHP_HTTP_INFO(info).response.status) : NULL);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static inline void message_headers(php_http_message_t *msg, php_http_buffer *str)
+{
+ php_http_array_hashkey_t key = php_http_array_hashkey_init(0);
+ HashPosition pos1;
+ zval **header;
+
+ switch (msg->type) {
+ case PHP_HTTP_REQUEST:
+ php_http_buffer_appendf(str, PHP_HTTP_INFO_REQUEST_FMT_ARGS(&msg->http, PHP_HTTP_CRLF));
+ break;
+
+ case PHP_HTTP_RESPONSE:
+ php_http_buffer_appendf(str, PHP_HTTP_INFO_RESPONSE_FMT_ARGS(&msg->http, PHP_HTTP_CRLF));
+ break;
+
+ default:
+ break;
+ }
+
+ FOREACH_HASH_KEYVAL(pos1, &msg->hdrs, key, header) {
+ if (key.type == HASH_KEY_IS_STRING) {
+ HashPosition pos2;
+ zval **single_header;
+
+ switch (Z_TYPE_PP(header)) {
+ case IS_BOOL:
+ php_http_buffer_appendf(str, "%s: %s" PHP_HTTP_CRLF, key.str, Z_BVAL_PP(header)?"true":"false");
+ break;
+
+ case IS_LONG:
+ php_http_buffer_appendf(str, "%s: %ld" PHP_HTTP_CRLF, key.str, Z_LVAL_PP(header));
+ break;
+
+ case IS_DOUBLE:
+ php_http_buffer_appendf(str, "%s: %F" PHP_HTTP_CRLF, key.str, Z_DVAL_PP(header));
+ break;
+
+ case IS_STRING:
+ if (Z_STRVAL_PP(header)[Z_STRLEN_PP(header)-1] == '\r') fprintf(stderr, "DOH!\n");
+ php_http_buffer_appendf(str, "%s: %s" PHP_HTTP_CRLF, key.str, Z_STRVAL_PP(header));
+ break;
+
+ case IS_ARRAY:
+ FOREACH_VAL(pos2, *header, single_header) {
+ switch (Z_TYPE_PP(single_header)) {
+ case IS_BOOL:
+ php_http_buffer_appendf(str, "%s: %s" PHP_HTTP_CRLF, key.str, Z_BVAL_PP(single_header)?"true":"false");
+ break;
+
+ case IS_LONG:
+ php_http_buffer_appendf(str, "%s: %ld" PHP_HTTP_CRLF, key.str, Z_LVAL_PP(single_header));
+ break;
+
+ case IS_DOUBLE:
+ php_http_buffer_appendf(str, "%s: %F" PHP_HTTP_CRLF, key.str, Z_DVAL_PP(single_header));
+ break;
+
+ case IS_STRING:
+ php_http_buffer_appendf(str, "%s: %s" PHP_HTTP_CRLF, key.str, Z_STRVAL_PP(single_header));
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+}
+
+PHP_HTTP_API void php_http_message_to_callback(php_http_message_t *msg, php_http_pass_callback_t cb, void *cb_arg)
+{
+ php_http_buffer str;
+ TSRMLS_FETCH_FROM_CTX(msg->ts);
+
+ php_http_buffer_init_ex(&str, 0x1000, 0);
+ message_headers(msg, &str);
+ cb(cb_arg, PHP_HTTP_BUFFER_VAL(&str), PHP_HTTP_BUFFER_LEN(&str));
+ php_http_buffer_dtor(&str);
+
+ if (php_http_message_body_size(&msg->body)) {
+ cb(cb_arg, ZEND_STRL(PHP_HTTP_CRLF) TSRMLS_CC);
+ php_http_message_body_to_callback(&msg->body, cb, cb_arg, 0, 0);
+ cb(cb_arg, ZEND_STRL(PHP_HTTP_CRLF) TSRMLS_CC);
+ }
+}
+
+PHP_HTTP_API void php_http_message_to_string(php_http_message_t *msg, char **string, size_t *length)
+{
+ php_http_buffer str;
+ char *data;
+
+ php_http_buffer_init_ex(&str, 0x1000, 0);
+ message_headers(msg, &str);
+ if (php_http_message_body_size(&msg->body)) {
+ php_http_buffer_appends(&str, PHP_HTTP_CRLF);
+ php_http_message_body_to_callback(&msg->body, (php_http_pass_callback_t) php_http_buffer_append, &str, 0, 0);
+ php_http_buffer_appends(&str, PHP_HTTP_CRLF);
+ }
+
+ data = php_http_buffer_data(&str, string, length);
+ if (!string) {
+ efree(data);
+ }
+
+ php_http_buffer_dtor(&str);
+}
+
+PHP_HTTP_API void php_http_message_serialize(php_http_message_t *message, char **string, size_t *length)
+{
+ char *buf;
+ size_t len;
+ php_http_buffer str;
+
+ php_http_buffer_init(&str);
+
+ do {
+ php_http_message_to_string(message, &buf, &len);
+ php_http_buffer_prepend(&str, buf, len);
+ efree(buf);
+ } while ((message = message->parent));
+
+ buf = php_http_buffer_data(&str, string, length);
+ if (!string) {
+ efree(buf);
+ }
+
+ php_http_buffer_dtor(&str);
+}
+
+PHP_HTTP_API php_http_message_t *php_http_message_reverse(php_http_message_t *msg)
+{
+ int i, c = 0;
+
+ php_http_message_count(c, msg);
+
+ if (c > 1) {
+ php_http_message_t *tmp = msg, **arr = ecalloc(c, sizeof(**arr));
+
+ for (i = 0; i < c; ++i) {
+ arr[i] = tmp;
+ tmp = tmp->parent;
+ }
+ arr[0]->parent = NULL;
+ for (i = 0; i < c-1; ++i) {
+ arr[i+1]->parent = arr[i];
+ }
+
+ msg = arr[c-1];
+ efree(arr);
+ }
+
+ return msg;
+}
+
+PHP_HTTP_API php_http_message_t *php_http_message_interconnect(php_http_message_t *m1, php_http_message_t *m2)
+{
+ if (m1 && m2) {
+ int i = 0, c1 = 0, c2 = 0;
+ php_http_message_t *t1 = m1, *t2 = m2, *p1, *p2;
+
+ php_http_message_count(c1, m1);
+ php_http_message_count(c2, m2);
+
+ while (i++ < (c1 - c2)) {
+ t1 = t1->parent;
+ }
+ while (i++ <= c1) {
+ p1 = t1->parent;
+ p2 = t2->parent;
+ t1->parent = t2;
+ t2->parent = p1;
+ t1 = p1;
+ t2 = p2;
+ }
+ } else if (!m1 && m2) {
+ m1 = m2;
+ }
+ return m1;
+}
+
+PHP_HTTP_API void php_http_message_to_struct(php_http_message_t *msg, zval *obj TSRMLS_DC)
+{
+ zval strct;
+ zval *headers;
+ char *version;
+
+ INIT_PZVAL_ARRAY(&strct, HASH_OF(obj));
+
+ add_assoc_long(&strct, "type", msg->type);
+ spprintf(&version, 0 ,"%u.%u", msg->http.version.major, msg->http.version.minor);
+ add_assoc_string_ex(&strct, ZEND_STRL("httpVersion"), version, 0);
+ switch (msg->type)
+ {
+ case PHP_HTTP_RESPONSE:
+ add_assoc_long(&strct, "responseCode", msg->http.info.response.code);
+ add_assoc_string(&strct, "responseStatus", STR_PTR(msg->http.info.response.status), 1);
+ break;
+
+ case PHP_HTTP_REQUEST:
+ add_assoc_string(&strct, "requestMethod", STR_PTR(msg->http.info.request.method), 1);
+ add_assoc_string(&strct, "requestUrl", STR_PTR(msg->http.info.request.url), 1);
+ break;
+
+ case PHP_HTTP_NONE:
+ /* avoid compiler warning */
+ break;
+ }
+
+ MAKE_STD_ZVAL(headers);
+ array_init(headers);
+ zend_hash_copy(Z_ARRVAL_P(headers), &msg->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
+ add_assoc_zval(&strct, "headers", headers);
+
+ add_assoc_stringl(&strct, "body", PHP_HTTP_BUFFER_VAL(msg), PHP_HTTP_BUFFER_LEN(msg), 1);
+
+ if (msg->parent) {
+ zval *parent;
+
+ MAKE_STD_ZVAL(parent);
+ if (Z_TYPE_P(obj) == IS_ARRAY) {
+ array_init(parent);
+ } else {
+ object_init(parent);
+ }
+ add_assoc_zval(&strct, "parentMessage", parent);
+ php_http_message_to_struct(msg->parent, parent);
+ } else {
+ add_assoc_null(&strct, "parentMessage");
+ }
+}
+/*
+PHP_HTTP_API STATUS _http_message_send(http_message *message TSRMLS_DC)
+{
+ STATUS rs = FAILURE;
+
+ switch (message->type) {
+ case PHP_HTTP_RESPONSE:
+ {
+ php_http_array_hashkey_t key = php_http_array_hashkey_init(0);
+ zval **val;
+ HashPosition pos;
+
+ FOREACH_HASH_KEYVAL(pos, &message->hdrs, key, val) {
+ if (key.type == HASH_KEY_IS_STRING) {
+ http_send_header_zval_ex(key.str, key.len-1, val, 1);
+ }
+ }
+ rs = SUCCESS == http_send_status(message->http.info.response.code) &&
+ SUCCESS == http_send_data(PHP_HTTP_BUFFER_VAL(message), PHP_HTTP_BUFFER_LEN(message)) ?
+ SUCCESS : FAILURE;
+ break;
+ }
+
+ case PHP_HTTP_REQUEST:
+ {
+#ifdef PHP_HTTP_HAVE_CURL
+ char *uri = NULL;
+ http_request request;
+ zval **zhost, *options, *headers;
+
+ MAKE_STD_ZVAL(options);
+ MAKE_STD_ZVAL(headers);
+ array_init(options);
+ array_init(headers);
+ zend_hash_copy(Z_ARRVAL_P(headers), &message->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
+ add_assoc_zval(options, "headers", headers);
+
+ if (SUCCESS == zend_hash_find(&message->hdrs, "Host", sizeof("Host"), (void *) &zhost) && Z_TYPE_PP(zhost) == IS_STRING) {
+ char *colon = NULL;
+ php_url parts, *url = php_url_parse(message->http.info.request.url);
+
+ memset(&parts, 0, sizeof(php_url));
+
+ if ((colon = strchr(Z_STRVAL_PP(zhost), ':'))) {
+ parts.port = atoi(colon + 1);
+ parts.host = estrndup(Z_STRVAL_PP(zhost), (Z_STRVAL_PP(zhost) - colon - 1));
+ } else {
+ parts.host = estrndup(Z_STRVAL_PP(zhost), Z_STRLEN_PP(zhost));
+ }
+
+ http_build_url(PHP_HTTP_URL_REPLACE, url, &parts, NULL, &uri, NULL);
+ php_url_free(url);
+ efree(parts.host);
+ } else {
+ uri = http_absolute_url(message->http.info.request.url);
+ }
+
+ if ((request.meth = http_request_method_exists(1, 0, message->http.info.request.method))) {
+ http_request_body body;
+
+ http_request_init_ex(&request, NULL, request.meth, uri);
+ request.body = http_request_body_init_ex(&body, PHP_HTTP_REQUEST_BODY_CSTRING, PHP_HTTP_BUFFER_VAL(message), PHP_HTTP_BUFFER_LEN(message), 0);
+ if (SUCCESS == (rs = http_request_prepare(&request, Z_ARRVAL_P(options)))) {
+ http_request_exec(&request);
+ }
+ http_request_dtor(&request);
+ } else {
+ http_error_ex(HE_WARNING, PHP_HTTP_E_REQUEST_METHOD,
+ "Cannot send HttpMessage. Request method %s not supported",
+ message->http.info.request.method);
+ }
+ efree(uri);
+ zval_ptr_dtor(&options);
+#else
+ http_error(HE_WARNING, PHP_HTTP_E_RUNTIME, "HTTP requests not supported - ext/http was not linked against libcurl.");
+#endif
+ break;
+ }
+
+ case PHP_HTTP_NONE:
+ default:
+ php_http_error(HE_WARNING, PHP_HTTP_E_MESSAGE_TYPE, "HttpMessage is neither of type PHP_HTTP_REQUEST nor PHP_HTTP_RESPONSE");
+ break;
+ }
+
+ return rs;
+}
+*/
+
+PHP_HTTP_API php_http_message_t *php_http_message_copy(php_http_message_t *from, php_http_message_t *to)
+{
+ php_http_message_t *temp, *copy = NULL;
+ php_http_info_t info;
+ TSRMLS_FETCH_FROM_CTX(from->ts);
+
+ if (from) {
+ info.type = from->type;
+ info.http = from->http;
+
+ copy = temp = php_http_message_init(to, 0);
+ php_http_message_set_info(temp, &info);
+ zend_hash_copy(&temp->hdrs, &from->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
+ php_http_message_body_copy(&from->body, &temp->body, 1);
+
+ while (from->parent) {
+ info.type = from->parent->type;
+ info.http = from->parent->http;
+
+ temp->parent = php_http_message_init(NULL, 0);
+ php_http_message_set_info(temp->parent, &info);
+ zend_hash_copy(&temp->parent->hdrs, &from->parent->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
+ php_http_message_body_copy(&from->body, &temp->body, 1);
+
+ temp = temp->parent;
+ from = from->parent;
+ }
+ }
+
+ return copy;
+}
+
+PHP_HTTP_API void php_http_message_dtor(php_http_message_t *message)
+{
+ if (message) {
+ zend_hash_destroy(&message->hdrs);
+ php_http_message_body_dtor(&message->body);
+
+ switch (message->type) {
+ case PHP_HTTP_REQUEST:
+ STR_SET(message->http.info.request.method, NULL);
+ STR_SET(message->http.info.request.url, NULL);
+ break;
+
+ case PHP_HTTP_RESPONSE:
+ STR_SET(message->http.info.response.status, NULL);
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+PHP_HTTP_API void php_http_message_free(php_http_message_t **message)
+{
+ if (*message) {
+ if ((*message)->parent) {
+ php_http_message_free(&(*message)->parent);
+ }
+ php_http_message_dtor(*message);
+ efree(*message);
+ *message = NULL;
+ }
+}
+
+
+/* PHP */
+
+#define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpMessage, method, 0, req_args)
+#define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpMessage, method, 0)
+#define PHP_HTTP_MESSAGE_ME(method, visibility) PHP_ME(HttpMessage, method, PHP_HTTP_ARGS(HttpMessage, method), visibility)
+
+PHP_HTTP_BEGIN_ARGS(__construct, 0)
+ PHP_HTTP_ARG_VAL(message, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_EMPTY_ARGS(getBody);
+PHP_HTTP_BEGIN_ARGS(setBody, 1)
+ PHP_HTTP_ARG_VAL(body, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(getHeader, 1)
+ PHP_HTTP_ARG_VAL(header, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(setHeader, 1)
+ PHP_HTTP_ARG_VAL(header, 0)
+ PHP_HTTP_ARG_VAL(value, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(addHeader, 2)
+ PHP_HTTP_ARG_VAL(header, 0)
+ PHP_HTTP_ARG_VAL(value, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_EMPTY_ARGS(getHeaders);
+PHP_HTTP_BEGIN_ARGS(setHeaders, 1)
+ PHP_HTTP_ARG_VAL(headers, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(addHeaders, 1)
+ PHP_HTTP_ARG_VAL(headers, 0)
+ PHP_HTTP_ARG_VAL(append, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_EMPTY_ARGS(getType);
+PHP_HTTP_BEGIN_ARGS(setType, 1)
+ PHP_HTTP_ARG_VAL(type, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_EMPTY_ARGS(getInfo);
+PHP_HTTP_BEGIN_ARGS(setInfo, 1)
+ PHP_HTTP_ARG_VAL(http_info, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_EMPTY_ARGS(getResponseCode);
+PHP_HTTP_BEGIN_ARGS(setResponseCode, 1)
+ PHP_HTTP_ARG_VAL(response_code, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_EMPTY_ARGS(getResponseStatus);
+PHP_HTTP_BEGIN_ARGS(setResponseStatus, 1)
+ PHP_HTTP_ARG_VAL(response_status, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_EMPTY_ARGS(getRequestMethod);
+PHP_HTTP_BEGIN_ARGS(setRequestMethod, 1)
+ PHP_HTTP_ARG_VAL(request_method, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_EMPTY_ARGS(getRequestUrl);
+PHP_HTTP_BEGIN_ARGS(setRequestUrl, 1)
+ PHP_HTTP_ARG_VAL(url, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_EMPTY_ARGS(getHttpVersion);
+PHP_HTTP_BEGIN_ARGS(setHttpVersion, 1)
+ PHP_HTTP_ARG_VAL(http_version, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(guessContentType, 1)
+ PHP_HTTP_ARG_VAL(magic_file, 0)
+ PHP_HTTP_ARG_VAL(magic_mode, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_EMPTY_ARGS(getParentMessage);
+PHP_HTTP_EMPTY_ARGS(send);
+PHP_HTTP_EMPTY_ARGS(__toString);
+PHP_HTTP_BEGIN_ARGS(toString, 0)
+ PHP_HTTP_ARG_VAL(include_parent, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_EMPTY_ARGS(toMessageTypeObject);
+
+PHP_HTTP_EMPTY_ARGS(count);
+
+PHP_HTTP_EMPTY_ARGS(serialize);
+PHP_HTTP_BEGIN_ARGS(unserialize, 1)
+ PHP_HTTP_ARG_VAL(serialized, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_EMPTY_ARGS(rewind);
+PHP_HTTP_EMPTY_ARGS(valid);
+PHP_HTTP_EMPTY_ARGS(key);
+PHP_HTTP_EMPTY_ARGS(current);
+PHP_HTTP_EMPTY_ARGS(next);
+
+PHP_HTTP_EMPTY_ARGS(detach);
+PHP_HTTP_BEGIN_ARGS(prepend, 1)
+ PHP_HTTP_ARG_OBJ(http\\Message, message, 0)
+PHP_HTTP_END_ARGS;
+PHP_HTTP_EMPTY_ARGS(reverse);
+
+static zval *php_http_message_object_read_prop(zval *object, zval *member, int type, const zend_literal *literal_key TSRMLS_DC);
+static void php_http_message_object_write_prop(zval *object, zval *member, zval *value, const zend_literal *literal_key TSRMLS_DC);
+static zval **php_http_message_object_get_prop_ptr(zval *object, zval *member, const zend_literal *literal_key TSRMLS_DC);
+static HashTable *php_http_message_object_get_props(zval *object TSRMLS_DC);
+
+zend_class_entry *php_http_message_class_entry;
+zend_function_entry php_http_message_method_entry[] = {
+ PHP_HTTP_MESSAGE_ME(__construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
+ PHP_HTTP_MESSAGE_ME(getBody, ZEND_ACC_PUBLIC)
+ PHP_HTTP_MESSAGE_ME(setBody, ZEND_ACC_PUBLIC)
+ PHP_HTTP_MESSAGE_ME(getHeader, ZEND_ACC_PUBLIC)
+ PHP_HTTP_MESSAGE_ME(setHeader, ZEND_ACC_PUBLIC)
+ PHP_HTTP_MESSAGE_ME(addHeader, ZEND_ACC_PUBLIC)
+ PHP_HTTP_MESSAGE_ME(getHeaders, ZEND_ACC_PUBLIC)
+ PHP_HTTP_MESSAGE_ME(setHeaders, ZEND_ACC_PUBLIC)
+ PHP_HTTP_MESSAGE_ME(addHeaders, ZEND_ACC_PUBLIC)
+ PHP_HTTP_MESSAGE_ME(getType, ZEND_ACC_PUBLIC)
+ PHP_HTTP_MESSAGE_ME(setType, ZEND_ACC_PUBLIC)
+ PHP_HTTP_MESSAGE_ME(getInfo, ZEND_ACC_PUBLIC)
+ PHP_HTTP_MESSAGE_ME(setInfo, ZEND_ACC_PUBLIC)
+ PHP_HTTP_MESSAGE_ME(getResponseCode, ZEND_ACC_PUBLIC)
+ PHP_HTTP_MESSAGE_ME(setResponseCode, ZEND_ACC_PUBLIC)
+ PHP_HTTP_MESSAGE_ME(getResponseStatus, ZEND_ACC_PUBLIC)
+ PHP_HTTP_MESSAGE_ME(setResponseStatus, ZEND_ACC_PUBLIC)
+ PHP_HTTP_MESSAGE_ME(getRequestMethod, ZEND_ACC_PUBLIC)
+ PHP_HTTP_MESSAGE_ME(setRequestMethod, ZEND_ACC_PUBLIC)
+ PHP_HTTP_MESSAGE_ME(getRequestUrl, ZEND_ACC_PUBLIC)
+ PHP_HTTP_MESSAGE_ME(setRequestUrl, ZEND_ACC_PUBLIC)
+ PHP_HTTP_MESSAGE_ME(getHttpVersion, ZEND_ACC_PUBLIC)
+ PHP_HTTP_MESSAGE_ME(setHttpVersion, ZEND_ACC_PUBLIC)
+ PHP_HTTP_MESSAGE_ME(getParentMessage, ZEND_ACC_PUBLIC)
+ PHP_HTTP_MESSAGE_ME(toString, ZEND_ACC_PUBLIC)
+
+ /* implements Countable */
+ PHP_HTTP_MESSAGE_ME(count, ZEND_ACC_PUBLIC)
+
+ /* implements Serializable */
+ PHP_HTTP_MESSAGE_ME(serialize, ZEND_ACC_PUBLIC)
+ PHP_HTTP_MESSAGE_ME(unserialize, ZEND_ACC_PUBLIC)
+
+ /* implements Iterator */
+ PHP_HTTP_MESSAGE_ME(rewind, ZEND_ACC_PUBLIC)
+ PHP_HTTP_MESSAGE_ME(valid, ZEND_ACC_PUBLIC)
+ PHP_HTTP_MESSAGE_ME(current, ZEND_ACC_PUBLIC)
+ PHP_HTTP_MESSAGE_ME(key, ZEND_ACC_PUBLIC)
+ PHP_HTTP_MESSAGE_ME(next, ZEND_ACC_PUBLIC)
+
+ ZEND_MALIAS(HttpMessage, __toString, toString, PHP_HTTP_ARGS(HttpMessage, __toString), ZEND_ACC_PUBLIC)
+
+ PHP_HTTP_MESSAGE_ME(detach, ZEND_ACC_PUBLIC)
+ PHP_HTTP_MESSAGE_ME(prepend, ZEND_ACC_PUBLIC)
+ PHP_HTTP_MESSAGE_ME(reverse, ZEND_ACC_PUBLIC)
+
+ EMPTY_FUNCTION_ENTRY
+};
+static zend_object_handlers php_http_message_object_handlers;
+static HashTable php_http_message_object_prophandlers;
+
+typedef void (*php_http_message_object_prophandler_func_t)(php_http_message_object_t *o, zval *v TSRMLS_DC);
+
+typedef struct php_http_message_object_prophandler {
+ php_http_message_object_prophandler_func_t read;
+ php_http_message_object_prophandler_func_t write;
+} php_http_message_object_prophandler_t;
+
+static STATUS php_http_message_object_add_prophandler(const char *prop_str, size_t prop_len, php_http_message_object_prophandler_func_t read, php_http_message_object_prophandler_func_t write) {
+ php_http_message_object_prophandler_t h = { read, write };
+ return zend_hash_add(&php_http_message_object_prophandlers, prop_str, prop_len + 1, (void *) &h, sizeof(h), NULL);
+}
+static int php_http_message_object_has_prophandler(const char *prop_str, size_t prop_len) {
+ return zend_hash_exists(&php_http_message_object_prophandlers, prop_str, prop_len + 1);
+}
+static STATUS php_http_message_object_get_prophandler(const char *prop_str, size_t prop_len, php_http_message_object_prophandler_t **handler) {
+ return zend_hash_find(&php_http_message_object_prophandlers, prop_str, prop_len + 1, (void *) handler);
+}
+static void php_http_message_object_prophandler_get_type(php_http_message_object_t *obj, zval *return_value TSRMLS_DC) {
+ RETVAL_LONG(obj->message->type);
+}
+static void php_http_message_object_prophandler_set_type(php_http_message_object_t *obj, zval *value TSRMLS_DC) {
+ zval *cpy = php_http_zsep(IS_LONG, value);
+ php_http_message_set_type(obj->message, Z_LVAL_P(cpy));
+ zval_ptr_dtor(&cpy);
+}
+static void php_http_message_object_prophandler_get_request_method(php_http_message_object_t *obj, zval *return_value TSRMLS_DC) {
+ if (PHP_HTTP_MESSAGE_TYPE(REQUEST, obj->message) && obj->message->http.info.request.method) {
+ RETVAL_STRING(obj->message->http.info.request.method, 1);
+ } else {
+ RETVAL_NULL();
+ }
+}
+static void php_http_message_object_prophandler_set_request_method(php_http_message_object_t *obj, zval *value TSRMLS_DC) {
+ if (PHP_HTTP_MESSAGE_TYPE(REQUEST, obj->message)) {
+ zval *cpy = php_http_zsep(IS_STRING, value);
+ STR_SET(obj->message->http.info.request.method, estrndup(Z_STRVAL_P(cpy), Z_STRLEN_P(cpy)));
+ zval_ptr_dtor(&cpy);
+ }
+}
+static void php_http_message_object_prophandler_get_request_url(php_http_message_object_t *obj, zval *return_value TSRMLS_DC) {
+ if (PHP_HTTP_MESSAGE_TYPE(REQUEST, obj->message) && obj->message->http.info.request.url) {
+ RETVAL_STRING(obj->message->http.info.request.url, 1);
+ } else {
+ RETVAL_NULL();
+ }
+}
+static void php_http_message_object_prophandler_set_request_url(php_http_message_object_t *obj, zval *value TSRMLS_DC) {
+ if (PHP_HTTP_MESSAGE_TYPE(REQUEST, obj->message)) {
+ zval *cpy = php_http_zsep(IS_STRING, value);
+ STR_SET(obj->message->http.info.request.url, estrndup(Z_STRVAL_P(cpy), Z_STRLEN_P(cpy)));
+ zval_ptr_dtor(&cpy);
+ }
+}
+static void php_http_message_object_prophandler_get_response_status(php_http_message_object_t *obj, zval *return_value TSRMLS_DC) {
+ if (PHP_HTTP_MESSAGE_TYPE(RESPONSE, obj->message) && obj->message->http.info.response.status) {
+ RETVAL_STRING(obj->message->http.info.response.status, 1);
+ } else {
+ RETVAL_NULL();
+ }
+}
+static void php_http_message_object_prophandler_set_response_status(php_http_message_object_t *obj, zval *value TSRMLS_DC) {
+ if (PHP_HTTP_MESSAGE_TYPE(RESPONSE, obj->message)) {
+ zval *cpy = php_http_zsep(IS_STRING, value);
+ STR_SET(obj->message->http.info.response.status, estrndup(Z_STRVAL_P(cpy), Z_STRLEN_P(cpy)));
+ zval_ptr_dtor(&cpy);
+ }
+}
+static void php_http_message_object_prophandler_get_response_code(php_http_message_object_t *obj, zval *return_value TSRMLS_DC) {
+ if (PHP_HTTP_MESSAGE_TYPE(RESPONSE, obj->message)) {
+ RETVAL_LONG(obj->message->http.info.response.code);
+ } else {
+ RETVAL_NULL();
+ }
+}
+static void php_http_message_object_prophandler_set_response_code(php_http_message_object_t *obj, zval *value TSRMLS_DC) {
+ if (PHP_HTTP_MESSAGE_TYPE(RESPONSE, obj->message)) {
+ zval *cpy = php_http_zsep(IS_LONG, value);
+ obj->message->http.info.response.code = Z_LVAL_P(cpy);
+ zval_ptr_dtor(&cpy);
+ }
+}
+static void php_http_message_object_prophandler_get_http_version(php_http_message_object_t *obj, zval *return_value TSRMLS_DC) {
+ char *version_str;
+ size_t version_len;
+
+ php_http_version_to_string(&obj->message->http.version, &version_str, &version_len, NULL, NULL TSRMLS_CC);
+ RETVAL_STRINGL(version_str, version_len, 0);
+}
+static void php_http_message_object_prophandler_set_http_version(php_http_message_object_t *obj, zval *value TSRMLS_DC) {
+ zval *cpy = php_http_zsep(IS_STRING, value);
+ php_http_version_parse(&obj->message->http.version, Z_STRVAL_P(cpy) TSRMLS_CC);
+ zval_ptr_dtor(&cpy);
+}
+static void php_http_message_object_prophandler_get_headers(php_http_message_object_t *obj, zval *return_value TSRMLS_DC) {
+ array_init(return_value);
+ zend_hash_copy(Z_ARRVAL_P(return_value), &obj->message->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
+}
+static void php_http_message_object_prophandler_set_headers(php_http_message_object_t *obj, zval *value TSRMLS_DC) {
+ zval *cpy = php_http_zsep(IS_ARRAY, value);
+
+ zend_hash_clean(&obj->message->hdrs);
+ zend_hash_copy(&obj->message->hdrs, Z_ARRVAL_P(cpy), (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
+ zval_ptr_dtor(&cpy);
+}
+static void php_http_message_object_prophandler_get_body(php_http_message_object_t *obj, zval *return_value TSRMLS_DC) {
+ if (obj->body.handle) {
+ RETVAL_OBJVAL(obj->body, 1);
+ } else {
+ RETVAL_NULL();
+ }
+}
+static void php_http_message_object_prophandler_set_body(php_http_message_object_t *obj, zval *value TSRMLS_DC) {
+ if (Z_TYPE_P(value) == IS_OBJECT && instanceof_function(Z_OBJCE_P(value), php_http_message_body_class_entry TSRMLS_CC)) {
+ if (obj->body.handle) {
+ zend_objects_store_del_ref_by_handle(obj->body.handle TSRMLS_CC);
+ }
+ Z_OBJ_ADDREF_P(value);
+ obj->body = Z_OBJVAL_P(value);
+ }
+}
+static void php_http_message_object_prophandler_get_parent_message(php_http_message_object_t *obj, zval *return_value TSRMLS_DC) {
+ if (obj->message->parent) {
+ RETVAL_OBJVAL(obj->parent, 1);
+ } else {
+ RETVAL_NULL();
+ }
+}
+static void php_http_message_object_prophandler_set_parent_message(php_http_message_object_t *obj, zval *value TSRMLS_DC) {
+ if (Z_TYPE_P(value) == IS_OBJECT && instanceof_function(Z_OBJCE_P(value), php_http_message_class_entry TSRMLS_CC)) {
+ if (obj->message->parent) {
+ zend_objects_store_del_ref_by_handle(obj->parent.handle TSRMLS_CC);
+ }
+ Z_OBJ_ADDREF_P(value);
+ obj->parent = Z_OBJVAL_P(value);
+ }
+}
+
+PHP_MINIT_FUNCTION(http_message)
+{
+ PHP_HTTP_REGISTER_CLASS(http, Message, http_message, php_http_object_class_entry, 0);
+ php_http_message_class_entry->create_object = php_http_message_object_new;
+ memcpy(&php_http_message_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
+ php_http_message_object_handlers.clone_obj = php_http_message_object_clone;
+ php_http_message_object_handlers.read_property = php_http_message_object_read_prop;
+ php_http_message_object_handlers.write_property = php_http_message_object_write_prop;
+ php_http_message_object_handlers.get_properties = php_http_message_object_get_props;
+ php_http_message_object_handlers.get_property_ptr_ptr = php_http_message_object_get_prop_ptr;
+
+ zend_class_implements(php_http_message_class_entry TSRMLS_CC, 3, spl_ce_Countable, zend_ce_serializable, zend_ce_iterator);
+
+ zend_hash_init(&php_http_message_object_prophandlers, 9, NULL, NULL, 1);
+ zend_declare_property_long(php_http_message_class_entry, ZEND_STRL("type"), PHP_HTTP_NONE, ZEND_ACC_PROTECTED TSRMLS_CC);
+ php_http_message_object_add_prophandler(ZEND_STRL("type"), php_http_message_object_prophandler_get_type, php_http_message_object_prophandler_set_type);
+ zend_declare_property_string(php_http_message_class_entry, ZEND_STRL("body"), "", ZEND_ACC_PROTECTED TSRMLS_CC);
+ php_http_message_object_add_prophandler(ZEND_STRL("body"), php_http_message_object_prophandler_get_body, php_http_message_object_prophandler_set_body);
+ zend_declare_property_string(php_http_message_class_entry, ZEND_STRL("requestMethod"), "", ZEND_ACC_PROTECTED TSRMLS_CC);
+ php_http_message_object_add_prophandler(ZEND_STRL("requestMethod"), php_http_message_object_prophandler_get_request_method, php_http_message_object_prophandler_set_request_method);
+ zend_declare_property_string(php_http_message_class_entry, ZEND_STRL("requestUrl"), "", ZEND_ACC_PROTECTED TSRMLS_CC);
+ php_http_message_object_add_prophandler(ZEND_STRL("requestUrl"), php_http_message_object_prophandler_get_request_url, php_http_message_object_prophandler_set_request_url);
+ zend_declare_property_string(php_http_message_class_entry, ZEND_STRL("responseStatus"), "", ZEND_ACC_PROTECTED TSRMLS_CC);
+ php_http_message_object_add_prophandler(ZEND_STRL("responseStatus"), php_http_message_object_prophandler_get_response_status, php_http_message_object_prophandler_set_response_status);
+ zend_declare_property_long(php_http_message_class_entry, ZEND_STRL("responseCode"), 0, ZEND_ACC_PROTECTED TSRMLS_CC);
+ php_http_message_object_add_prophandler(ZEND_STRL("responseCode"), php_http_message_object_prophandler_get_response_code, php_http_message_object_prophandler_set_response_code);
+ zend_declare_property_null(php_http_message_class_entry, ZEND_STRL("httpVersion"), ZEND_ACC_PROTECTED TSRMLS_CC);
+ php_http_message_object_add_prophandler(ZEND_STRL("httpVersion"), php_http_message_object_prophandler_get_http_version, php_http_message_object_prophandler_set_http_version);
+ zend_declare_property_null(php_http_message_class_entry, ZEND_STRL("headers"), ZEND_ACC_PROTECTED TSRMLS_CC);
+ php_http_message_object_add_prophandler(ZEND_STRL("headers"), php_http_message_object_prophandler_get_headers, php_http_message_object_prophandler_set_headers);
+ zend_declare_property_null(php_http_message_class_entry, ZEND_STRL("parentMessage"), ZEND_ACC_PROTECTED TSRMLS_CC);
+ php_http_message_object_add_prophandler(ZEND_STRL("parentMessage"), php_http_message_object_prophandler_get_parent_message, php_http_message_object_prophandler_set_parent_message);
+
+ zend_declare_class_constant_long(php_http_message_class_entry, ZEND_STRL("TYPE_NONE"), PHP_HTTP_NONE TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_message_class_entry, ZEND_STRL("TYPE_REQUEST"), PHP_HTTP_REQUEST TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_message_class_entry, ZEND_STRL("TYPE_RESPONSE"), PHP_HTTP_RESPONSE TSRMLS_CC);
+
+ return SUCCESS;
+}
+
+PHP_MSHUTDOWN_FUNCTION(http_message)
+{
+ zend_hash_destroy(&php_http_message_object_prophandlers);
+
+ return SUCCESS;
+}
+
+void php_http_message_object_reverse(zval *this_ptr, zval *return_value TSRMLS_DC)
+{
+ int i = 0;
+ php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ /* count */
+ php_http_message_count(i, obj->message);
+
+ if (i > 1) {
+ zval o;
+ zend_object_value *ovalues = NULL;
+ php_http_message_object_t **objects = NULL;
+ int last = i - 1;
+
+ objects = ecalloc(i, sizeof(**objects));
+ ovalues = ecalloc(i, sizeof(*ovalues));
+
+ /* we are the first message */
+ objects[0] = obj;
+ ovalues[0] = getThis()->value.obj;
+
+ /* fetch parents */
+ INIT_PZVAL(&o);
+ o.type = IS_OBJECT;
+ for (i = 1; obj->parent.handle; ++i) {
+ o.value.obj = obj->parent;
+ ovalues[i] = o.value.obj;
+ objects[i] = obj = zend_object_store_get_object(&o TSRMLS_CC);
+ }
+
+ /* reorder parents */
+ for (last = --i; i; --i) {
+ objects[i]->message->parent = objects[i-1]->message;
+ objects[i]->parent = ovalues[i-1];
+ }
+ objects[0]->message->parent = NULL;
+ objects[0]->parent.handle = 0;
+ objects[0]->parent.handlers = NULL;
+
+ /* add ref (why?) */
+ Z_OBJ_ADDREF_P(getThis());
+ RETVAL_OBJVAL(ovalues[last], 1);
+
+ efree(objects);
+ efree(ovalues);
+ } else {
+ RETURN_ZVAL(getThis(), 1, 0);
+ }
+}
+
+void php_http_message_object_prepend(zval *this_ptr, zval *prepend, zend_bool top TSRMLS_DC)
+{
+ zval m;
+ php_http_message_t *save_parent_msg = NULL;
+ zend_object_value save_parent_obj = {0, NULL};
+ php_http_message_object_t *obj = zend_object_store_get_object(this_ptr TSRMLS_CC);
+ php_http_message_object_t *prepend_obj = zend_object_store_get_object(prepend TSRMLS_CC);
+
+ INIT_PZVAL(&m);
+ m.type = IS_OBJECT;
+
+ if (!top) {
+ save_parent_obj = obj->parent;
+ save_parent_msg = obj->message->parent;
+ } else {
+ /* iterate to the most parent object */
+ while (obj->parent.handle) {
+ m.value.obj = obj->parent;
+ obj = zend_object_store_get_object(&m TSRMLS_CC);
+ }
+ }
+
+ /* prepend */
+ obj->parent = prepend->value.obj;
+ obj->message->parent = prepend_obj->message;
+
+ /* add ref */
+ zend_objects_store_add_ref(prepend TSRMLS_CC);
+ while (prepend_obj->parent.handle) {
+ m.value.obj = prepend_obj->parent;
+ zend_objects_store_add_ref(&m TSRMLS_CC);
+ prepend_obj = zend_object_store_get_object(&m TSRMLS_CC);
+ }
+
+ if (!top) {
+ prepend_obj->parent = save_parent_obj;
+ prepend_obj->message->parent = save_parent_msg;
+ }
+}
+
+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);
+}
+
+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)
+{
+ zend_object_value ov;
+ php_http_message_object_t *o;
+
+ o = ecalloc(1, sizeof(php_http_message_object_t));
+ zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
+ object_properties_init((zend_object *) o, ce);
+
+ if (ptr) {
+ *ptr = o;
+ }
+
+ if (msg) {
+ o->message = msg;
+ if (msg->parent) {
+ o->parent = php_http_message_object_new_ex(ce, msg->parent, NULL TSRMLS_CC);
+ }
+ o->body = php_http_message_body_object_new_ex(php_http_message_body_class_entry, php_http_message_body_copy(&msg->body, NULL, 0), NULL TSRMLS_CC);
+ }
+
+ ov.handle = zend_objects_store_put((zend_object *) o, NULL, php_http_message_object_free, NULL TSRMLS_CC);
+ ov.handlers = &php_http_message_object_handlers;
+
+ return ov;
+}
+
+zend_object_value php_http_message_object_clone(zval *this_ptr TSRMLS_DC)
+{
+ zend_object_value new_ov;
+ php_http_message_object_t *new_obj = NULL;
+ php_http_message_object_t *old_obj = zend_object_store_get_object(this_ptr TSRMLS_CC);
+
+ new_ov = php_http_message_object_new_ex(old_obj->zo.ce, php_http_message_copy(old_obj->message, NULL), &new_obj);
+ zend_objects_clone_members(&new_obj->zo, new_ov, &old_obj->zo, Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC);
+
+ return new_ov;
+}
+
+void php_http_message_object_free(void *object TSRMLS_DC)
+{
+ php_http_message_object_t *o = (php_http_message_object_t *) object;
+
+ if (o->iterator) {
+ zval_ptr_dtor(&o->iterator);
+ o->iterator = NULL;
+ }
+ if (o->message) {
+ /* do NOT free recursivly */
+ php_http_message_dtor(o->message);
+ efree(o->message);
+ o->message = NULL;
+ }
+ if (o->parent.handle) {
+ zend_objects_store_del_ref_by_handle(o->parent.handle TSRMLS_CC);
+ }
+ if (o->body.handle) {
+ zend_objects_store_del_ref_by_handle(o->body.handle TSRMLS_CC);
+ }
+ zend_object_std_dtor((zend_object *) o TSRMLS_CC);
+ efree(o);
+}
+
+
+static zval **php_http_message_object_get_prop_ptr(zval *object, zval *member, const zend_literal *literal_key TSRMLS_DC) {
+ php_http_message_object_prophandler_t *handler;
+ zval *copy = php_http_zsep(IS_STRING, member);
+
+ if (SUCCESS == php_http_message_object_get_prophandler(Z_STRVAL_P(copy), Z_STRLEN_P(copy), &handler)) {
+ zval_ptr_dtor(©);
+ return &php_http_property_proxy_init(NULL, object, member TSRMLS_CC)->myself;
+ }
+ zval_ptr_dtor(©);
+
+ return zend_get_std_object_handlers()->get_property_ptr_ptr(object, member, literal_key TSRMLS_CC);
+}
+
+static zval *php_http_message_object_read_prop(zval *object, zval *member, int type, const zend_literal *literal_key TSRMLS_DC)
+{
+ php_http_message_object_t *obj = zend_object_store_get_object(object TSRMLS_CC);
+ php_http_message_object_prophandler_t *handler;
+ zval *return_value, *copy = php_http_zsep(IS_STRING, member);
+
+ if (SUCCESS == php_http_message_object_get_prophandler(Z_STRVAL_P(copy), Z_STRLEN_P(copy), &handler)) {
+ if (type == BP_VAR_W) {
+ zval_ptr_dtor(©);
+ zend_error(E_ERROR, "Cannot access HttpMessage properties by reference or array key/index");
+ return NULL;
+ }
+
+ ALLOC_ZVAL(return_value);
+ Z_SET_REFCOUNT_P(return_value, 0);
+ Z_UNSET_ISREF_P(return_value);
+
+ handler->read(obj, return_value TSRMLS_CC);
+
+ } else {
+ return_value = zend_get_std_object_handlers()->read_property(object, member, type, literal_key TSRMLS_CC);
+ }
+
+ zval_ptr_dtor(©);
+
+ return return_value;
+}
+
+static void php_http_message_object_write_prop(zval *object, zval *member, zval *value, const zend_literal *literal_key TSRMLS_DC)
+{
+ php_http_message_object_t *obj = zend_object_store_get_object(object TSRMLS_CC);
+ php_http_message_object_prophandler_t *handler;
+ zval *copy = php_http_zsep(IS_STRING, member);
+
+ if (SUCCESS == php_http_message_object_get_prophandler(Z_STRVAL_P(copy), Z_STRLEN_P(copy), &handler)) {
+ handler->write(obj, value TSRMLS_CC);
+ } else {
+ zend_get_std_object_handlers()->write_property(object, member, value, literal_key TSRMLS_CC);
+ }
+
+ zval_ptr_dtor(©);
+}
+
+
+static HashTable *php_http_message_object_get_props(zval *object TSRMLS_DC)
+{
+ zval *headers;
+ php_http_message_object_t *obj = zend_object_store_get_object(object TSRMLS_CC);
+ php_http_message_t *msg = obj->message;
+ HashTable *props = zend_get_std_object_handlers()->get_properties(object TSRMLS_CC);
+ zval array, *parent, *body;
+ char *version;
+
+ INIT_PZVAL_ARRAY(&array, props);
+
+#define ASSOC_PROP(array, ptype, name, val) \
+ { \
+ char *m_prop_name; \
+ int m_prop_len; \
+ zend_mangle_property_name(&m_prop_name, &m_prop_len, "*", 1, name, lenof(name), 0); \
+ add_assoc_ ##ptype## _ex(&array, m_prop_name, sizeof(name)+3, val); \
+ efree(m_prop_name); \
+ }
+#define ASSOC_STRING(array, name, val) ASSOC_STRINGL(array, name, val, strlen(val))
+#define ASSOC_STRINGL(array, name, val, len) ASSOC_STRINGL_EX(array, name, val, len, 1)
+#define ASSOC_STRINGL_EX(array, name, val, len, cpy) \
+ { \
+ char *m_prop_name; \
+ int m_prop_len; \
+ zend_mangle_property_name(&m_prop_name, &m_prop_len, "*", 1, name, lenof(name), 0); \
+ add_assoc_stringl_ex(&array, m_prop_name, sizeof(name)+3, val, len, cpy); \
+ efree(m_prop_name); \
+ }
+
+ ASSOC_PROP(array, long, "type", msg->type);
+ ASSOC_STRINGL_EX(array, "httpVersion", version, spprintf(&version, 0, "%u.%u", msg->http.version.major, msg->http.version.minor), 0);
+
+ switch (msg->type) {
+ case PHP_HTTP_REQUEST:
+ ASSOC_PROP(array, long, "responseCode", 0);
+ ASSOC_STRINGL(array, "responseStatus", "", 0);
+ ASSOC_STRING(array, "requestMethod", STR_PTR(msg->http.info.request.method));
+ ASSOC_STRING(array, "requestUrl", STR_PTR(msg->http.info.request.url));
+ break;
+
+ case PHP_HTTP_RESPONSE:
+ ASSOC_PROP(array, long, "responseCode", msg->http.info.response.code);
+ ASSOC_STRING(array, "responseStatus", STR_PTR(msg->http.info.response.status));
+ ASSOC_STRINGL(array, "requestMethod", "", 0);
+ ASSOC_STRINGL(array, "requestUrl", "", 0);
+ break;
+
+ case PHP_HTTP_NONE:
+ default:
+ ASSOC_PROP(array, long, "responseCode", 0);
+ ASSOC_STRINGL(array, "responseStatus", "", 0);
+ ASSOC_STRINGL(array, "requestMethod", "", 0);
+ ASSOC_STRINGL(array, "requestUrl", "", 0);
+ break;
+ }
+
+ MAKE_STD_ZVAL(headers);
+ array_init(headers);
+ zend_hash_copy(Z_ARRVAL_P(headers), &msg->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
+ ASSOC_PROP(array, zval, "headers", headers);
+
+ MAKE_STD_ZVAL(body);
+ if (!obj->body.handle) {
+ php_http_new(&obj->body, php_http_message_body_class_entry, (php_http_new_t) php_http_message_body_object_new_ex, NULL, (void *) php_http_message_body_copy(&obj->message->body, NULL, 0), NULL TSRMLS_CC);
+ }
+ ZVAL_OBJVAL(body, obj->body, 1);
+ ASSOC_PROP(array, zval, "body", body);
+
+ MAKE_STD_ZVAL(parent);
+ if (msg->parent) {
+ ZVAL_OBJVAL(parent, obj->parent, 1);
+ } else {
+ ZVAL_NULL(parent);
+ }
+ ASSOC_PROP(array, zval, "parentMessage", parent);
+
+ return props;
+}
+
+/* PHP */
+
+PHP_METHOD(HttpMessage, __construct)
+{
+ int length = 0;
+ char *message = NULL;
+ php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ with_error_handling(EH_THROW, PHP_HTTP_EX_CE(runtime)) {
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &message, &length) && message && length) {
+ php_http_message_t *msg = obj->message;
+
+ php_http_message_dtor(msg);
+ with_error_handling(EH_THROW, PHP_HTTP_EX_CE(message)) {
+ if ((obj->message = php_http_message_parse(msg, message, length))) {
+ if (obj->message->parent) {
+ obj->parent = php_http_message_object_new_ex(Z_OBJCE_P(getThis()), obj->message->parent, NULL TSRMLS_CC);
+ }
+ } else {
+ obj->message = php_http_message_init(msg, 0 TSRMLS_CC);
+ }
+ } end_error_handling();
+ }
+ if (!obj->message) {
+ obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
+ }
+ } end_error_handling();
+
+}
+
+PHP_METHOD(HttpMessage, getBody)
+{
+ with_error_handling(EH_THROW, PHP_HTTP_EX_CE(message)) {
+ if (SUCCESS == zend_parse_parameters_none()) {
+ php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (!obj->message) {
+ obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
+ }
+
+ if (obj->body.handle || SUCCESS == php_http_new(&obj->body, php_http_message_body_class_entry, (php_http_new_t) php_http_message_body_object_new_ex, NULL, (void *) php_http_message_body_copy(&obj->message->body, NULL, 0), NULL TSRMLS_CC)) {
+ RETVAL_OBJVAL(obj->body, 1);
+ }
+ }
+ } end_error_handling();
+}
+
+PHP_METHOD(HttpMessage, setBody)
+{
+ zval *zbody;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &zbody, php_http_message_body_class_entry)) {
+ php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+ php_http_message_body_object_t *body_obj = zend_object_store_get_object(zbody TSRMLS_CC);
+
+ if (!obj->message) {
+ obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
+ }
+
+ php_http_message_body_dtor(&obj->message->body);
+ php_http_message_body_init(&obj->message->body, php_http_message_body_stream(body_obj->body));
+ Z_OBJ_ADDREF_P(zbody);
+ obj->body = Z_OBJVAL_P(zbody);
+ RETURN_TRUE;
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpMessage, getHeader)
+{
+ char *header_str;
+ int header_len;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &header_str, &header_len)) {
+ php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+ zval *header;
+
+ if (!obj->message) {
+ obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
+ }
+
+ if ((header = php_http_message_header(obj->message, header_str, header_len, 0))) {
+ RETURN_ZVAL(header, 1, 1);
+ }
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpMessage, getHeaders)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (!obj->message) {
+ obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
+ }
+
+ array_init(return_value);
+ array_copy(&obj->message->hdrs, Z_ARRVAL_P(return_value));
+ }
+}
+
+PHP_METHOD(HttpMessage, setHeader)
+{
+ zval *zvalue = NULL;
+ char *name_str;
+ int name_len;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z!", &name_str, &name_len, &zvalue)) {
+ php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+ char *name = php_http_pretty_key(estrndup(name_str, name_len), name_len, 1, 1);
+
+ if (!obj->message) {
+ obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
+ }
+
+ if (!zvalue) {
+ RETVAL_SUCCESS(zend_hash_del(&obj->message->hdrs, name, name_len + 1));
+ } else {
+ Z_ADDREF_P(zvalue);
+ RETVAL_SUCCESS(zend_hash_update(&obj->message->hdrs, name, name_len + 1, &zvalue, sizeof(void *), NULL));
+ }
+ efree(name);
+ return;
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpMessage, setHeaders)
+{
+ zval *new_headers = NULL;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/!", &new_headers)) {
+ php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (!obj->message) {
+ obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
+ }
+
+ zend_hash_clean(&obj->message->hdrs);
+ if (new_headers) {
+ array_join(Z_ARRVAL_P(new_headers), &obj->message->hdrs, 0, ARRAY_JOIN_PRETTIFY|ARRAY_JOIN_STRONLY);
+ }
+ RETURN_TRUE;
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpMessage, addHeader)
+{
+ zval *zvalue;
+ char *name_str;
+ int name_len;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &name_str, &name_len, &zvalue)) {
+ php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+ char *name = php_http_pretty_key(estrndup(name_str, name_len), name_len, 1, 1);
+ zval *header;
+
+ if (!obj->message) {
+ obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
+ }
+
+ Z_ADDREF_P(zvalue);
+ if ((header = php_http_message_header(obj->message, name, name_len, 0))) {
+ convert_to_array(header);
+ RETVAL_SUCCESS(zend_hash_next_index_insert(Z_ARRVAL_P(header), &zvalue, sizeof(void *), NULL));
+ } else {
+ RETVAL_SUCCESS(zend_hash_update(&obj->message->hdrs, name, name_len + 1, &zvalue, sizeof(void *), NULL));
+ }
+ efree(name);
+ return;
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpMessage, addHeaders)
+{
+ zval *new_headers;
+ zend_bool append = 0;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|b", &new_headers, &append)) {
+ php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (!obj->message) {
+ obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
+ }
+
+ array_join(Z_ARRVAL_P(new_headers), &obj->message->hdrs, append, ARRAY_JOIN_STRONLY|ARRAY_JOIN_PRETTIFY);
+ RETURN_TRUE;
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpMessage, getType)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (!obj->message) {
+ obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
+ }
+
+ RETURN_LONG(obj->message->type);
+ }
+}
+
+PHP_METHOD(HttpMessage, setType)
+{
+ long type;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &type)) {
+ php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (!obj->message) {
+ obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
+ }
+
+ php_http_message_set_type(obj->message, type);
+ RETURN_TRUE;
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpMessage, getInfo)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (!obj->message) {
+ obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
+ }
+
+ switch (obj->message->type) {
+ case PHP_HTTP_REQUEST:
+ Z_STRLEN_P(return_value) = spprintf(&Z_STRVAL_P(return_value), 0, PHP_HTTP_INFO_REQUEST_FMT_ARGS(&obj->message->http, ""));
+ break;
+ case PHP_HTTP_RESPONSE:
+ Z_STRLEN_P(return_value) = spprintf(&Z_STRVAL_P(return_value), 0, PHP_HTTP_INFO_RESPONSE_FMT_ARGS(&obj->message->http, ""));
+ break;
+ default:
+ RETURN_NULL();
+ break;
+ }
+ Z_TYPE_P(return_value) = IS_STRING;
+ return;
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpMessage, setInfo)
+{
+ char *str;
+ int len;
+ php_http_info_t inf;
+
+ if ( SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len)
+ && php_http_info_parse(&inf, str TSRMLS_CC)) {
+ php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (!obj->message) {
+ obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
+ }
+
+ php_http_message_set_info(obj->message, &inf);
+ php_http_info_dtor(&inf);
+ RETURN_TRUE;
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpMessage, getHttpVersion)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ char *str;
+ size_t len;
+ php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (!obj->message) {
+ obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
+ }
+
+ php_http_version_to_string(&obj->message->http.version, &str, &len, NULL, NULL TSRMLS_CC);
+ RETURN_STRINGL(str, len, 0);
+ }
+
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpMessage, setHttpVersion)
+{
+ char *v_str;
+ int v_len;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &v_str, &v_len)) {
+ php_http_version_t version;
+ php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (!obj->message) {
+ obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
+ }
+
+ if (php_http_version_parse(&version, v_str TSRMLS_CC)) {
+ obj->message->http.version = version;
+ RETURN_TRUE;
+ }
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpMessage, getResponseCode)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (!obj->message) {
+ obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
+ }
+
+ PHP_HTTP_MESSAGE_TYPE_CHECK(RESPONSE, obj->message, RETURN_FALSE);
+ RETURN_LONG(obj->message->http.info.response.code);
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpMessage, setResponseCode)
+{
+ long code;
+ zend_bool strict = 1;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|b", &code, &strict)) {
+ php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (!obj->message) {
+ obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
+ }
+
+ PHP_HTTP_MESSAGE_TYPE_CHECK(RESPONSE, obj->message, RETURN_FALSE);
+ if (strict && (code < 100 || code > 599)) {
+ php_http_error(HE_WARNING, PHP_HTTP_E_INVALID_PARAM, "Invalid response code (100-599): %ld", code);
+ RETURN_FALSE;
+ }
+
+ obj->message->http.info.response.code = code;
+ RETURN_TRUE;
+ }
+
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpMessage, getResponseStatus)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (!obj->message) {
+ obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
+ }
+
+ PHP_HTTP_MESSAGE_TYPE_CHECK(RESPONSE, obj->message, RETURN_FALSE);
+ if (obj->message->http.info.response.status) {
+ RETURN_STRING(obj->message->http.info.response.status, 1);
+ } else {
+ RETURN_EMPTY_STRING();
+ }
+ }
+
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpMessage, setResponseStatus)
+{
+ char *status;
+ int status_len;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &status, &status_len)) {
+ php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (!obj->message) {
+ obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
+ }
+
+ PHP_HTTP_MESSAGE_TYPE_CHECK(RESPONSE, obj->message, RETURN_FALSE);
+ STR_SET(obj->message->http.info.response.status, estrndup(status, status_len));
+ RETURN_TRUE;
+ }
+
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpMessage, getRequestMethod)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (!obj->message) {
+ obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
+ }
+
+ PHP_HTTP_MESSAGE_TYPE_CHECK(REQUEST, obj->message, RETURN_FALSE);
+ if (obj->message->http.info.request.method) {
+ RETURN_STRING(obj->message->http.info.request.method, 1);
+ } else {
+ RETURN_EMPTY_STRING();
+ }
+ }
+
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpMessage, setRequestMethod)
+{
+ char *method;
+ int method_len;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &method, &method_len)) {
+ php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (!obj->message) {
+ obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
+ }
+
+ PHP_HTTP_MESSAGE_TYPE_CHECK(REQUEST, obj->message, RETURN_FALSE);
+ if (method_len < 1) {
+ php_http_error(HE_WARNING, PHP_HTTP_E_INVALID_PARAM, "Cannot set HttpMessage::requestMethod to an empty string");
+ RETURN_FALSE;
+ }
+
+ STR_SET(obj->message->http.info.request.method, estrndup(method, method_len));
+ RETURN_TRUE;
+ }
+
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpMessage, getRequestUrl)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (!obj->message) {
+ obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
+ }
+
+ PHP_HTTP_MESSAGE_TYPE_CHECK(REQUEST, obj->message, RETURN_FALSE);
+ if (obj->message->http.info.request.url) {
+ RETURN_STRING(obj->message->http.info.request.url, 1);
+ } else {
+ RETURN_EMPTY_STRING();
+ }
+ }
+
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpMessage, setRequestUrl)
+{
+ char *url_str;
+ int url_len;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &url_str, &url_len)) {
+ php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (!obj->message) {
+ obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
+ }
+
+ PHP_HTTP_MESSAGE_TYPE_CHECK(REQUEST, obj->message, RETURN_FALSE);
+ if (url_len < 1) {
+ php_http_error(HE_WARNING, PHP_HTTP_E_INVALID_PARAM, "Cannot set HttpMessage::requestUrl to an empty string");
+ RETURN_FALSE;
+ }
+ STR_SET(obj->message->http.info.request.url, estrndup(url_str, url_len));
+ RETURN_TRUE;
+ }
+
+ RETURN_FALSE;
+}
+
+
+PHP_METHOD(HttpMessage, getParentMessage)
+{
+ with_error_handling(EH_THROW, PHP_HTTP_EX_CE(message)) {
+ if (SUCCESS == zend_parse_parameters_none()) {
+ php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (!obj->message) {
+ obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
+ }
+
+ if (obj->message->parent) {
+ RETVAL_OBJVAL(obj->parent, 1);
+ } else {
+ php_http_error(HE_WARNING, PHP_HTTP_E_RUNTIME, "HttpMessage does not have a parent message");
+ }
+ }
+ } end_error_handling();
+}
+
+PHP_METHOD(HttpMessage, toString)
+{
+ zend_bool include_parent = 0;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &include_parent)) {
+ php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+ char *string;
+ size_t length;
+
+ if (!obj->message) {
+ obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
+ }
+
+ if (include_parent) {
+ php_http_message_serialize(obj->message, &string, &length);
+ } else {
+ php_http_message_to_string(obj->message, &string, &length);
+ }
+ if (string) {
+ RETURN_STRINGL(string, length, 0);
+ }
+ }
+ RETURN_EMPTY_STRING();
+}
+
+PHP_METHOD(HttpMessage, serialize)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+ char *string;
+ size_t length;
+
+ if (!obj->message) {
+ obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
+ }
+
+ php_http_message_serialize(obj->message, &string, &length);
+ RETURN_STRINGL(string, length, 0);
+ }
+ RETURN_EMPTY_STRING();
+}
+
+PHP_METHOD(HttpMessage, unserialize)
+{
+ int length;
+ char *serialized;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &serialized, &length)) {
+ php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+ php_http_message_t *msg;
+
+ if (obj->message) {
+ php_http_message_dtor(obj->message);
+ efree(obj->message);
+ }
+ if ((msg = php_http_message_parse(NULL, serialized, (size_t) length TSRMLS_CC))) {
+ obj->message = msg;
+ } else {
+ obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
+ php_http_error(HE_ERROR, PHP_HTTP_E_RUNTIME, "Could not unserialize HttpMessage");
+ }
+ }
+}
+
+PHP_METHOD(HttpMessage, detach)
+{
+ with_error_handling(EH_THROW, PHP_HTTP_EX_CE(message)) {
+ if (SUCCESS == zend_parse_parameters_none()) {
+ php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (!obj->message) {
+ obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
+ }
+
+ RETVAL_OBJVAL(php_http_message_object_new_ex(obj->zo.ce, php_http_message_copy(obj->message, NULL), NULL TSRMLS_CC), 0);
+ }
+ } end_error_handling();
+}
+
+PHP_METHOD(HttpMessage, prepend)
+{
+ zval *prepend;
+ zend_bool top = 1;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|b", &prepend, php_http_message_class_entry, &top)) {
+ php_http_message_t *msg[2];
+ php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+ php_http_message_object_t *prepend_obj = zend_object_store_get_object(prepend TSRMLS_CC);
+
+ if (!obj->message) {
+ obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
+ }
+ if (!prepend_obj->message) {
+ prepend_obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
+ }
+
+ /* safety check */
+ for (msg[0] = obj->message; msg[0]; msg[0] = msg[0]->parent) {
+ for (msg[1] = prepend_obj->message; msg[1]; msg[1] = msg[1]->parent) {
+ if (msg[0] == msg[1]) {
+ php_http_error(HE_THROW, PHP_HTTP_E_INVALID_PARAM, "Cannot prepend a message located within the same message chain");
+ return;
+ }
+ }
+ }
+
+ php_http_message_object_prepend(getThis(), prepend, top TSRMLS_CC);
+ }
+}
+
+PHP_METHOD(HttpMessage, reverse)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ php_http_message_object_reverse(getThis(), return_value TSRMLS_CC);
+ }
+}
+
+PHP_METHOD(HttpMessage, count)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ long i = 0;
+ php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (!obj->message) {
+ obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
+ }
+
+ php_http_message_count(i, obj->message);
+ RETURN_LONG(i);
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpMessage, rewind)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ zval *zobj = getThis();
+ php_http_message_object_t *obj = zend_object_store_get_object(zobj TSRMLS_CC);
+
+ if (obj->iterator) {
+ zval_ptr_dtor(&obj->iterator);
+ }
+ Z_ADDREF_P(zobj);
+ obj->iterator = zobj;
+ }
+}
+
+PHP_METHOD(HttpMessage, valid)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ RETURN_BOOL(obj->iterator != NULL);
+ }
+}
+
+PHP_METHOD(HttpMessage, next)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (obj->iterator) {
+ php_http_message_object_t *itr = zend_object_store_get_object(obj->iterator TSRMLS_CC);
+
+ if (itr && itr->parent.handle) {
+ zval *old = obj->iterator;
+ MAKE_STD_ZVAL(obj->iterator);
+ ZVAL_OBJVAL(obj->iterator, itr->parent, 1);
+ zval_ptr_dtor(&old);
+ } else {
+ zval_ptr_dtor(&obj->iterator);
+ obj->iterator = NULL;
+ }
+ }
+ }
+}
+
+PHP_METHOD(HttpMessage, key)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ RETURN_LONG(obj->iterator ? obj->iterator->value.obj.handle:0);
+ }
+}
+
+PHP_METHOD(HttpMessage, current)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (obj->iterator) {
+ RETURN_ZVAL(obj->iterator, 1, 0);
+ }
+ }
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
+
--- /dev/null
+/*
+ +--------------------------------------------------------------------+
+ | PECL :: http |
+ +--------------------------------------------------------------------+
+ | Redistribution and use in source and binary forms, with or without |
+ | modification, are permitted provided that the conditions mentioned |
+ | in the accompanying LICENSE file are met. |
+ +--------------------------------------------------------------------+
+ | Copyright (c) 2004-2010, Michael Wallner <mike@php.net> |
+ +--------------------------------------------------------------------+
+*/
+
+/* $Id: php_http_message.h 292841 2009-12-31 08:48:57Z mike $ */
+
+#ifndef PHP_HTTP_MESSAGE_H
+#define PHP_HTTP_MESSAGE_H
+
+/* required minimum length of an HTTP message "HTTP/1.1" */
+#define PHP_HTTP_MESSAGE_MIN_SIZE 8
+#define PHP_HTTP_MESSAGE_TYPE(TYPE, msg) ((msg) && ((msg)->type == PHP_HTTP_ ##TYPE))
+#define PHP_HTTP_MESSAGE_TYPE_CHECK(type, msg, action) \
+ if (!PHP_HTTP_MESSAGE_TYPE(type, (msg))) { \
+ php_http_error(HE_NOTICE, PHP_HTTP_E_MESSAGE_TYPE, "HttpMessage is not of type "#type); \
+ action; \
+ }
+
+typedef php_http_info_type_t php_http_message_type_t;
+typedef struct php_http_message php_http_message_t;
+
+struct php_http_message {
+ PHP_HTTP_INFO_IMPL(http, type)
+ HashTable hdrs;
+ php_http_message_body_t body;
+ php_http_message_t *parent;
+ void *opaque;
+#ifdef ZTS
+ void ***ts;
+#endif
+};
+
+PHP_HTTP_API zend_bool php_http_message_info_callback(php_http_message_t **message, HashTable **headers, php_http_info_t *info TSRMLS_DC);
+
+PHP_HTTP_API php_http_message_t *php_http_message_init(php_http_message_t *m, php_http_message_type_t t TSRMLS_DC);
+PHP_HTTP_API php_http_message_t *php_http_message_init_env(php_http_message_t *m, php_http_message_type_t t TSRMLS_DC);
+PHP_HTTP_API php_http_message_t *php_http_message_copy(php_http_message_t *from, php_http_message_t *to);
+PHP_HTTP_API void php_http_message_dtor(php_http_message_t *message);
+PHP_HTTP_API void php_http_message_free(php_http_message_t **message);
+
+PHP_HTTP_API void php_http_message_set_type(php_http_message_t *m, php_http_message_type_t t);
+PHP_HTTP_API void php_http_message_set_info(php_http_message_t *message, php_http_info_t *info);
+
+PHP_HTTP_API zval *php_http_message_header(php_http_message_t *msg, char *key_str, size_t key_len, int join);
+
+PHP_HTTP_API void php_http_message_to_string(php_http_message_t *msg, char **string, size_t *length);
+PHP_HTTP_API void php_http_message_to_struct(php_http_message_t *msg, zval *strct);
+PHP_HTTP_API void php_http_message_to_callback(php_http_message_t *msg, php_http_pass_callback_t cb, void *cb_arg);
+
+PHP_HTTP_API void php_http_message_serialize(php_http_message_t *message, char **string, size_t *length);
+PHP_HTTP_API php_http_message_t *php_http_message_reverse(php_http_message_t *msg);
+PHP_HTTP_API php_http_message_t *php_http_message_interconnect(php_http_message_t *m1, php_http_message_t *m2);
+
+#define php_http_message_count(c, m) \
+{ \
+ php_http_message_t *__tmp_msg = (m); \
+ for (c = 0; __tmp_msg; __tmp_msg = __tmp_msg->parent, ++(c)); \
+}
+
+PHP_HTTP_API php_http_message_t *php_http_message_parse(php_http_message_t *msg, const char *str, size_t len TSRMLS_DC);
+
+/* PHP */
+
+typedef struct php_http_message_object {
+ zend_object zo;
+ php_http_message_t *message;
+ zend_object_value parent, body;
+ zval *iterator;
+} php_http_message_object_t;
+
+extern zend_class_entry *php_http_message_class_entry;
+extern zend_function_entry http_message_method_entry[];
+
+extern PHP_MINIT_FUNCTION(http_message);
+extern PHP_MSHUTDOWN_FUNCTION(http_message);
+
+extern void php_http_message_object_prepend(zval *this_ptr, zval *prepend, zend_bool top /* = 1 */ TSRMLS_DC);
+extern void php_http_message_object_reverse(zval *this_ptr, zval *return_value TSRMLS_DC);
+
+extern zend_object_value php_http_message_object_new(zend_class_entry *ce TSRMLS_DC);
+extern 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);
+extern zend_object_value php_http_message_object_clone(zval *object TSRMLS_DC);
+extern void php_http_message_object_free(void *object TSRMLS_DC);
+
+PHP_METHOD(HttpMessage, __construct);
+PHP_METHOD(HttpMessage, getBody);
+PHP_METHOD(HttpMessage, setBody);
+PHP_METHOD(HttpMessage, getHeader);
+PHP_METHOD(HttpMessage, setHeader);
+PHP_METHOD(HttpMessage, addHeader);
+PHP_METHOD(HttpMessage, getHeaders);
+PHP_METHOD(HttpMessage, setHeaders);
+PHP_METHOD(HttpMessage, addHeaders);
+PHP_METHOD(HttpMessage, getType);
+PHP_METHOD(HttpMessage, setType);
+PHP_METHOD(HttpMessage, getInfo);
+PHP_METHOD(HttpMessage, setInfo);
+PHP_METHOD(HttpMessage, getResponseCode);
+PHP_METHOD(HttpMessage, setResponseCode);
+PHP_METHOD(HttpMessage, getResponseStatus);
+PHP_METHOD(HttpMessage, setResponseStatus);
+PHP_METHOD(HttpMessage, getRequestMethod);
+PHP_METHOD(HttpMessage, setRequestMethod);
+PHP_METHOD(HttpMessage, getRequestUrl);
+PHP_METHOD(HttpMessage, setRequestUrl);
+PHP_METHOD(HttpMessage, getHttpVersion);
+PHP_METHOD(HttpMessage, setHttpVersion);
+PHP_METHOD(HttpMessage, guessContentType);
+PHP_METHOD(HttpMessage, getParentMessage);
+PHP_METHOD(HttpMessage, send);
+PHP_METHOD(HttpMessage, toString);
+PHP_METHOD(HttpMessage, toMessageTypeObject);
+
+PHP_METHOD(HttpMessage, count);
+PHP_METHOD(HttpMessage, serialize);
+PHP_METHOD(HttpMessage, unserialize);
+PHP_METHOD(HttpMessage, rewind);
+PHP_METHOD(HttpMessage, valid);
+PHP_METHOD(HttpMessage, current);
+PHP_METHOD(HttpMessage, key);
+PHP_METHOD(HttpMessage, next);
+
+PHP_METHOD(HttpMessage, factory);
+
+PHP_METHOD(HttpMessage, detach);
+PHP_METHOD(HttpMessage, prepend);
+PHP_METHOD(HttpMessage, reverse);
+
+#endif
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
+
--- /dev/null
+/*
+ +--------------------------------------------------------------------+
+ | PECL :: http |
+ +--------------------------------------------------------------------+
+ | Redistribution and use in source and binary forms, with or without |
+ | modification, are permitted provided that the conditions mentioned |
+ | in the accompanying LICENSE file are met. |
+ +--------------------------------------------------------------------+
+ | Copyright (c) 2004-2010, Michael Wallner <mike@php.net> |
+ +--------------------------------------------------------------------+
+*/
+
+/* $Id: http_message_body.c 292841 2009-12-31 08:48:57Z mike $ */
+
+#include "php_http.h"
+
+typedef struct curl_httppost *post_data[2];
+
+static inline STATUS add_field(php_http_message_body_t *body, const char *name, const char *value_str, size_t value_len);
+static inline STATUS add_file(php_http_message_body_t *body, const char *name, const char *path, const char *ctype);
+static STATUS recursive_fields(post_data http_post_data, HashTable *fields, const char *prefix TSRMLS_DC);
+static STATUS recursive_files(post_data http_post_data, HashTable *files, const char *prefix TSRMLS_DC);
+
+PHP_HTTP_API php_http_message_body_t *php_http_message_body_init(php_http_message_body_t *body, php_stream *stream TSRMLS_DC)
+{
+ if (!body) {
+ body = emalloc(sizeof(php_http_message_body_t));
+ }
+
+ if (stream) {
+ php_stream_auto_cleanup(stream);
+ body->stream_id = php_stream_get_resource_id(stream);
+ zend_list_addref(body->stream_id);
+ } else {
+ stream = php_stream_temp_new();
+ php_stream_auto_cleanup(stream);
+ body->stream_id = php_stream_get_resource_id(stream);
+ }
+ TSRMLS_SET_CTX(body->ts);
+
+ return body;
+}
+
+PHP_HTTP_API php_http_message_body_t *php_http_message_body_copy(php_http_message_body_t *from, php_http_message_body_t *to, zend_bool dup_internal_stream_and_contents)
+{
+ if (!from) {
+ return NULL;
+ } else {
+ TSRMLS_FETCH_FROM_CTX(from->ts);
+
+ if (dup_internal_stream_and_contents) {
+ to = php_http_message_body_init(to, NULL TSRMLS_CC);
+ php_http_message_body_to_stream(from, php_http_message_body_stream(to), 0, 0);
+ } else {
+ to = php_http_message_body_init(to, php_http_message_body_stream(from) TSRMLS_CC);
+ }
+
+ return to;
+ }
+}
+
+PHP_HTTP_API void php_http_message_body_dtor(php_http_message_body_t *body)
+{
+ if (body) {
+ /* NO FIXME: shows leakinfo in DEBUG mode */
+ zend_list_delete(body->stream_id);
+ }
+}
+
+PHP_HTTP_API void php_http_message_body_free(php_http_message_body_t **body)
+{
+ if (*body) {
+ php_http_message_body_dtor(*body);
+ efree(*body);
+ *body = NULL;
+ }
+}
+
+PHP_HTTP_API php_stream_statbuf *php_http_message_body_stat(php_http_message_body_t *body)
+{
+ TSRMLS_FETCH_FROM_CTX(body->ts);
+ php_stream_stat(php_http_message_body_stream(body), &body->ssb);
+ return &body->ssb;
+}
+
+PHP_HTTP_API char *php_http_message_body_etag(php_http_message_body_t *body)
+{
+ TSRMLS_FETCH_FROM_CTX(body->ts);
+ php_stream_statbuf *ssb = php_http_message_body_stat(body);
+
+ /* real file or temp buffer ? */
+ if (body->ssb.sb.st_mtime) {
+ char *etag;
+
+ spprintf(&etag, 0, "%lx-%lx-%lx", ssb->sb.st_ino, ssb->sb.st_mtime, ssb->sb.st_size);
+ return etag;
+ } else {
+ void *ctx = php_http_etag_init(TSRMLS_C);
+
+ php_http_message_body_to_callback(body, php_http_etag_update, ctx, 0, 0);
+ return php_http_etag_finish(ctx TSRMLS_CC);
+ }
+}
+
+PHP_HTTP_API void php_http_message_body_to_string(php_http_message_body_t *body, char **buf, size_t *len, off_t offset, size_t forlen)
+{
+ TSRMLS_FETCH_FROM_CTX(body->ts);
+ php_stream *s = php_http_message_body_stream(body);
+
+ php_stream_seek(s, offset, SEEK_SET);
+ if (!forlen) {
+ forlen = -1;
+ }
+ *len = php_stream_copy_to_mem(s, buf, forlen, 0);
+}
+
+PHP_HTTP_API void php_http_message_body_to_stream(php_http_message_body_t *body, php_stream *dst, off_t offset, size_t forlen)
+{
+ TSRMLS_FETCH_FROM_CTX(body->ts);
+ php_stream *s = php_http_message_body_stream(body);
+
+ php_stream_seek(s, offset, SEEK_SET);
+ if (!forlen) {
+ forlen = -1;
+ }
+ php_stream_copy_to_stream_ex(s, dst, forlen, NULL);
+}
+
+PHP_HTTP_API void php_http_message_body_to_callback(php_http_message_body_t *body, php_http_pass_callback_t cb, void *cb_arg, off_t offset, size_t forlen)
+{
+ TSRMLS_FETCH_FROM_CTX(body->ts);
+ php_stream *s = php_http_message_body_stream(body);
+
+ php_stream_seek(s, offset, SEEK_SET);
+
+ if (!forlen) {
+ forlen = -1;
+ }
+ while (!php_stream_eof(s)) {
+ char buf[0x1000];
+ size_t read = php_stream_read(s, buf, MIN(forlen, sizeof(buf)));
+
+ if (read) {
+ cb(cb_arg, buf, read);
+ }
+
+ if (read < MIN(forlen, sizeof(buf))) {
+ break;
+ }
+
+ if (forlen && !(forlen -= read)) {
+ break;
+ }
+ }
+}
+
+PHP_HTTP_API STATUS php_http_message_body_to_callback_in_chunks(php_http_message_body_t *body, php_http_pass_callback_t cb, void *cb_arg, HashTable *chunks)
+{
+ TSRMLS_FETCH_FROM_CTX(body->ts);
+ php_stream *s = php_http_message_body_stream(body);
+ HashPosition pos;
+ zval **chunk;
+
+ FOREACH_HASH_VAL(pos, chunks, chunk) {
+ zval **begin, **end;
+
+ if (IS_ARRAY == Z_TYPE_PP(chunk)
+ && SUCCESS == zend_hash_index_find(Z_ARRVAL_PP(chunk), 0, (void *) &begin)
+ && IS_LONG == Z_TYPE_PP(begin)
+ && SUCCESS == zend_hash_index_find(Z_ARRVAL_PP(chunk), 1, (void *) &end)
+ && IS_LONG == Z_TYPE_PP(end)
+ ) {
+ if (SUCCESS != php_stream_seek(s, Z_LVAL_PP(begin), SEEK_SET)) {
+ return FAILURE;
+ } else {
+ long length = Z_LVAL_PP(end) - Z_LVAL_PP(begin) + 1;
+
+ while (length > 0 && !php_stream_eof(s)) {
+ char buf[0x1000];
+ size_t read = php_stream_read(s, buf, MIN(length, sizeof(buf)));
+
+ if (read) {
+ cb(cb_arg, buf, read);
+ }
+
+ if (read < MIN(length, sizeof(buf))) {
+ break;
+ }
+
+ length -= read;
+ }
+ }
+ }
+ }
+
+ return SUCCESS;
+}
+
+PHP_HTTP_API size_t php_http_message_body_append(php_http_message_body_t *body, const char *buf, size_t len)
+{
+ TSRMLS_FETCH_FROM_CTX(body->ts);
+ php_stream *s = php_http_message_body_stream(body);
+
+ php_stream_seek(s, 0, SEEK_END);
+ return php_stream_write(s, buf, len);
+}
+
+PHP_HTTP_API STATUS php_http_message_body_add(php_http_message_body_t *body, HashTable *fields, HashTable *files)
+{
+ post_data http_post_data = {NULL, NULL};
+ TSRMLS_FETCH_FROM_CTX(body->ts);
+
+ if (fields && SUCCESS != recursive_fields(http_post_data, fields, NULL TSRMLS_CC)) {
+ return FAILURE;
+ }
+ if (files && (zend_hash_num_elements(files) > 0) && (SUCCESS != recursive_files(http_post_data, files, NULL TSRMLS_CC))) {
+ return FAILURE;
+ }
+ if (CURLE_OK != curl_formget(http_post_data[0], body, (curl_formget_callback) php_http_message_body_append)) {
+ return FAILURE;
+ }
+ return SUCCESS;
+}
+
+PHP_HTTP_API STATUS php_http_message_body_add_field(php_http_message_body_t *body, const char *name, const char *value_str, size_t value_len)
+{
+ return add_field(body, name, value_str, value_len);
+}
+
+PHP_HTTP_API STATUS php_http_message_body_add_file(php_http_message_body_t *body, const char *name, const char *path, const char *ctype)
+{
+ return add_file(body, name, path, ctype);
+}
+
+static inline char *format_key(uint type, char *str, ulong num, const char *prefix, int numeric_key_for_empty_prefix) {
+ char *new_key = NULL;
+
+ if (prefix && *prefix) {
+ if (type == HASH_KEY_IS_STRING) {
+ spprintf(&new_key, 0, "%s[%s]", prefix, str);
+ } else {
+ spprintf(&new_key, 0, "%s[%lu]", prefix, num);
+ }
+ } else if (type == HASH_KEY_IS_STRING) {
+ new_key = estrdup(str);
+ } else if (numeric_key_for_empty_prefix) {
+ spprintf(&new_key, 0, "%lu", num);
+ }
+
+ return new_key;
+}
+
+static inline STATUS add_field(php_http_message_body_t *body, const char *name, const char *value_str, size_t value_len)
+{
+ post_data http_post_data = {NULL, NULL};
+ CURLcode err;
+
+ err = curl_formadd(&http_post_data[0], &http_post_data[1],
+ CURLFORM_COPYNAME, name,
+ CURLFORM_COPYCONTENTS, value_str,
+ CURLFORM_CONTENTSLENGTH, (long) value_len,
+ CURLFORM_END
+ );
+
+ if (CURLE_OK != err) {
+ return FAILURE;
+ }
+
+ err = curl_formget(http_post_data[0], body, (curl_formget_callback) php_http_message_body_append);
+
+ if (CURLE_OK != err) {
+ curl_formfree(http_post_data[0]);
+ return FAILURE;
+ }
+
+ curl_formfree(http_post_data[0]);
+ return SUCCESS;
+}
+
+static inline STATUS add_file(php_http_message_body_t *body, const char *name, const char *path, const char *ctype)
+{
+ post_data http_post_data = {NULL, NULL};
+ CURLcode err;
+
+ err = curl_formadd(&http_post_data[0], &http_post_data[1],
+ CURLFORM_COPYNAME, name,
+ CURLFORM_FILE, path,
+ CURLFORM_CONTENTTYPE, ctype ? ctype : "application/octet-stream",
+ CURLFORM_END
+ );
+
+ if (CURLE_OK != err) {
+ return FAILURE;
+ }
+
+ err = curl_formget(http_post_data[0], body, (curl_formget_callback) php_http_message_body_append);
+
+ if (CURLE_OK != err) {
+ curl_formfree(http_post_data[0]);
+ return FAILURE;
+ }
+
+ curl_formfree(http_post_data[0]);
+ return SUCCESS;
+}
+
+static STATUS recursive_fields(post_data http_post_data, HashTable *fields, const char *prefix TSRMLS_DC) {
+ php_http_array_hashkey_t key = php_http_array_hashkey_init(0);
+ zval **data_ptr;
+ HashPosition pos;
+ char *new_key = NULL;
+ CURLcode err = 0;
+
+ if (fields && !fields->nApplyCount) {
+ FOREACH_HASH_KEYVAL(pos, fields, key, data_ptr) {
+ if (key.type != HASH_KEY_IS_STRING || *key.str) {
+ new_key = format_key(key.type, key.str, key.num, prefix, 1);
+
+ switch (Z_TYPE_PP(data_ptr)) {
+ case IS_ARRAY:
+ case IS_OBJECT: {
+ STATUS status;
+
+ ++fields->nApplyCount;
+ status = recursive_fields(http_post_data, HASH_OF(*data_ptr), new_key TSRMLS_CC);
+ --fields->nApplyCount;
+
+ if (SUCCESS != status) {
+ goto error;
+ }
+ break;
+ }
+
+ default: {
+ zval *data = php_http_zsep(IS_STRING, *data_ptr);
+
+ err = curl_formadd(&http_post_data[0], &http_post_data[1],
+ CURLFORM_COPYNAME, new_key,
+ CURLFORM_COPYCONTENTS, Z_STRVAL_P(data),
+ CURLFORM_CONTENTSLENGTH, (long) Z_STRLEN_P(data),
+ CURLFORM_END
+ );
+
+ zval_ptr_dtor(&data);
+
+ if (CURLE_OK != err) {
+ goto error;
+ }
+ break;
+ }
+ }
+ STR_FREE(new_key);
+ }
+ }
+ }
+
+ return SUCCESS;
+
+error:
+ if (new_key) {
+ efree(new_key);
+ }
+ if (http_post_data[0]) {
+ curl_formfree(http_post_data[0]);
+ }
+ if (err) {
+ php_http_error(HE_WARNING, PHP_HTTP_E_ENCODING, "Could not encode post fields: %s", curl_easy_strerror(err));
+ } else {
+ php_http_error(HE_WARNING, PHP_HTTP_E_ENCODING, "Could not encode post fields: unknown error");
+ }
+ return FAILURE;
+}
+
+static STATUS recursive_files(post_data http_post_data, HashTable *files, const char *prefix TSRMLS_DC) {
+ php_http_array_hashkey_t key = php_http_array_hashkey_init(0);
+ zval **data_ptr;
+ HashPosition pos;
+ char *new_key = NULL;
+ CURLcode err = 0;
+
+ if (files && !files->nApplyCount) {
+ FOREACH_HASH_KEYVAL(pos, files, key, data_ptr) {
+ zval **file_ptr, **type_ptr, **name_ptr;
+
+ if (key.type != HASH_KEY_IS_STRING || *key.str) {
+ new_key = format_key(key.type, key.str, key.num, prefix, 0);
+
+ if (Z_TYPE_PP(data_ptr) != IS_ARRAY && Z_TYPE_PP(data_ptr) != IS_OBJECT) {
+ if (new_key || key.type == HASH_KEY_IS_STRING) {
+ php_http_error(HE_NOTICE, PHP_HTTP_E_INVALID_PARAM, "Unrecognized type of post file array entry '%s'", new_key ? new_key : key.str);
+ } else {
+ php_http_error(HE_NOTICE, PHP_HTTP_E_INVALID_PARAM, "Unrecognized type of post file array entry '%lu'", key.num);
+ }
+ } else if ( SUCCESS != zend_hash_find(HASH_OF(*data_ptr), "name", sizeof("name"), (void *) &name_ptr) ||
+ SUCCESS != zend_hash_find(HASH_OF(*data_ptr), "type", sizeof("type"), (void *) &type_ptr) ||
+ SUCCESS != zend_hash_find(HASH_OF(*data_ptr), "file", sizeof("file"), (void *) &file_ptr)) {
+ STATUS status;
+
+ ++files->nApplyCount;
+ status = recursive_files(http_post_data, HASH_OF(*data_ptr), new_key TSRMLS_CC);
+ --files->nApplyCount;
+
+ if (SUCCESS != status) {
+ goto error;
+ }
+ } else {
+ const char *path;
+ zval *file = php_http_zsep(IS_STRING, *file_ptr);
+ zval *type = php_http_zsep(IS_STRING, *type_ptr);
+ zval *name = php_http_zsep(IS_STRING, *name_ptr);
+
+ if (SUCCESS != php_check_open_basedir(Z_STRVAL_P(file) TSRMLS_CC)) {
+ goto error;
+ }
+
+ /* this is blatant but should be sufficient for most cases */
+ if (strncasecmp(Z_STRVAL_P(file), "file://", lenof("file://"))) {
+ path = Z_STRVAL_P(file);
+ } else {
+ path = Z_STRVAL_P(file) + lenof("file://");
+ }
+
+ if (new_key) {
+ char *tmp_key = format_key(HASH_KEY_IS_STRING, Z_STRVAL_P(name), 0, new_key, 0);
+ STR_SET(new_key, tmp_key);
+ }
+
+ err = curl_formadd(&http_post_data[0], &http_post_data[1],
+ CURLFORM_COPYNAME, new_key ? new_key : Z_STRVAL_P(name),
+ CURLFORM_FILE, path,
+ CURLFORM_CONTENTTYPE, Z_STRVAL_P(type),
+ CURLFORM_END
+ );
+
+ zval_ptr_dtor(&file);
+ zval_ptr_dtor(&type);
+ zval_ptr_dtor(&name);
+
+ if (CURLE_OK != err) {
+ goto error;
+ }
+ }
+ STR_FREE(new_key);
+ }
+ }
+ }
+
+ return SUCCESS;
+
+error:
+ if (new_key) {
+ efree(new_key);
+ }
+ if (http_post_data[0]) {
+ curl_formfree(http_post_data[0]);
+ }
+ if (err) {
+ php_http_error(HE_WARNING, PHP_HTTP_E_ENCODING, "Could not encode post files: %s", curl_easy_strerror(err));
+ } else {
+ php_http_error(HE_WARNING, PHP_HTTP_E_ENCODING, "Could not encode post files: unknown error");
+ }
+ return FAILURE;
+}
+
+/* PHP */
+
+#define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpMessageBody, method, 0, req_args)
+#define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpMessageBody, method, 0)
+#define PHP_HTTP_MESSAGE_BODY_ME(method, visibility) PHP_ME(HttpMessageBody, method, PHP_HTTP_ARGS(HttpMessageBody, method), visibility)
+
+PHP_HTTP_BEGIN_ARGS(__construct, 0)
+ PHP_HTTP_ARG_VAL(stream, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_EMPTY_ARGS(__toString);
+
+PHP_HTTP_BEGIN_ARGS(toStream, 1)
+ PHP_HTTP_ARG_VAL(stream, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(toCallback, 1)
+ PHP_HTTP_ARG_VAL(callback, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(append, 1)
+ PHP_HTTP_ARG_VAL(string, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(add, 0)
+ PHP_HTTP_ARG_VAL(fields, 0)
+ PHP_HTTP_ARG_VAL(files, 0)
+PHP_HTTP_END_ARGS;
+
+
+zend_class_entry *php_http_message_body_class_entry;
+zend_function_entry php_http_message_body_method_entry[] = {
+ PHP_HTTP_MESSAGE_BODY_ME(__construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
+ PHP_HTTP_MESSAGE_BODY_ME(__toString, ZEND_ACC_PUBLIC)
+ PHP_MALIAS(HttpMessageBody, toString, __toString, args_for_HttpMessageBody___toString, ZEND_ACC_PUBLIC)
+ PHP_HTTP_MESSAGE_BODY_ME(toStream, ZEND_ACC_PUBLIC)
+ PHP_HTTP_MESSAGE_BODY_ME(toCallback, ZEND_ACC_PUBLIC)
+ PHP_HTTP_MESSAGE_BODY_ME(append, ZEND_ACC_PUBLIC)
+ PHP_HTTP_MESSAGE_BODY_ME(add, ZEND_ACC_PUBLIC)
+ EMPTY_FUNCTION_ENTRY
+};
+static zend_object_handlers php_http_message_body_object_handlers;
+
+PHP_MINIT_FUNCTION(http_message_body)
+{
+ PHP_HTTP_REGISTER_CLASS(http\\message, Body, http_message_body, php_http_object_class_entry, 0);
+ php_http_message_body_class_entry->create_object = php_http_message_body_object_new;
+ memcpy(&php_http_message_body_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
+ php_http_message_body_object_handlers.clone_obj = php_http_message_body_object_clone;
+
+ return SUCCESS;
+}
+
+zend_object_value php_http_message_body_object_new(zend_class_entry *ce TSRMLS_DC)
+{
+ return php_http_message_body_object_new_ex(ce, NULL, NULL TSRMLS_CC);
+}
+
+zend_object_value php_http_message_body_object_new_ex(zend_class_entry *ce, php_http_message_body_t *body, php_http_message_body_object_t **ptr TSRMLS_DC)
+{
+ zend_object_value ov;
+ php_http_message_body_object_t *o;
+
+ o = ecalloc(1, sizeof(php_http_message_body_object_t));
+ zend_object_std_init((zend_object *) o, php_http_message_body_class_entry TSRMLS_CC);
+ object_properties_init((zend_object *) o, ce);
+
+ if (ptr) {
+ *ptr = o;
+ }
+
+ if (body) {
+ o->body = body;
+ }
+
+ ov.handle = zend_objects_store_put((zend_object *) o, NULL, php_http_message_body_object_free, NULL TSRMLS_CC);
+ ov.handlers = &php_http_message_body_object_handlers;
+
+ return ov;
+}
+
+zend_object_value php_http_message_body_object_clone(zval *object TSRMLS_DC)
+{
+ zend_object_value new_ov;
+ php_http_message_body_object_t *new_obj = NULL;
+ php_http_message_body_object_t *old_obj = zend_object_store_get_object(object TSRMLS_CC);
+
+ new_ov = php_http_message_body_object_new_ex(old_obj->zo.ce, php_http_message_body_copy(old_obj->body, NULL, 1), &new_obj);
+ zend_objects_clone_members(&new_obj->zo, new_ov, &old_obj->zo, Z_OBJ_HANDLE_P(object) TSRMLS_CC);
+
+ return new_ov;
+}
+
+void php_http_message_body_object_free(void *object TSRMLS_DC)
+{
+ php_http_message_body_object_t *obj = object;
+
+ php_http_message_body_free(&obj->body);
+
+ zend_object_std_dtor((zend_object *) obj TSRMLS_CC);
+ efree(obj);
+}
+
+PHP_METHOD(HttpMessageBody, __construct)
+{
+ php_http_message_body_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+ zval *zstream;
+ php_stream *stream;
+
+ with_error_handling(EH_THROW, PHP_HTTP_EX_CE(runtime)) {
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zstream)) {
+ php_stream_from_zval(stream, &zstream);
+
+ if (stream) {
+ if (obj->body) {
+ php_http_message_body_dtor(obj->body);
+ }
+ obj->body = php_http_message_body_init(obj->body, stream TSRMLS_CC);
+ }
+ }
+ } end_error_handling();
+}
+
+PHP_METHOD(HttpMessageBody, __toString)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ php_http_message_body_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+ char *str;
+ size_t len;
+
+ php_http_message_body_to_string(obj->body, &str, &len, 0, 0);
+ if (str) {
+ RETURN_STRINGL(str, len, 0);
+ }
+ }
+ RETURN_EMPTY_STRING();
+}
+
+PHP_METHOD(HttpMessageBody, toStream)
+{
+ zval *zstream;
+ long offset = 0, forlen = 0;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|ll", &zstream, &offset, &forlen)) {
+ php_stream *stream;
+ php_http_message_body_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ php_stream_from_zval(stream, &zstream);
+ php_http_message_body_to_stream(obj->body, stream, offset, forlen);
+ RETURN_TRUE;
+ }
+ RETURN_FALSE;
+}
+
+struct fcd {
+ zval *fcz;
+ zend_fcall_info *fci;
+ zend_fcall_info_cache *fcc;
+};
+
+static size_t pass(void *cb_arg, const char *str, size_t len TSRMLS_DC)
+{
+ struct fcd *fcd = cb_arg;
+ zval *zdata;
+
+ MAKE_STD_ZVAL(zdata);
+ ZVAL_STRINGL(zdata, str, len, 1);
+ if (SUCCESS == zend_fcall_info_argn(fcd->fci TSRMLS_CC, 2, fcd->fcz, zdata)) {
+ zend_fcall_info_call(fcd->fci, fcd->fcc, NULL, NULL TSRMLS_CC);
+ zend_fcall_info_args_clear(fcd->fci, 0);
+ }
+ zval_ptr_dtor(&zdata);
+ return len;
+}
+
+PHP_METHOD(HttpMessageBody, toCallback)
+{
+ struct fcd fcd;
+ long offset = 0, forlen = 0;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "f|ll", &fcd.fci, &fcd.fcc, &offset, &forlen)) {
+ php_http_message_body_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+ fcd.fcz = getThis();
+ Z_ADDREF_P(fcd.fcz);
+ php_http_message_body_to_callback(obj->body, pass, &fcd, offset, forlen);
+ zval_ptr_dtor(&fcd.fcz);
+ RETURN_TRUE;
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpMessageBody, append)
+{
+ char *str;
+ int len;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len)) {
+ php_http_message_body_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ RETURN_LONG(php_http_message_body_append(obj->body, str, len));
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpMessageBody, add)
+{
+ HashTable *fields = NULL, *files = NULL;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|hh", &fields, &files)) {
+ php_http_message_body_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ RETURN_SUCCESS(php_http_message_body_add(obj->body, fields, files));
+ }
+ RETURN_FALSE;
+}
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
--- /dev/null
+/*
+ +--------------------------------------------------------------------+
+ | PECL :: http |
+ +--------------------------------------------------------------------+
+ | Redistribution and use in source and binary forms, with or without |
+ | modification, are permitted provided that the conditions mentioned |
+ | in the accompanying LICENSE file are met. |
+ +--------------------------------------------------------------------+
+ | Copyright (c) 2004-2010, Michael Wallner <mike@php.net> |
+ +--------------------------------------------------------------------+
+*/
+
+/* $Id: php_http_message_body_api.h 292841 2009-12-31 08:48:57Z mike $ */
+
+#ifndef PHP_HTTP_MESSAGE_BODY_H
+#define PHP_HTTP_MESSAGE_BODY_H
+
+typedef struct php_http_message_body {
+ int stream_id;
+ php_stream_statbuf ssb;
+#ifdef ZTS
+ void ***ts;
+#endif
+} php_http_message_body_t;
+
+PHP_HTTP_API php_http_message_body_t *php_http_message_body_init(php_http_message_body_t *body, php_stream *stream TSRMLS_DC);
+PHP_HTTP_API php_http_message_body_t *php_http_message_body_copy(php_http_message_body_t *from, php_http_message_body_t *to, zend_bool dup_internal_stream_and_contents TSRMLS_DC);
+PHP_HTTP_API STATUS php_http_message_body_add(php_http_message_body_t *body, HashTable *fields, HashTable *files);
+PHP_HTTP_API STATUS php_http_message_body_add_field(php_http_message_body_t *body, const char *name, const char *value_str, size_t value_len);
+PHP_HTTP_API STATUS php_http_message_body_add_file(php_http_message_body_t *body, const char *name, const char *path, const char *ctype);
+PHP_HTTP_API size_t php_http_message_body_append(php_http_message_body_t *body, const char *buf, size_t len);
+PHP_HTTP_API void php_http_message_body_to_string(php_http_message_body_t *body, char **buf, size_t *len, off_t offset, size_t forlen);
+PHP_HTTP_API void php_http_message_body_to_stream(php_http_message_body_t *body, php_stream *s, off_t offset, size_t forlen);
+PHP_HTTP_API void php_http_message_body_to_callback(php_http_message_body_t *body, php_http_pass_callback_t cb, void *cb_arg, off_t offset, size_t forlen);
+PHP_HTTP_API void php_http_message_body_dtor(php_http_message_body_t *body);
+PHP_HTTP_API void php_http_message_body_free(php_http_message_body_t **body);
+PHP_HTTP_API php_stream_statbuf *php_http_message_body_stat(php_http_message_body_t *body);
+#define php_http_message_body_size(b) (php_http_message_body_stat((b))->sb.st_size)
+#define php_http_message_body_mtime(b) (php_http_message_body_stat((b))->sb.st_mtime)
+PHP_HTTP_API char *php_http_message_body_etag(php_http_message_body_t *body);
+
+static inline php_stream *php_http_message_body_stream(php_http_message_body_t *body)
+{
+ TSRMLS_FETCH_FROM_CTX(body->ts);
+ return zend_fetch_resource(NULL TSRMLS_CC, body->stream_id, "stream", NULL, 2, php_file_le_stream(), php_file_le_pstream());
+}
+
+
+typedef struct php_http_message_body_object {
+ zend_object zo;
+ php_http_message_body_t *body;
+} php_http_message_body_object_t;
+
+extern zend_class_entry *php_http_message_body_class_entry;
+extern zend_function_entry php_http_message_body_method_entry[];
+
+extern PHP_MINIT_FUNCTION(http_message_body);
+
+extern zend_object_value php_http_message_body_object_new(zend_class_entry *ce TSRMLS_DC);
+extern zend_object_value php_http_message_body_object_new_ex(zend_class_entry *ce, php_http_message_body_t *body, php_http_message_body_object_t **ptr TSRMLS_DC);
+extern zend_object_value php_http_message_body_object_clone(zval *object TSRMLS_DC);
+extern void php_http_message_body_object_free(void *object TSRMLS_DC);
+
+PHP_METHOD(HttpMessageBody, __construct);
+PHP_METHOD(HttpMessageBody, __toString);
+PHP_METHOD(HttpMessageBody, toStream);
+PHP_METHOD(HttpMessageBody, toCallback);
+PHP_METHOD(HttpMessageBody, append);
+PHP_METHOD(HttpMessageBody, add);
+
+#endif
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
+
--- /dev/null
+#include "php_http.h"
+
+typedef struct php_http_message_parser_state_spec {
+ php_http_message_parser_state_t state;
+ unsigned need_data:1;
+} php_http_message_parser_state_spec_t;
+
+static const php_http_message_parser_state_spec_t php_http_message_parser_states[] = {
+ {PHP_HTTP_MESSAGE_PARSER_STATE_START, 1},
+ {PHP_HTTP_MESSAGE_PARSER_STATE_HEADER, 1},
+ {PHP_HTTP_MESSAGE_PARSER_STATE_HEADER_DONE, 0},
+ {PHP_HTTP_MESSAGE_PARSER_STATE_BODY, 0},
+ {PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DUMB, 1},
+ {PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH, 1},
+ {PHP_HTTP_MESSAGE_PARSER_STATE_BODY_CHUNKED, 1},
+ {PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE, 0},
+ {PHP_HTTP_MESSAGE_PARSER_STATE_DONE, 0}
+};
+
+PHP_HTTP_API php_http_message_parser_t *php_http_message_parser_init(php_http_message_parser_t *parser TSRMLS_DC)
+{
+ if (!parser) {
+ parser = emalloc(sizeof(*parser));
+ }
+ memset(parser, 0, sizeof(*parser));
+
+ TSRMLS_SET_CTX(parser->ts);
+
+ php_http_header_parser_init(&parser->header TSRMLS_CC);
+ zend_stack_init(&parser->stack);
+
+ return parser;
+}
+
+PHP_HTTP_API php_http_message_parser_state_t php_http_message_parser_state_push(php_http_message_parser_t *parser, unsigned argc, ...)
+{
+ va_list va_args;
+ unsigned i;
+ va_start(va_args, argc);
+ php_http_message_parser_state_t state;
+
+ 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));
+ }
+ va_end(va_args);
+
+ return state;
+}
+
+PHP_HTTP_API 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;
+ }
+ return PHP_HTTP_MESSAGE_PARSER_STATE_START;
+}
+
+PHP_HTTP_API 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;
+ }
+ return PHP_HTTP_MESSAGE_PARSER_STATE_START;
+}
+
+PHP_HTTP_API void php_http_message_parser_dtor(php_http_message_parser_t *parser)
+{
+ php_http_header_parser_dtor(&parser->header);
+ zend_stack_destroy(&parser->stack);
+ if (parser->dechunk) {
+ php_http_encoding_stream_free(&parser->dechunk TSRMLS_CC);
+ }
+ if (parser->inflate) {
+ php_http_encoding_stream_free(&parser->inflate TSRMLS_CC);
+ }
+}
+
+PHP_HTTP_API void php_http_message_parser_free(php_http_message_parser_t **parser)
+{
+ if (*parser) {
+ php_http_message_parser_dtor(*parser);
+ efree(*parser);
+ *parser = NULL;
+ }
+}
+
+
+PHP_HTTP_API php_http_message_parser_state_t php_http_message_parser_parse(php_http_message_parser_t *parser, php_http_buffer *buffer, unsigned flags, php_http_message_t **message)
+{
+ TSRMLS_FETCH_FROM_CTX(parser->ts);
+ char *str = NULL;
+ size_t len = 0;
+ size_t cut = 0;
+
+ while (buffer->used || !php_http_message_parser_states[php_http_message_parser_state_is(parser)].need_data) {
+#if 0
+ const char *state[] = {"START", "HEADER", "HEADER_DONE", "BODY", "BODY_DUMB", "BODY_LENGTH", "BODY_CHUNK", "BODY_DONE", "DONE"};
+ fprintf(stderr, "#MP: %s (%d) %zu\n",
+ state[php_http_message_parser_state_is(parser)], (*message)->type, buffer->used);
+#endif
+
+ switch (php_http_message_parser_state_pop(parser))
+ {
+ case PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE:
+ return php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE);
+
+ case PHP_HTTP_MESSAGE_PARSER_STATE_START:
+ {
+ char *ptr = buffer->data;
+
+ while (ptr - buffer->data < buffer->used && PHP_HTTP_IS_CTYPE(space, *ptr)) {
+ ++ptr;
+ }
+
+ php_http_buffer_cut(buffer, 0, ptr - buffer->data);
+
+ if (buffer->used) {
+ php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_HEADER);
+ }
+ break;
+ }
+
+ case PHP_HTTP_MESSAGE_PARSER_STATE_HEADER:
+ {
+ unsigned header_parser_flags = (flags & PHP_HTTP_MESSAGE_PARSER_CLEANUP) ? PHP_HTTP_HEADER_PARSER_CLEANUP : 0;
+
+ switch (php_http_header_parser_parse(&parser->header, buffer, header_parser_flags, &(*message)->hdrs, (php_http_info_callback_t) php_http_message_info_callback, message)) {
+ case PHP_HTTP_HEADER_PARSER_STATE_FAILURE:
+ return PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE;
+
+ case PHP_HTTP_HEADER_PARSER_STATE_DONE:
+ php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_HEADER_DONE);
+ break;
+
+ default:
+ php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_HEADER);
+ if (buffer->used) {
+ return PHP_HTTP_MESSAGE_PARSER_STATE_HEADER;
+ }
+ }
+ break;
+ }
+
+ case PHP_HTTP_MESSAGE_PARSER_STATE_HEADER_DONE:
+ {
+ zval *h, **h_cl = NULL, **h_cr = NULL, **h_te = NULL;
+
+ if ((h = php_http_message_header(*message, ZEND_STRL("Transfer-Encoding"), 1))) {
+ zend_hash_update(&(*message)->hdrs, "X-Original-Transfer-Encoding", sizeof("X-Original-Transfer-Encoding"), &h, sizeof(zval *), (void *) &h_te);
+ zend_hash_del(&(*message)->hdrs, "Transfer-Encoding", sizeof("Transfer-Encoding"));
+ }
+ if ((h = php_http_message_header(*message, ZEND_STRL("Content-Length"), 1))) {
+ zend_hash_update(&(*message)->hdrs, "X-Original-Content-Length", sizeof("X-Original-Content-Length"), &h, sizeof(zval *), (void *) &h_cl);
+ }
+ if ((h = php_http_message_header(*message, ZEND_STRL("Content-Range"), 1))) {
+ zend_hash_update(&(*message)->hdrs, "X-Original-Content-Range", sizeof("X-Original-Content-Range"), &h, sizeof(zval *), (void *) &h_cr);
+ zend_hash_del(&(*message)->hdrs, "Content-Range", sizeof("Content-Range"));
+ }
+
+ if ((h = php_http_message_header(*message, ZEND_STRL("Content-Encoding"), 1))) {
+ if (strstr(Z_STRVAL_P(h), "gzip") || strstr(Z_STRVAL_P(h), "x-gzip") || strstr(Z_STRVAL_P(h), "deflate")) {
+ parser->inflate = php_http_encoding_stream_init(parser->inflate, php_http_encoding_stream_get_inflate_ops(), 0 TSRMLS_CC);
+ zend_hash_update(&(*message)->hdrs, "X-Original-Content-Encoding", sizeof("X-Original-Content-Encoding"), &h, sizeof(zval *), NULL);
+ zend_hash_del(&(*message)->hdrs, "Content-Encoding", sizeof("Content-Encoding"));
+ } else {
+ zval_ptr_dtor(&h);
+ }
+ }
+
+ /* default */
+ MAKE_STD_ZVAL(h);
+ ZVAL_LONG(h, 0);
+ zend_hash_update(&(*message)->hdrs, "Content-Length", sizeof("Content-Length"), &h, sizeof(zval *), NULL);
+
+ if (h_te) {
+ if (strstr(Z_STRVAL_PP(h_te), "chunked")) {
+ parser->dechunk = php_http_encoding_stream_init(parser->dechunk, php_http_encoding_stream_get_dechunk_ops(), 0 TSRMLS_CC);
+ php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_CHUNKED);
+ break;
+ }
+ }
+
+ if (h_cl) {
+ char *stop;
+
+ parser->body_length = strtoul(Z_STRVAL_PP(h_cl), &stop, 10);
+
+ if (stop != Z_STRVAL_PP(h_cl)) {
+ php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH);
+ break;
+ }
+ }
+
+ if (h_cr) {
+ ulong total = 0, start = 0, end = 0;
+
+ if (!strncasecmp(Z_STRVAL_PP(h_cr), "bytes", lenof("bytes"))
+ && ( Z_STRVAL_P(h)[lenof("bytes")] == ':'
+ || Z_STRVAL_P(h)[lenof("bytes")] == ' '
+ || Z_STRVAL_P(h)[lenof("bytes")] == '='
+ )
+ ) {
+ char *total_at = NULL, *end_at = NULL;
+ char *start_at = Z_STRVAL_PP(h_cr) + sizeof("bytes");
+
+ start = strtoul(start_at, &end_at, 10);
+ if (end_at) {
+ end = strtoul(end_at + 1, &total_at, 10);
+ if (total_at && strncmp(total_at + 1, "*", 1)) {
+ total = strtoul(total_at + 1, NULL, 10);
+ }
+
+ if (end >= start && (!total || end < total)) {
+ parser->body_length = end + 1 - start;
+ php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH);
+ break;
+ }
+ }
+ }
+ }
+
+
+ if ((*message)->type == PHP_HTTP_REQUEST) {
+ php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_DONE);
+ } else {
+ php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DUMB);
+ }
+ break;
+ }
+
+ case PHP_HTTP_MESSAGE_PARSER_STATE_BODY:
+ {
+ zval *zcl;
+
+ if (parser->inflate) {
+ char *dec_str = NULL;
+ size_t dec_len;
+
+ if (SUCCESS != php_http_encoding_stream_update(parser->inflate, str, len, &dec_str, &dec_len TSRMLS_CC)) {
+ return php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE);
+ }
+
+ if (str != buffer->data) {
+ STR_FREE(str);
+ }
+ str = dec_str;
+ len = dec_len;
+ }
+
+ php_stream_write(php_http_message_body_stream(&(*message)->body), str, len);
+ php_http_buffer_cut(buffer, 0, cut);
+
+ /* keep track */
+ MAKE_STD_ZVAL(zcl);
+ ZVAL_LONG(zcl, php_http_message_body_size(&(*message)->body));
+ zend_hash_update(&(*message)->hdrs, "Content-Length", sizeof("Content-Length"), &zcl, sizeof(zval *), NULL);
+
+ if (str != buffer->data) {
+ STR_FREE(str);
+ }
+ str = NULL;
+ len = 0;
+ cut = 0;
+ break;
+ }
+
+ case PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DUMB:
+ {
+ str = buffer->data;
+ len = buffer->used;
+ cut = len;
+
+ php_http_message_parser_state_push(parser, 2, !buffer->used?PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE:PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DUMB, PHP_HTTP_MESSAGE_PARSER_STATE_BODY);
+ break;
+ }
+
+ case PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH:
+ {
+ len = MIN(parser->body_length, buffer->used);
+ str = buffer->data;
+ cut = len;
+
+ parser->body_length -= len;
+
+ php_http_message_parser_state_push(parser, 2, !parser->body_length?PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE:PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH, PHP_HTTP_MESSAGE_PARSER_STATE_BODY);
+ break;
+ }
+
+ case PHP_HTTP_MESSAGE_PARSER_STATE_BODY_CHUNKED:
+ {
+ /*
+ * - pass available data through the dechunk stream
+ * - pass decoded data along
+ * - if stream zeroed:
+ * Y: - cut processed string out of buffer, but leave length of unprocessed dechunk stream data untouched
+ * - body done
+ * N: - parse ahaed
+ */
+ size_t dec_len;
+ char *dec_str = NULL;
+
+ if (SUCCESS != php_http_encoding_stream_update(parser->dechunk, buffer->data, buffer->used, &dec_str, &dec_len TSRMLS_CC)) {
+ return FAILURE;
+ }
+
+ str = dec_str;
+ len = dec_len;
+
+ if (php_http_encoding_stream_done(parser->dechunk)) {
+ cut = buffer->used - PHP_HTTP_BUFFER_LEN(parser->dechunk->ctx);
+ php_http_message_parser_state_push(parser, 2, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE, PHP_HTTP_MESSAGE_PARSER_STATE_BODY);
+ } else {
+ cut = buffer->used;
+ php_http_message_parser_state_push(parser, 2, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_CHUNKED, PHP_HTTP_MESSAGE_PARSER_STATE_BODY);
+ }
+ break;
+ }
+
+ case PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE:
+ {
+ php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_DONE);
+
+ if (parser->dechunk) {
+ char *dec_str;
+ size_t dec_len;
+
+ if (SUCCESS != php_http_encoding_stream_finish(parser->dechunk, &dec_str, &dec_len TSRMLS_CC)) {
+ return php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE);
+ }
+ php_http_encoding_stream_dtor(parser->dechunk);
+
+ if (dec_str && dec_len) {
+ str = dec_str;
+ len = dec_len;
+ cut = 0;
+ php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_BODY);
+ }
+ }
+
+ break;
+ }
+
+ case PHP_HTTP_MESSAGE_PARSER_STATE_DONE: {
+ char *ptr = buffer->data;
+
+ while (ptr - buffer->data < buffer->used && PHP_HTTP_IS_CTYPE(space, *ptr)) {
+ ++ptr;
+ }
+
+ php_http_buffer_cut(buffer, 0, ptr - buffer->data);
+ break;
+ }
+ }
+ }
+
+ return php_http_message_parser_state_is(parser);
+}
--- /dev/null
+
+#ifndef PHP_HTTP_MESSAGE_PARSER_H
+#define PHP_HTTP_MESSAGE_PARSER_H
+
+typedef enum php_http_message_parser_state {
+ PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE = FAILURE,
+ PHP_HTTP_MESSAGE_PARSER_STATE_START = 0,
+ PHP_HTTP_MESSAGE_PARSER_STATE_HEADER,
+ PHP_HTTP_MESSAGE_PARSER_STATE_HEADER_DONE,
+ PHP_HTTP_MESSAGE_PARSER_STATE_BODY,
+ PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DUMB,
+ PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH,
+ PHP_HTTP_MESSAGE_PARSER_STATE_BODY_CHUNKED,
+ PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE,
+ PHP_HTTP_MESSAGE_PARSER_STATE_DONE
+} php_http_message_parser_state_t;
+
+#define PHP_HTTP_MESSAGE_PARSER_CLEANUP 0x1
+
+typedef struct php_http_message_parser {
+ php_http_header_parser_t header;
+ zend_stack stack;
+ size_t body_length;
+ php_http_message_t *message;
+ php_http_encoding_stream_t *dechunk;
+ php_http_encoding_stream_t *inflate;
+#ifdef ZTS
+ void ***ts;
+#endif
+} php_http_message_parser_t;
+
+PHP_HTTP_API php_http_message_parser_t *php_http_message_parser_init(php_http_message_parser_t *parser TSRMLS_DC);
+PHP_HTTP_API php_http_message_parser_state_t php_http_message_parser_state_push(php_http_message_parser_t *parser, unsigned argc, ...);
+PHP_HTTP_API php_http_message_parser_state_t php_http_message_parser_state_is(php_http_message_parser_t *parser);
+PHP_HTTP_API php_http_message_parser_state_t php_http_message_parser_state_pop(php_http_message_parser_t *parser);
+PHP_HTTP_API void php_http_message_parser_dtor(php_http_message_parser_t *parser);
+PHP_HTTP_API void php_http_message_parser_free(php_http_message_parser_t **parser);
+PHP_HTTP_API php_http_message_parser_state_t php_http_message_parser_parse(php_http_message_parser_t *parser, php_http_buffer *buffer, unsigned flags, php_http_message_t **message);
+
+#endif
--- /dev/null
+/*
+ +--------------------------------------------------------------------+
+ | PECL :: http |
+ +--------------------------------------------------------------------+
+ | Redistribution and use in source and binary forms, with or without |
+ | modification, are permitted provided that the conditions mentioned |
+ | in the accompanying LICENSE file are met. |
+ +--------------------------------------------------------------------+
+ | Copyright (c) 2004-2010, Michael Wallner <mike@php.net> |
+ +--------------------------------------------------------------------+
+*/
+
+/* $Id $ */
+
+#include "php_http.h"
+
+/* SLEEP */
+
+PHP_HTTP_API void php_http_sleep(double s)
+{
+#if defined(PHP_WIN32)
+ Sleep((DWORD) PHP_HTTP_MSEC(s));
+#elif defined(HAVE_USLEEP)
+ usleep(PHP_HTTP_USEC(s));
+#elif defined(HAVE_NANOSLEEP)
+ struct timespec req, rem;
+
+ req.tv_sec = (time_t) s;
+ req.tv_nsec = PHP_HTTP_NSEC(s) % PHP_HTTP_NANOSEC;
+
+ while (nanosleep(&req, &rem) && (errno == EINTR) && (PHP_HTTP_NSEC(rem.tv_sec) + rem.tv_nsec) > PHP_HTTP_NSEC(PHP_HTTP_DIFFSEC))) {
+ req.tv_sec = rem.tv_sec;
+ req.tv_nsec = rem.tv_nsec;
+ }
+#else
+ struct timeval timeout;
+
+ timeout.tv.sec = (time_t) s;
+ timeout.tv_usec = PHP_HTTP_USEC(s) % PHP_HTTP_MCROSEC;
+
+ select(0, NULL, NULL, NULL, &timeout);
+#endif
+}
+
+
+/* STRING UTILITIES */
+
+int php_http_match(const char *haystack_str, const char *needle_str, int flags)
+{
+ int result;
+
+ if (flags & PHP_HTTP_MATCH_FULL) {
+ if (flags & PHP_HTTP_MATCH_CASE) {
+ result = !strcmp(haystack_str, needle_str);
+ } else {
+ result = !strcasecmp(haystack_str, needle_str);
+ }
+ } else {
+ char *found, *haystack = estrdup(haystack_str), *needle = estrdup(needle_str);
+
+ if (flags & PHP_HTTP_MATCH_CASE) {
+ found = zend_memnstr(haystack, needle, strlen(needle), haystack+strlen(haystack));
+ } else {
+ found = php_stristr(haystack, needle, strlen(haystack), strlen(needle));
+ }
+
+ if (found) {
+ if (!(flags & PHP_HTTP_MATCH_WORD)
+ || ( (found == haystack || !PHP_HTTP_IS_CTYPE(alnum, *(found - 1)))
+ && (!*(found + strlen(needle)) || !PHP_HTTP_IS_CTYPE(alnum, *(found + strlen(needle))))
+ )
+ ) {
+ result = 1;
+ }
+ }
+
+ STR_FREE(haystack);
+ STR_FREE(needle);
+ }
+
+ return result;
+}
+
+char *php_http_pretty_key(char *key, size_t key_len, zend_bool uctitle, zend_bool xhyphen)
+{
+ size_t i;
+ int wasalpha;
+
+ if (key && key_len) {
+ if ((wasalpha = PHP_HTTP_IS_CTYPE(alpha, key[0]))) {
+ key[0] = (char) (uctitle ? PHP_HTTP_TO_CTYPE(upper, key[0]) : PHP_HTTP_TO_CTYPE(lower, key[0]));
+ }
+ for (i = 1; i < key_len; i++) {
+ 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;
+ } else {
+ if (xhyphen && (key[i] == '_')) {
+ key[i] = '-';
+ }
+ wasalpha = 0;
+ }
+ }
+ }
+ return key;
+}
+
+
+size_t php_http_boundary(char *buf, size_t buf_len TSRMLS_DC)
+{
+ return snprintf(buf, buf_len, "%lu%0.9f", (ulong) PHP_HTTP_G->env.request.time, (float) php_combined_lcg(TSRMLS_C));
+}
+
+/* ARRAYS */
+
+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;
+
+ dst = va_arg(args, HashTable *);
+ flags = va_arg(args, int);
+
+ if ((!(flags & ARRAY_JOIN_STRONLY)) || hash_key->nKeyLength) {
+ 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_find(dst, key, hash_key->nKeyLength, (void *) &data);
+ } else {
+ zend_hash_quick_find(dst, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void *) &data);
+ }
+
+ Z_ADDREF_P(*value);
+ if (data) {
+ if (Z_TYPE_PP(data) != IS_ARRAY) {
+ convert_to_array(*data);
+ }
+ add_next_index_zval(*data, *value);
+ } else if (key) {
+ zend_hash_add(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);
+ }
+
+ if (key) {
+ efree(key);
+ }
+ }
+
+ return ZEND_HASH_APPLY_KEEP;
+}
+
+int php_http_array_apply_merge_func(void *pDest TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
+{
+ int flags;
+ char *key = NULL;
+ HashTable *dst;
+ 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_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);
+ efree(key);
+ } else {
+ zend_hash_quick_update(dst, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void *) value, sizeof(zval *), NULL);
+ }
+ }
+
+ return ZEND_HASH_APPLY_KEEP;
+}
+
+/* PASS CALLBACK */
+
+PHP_HTTP_API size_t php_http_pass_wrapper(php_http_pass_callback_arg_t *cb, const char *str, size_t len)
+{
+ TSRMLS_FETCH();
+ return cb->cb_zts(cb->cb_arg, str, len TSRMLS_CC);
+}
+
+/* ERROR */
+
+static inline int scope_error_handling(long type TSRMLS_DC)
+{
+ if ((type == E_THROW) || (EG(error_handling) == EH_THROW)) {
+ return EH_THROW;
+ }
+
+ if (EG(This) && instanceof_function(Z_OBJCE_P(EG(This)), php_http_object_class_entry)) {
+ return php_http_object_get_error_handling(EG(This) TSRMLS_CC);
+ }
+
+ return EH_NORMAL;
+}
+
+void php_http_error(long type TSRMLS_DC, long code, const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ switch (scope_error_handling(type TSRMLS_CC)) {
+ case EH_THROW: {
+ char *message;
+ zend_class_entry *ce;
+
+ if (EG(exception_class) && instanceof_function(EG(exception_class), php_http_exception_class_entry)) {
+ ce = EG(exception_class);
+ } else {
+ ce = php_http_exception_get_for_code(code);
+ }
+
+ vspprintf(&message, 0, format, args);
+ zend_throw_exception(ce, message, code TSRMLS_CC);
+ efree(message);
+ break;
+ }
+ case EH_NORMAL:
+ php_verror(NULL, "", type, format, args TSRMLS_CC);
+ break;
+ case EH_SUPPRESS:
+ break;
+ }
+ va_end(args);
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
--- /dev/null
+/*
+ +--------------------------------------------------------------------+
+ | PECL :: http |
+ +--------------------------------------------------------------------+
+ | Redistribution and use in source and binary forms, with or without |
+ | modification, are permitted provided that the conditions mentioned |
+ | in the accompanying LICENSE file are met. |
+ +--------------------------------------------------------------------+
+ | Copyright (c) 2004-2010, Michael Wallner <mike@php.net> |
+ +--------------------------------------------------------------------+
+*/
+
+/* $Id: php_http_api.h 298891 2010-05-03 08:26:38Z mike $ */
+
+#ifndef PHP_HTTP_MISC_H
+#define PHP_HTTP_MISC_H
+
+/* DEFAULTS */
+
+/* DATE FORMAT RFC1123 */
+#define PHP_HTTP_DATE_FORMAT "D, d M Y H:i:s \\G\\M\\T"
+
+/* CR LF */
+#define PHP_HTTP_CRLF "\r\n"
+
+/* default cache control */
+#define PHP_HTTP_DEFAULT_CACHECONTROL "private, must-revalidate, max-age=0"
+
+/* max URL length */
+#define PHP_HTTP_URL_MAXLEN 4096
+
+/* max request method length */
+#define PHP_HTTP_REQUEST_METHOD_MAXLEN 31
+
+/* def URL arg separator */
+#define PHP_HTTP_URL_ARGSEP "&"
+
+/* send buffer size */
+#define PHP_HTTP_SENDBUF_SIZE 40960
+
+/* CURL buffer size */
+#define PHP_HTTP_CURLBUF_SIZE 16384
+
+/* SLEEP */
+
+#define PHP_HTTP_DIFFSEC (0.001)
+#define PHP_HTTP_MLLISEC (1000)
+#define PHP_HTTP_MCROSEC (1000 * 1000)
+#define PHP_HTTP_NANOSEC (1000 * 1000 * 1000)
+#define PHP_HTTP_MSEC(s) ((long)(s * PHP_HTTP_MLLISEC))
+#define PHP_HTTP_USEC(s) ((long)(s * PHP_HTTP_MCROSEC))
+#define PHP_HTTP_NSEC(s) ((long)(s * PHP_HTTP_NANOSEC))
+
+PHP_HTTP_API void php_http_sleep(double s);
+
+/* STRING UTILITIES */
+
+#define PHP_HTTP_CHECK_CONTENT_TYPE(ct, action) \
+ if (!strchr((ct), '/')) { \
+ php_http_error(HE_WARNING, PHP_HTTP_E_INVALID_PARAM, \
+ "Content type \"%s\" does not seem to contain a primary and a secondary part", (ct)); \
+ action; \
+ }
+
+
+#ifndef STR_SET
+# define STR_SET(STR, SET) \
+ { \
+ STR_FREE(STR); \
+ STR = SET; \
+ }
+#endif
+
+#define STR_PTR(s) (s?s:"")
+
+#define lenof(S) (sizeof(S) - 1)
+
+#define PHP_HTTP_MATCH_LOOSE 0
+#define PHP_HTTP_MATCH_CASE 0x01
+#define PHP_HTTP_MATCH_WORD 0x10
+#define PHP_HTTP_MATCH_FULL 0x20
+#define PHP_HTTP_MATCH_STRICT (PHP_HTTP_ENV_MATCH_CASE|PHP_HTTP_ENV_MATCH_FULL)
+
+extern int php_http_match(const char *haystack, const char *needle, int flags);
+
+extern char *php_http_pretty_key(char *key, size_t key_len, zend_bool uctitle, zend_bool xhyphen);
+extern size_t php_http_boundary(char *buf, size_t len TSRMLS_DC);
+
+static inline const char *php_http_locate_str(const char *h, size_t h_len, const char *n, size_t n_len)
+{
+ const char *p, *e;
+
+ if (n_len && h_len) {
+ e = h + h_len;
+ do {
+ if (*h == *n) {
+ for (p = n; *p == h[p-n]; ++p) {
+ if (p == n+n_len-1) {
+ return h;
+ }
+ }
+ }
+ } while (h++ != e);
+ }
+
+ return NULL;
+}
+
+static inline const char *php_http_locate_body(const char *message)
+{
+ const char *body = NULL, *msg = message;
+
+ while (*msg) {
+ if (*msg == '\n') {
+ if (*(msg+1) == '\n') {
+ body = msg + 2;
+ break;
+ } else if (*(msg+1) == '\r' && *(msg+2) == '\n') {
+ body = msg + 3;
+ break;
+ }
+ }
+ ++msg;
+ }
+ return body;
+}
+
+static inline const char *php_http_locate_eol(const char *line, int *eol_len)
+{
+ const char *eol = strpbrk(line, "\r\n");
+
+ if (eol_len) {
+ *eol_len = eol ? ((eol[0] == '\r' && eol[1] == '\n') ? 2 : 1) : 0;
+ }
+ return eol;
+}
+
+static inline const char *php_http_locate_bin_eol(const char *bin, size_t len, int *eol_len)
+{
+ const char *eol;
+
+ for (eol = bin; eol - bin < len; ++eol) {
+ if (*eol == '\r' || *eol == '\n') {
+ *eol_len = eol ? ((eol[0] == '\r' && eol[1] == '\n') ? 2 : 1) : 0;
+ return eol;
+ }
+ }
+
+ return NULL;
+}
+
+/* ZEND */
+
+#define INIT_PZVAL_ARRAY(zv, ht) \
+ { \
+ INIT_PZVAL((zv)); \
+ Z_TYPE_P(zv) = IS_ARRAY; \
+ Z_ARRVAL_P(zv) = (ht); \
+ }
+
+static inline zval *php_http_zsep(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;
+ }
+ }
+ return z;
+}
+
+
+/* return bool (v == SUCCESS) */
+#define RETVAL_SUCCESS(v) RETVAL_BOOL(SUCCESS == (v))
+#define RETURN_SUCCESS(v) RETURN_BOOL(SUCCESS == (v))
+/* return object(values) */
+#define RETVAL_OBJECT(o, addref) \
+ RETVAL_OBJVAL((o)->value.obj, addref)
+#define RETURN_OBJECT(o, addref) \
+ RETVAL_OBJECT(o, addref); \
+ return
+#define RETVAL_OBJVAL(ov, addref) \
+ ZVAL_OBJVAL(return_value, ov, addref)
+#define RETURN_OBJVAL(ov, addref) \
+ RETVAL_OBJVAL(ov, addref); \
+ return
+#define ZVAL_OBJVAL(zv, ov, addref) \
+ (zv)->type = IS_OBJECT; \
+ (zv)->value.obj = (ov);\
+ if (addref && Z_OBJ_HT_P(zv)->add_ref) { \
+ Z_OBJ_HT_P(zv)->add_ref((zv) TSRMLS_CC); \
+ }
+/* return property */
+#define RETVAL_PROP(CE, n) RETVAL_PROP_EX(CE, getThis(), n)
+#define RETURN_PROP(CE, n) RETURN_PROP_EX(CE, getThis(), n)
+#define RETVAL_PROP_EX(CE, this, n) \
+ { \
+ zval *__prop = zend_read_property(CE, this, ZEND_STRL(n), 0 TSRMLS_CC); \
+ RETVAL_ZVAL(__prop, 1, 0); \
+ }
+#define RETURN_PROP_EX(CE, this, n) \
+ { \
+ zval *__prop = zend_read_property(CE, this, ZEND_STRL(n), 0 TSRMLS_CC); \
+ RETURN_ZVAL(__prop, 1, 0); \
+ }
+#define RETVAL_SPROP(CE, n) \
+ { \
+ zval *__prop = zend_read_static_property(CE, ZEND_STRL(n), 0 TSRMLS_CC); \
+ RETVAL_ZVAL(__prop, 1, 0); \
+ }
+#define RETURN_SPROP(CE, n) \
+ { \
+ zval *__prop = zend_read_static_property(CE, ZEND_STRL(n), 0 TSRMLS_CC); \
+ RETURN_ZVAL(__prop, 1, 0); \
+ }
+
+#define Z_OBJ_DELREF(z) \
+ if (Z_OBJ_HT(z)->del_ref) { \
+ Z_OBJ_HT(z)->del_ref(&(z) TSRMLS_CC); \
+ }
+#define Z_OBJ_ADDREF(z) \
+ if (Z_OBJ_HT(z)->add_ref) { \
+ Z_OBJ_HT(z)->add_ref(&(z) TSRMLS_CC); \
+ }
+#define Z_OBJ_DELREF_P(z) \
+ if (Z_OBJ_HT_P(z)->del_ref) { \
+ Z_OBJ_HT_P(z)->del_ref((z) TSRMLS_CC); \
+ }
+#define Z_OBJ_ADDREF_P(z) \
+ if (Z_OBJ_HT_P(z)->add_ref) { \
+ Z_OBJ_HT_P(z)->add_ref((z) TSRMLS_CC); \
+ }
+#define Z_OBJ_DELREF_PP(z) \
+ if (Z_OBJ_HT_PP(z)->del_ref) { \
+ Z_OBJ_HT_PP(z)->del_ref(*(z) TSRMLS_CC); \
+ }
+#define Z_OBJ_ADDREF_PP(z) \
+ if (Z_OBJ_HT_PP(z)->add_ref) { \
+ Z_OBJ_HT_PP(z)->add_ref(*(z) TSRMLS_CC); \
+ }
+
+#define PHP_HTTP_BEGIN_ARGS_EX(class, method, ret_ref, req_args) ZEND_BEGIN_ARG_INFO_EX(args_for_ ##class## _ ##method , 0, ret_ref, req_args)
+#define PHP_HTTP_BEGIN_ARGS_AR(class, method, ret_ref, req_args) ZEND_BEGIN_ARG_INFO_EX(args_for_ ##class## _ ##method , 1, ret_ref, req_args)
+#define PHP_HTTP_END_ARGS }
+#define PHP_HTTP_EMPTY_ARGS_EX(class, method, ret_ref) PHP_HTTP_BEGIN_ARGS_EX(class, method, ret_ref, 0) PHP_HTTP_END_ARGS
+#define PHP_HTTP_ARGS(class, method) args_for_ ##class## _ ##method
+#define PHP_HTTP_ARG_VAL(name, pass_ref) ZEND_ARG_INFO(pass_ref, name)
+#define PHP_HTTP_ARG_OBJ(class, name, allow_null) ZEND_ARG_OBJ_INFO(0, name, class, allow_null)
+
+#define EMPTY_FUNCTION_ENTRY {NULL, NULL, NULL, 0, 0}
+
+#define PHP_MINIT_CALL(func) PHP_MINIT(func)(INIT_FUNC_ARGS_PASSTHRU)
+#define PHP_RINIT_CALL(func) PHP_RINIT(func)(INIT_FUNC_ARGS_PASSTHRU)
+#define PHP_MSHUTDOWN_CALL(func) PHP_MSHUTDOWN(func)(SHUTDOWN_FUNC_ARGS_PASSTHRU)
+#define PHP_RSHUTDOWN_CALL(func) PHP_RSHUTDOWN(func)(SHUTDOWN_FUNC_ARGS_PASSTHRU)
+
+
+#define PHP_HTTP_INI_ENTRY(entry, default, scope, updater, global) \
+ STD_PHP_INI_ENTRY(entry, default, scope, updater, global, zend_php_http_globals, php_http_globals)
+#define PHP_HTTP_INI_ENTRY_EX(entry, default, scope, updater, displayer, global) \
+ STD_PHP_INI_ENTRY_EX(entry, default, scope, updater, global, zend_php_http_globals, php_http_globals, displayer)
+
+#define PHP_HTTP_REGISTER_CLASS(ns, classname, name, parent, flags) \
+ { \
+ zend_class_entry ce; \
+ memset(&ce, 0, sizeof(zend_class_entry)); \
+ INIT_NS_CLASS_ENTRY(ce, #ns, #classname, php_ ##name## _method_entry); \
+ php_ ##name## _class_entry = zend_register_internal_class_ex(&ce, parent, NULL TSRMLS_CC); \
+ php_ ##name## _class_entry->ce_flags |= flags; \
+ }
+
+#define PHP_HTTP_REGISTER_EXCEPTION(classname, cename, parent) \
+ { \
+ zend_class_entry ce; \
+ memset(&ce, 0, sizeof(zend_class_entry)); \
+ INIT_NS_CLASS_ENTRY(ce, "http", #classname, NULL); \
+ ce.create_object = NULL; \
+ cename = zend_register_internal_class_ex(&ce, parent, NULL TSRMLS_CC); \
+ }
+
+#define ACC_PROP_PRIVATE(ce, flags) ((flags & ZEND_ACC_PRIVATE) && (EG(scope) && ce == EG(scope))
+#define ACC_PROP_PROTECTED(ce, flags) ((flags & ZEND_ACC_PROTECTED) && (zend_check_protected(ce, EG(scope))))
+#define ACC_PROP_PUBLIC(flags) (flags & ZEND_ACC_PUBLIC)
+#define ACC_PROP(ce, flags) (ACC_PROP_PUBLIC(flags) || ACC_PROP_PRIVATE(ce, flags) || ACC_PROP_PROTECTED(ce, flags))
+
+#ifdef PHP_HTTP_HAVE_CURL
+# define PHP_HTTP_DECLARE_ARG_PASS_INFO() \
+ ZEND_BEGIN_ARG_INFO(http_arg_pass_ref_2, 0) \
+ ZEND_ARG_PASS_INFO(0) \
+ ZEND_ARG_PASS_INFO(1) \
+ ZEND_END_ARG_INFO(); \
+ \
+ ZEND_BEGIN_ARG_INFO(http_arg_pass_ref_3, 0) \
+ ZEND_ARG_PASS_INFO(0) \
+ ZEND_ARG_PASS_INFO(0) \
+ ZEND_ARG_PASS_INFO(1) \
+ ZEND_END_ARG_INFO(); \
+ \
+ ZEND_BEGIN_ARG_INFO(http_arg_pass_ref_4, 0) \
+ ZEND_ARG_PASS_INFO(0) \
+ ZEND_ARG_PASS_INFO(0) \
+ ZEND_ARG_PASS_INFO(0) \
+ ZEND_ARG_PASS_INFO(1) \
+ ZEND_END_ARG_INFO(); \
+ \
+ ZEND_BEGIN_ARG_INFO(http_arg_pass_ref_5, 0) \
+ ZEND_ARG_PASS_INFO(0) \
+ ZEND_ARG_PASS_INFO(0) \
+ ZEND_ARG_PASS_INFO(0) \
+ ZEND_ARG_PASS_INFO(0) \
+ ZEND_ARG_PASS_INFO(1) \
+ ZEND_END_ARG_INFO();
+
+#else
+# define PHP_HTTP_DECLARE_ARG_PASS_INFO() \
+ ZEND_BEGIN_ARG_INFO(http_arg_pass_ref_2, 0) \
+ ZEND_ARG_PASS_INFO(0) \
+ ZEND_ARG_PASS_INFO(1) \
+ ZEND_END_ARG_INFO(); \
+\
+ ZEND_BEGIN_ARG_INFO(http_arg_pass_ref_4, 0) \
+ ZEND_ARG_PASS_INFO(0) \
+ ZEND_ARG_PASS_INFO(0) \
+ ZEND_ARG_PASS_INFO(0) \
+ ZEND_ARG_PASS_INFO(1) \
+ ZEND_END_ARG_INFO();
+#endif /* PHP_HTTP_HAVE_CURL */
+
+/* ARRAYS */
+
+typedef struct php_http_array_hashkey {
+ char *str;
+ uint len;
+ ulong num;
+ uint dup:1;
+ uint type:31;
+} php_http_array_hashkey_t;
+#define php_http_array_hashkey_init(dup) {NULL, 0, 0, (dup), 0}
+
+#define FOREACH_VAL(pos, array, val) FOREACH_HASH_VAL(pos, Z_ARRVAL_P(array), val)
+#define FOREACH_HASH_VAL(pos, hash, val) \
+ for ( zend_hash_internal_pointer_reset_ex(hash, &pos); \
+ zend_hash_get_current_data_ex(hash, (void *) &val, &pos) == SUCCESS; \
+ zend_hash_move_forward_ex(hash, &pos))
+
+#define FOREACH_KEY(pos, array, key) FOREACH_HASH_KEY(pos, Z_ARRVAL_P(array), key)
+#define FOREACH_HASH_KEY(pos, hash, _key) \
+ for ( zend_hash_internal_pointer_reset_ex(hash, &pos); \
+ ((_key).type = zend_hash_get_current_key_ex(hash, &(_key).str, &(_key).len, &(_key).num, (zend_bool) (_key).dup, &pos)) != HASH_KEY_NON_EXISTANT; \
+ zend_hash_move_forward_ex(hash, &pos)) \
+
+#define FOREACH_KEYVAL(pos, array, key, val) FOREACH_HASH_KEYVAL(pos, Z_ARRVAL_P(array), key, val)
+#define FOREACH_HASH_KEYVAL(pos, hash, _key, val) \
+ for ( zend_hash_internal_pointer_reset_ex(hash, &pos); \
+ ((_key).type = zend_hash_get_current_key_ex(hash, &(_key).str, &(_key).len, &(_key).num, (zend_bool) (_key).dup, &pos)) != HASH_KEY_NON_EXISTANT && \
+ zend_hash_get_current_data_ex(hash, (void *) &val, &pos) == SUCCESS; \
+ 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_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)
+
+extern int php_http_array_apply_append_func(void *pDest TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key);
+extern int php_http_array_apply_merge_func(void *pDest TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key);
+
+/* PASS CALLBACK */
+
+typedef size_t (*php_http_pass_callback_t)(void *cb_arg, const char *str, size_t len);
+typedef size_t (*php_http_pass_php_http_buffer_callback_t)(void *cb_arg, php_http_buffer *str);
+
+typedef struct php_http_pass_callback_arg {
+ size_t (*cb_zts)(void *cb_arg, const char *str, size_t len TSRMLS_DC);
+ void *cb_arg;
+} php_http_pass_callback_arg_t;
+
+PHP_HTTP_API size_t php_http_pass_wrapper(php_http_pass_callback_arg_t *cb_arg, const char *str, size_t len);
+
+/* ERROR */
+
+extern void php_http_error(long type TSRMLS_DC, long code, const char *format, ...);
+
+#define with_error_handling(eh, ec) \
+ { \
+ zend_error_handling __eh; \
+ zend_replace_error_handling((eh), (ec), &__eh TSRMLS_CC);
+
+#define end_error_handling() \
+ zend_restore_error_handling(&__eh TSRMLS_CC); \
+ }
+
+#ifndef E_THROW
+# define E_THROW -1
+#endif
+#define HE_THROW E_THROW TSRMLS_CC
+#define HE_NOTICE E_NOTICE TSRMLS_CC
+#define HE_WARNING E_WARNING TSRMLS_CC
+#define HE_ERROR E_ERROR TSRMLS_CC
+
+typedef enum php_http_error {
+ PHP_HTTP_E_RUNTIME,
+ PHP_HTTP_E_INVALID_PARAM,
+ PHP_HTTP_E_HEADER,
+ PHP_HTTP_E_MALFORMED_HEADERS,
+ PHP_HTTP_E_REQUEST_METHOD,
+ PHP_HTTP_E_MESSAGE,
+ PHP_HTTP_E_MESSAGE_TYPE,
+ PHP_HTTP_E_ENCODING,
+ PHP_HTTP_E_REQUEST,
+ PHP_HTTP_E_REQUEST_POOL,
+ PHP_HTTP_E_SOCKET,
+ PHP_HTTP_E_RESPONSE,
+ PHP_HTTP_E_URL,
+ PHP_HTTP_E_QUERYSTRING,
+ PHP_HTTP_E_COOKIE,
+} php_http_error_t;
+
+/* CURL */
+
+#define PHP_HTTP_CURL_OPT(OPTION, p) curl_easy_setopt((request->ch), OPTION, (p))
+
+#define PHP_HTTP_CURL_OPT_STRING(OPTION, ldiff, obdc) \
+ { \
+ char *K = #OPTION; \
+ PHP_HTTP_CURL_OPT_STRING_EX(K+lenof("CURLOPT_KEY")+ldiff, OPTION, obdc); \
+ }
+#define PHP_HTTP_CURL_OPT_STRING_EX(keyname, optname, obdc) \
+ if (!strcasecmp(key.str, keyname)) { \
+ zval *copy = php_http_request_option_cache(request, keyname, strlen(keyname)+1, 0, php_http_zsep(IS_STRING, *param)); \
+ if (obdc) { \
+ if (SUCCESS != php_check_open_basedir(Z_STRVAL_P(copy) TSRMLS_CC)) { \
+ return FAILURE; \
+ } \
+ } \
+ PHP_HTTP_CURL_OPT(optname, Z_STRVAL_P(copy)); \
+ zval_ptr_dtor(©); \
+ continue; \
+ }
+#define PHP_HTTP_CURL_OPT_LONG(OPTION, ldiff) \
+ { \
+ char *K = #OPTION; \
+ PHP_HTTP_CURL_OPT_LONG_EX(K+lenof("CURLOPT_KEY")+ldiff, OPTION); \
+ }
+#define PHP_HTTP_CURL_OPT_LONG_EX(keyname, optname) \
+ if (!strcasecmp(key.str, keyname)) { \
+ zval *copy = php_http_zsep(IS_LONG, *param); \
+ PHP_HTTP_CURL_OPT(optname, Z_LVAL_P(copy)); \
+ zval_ptr_dtor(©); \
+ continue; \
+ }
+
+#endif
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
--- /dev/null
+/*
+ +--------------------------------------------------------------------+
+ | PECL :: http |
+ +--------------------------------------------------------------------+
+ | Redistribution and use in source and binary forms, with or without |
+ | modification, are permitted provided that the conditions mentioned |
+ | in the accompanying LICENSE file are met. |
+ +--------------------------------------------------------------------+
+ | Copyright (c) 2004-2010, Michael Wallner <mike@php.net> |
+ +--------------------------------------------------------------------+
+*/
+
+/* $Id: php_http_headers_api.h 300300 2010-06-09 07:29:35Z mike $ */
+
+#include "php_http.h"
+
+#ifndef PHP_HTTP_DBG_NEG
+# define PHP_HTTP_DBG_NEG 0
+#endif
+
+char *php_http_negotiate_language_func(const char *test, double *quality, HashTable *supported TSRMLS_DC)
+{
+ zval **value;
+ HashPosition pos;
+ const char *dash_test;
+
+ FOREACH_HASH_VAL(pos, supported, value) {
+#if PHP_HTTP_DBG_NEG
+ fprintf(stderr, "strcasecmp('%s', '%s')\n", Z_STRVAL_PP(value), test);
+#endif
+ if (!strcasecmp(Z_STRVAL_PP(value), test)) {
+ return Z_STRVAL_PP(value);
+ }
+ }
+
+ /* no distinct match found, so try primaries */
+ if ((dash_test = strchr(test, '-'))) {
+ FOREACH_HASH_VAL(pos, supported, value) {
+ int len = dash_test - test;
+#if PHP_HTTP_DBG_NEG
+ fprintf(stderr, "strncasecmp('%s', '%s', %d)\n", Z_STRVAL_PP(value), test, len);
+#endif
+ if ( (!strncasecmp(Z_STRVAL_PP(value), test, len)) &&
+ ( (Z_STRVAL_PP(value)[len] == '\0') ||
+ (Z_STRVAL_PP(value)[len] == '-'))) {
+ *quality *= .9;
+ return Z_STRVAL_PP(value);
+ }
+ }
+ }
+
+ return NULL;
+}
+
+
+char *php_http_negotiate_default_func(const char *test, double *quality, HashTable *supported TSRMLS_DC)
+{
+ zval **value;
+ HashPosition pos;
+ (void) quality;
+
+ FOREACH_HASH_VAL(pos, supported, value) {
+#if PHP_HTTP_DBG_NEG
+ fprintf(stderr, "strcasecmp('%s', '%s')\n", Z_STRVAL_PP(value), test);
+#endif
+ if (!strcasecmp(Z_STRVAL_PP(value), test)) {
+ return Z_STRVAL_PP(value);
+ }
+ }
+
+ return NULL;
+}
+
+
+static int php_http_negotiate_sort(const void *a, const void *b TSRMLS_DC)
+{
+ zval result, *first, *second;
+
+ first = *((zval **) (*((Bucket **) a))->pData);
+ second= *((zval **) (*((Bucket **) b))->pData);
+
+ if (numeric_compare_function(&result, first, second TSRMLS_CC) != SUCCESS) {
+ return 0;
+ }
+ return (Z_LVAL(result) > 0 ? -1 : (Z_LVAL(result) < 0 ? 1 : 0));
+}
+
+
+PHP_HTTP_API HashTable *php_http_negotiate(const char *value, HashTable *supported, php_http_negotiate_func_t neg TSRMLS_DC)
+{
+ HashTable *result = NULL;
+
+ if (*value) {
+ zval ex_arr, ex_del, ex_val;
+
+ INIT_PZVAL(&ex_del);
+ INIT_PZVAL(&ex_arr);
+ INIT_PZVAL(&ex_val);
+ ZVAL_STRINGL(&ex_del, ",", 1, 0);
+ ZVAL_STRING(&ex_val, value, 1);
+ array_init(&ex_arr);
+
+ php_explode(&ex_del, &ex_val, &ex_arr, INT_MAX);
+
+ if (zend_hash_num_elements(Z_ARRVAL(ex_arr)) > 0) {
+ int i = 0;
+ HashPosition pos;
+ zval **entry, array;
+
+ INIT_PZVAL(&array);
+ array_init(&array);
+
+ if (!neg) {
+ neg = php_http_negotiate_default_func;
+ }
+
+ FOREACH_HASH_VAL(pos, Z_ARRVAL(ex_arr), entry) {
+ int ident_len;
+ double quality;
+ char *selected, *identifier, *freeme;
+ const char *separator;
+
+#if PHP_HTTP_DBG_NEG
+ fprintf(stderr, "Checking %s\n", Z_STRVAL_PP(entry));
+#endif
+
+ if ((separator = strchr(Z_STRVAL_PP(entry), ';'))) {
+ const char *ptr = separator;
+
+ while (*++ptr && !PHP_HTTP_IS_CTYPE(digit, *ptr) && '.' != *ptr);
+
+ quality = zend_strtod(ptr, NULL);
+ identifier = estrndup(Z_STRVAL_PP(entry), ident_len = separator - Z_STRVAL_PP(entry));
+ } else {
+ quality = 1000.0 - i++;
+ identifier = estrndup(Z_STRVAL_PP(entry), ident_len = Z_STRLEN_PP(entry));
+ }
+ freeme = identifier;
+
+ while (PHP_HTTP_IS_CTYPE(space, *identifier)) {
+ ++identifier;
+ --ident_len;
+ }
+ while (ident_len && PHP_HTTP_IS_CTYPE(space, identifier[ident_len - 1])) {
+ identifier[--ident_len] = '\0';
+ }
+
+ if ((selected = neg(identifier, &quality, supported TSRMLS_CC))) {
+ /* don't overwrite previously set with higher quality */
+ if (!zend_hash_exists(Z_ARRVAL(array), selected, strlen(selected) + 1)) {
+ add_assoc_double(&array, selected, quality);
+ }
+ }
+
+ efree(freeme);
+ }
+
+ result = Z_ARRVAL(array);
+ zend_hash_sort(result, zend_qsort, php_http_negotiate_sort, 0 TSRMLS_CC);
+ }
+
+ zval_dtor(&ex_arr);
+ zval_dtor(&ex_val);
+ }
+
+ return result;
+}
+
+
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
+
+
--- /dev/null
+/*
+ +--------------------------------------------------------------------+
+ | PECL :: http |
+ +--------------------------------------------------------------------+
+ | Redistribution and use in source and binary forms, with or without |
+ | modification, are permitted provided that the conditions mentioned |
+ | in the accompanying LICENSE file are met. |
+ +--------------------------------------------------------------------+
+ | Copyright (c) 2004-2010, Michael Wallner <mike@php.net> |
+ +--------------------------------------------------------------------+
+*/
+
+/* $Id: php_http_headers_api.h 300300 2010-06-09 07:29:35Z mike $ */
+
+#ifndef PHP_HTTP_NEGOTIATE_H
+#define PHP_HTTP_NEGOTIATE_H
+
+typedef char *(*php_http_negotiate_func_t)(const char *test, double *quality, HashTable *supported TSRMLS_DC);
+
+extern char *php_http_negotiate_language_func(const char *test, double *quality, HashTable *supported TSRMLS_DC);
+extern char *php_http_negotiate_default_func(const char *test, double *quality, HashTable *supported TSRMLS_DC);
+
+PHP_HTTP_API HashTable *php_http_negotiate(const char *value, HashTable *supported, php_http_negotiate_func_t neg TSRMLS_DC);
+
+static inline HashTable *php_http_negotiate_language(HashTable *supported TSRMLS_DC)
+{
+ HashTable *result = NULL;
+ char *value = php_http_env_get_request_header(ZEND_STRL("Accept-Language") TSRMLS_CC);
+
+ if (value) {
+ result = php_http_negotiate(value, supported, php_http_negotiate_language_func TSRMLS_CC);
+ }
+ STR_FREE(value);
+
+ return result;
+}
+
+static inline HashTable *php_http_negotiate_encoding(HashTable *supported TSRMLS_DC)
+{
+ HashTable *result = NULL;
+ char *value = php_http_env_get_request_header(ZEND_STRL("Accept-Encoding") TSRMLS_CC);
+
+ if (value) {
+ result = php_http_negotiate(value, supported, NULL TSRMLS_CC);
+ }
+ STR_FREE(value);
+
+ return result;
+}
+
+static inline HashTable *php_http_negotiate_charset(HashTable *supported TSRMLS_DC)
+{
+ HashTable *result = NULL;
+ char *value = php_http_env_get_request_header(ZEND_STRL("Accept-Charset") TSRMLS_CC);
+
+ if (value) {
+ result = php_http_negotiate(value, supported, NULL TSRMLS_CC);
+ }
+ STR_FREE(value);
+
+ return result;
+}
+
+static inline HashTable *php_http_negotiate_content_type(HashTable *supported TSRMLS_DC)
+{
+ HashTable *result = NULL;
+ char *value = php_http_env_get_request_header(ZEND_STRL("Accept") TSRMLS_CC);
+
+ if (value) {
+ result = php_http_negotiate(value, supported, NULL TSRMLS_CC);
+ }
+ STR_FREE(value);
+
+ return result;
+}
+
+
+#endif
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
+
--- /dev/null
+/*
+ +--------------------------------------------------------------------+
+ | PECL :: http |
+ +--------------------------------------------------------------------+
+ | Redistribution and use in source and binary forms, with or without |
+ | modification, are permitted provided that the conditions mentioned |
+ | in the accompanying LICENSE file are met. |
+ +--------------------------------------------------------------------+
+ | Copyright (c) 2004-2010, Michael Wallner <mike@php.net> |
+ +--------------------------------------------------------------------+
+*/
+
+/* $Id: http_api.c 300299 2010-06-09 06:23:16Z mike $ */
+
+
+#include "php_http.h"
+
+STATUS php_http_new(zend_object_value *ov, zend_class_entry *ce, php_http_new_t create, zend_class_entry *parent_ce, void *intern_ptr, void **obj_ptr TSRMLS_DC)
+{
+ if (!ce) {
+ ce = parent_ce;
+ } else if (parent_ce && !instanceof_function(ce, parent_ce TSRMLS_CC)) {
+ php_http_error(HE_WARNING, PHP_HTTP_E_RUNTIME, "Class %s does not extend %s", ce->name, parent_ce->name);
+ return FAILURE;
+ }
+
+ *ov = create(ce, intern_ptr, obj_ptr TSRMLS_CC);
+ return SUCCESS;
+}
+
+PHP_HTTP_API zend_error_handling_t php_http_object_get_error_handling(zval *object TSRMLS_DC)
+{
+ zval *zeh, *lzeh;
+ long eh;
+
+ zeh = zend_read_property(Z_OBJCE_P(object), object, ZEND_STRL("errorHandling"), 0 TSRMLS_CC);
+ if (Z_TYPE_P(zeh) != IS_NULL) {
+ lzeh = php_http_zsep(IS_LONG, zeh);
+ eh = Z_LVAL_P(lzeh);
+ zval_ptr_dtor(&lzeh);
+ return eh;
+ }
+ zeh = zend_read_static_property(php_http_object_class_entry, ZEND_STRL("defaultErrorHandling"), 0 TSRMLS_CC);
+ if (Z_TYPE_P(zeh) != IS_NULL) {
+ lzeh = php_http_zsep(IS_LONG, zeh);
+ eh = Z_LVAL_P(lzeh);
+ zval_ptr_dtor(&lzeh);
+ return eh;
+ }
+ return EH_NORMAL;
+}
+
+#define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpObject, method, 0, req_args)
+#define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpObject, method, 0)
+#define PHP_HTTP_OBJECT_ME(method, visibility) PHP_ME(HttpObject, method, PHP_HTTP_ARGS(HttpObject, method), visibility)
+
+PHP_HTTP_BEGIN_ARGS(factory, 1)
+ PHP_HTTP_ARG_VAL(class_name, 0)
+ PHP_HTTP_ARG_VAL(ctor_args, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(setErrorHandling, 1)
+ PHP_HTTP_ARG_VAL(eh, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_EMPTY_ARGS(getErrorHandling);
+
+PHP_HTTP_BEGIN_ARGS(setDefaultErrorHandling, 1)
+ PHP_HTTP_ARG_VAL(eh, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_EMPTY_ARGS(getDefaultErrorHandling);
+
+zend_class_entry *php_http_object_class_entry;
+zend_function_entry php_http_object_method_entry[] = {
+ PHP_HTTP_OBJECT_ME(factory, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
+
+ PHP_HTTP_OBJECT_ME(setErrorHandling, ZEND_ACC_PUBLIC)
+ PHP_HTTP_OBJECT_ME(getErrorHandling, ZEND_ACC_PUBLIC)
+ PHP_HTTP_OBJECT_ME(setDefaultErrorHandling, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
+ PHP_HTTP_OBJECT_ME(getDefaultErrorHandling, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
+
+ EMPTY_FUNCTION_ENTRY
+};
+
+zend_object_value php_http_object_new(zend_class_entry *ce TSRMLS_DC)
+{
+ return php_http_object_new_ex(ce, NULL, NULL TSRMLS_CC);
+}
+
+zend_object_value php_http_object_new_ex(zend_class_entry *ce, void *nothing, php_http_object_t **ptr TSRMLS_DC)
+{
+ zend_object_value ov;
+ php_http_object_t *o;
+
+ o = ecalloc(1, sizeof(php_http_object_t));
+ zend_object_std_init((zend_object *)o, ce TSRMLS_CC);
+ object_properties_init((zend_object *) o, ce);
+
+ if (ptr) {
+ *ptr = o;
+ }
+
+ ov.handle = zend_objects_store_put(o, NULL, (zend_objects_free_object_storage_t) zend_objects_free_object_storage, NULL TSRMLS_CC);
+ ov.handlers = zend_get_std_object_handlers();
+
+ return ov;
+}
+
+PHP_METHOD(HttpObject, factory)
+{
+ zval *ctor_args = NULL;
+ zend_class_entry *class_entry = NULL;
+ zval *object_ctor;
+ zend_fcall_info fci;
+ zend_fcall_info_cache fcc;
+
+ with_error_handling(EH_THROW, PHP_HTTP_EX_CE(runtime)) {
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "C|a/!", &class_entry, &ctor_args)) {
+ object_init_ex(return_value, class_entry);
+
+ MAKE_STD_ZVAL(object_ctor);
+ array_init(object_ctor);
+
+ Z_ADDREF_P(return_value);
+ add_next_index_zval(object_ctor, return_value);
+ add_next_index_stringl(object_ctor, ZEND_STRL("__construct"), 1);
+
+ zend_fcall_info_init(object_ctor, 0, &fci, &fcc, NULL, NULL TSRMLS_CC);
+ zend_fcall_info_call(&fci, &fcc, NULL, ctor_args TSRMLS_CC);
+
+ zval_ptr_dtor(&object_ctor);
+ }
+ } end_error_handling();
+}
+
+PHP_METHOD(HttpObject, getErrorHandling)
+{
+ RETURN_PROP(php_http_object_class_entry, "errorHandling");
+}
+
+PHP_METHOD(HttpObject, setErrorHandling)
+{
+ long eh;
+ zval *old;
+
+ if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &eh)) {
+ RETURN_FALSE;
+ }
+
+ switch (eh) {
+ case EH_NORMAL:
+ case EH_SUPPRESS:
+ case EH_THROW:
+ break;
+ default:
+ php_http_error(HE_WARNING, PHP_HTTP_E_RUNTIME, "unknown error handling code (%ld)", eh);
+ RETURN_FALSE;
+ }
+
+ old = zend_read_property(php_http_object_class_entry, getThis(), ZEND_STRL("errorHandling"), 0 TSRMLS_CC);
+ Z_ADDREF_P(old);
+ zend_update_property_long(php_http_object_class_entry, getThis(), ZEND_STRL("errorHandling"), eh TSRMLS_CC);
+ RETURN_ZVAL(old, 0, 0);
+}
+
+PHP_METHOD(HttpObject, getDefaultErrorHandling)
+{
+ RETURN_SPROP(php_http_object_class_entry, "defaultErrorHandling");
+}
+
+PHP_METHOD(HttpObject, setDefaultErrorHandling)
+{
+ long eh;
+ zval *old;
+
+ if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &eh)) {
+ RETURN_FALSE;
+ }
+
+ switch (eh) {
+ case EH_NORMAL:
+ case EH_SUPPRESS:
+ case EH_THROW:
+ break;
+ default:
+ php_http_error(HE_WARNING, PHP_HTTP_E_RUNTIME, "unknown error handling code (%ld)", eh);
+ RETURN_FALSE;
+ }
+
+ old = zend_read_static_property(php_http_object_class_entry, ZEND_STRL("defaultErrorHandling"), 0 TSRMLS_CC);
+ Z_ADDREF_P(old);
+ zend_update_static_property_long(php_http_object_class_entry, ZEND_STRL("defaultErrorHandling"), eh TSRMLS_CC);
+ RETURN_ZVAL(old, 0, 1);
+}
+PHP_MINIT_FUNCTION(http_object)
+{
+ PHP_HTTP_REGISTER_CLASS(http, Object, http_object, NULL, ZEND_ACC_ABSTRACT);
+ php_http_object_class_entry->create_object = php_http_object_new;
+
+ zend_declare_property_null(php_http_object_class_entry, ZEND_STRL("defaultErrorHandling"), (ZEND_ACC_STATIC|ZEND_ACC_PROTECTED) TSRMLS_CC);
+ zend_declare_property_null(php_http_object_class_entry, ZEND_STRL("errorHandling"), ZEND_ACC_PROTECTED TSRMLS_CC);
+
+ zend_declare_class_constant_long(php_http_object_class_entry, ZEND_STRL("EH_NORMAL"), EH_NORMAL TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_object_class_entry, ZEND_STRL("EH_SUPPRESS"), EH_SUPPRESS TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_object_class_entry, ZEND_STRL("EH_THROW"), EH_THROW TSRMLS_CC);
+
+ return SUCCESS;
+}
+
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
+
--- /dev/null
+/*
+ +--------------------------------------------------------------------+
+ | PECL :: http |
+ +--------------------------------------------------------------------+
+ | Redistribution and use in source and binary forms, with or without |
+ | modification, are permitted provided that the conditions mentioned |
+ | in the accompanying LICENSE file are met. |
+ +--------------------------------------------------------------------+
+ | Copyright (c) 2004-2010, Michael Wallner <mike@php.net> |
+ +--------------------------------------------------------------------+
+*/
+
+/* $Id: http_api.c 300299 2010-06-09 06:23:16Z mike $ */
+
+#ifndef PHP_HTTP_OBJECT_H
+#define PHP_HTTP_OBJECT_H
+
+typedef zend_object_value (*php_http_new_t)(zend_class_entry *ce, void *, void ** TSRMLS_DC);
+
+extern STATUS php_http_new(zend_object_value *ov, zend_class_entry *ce, php_http_new_t create, zend_class_entry *parent_ce, void *intern_ptr, void **obj_ptr TSRMLS_DC);
+
+typedef struct php_http_object {
+ zend_object zo;
+} php_http_object_t;
+
+extern zend_class_entry *php_http_object_class_entry;
+extern zend_function_entry php_http_object_method_entry[];
+
+extern PHP_MINIT_FUNCTION(http_object);
+
+extern zend_object_value php_http_object_new(zend_class_entry *ce TSRMLS_DC);
+extern zend_object_value php_http_object_new_ex(zend_class_entry *ce, void *nothing, php_http_object_t **ptr TSRMLS_DC);
+
+PHP_HTTP_API zend_error_handling_t php_http_object_get_error_handling(zval *object TSRMLS_DC);
+
+PHP_METHOD(HttpObject, factory);
+PHP_METHOD(HttpObject, setErrorHandling);
+PHP_METHOD(HttpObject, getErrorHandling);
+PHP_METHOD(HttpObject, setDefaultErrorHandling);
+PHP_METHOD(HttpObject, getDefaultErrorHandling);
+
+#endif
+
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
+
--- /dev/null
+/*
+ +--------------------------------------------------------------------+
+ | PECL :: http |
+ +--------------------------------------------------------------------+
+ | Redistribution and use in source and binary forms, with or without |
+ | modification, are permitted provided that the conditions mentioned |
+ | in the accompanying LICENSE file are met. |
+ +--------------------------------------------------------------------+
+ | Copyright (c) 2004-2010, Michael Wallner <mike@php.net> |
+ +--------------------------------------------------------------------+
+*/
+
+/* $Id: http_api.c 300299 2010-06-09 06:23:16Z mike $ */
+
+#include "php_http.h"
+
+PHP_HTTP_API void php_http_params_parse_default_func(void *arg, const char *key, int keylen, const char *val, int vallen TSRMLS_DC)
+{
+ char *kdup;
+ zval tmp, *entry;
+ HashTable *ht = (HashTable *) arg;
+
+ if (ht) {
+ INIT_PZVAL_ARRAY(&tmp, ht);
+
+ if (vallen) {
+ MAKE_STD_ZVAL(entry);
+ array_init(entry);
+ if (keylen) {
+ kdup = estrndup(key, keylen);
+ add_assoc_stringl_ex(entry, kdup, keylen + 1, (char *) val, vallen, 1);
+ efree(kdup);
+ } else {
+ add_next_index_stringl(entry, (char *) val, vallen, 1);
+ }
+ add_next_index_zval(&tmp, entry);
+ } else {
+ add_next_index_stringl(&tmp, (char *) key, keylen, 1);
+ }
+ }
+}
+
+PHP_HTTP_API STATUS php_http_params_parse(const char *param, int flags, php_http_params_parse_func_t cb, void *cb_arg TSRMLS_DC)
+{
+#define ST_QUOTE 1
+#define ST_VALUE 2
+#define ST_KEY 3
+#define ST_ASSIGN 4
+#define ST_ADD 5
+
+ int st = ST_KEY, keylen = 0, vallen = 0;
+ char *s, *c, *key = NULL, *val = NULL;
+
+ if (!cb) {
+ cb = php_http_params_parse_default_func;
+ }
+
+ for(c = s = estrdup(param);;) {
+ continued:
+#if 0
+ {
+ char *tk = NULL, *tv = NULL;
+
+ if (key) {
+ if (keylen) {
+ tk= estrndup(key, keylen);
+ } else {
+ tk = ecalloc(1, 7);
+ memcpy(tk, key, 3);
+ tk[3]='.'; tk[4]='.'; tk[5]='.';
+ }
+ }
+ if (val) {
+ if (vallen) {
+ tv = estrndup(val, vallen);
+ } else {
+ tv = ecalloc(1, 7);
+ memcpy(tv, val, 3);
+ tv[3]='.'; tv[4]='.'; tv[5]='.';
+ }
+ }
+ fprintf(stderr, "[%6s] %c \"%s=%s\"\n",
+ (
+ st == ST_QUOTE ? "QUOTE" :
+ st == ST_VALUE ? "VALUE" :
+ st == ST_KEY ? "KEY" :
+ st == ST_ASSIGN ? "ASSIGN" :
+ st == ST_ADD ? "ADD":
+ "HUH?"
+ ), *c?*c:'0', tk, tv
+ );
+ STR_FREE(tk); STR_FREE(tv);
+ }
+#endif
+ switch (st) {
+ case ST_QUOTE:
+ quote:
+ if (*c == '"') {
+ if (*(c-1) == '\\') {
+ memmove(c-1, c, strlen(c)+1);
+ goto quote;
+ } else {
+ goto add;
+ }
+ } else {
+ if (!val) {
+ val = c;
+ }
+ if (!*c) {
+ --val;
+ st = ST_ADD;
+ }
+ }
+ break;
+
+ case ST_VALUE:
+ switch (*c) {
+ case '"':
+ if (!val) {
+ st = ST_QUOTE;
+ }
+ break;
+
+ case ' ':
+ break;
+
+ case ';':
+ case '\0':
+ goto add;
+ break;
+ case ',':
+ if (flags & PHP_HTTP_PARAMS_ALLOW_COMMA) {
+ goto add;
+ }
+ default:
+ if (!val) {
+ val = c;
+ }
+ break;
+ }
+ break;
+
+ case ST_KEY:
+ switch (*c) {
+ case ',':
+ if (flags & PHP_HTTP_PARAMS_ALLOW_COMMA) {
+ goto allow_comma;
+ }
+ case '\r':
+ case '\n':
+ case '\t':
+ case '\013':
+ case '\014':
+ goto failure;
+ break;
+
+ case ' ':
+ if (key) {
+ keylen = c - key;
+ st = ST_ASSIGN;
+ }
+ break;
+
+ case ';':
+ case '\0':
+ allow_comma:
+ if (key) {
+ keylen = c-- - key;
+ st = ST_ADD;
+ }
+ break;
+
+ case ':':
+ if (!(flags & PHP_HTTP_PARAMS_COLON_SEPARATOR)) {
+ goto not_separator;
+ }
+ if (key) {
+ keylen = c - key;
+ st = ST_VALUE;
+ } else {
+ goto failure;
+ }
+ break;
+
+ case '=':
+ if (flags & PHP_HTTP_PARAMS_COLON_SEPARATOR) {
+ goto not_separator;
+ }
+ if (key) {
+ keylen = c - key;
+ st = ST_VALUE;
+ } else {
+ goto failure;
+ }
+ break;
+
+ default:
+ not_separator:
+ if (!key) {
+ key = c;
+ }
+ break;
+ }
+ break;
+
+ case ST_ASSIGN:
+ if (*c == '=') {
+ st = ST_VALUE;
+ } else if (!*c || *c == ';' || ((flags & PHP_HTTP_PARAMS_ALLOW_COMMA) && *c == ',')) {
+ st = ST_ADD;
+ } else if (*c != ' ') {
+ goto failure;
+ }
+ break;
+
+ case ST_ADD:
+ add:
+ if (val) {
+ vallen = c - val;
+ if (st != ST_QUOTE) {
+ while (val[vallen-1] == ' ') --vallen;
+ }
+ } else {
+ val = "";
+ vallen = 0;
+ }
+
+ cb(cb_arg, key, keylen, val, vallen TSRMLS_CC);
+
+ st = ST_KEY;
+ key = val = NULL;
+ keylen = vallen = 0;
+ break;
+ }
+ if (*c) {
+ ++c;
+ } else if (st == ST_ADD) {
+ goto add;
+ } else {
+ break;
+ }
+ }
+
+ efree(s);
+ return SUCCESS;
+
+failure:
+ if (flags & PHP_HTTP_PARAMS_RAISE_ERROR) {
+ php_http_error(HE_WARNING, PHP_HTTP_E_INVALID_PARAM, "Unexpected character (%c) at pos %tu of %zu", *c, c-s, strlen(s));
+ }
+ if (flags & PHP_HTTP_PARAMS_ALLOW_FAILURE) {
+ if (st == ST_KEY) {
+ if (key) {
+ keylen = c - key;
+ } else {
+ key = c;
+ }
+ } else {
+ --c;
+ }
+ st = ST_ADD;
+ goto continued;
+ }
+ efree(s);
+ return FAILURE;
+}
+
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
+
--- /dev/null
+/*
+ +--------------------------------------------------------------------+
+ | PECL :: http |
+ +--------------------------------------------------------------------+
+ | Redistribution and use in source and binary forms, with or without |
+ | modification, are permitted provided that the conditions mentioned |
+ | in the accompanying LICENSE file are met. |
+ +--------------------------------------------------------------------+
+ | Copyright (c) 2004-2010, Michael Wallner <mike@php.net> |
+ +--------------------------------------------------------------------+
+*/
+
+/* $Id: php_http_api.h 298891 2010-05-03 08:26:38Z mike $ */
+
+#ifndef PHP_HTTP_PARAMS_H
+#define PHP_HTTP_PARAMS_H
+
+#define PHP_HTTP_PARAMS_ALLOW_COMMA 0x01
+#define PHP_HTTP_PARAMS_ALLOW_FAILURE 0x02
+#define PHP_HTTP_PARAMS_RAISE_ERROR 0x04
+#define PHP_HTTP_PARAMS_DEFAULT (PHP_HTTP_PARAMS_ALLOW_COMMA|PHP_HTTP_PARAMS_ALLOW_FAILURE|PHP_HTTP_PARAMS_RAISE_ERROR)
+#define PHP_HTTP_PARAMS_COLON_SEPARATOR 0x10
+
+typedef void (*php_http_params_parse_func_t)(void *cb_arg, const char *key, int keylen, const char *val, int vallen TSRMLS_DC);
+
+PHP_HTTP_API void php_http_params_parse_default_func(void *ht, const char *key, int keylen, const char *val, int vallen TSRMLS_DC);
+PHP_HTTP_API STATUS php_http_params_parse(const char *params, int flags, php_http_params_parse_func_t cb, void *cb_arg TSRMLS_DC);
+
+#endif
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
+
--- /dev/null
+/*
+ +--------------------------------------------------------------------+
+ | PECL :: http |
+ +--------------------------------------------------------------------+
+ | Redistribution and use in source and binary forms, with or without |
+ | modification, are permitted provided that the conditions mentioned |
+ | in the accompanying LICENSE file are met. |
+ +--------------------------------------------------------------------+
+ | Copyright (c) 2004-2010, Michael Wallner <mike@php.net> |
+ +--------------------------------------------------------------------+
+*/
+
+/* $Id: http_persistent_handle_api.c 292841 2009-12-31 08:48:57Z mike $ */
+
+#include "php_http.h"
+
+#ifndef PHP_HTTP_DEBUG_PHANDLES
+# define PHP_HTTP_DEBUG_PHANDLES 0
+#endif
+#if PHP_HTTP_DEBUG_PHANDLES
+# undef inline
+# define inline
+#endif
+
+static HashTable php_http_persistent_handles_hash;
+#ifdef ZTS
+# define LOCK() tsrm_mutex_lock(php_http_persistent_handles_lock)
+# define UNLOCK() tsrm_mutex_unlock(php_http_persistent_handles_lock)
+static MUTEX_T php_http_persistent_handles_lock;
+#else
+# define LOCK()
+# define UNLOCK()
+#endif
+
+typedef struct php_http_persistent_handle_list {
+ HashTable free;
+ ulong used;
+} php_http_persistent_handle_list_t;
+
+typedef struct php_http_persistent_handle_provider {
+ php_http_persistent_handle_list_t list; /* "ident" => array(handles) entries */
+ php_http_persistent_handle_ctor_t ctor;
+ php_http_persistent_handle_dtor_t dtor;
+ php_http_persistent_handle_copy_t copy;
+} php_http_persistent_handle_provider_t;
+
+static inline php_http_persistent_handle_list_t *php_http_persistent_handle_list_init(php_http_persistent_handle_list_t *list)
+{
+ int free_list;
+
+ if ((free_list = !list)) {
+ list = pemalloc(sizeof(php_http_persistent_handle_list_t), 1);
+ }
+
+ list->used = 0;
+
+ if (SUCCESS != zend_hash_init(&list->free, 0, NULL, NULL, 1)) {
+ if (free_list) {
+ pefree(list, 1);
+ }
+ list = NULL;
+ }
+
+ return list;
+}
+
+static inline void php_http_persistent_handle_list_dtor(php_http_persistent_handle_list_t *list, php_http_persistent_handle_dtor_t dtor)
+{
+ HashPosition pos;
+ void **handle;
+
+#if PHP_HTTP_DEBUG_PHANDLES
+ fprintf(stderr, "LSTDTOR: %p\n", list);
+#endif
+ FOREACH_HASH_VAL(pos, &list->free, handle) {
+#if PHP_HTTP_DEBUG_PHANDLES
+ fprintf(stderr, "DESTROY: %p\n", *handle);
+#endif
+
+ dtor(*handle);
+ }
+ zend_hash_destroy(&list->free);
+}
+
+static inline void php_http_persistent_handle_list_free(php_http_persistent_handle_list_t **list, php_http_persistent_handle_dtor_t dtor)
+{
+ php_http_persistent_handle_list_dtor(*list, dtor);
+#if PHP_HTTP_DEBUG_PHANDLES
+ fprintf(stderr, "LSTFREE: %p\n", *list);
+#endif
+ pefree(*list, 1);
+ *list = NULL;
+}
+
+static inline php_http_persistent_handle_list_t *php_http_persistent_handle_list_find(php_http_persistent_handle_provider_t *provider TSRMLS_DC)
+{
+ php_http_persistent_handle_list_t **list, *new_list;
+
+ if (SUCCESS == zend_hash_quick_find(&provider->list.free, PHP_HTTP_G->persistent_handle.ident.s, PHP_HTTP_G->persistent_handle.ident.l, PHP_HTTP_G->persistent_handle.ident.h, (void *) &list)) {
+#if PHP_HTTP_DEBUG_PHANDLES
+ fprintf(stderr, "LSTFIND: %p\n", *list);
+#endif
+ return *list;
+ }
+
+ if ((new_list = php_http_persistent_handle_list_init(NULL))) {
+ if (SUCCESS == zend_hash_quick_add(&provider->list.free, PHP_HTTP_G->persistent_handle.ident.s, PHP_HTTP_G->persistent_handle.ident.l, PHP_HTTP_G->persistent_handle.ident.h, (void *) &new_list, sizeof(php_http_persistent_handle_list_t *), (void *) &list)) {
+#if PHP_HTTP_DEBUG_PHANDLES
+ fprintf(stderr, "LSTFIND: %p (new)\n", *list);
+#endif
+ return *list;
+ }
+ php_http_persistent_handle_list_free(&new_list, provider->dtor);
+ }
+
+ return NULL;
+}
+
+static inline STATUS php_http_persistent_handle_do_acquire(php_http_persistent_handle_provider_t *provider, void **handle TSRMLS_DC)
+{
+ ulong index;
+ void **handle_ptr;
+ php_http_persistent_handle_list_t *list;
+
+ if ((list = php_http_persistent_handle_list_find(provider TSRMLS_CC))) {
+ zend_hash_internal_pointer_end(&list->free);
+ if (HASH_KEY_NON_EXISTANT != zend_hash_get_current_key(&list->free, NULL, &index, 0) && SUCCESS == zend_hash_get_current_data(&list->free, (void *) &handle_ptr)) {
+ *handle = *handle_ptr;
+ zend_hash_index_del(&list->free, index);
+ } else {
+ *handle = provider->ctor();
+ }
+
+ if (*handle) {
+ ++provider->list.used;
+ ++list->used;
+ return SUCCESS;
+ }
+ } else {
+ *handle = NULL;
+ }
+
+ return FAILURE;
+}
+
+static inline STATUS php_http_persistent_handle_do_release(php_http_persistent_handle_provider_t *provider, void **handle TSRMLS_DC)
+{
+ php_http_persistent_handle_list_t *list;
+
+ if ((list = php_http_persistent_handle_list_find(provider TSRMLS_CC))) {
+ if (provider->list.used >= PHP_HTTP_G->persistent_handle.limit) {
+ provider->dtor(*handle);
+ } else {
+ if (SUCCESS != zend_hash_next_index_insert(&list->free, (void *) handle, sizeof(void *), NULL)) {
+ return FAILURE;
+ }
+ }
+
+ *handle = NULL;
+ --provider->list.used;
+ --list->used;
+ return SUCCESS;
+ }
+
+ return FAILURE;
+}
+
+static inline STATUS php_http_persistent_handle_do_accrete(php_http_persistent_handle_provider_t *provider, void *old_handle, void **new_handle TSRMLS_DC)
+{
+ php_http_persistent_handle_list_t *list;
+
+ if (provider->copy && (*new_handle = provider->copy(old_handle))) {
+ if ((list = php_http_persistent_handle_list_find(provider TSRMLS_CC))) {
+ ++list->used;
+ }
+ ++provider->list.used;
+ return SUCCESS;
+ }
+ return FAILURE;
+}
+
+static void php_http_persistent_handles_hash_dtor(void *p)
+{
+ php_http_persistent_handle_provider_t *provider = (php_http_persistent_handle_provider_t *) p;
+ php_http_persistent_handle_list_t **list, *list_tmp;
+ HashPosition pos;
+
+ FOREACH_HASH_VAL(pos, &provider->list.free, list) {
+ /* fix shutdown crash in PHP4 */
+ list_tmp = *list;
+ php_http_persistent_handle_list_free(&list_tmp, provider->dtor);
+ }
+
+ zend_hash_destroy(&provider->list.free);
+}
+
+PHP_MINIT_FUNCTION(http_persistent_handle)
+{
+ zend_hash_init(&php_http_persistent_handles_hash, 0, NULL, php_http_persistent_handles_hash_dtor, 1);
+#ifdef ZTS
+ php_http_persistent_handles_lock = tsrm_mutex_alloc();
+#endif
+ return SUCCESS;
+}
+
+PHP_MSHUTDOWN_FUNCTION(http_persistent_handle)
+{
+ zend_hash_destroy(&php_http_persistent_handles_hash);
+#ifdef ZTS
+ tsrm_mutex_free(php_http_persistent_handles_lock);
+#endif
+ return SUCCESS;
+}
+
+PHP_HTTP_API STATUS php_http_persistent_handle_provide(const char *name_str, size_t name_len, php_http_persistent_handle_ctor_t ctor, php_http_persistent_handle_dtor_t dtor, php_http_persistent_handle_copy_t copy)
+{
+ STATUS status = FAILURE;
+ php_http_persistent_handle_provider_t provider;
+
+ LOCK();
+ if (php_http_persistent_handle_list_init(&provider.list)) {
+ provider.ctor = ctor;
+ provider.dtor = dtor;
+ provider.copy = copy;
+
+#if PHP_HTTP_DEBUG_PHANDLES
+ fprintf(stderr, "PROVIDE: %s\n", name_str);
+#endif
+
+ if (SUCCESS == zend_hash_add(&php_http_persistent_handles_hash, name_str, name_len+1, (void *) &provider, sizeof(php_http_persistent_handle_provider_t), NULL)) {
+ status = SUCCESS;
+ }
+ }
+ UNLOCK();
+
+ return status;
+}
+
+PHP_HTTP_API STATUS php_http_persistent_handle_acquire(const char *name_str, size_t name_len, void **handle TSRMLS_DC)
+{
+ STATUS status = FAILURE;
+ php_http_persistent_handle_provider_t *provider;
+
+ *handle = NULL;
+ LOCK();
+ if (SUCCESS == zend_hash_find(&php_http_persistent_handles_hash, name_str, name_len+1, (void *) &provider)) {
+ status = php_http_persistent_handle_do_acquire(provider, handle TSRMLS_CC);
+ }
+ UNLOCK();
+
+#if PHP_HTTP_DEBUG_PHANDLES
+ fprintf(stderr, "ACQUIRE: %p (%s)\n", *handle, name_str);
+#endif
+
+ return status;
+}
+
+PHP_HTTP_API STATUS php_http_persistent_handle_release(const char *name_str, size_t name_len, void **handle TSRMLS_DC)
+{
+ STATUS status = FAILURE;
+ php_http_persistent_handle_provider_t *provider;
+#if PHP_HTTP_DEBUG_PHANDLES
+ void *handle_tmp = *handle;
+#endif
+
+ LOCK();
+ if (SUCCESS == zend_hash_find(&php_http_persistent_handles_hash, name_str, name_len+1, (void *) &provider)) {
+ status = php_http_persistent_handle_do_release(provider, handle TSRMLS_CC);
+ }
+ UNLOCK();
+
+#if PHP_HTTP_DEBUG_PHANDLES
+ fprintf(stderr, "RELEASE: %p (%s)\n", handle_tmp, name_str);
+#endif
+
+ return status;
+}
+
+PHP_HTTP_API STATUS php_http_persistent_handle_accrete(const char *name_str, size_t name_len, void *old_handle, void **new_handle TSRMLS_DC)
+{
+ STATUS status = FAILURE;
+ php_http_persistent_handle_provider_t *provider;
+
+ *new_handle = NULL;
+ LOCK();
+ if (SUCCESS == zend_hash_find(&php_http_persistent_handles_hash, name_str, name_len+1, (void *) &provider)) {
+ status = php_http_persistent_handle_do_accrete(provider, old_handle, new_handle TSRMLS_CC);
+ }
+ UNLOCK();
+
+#if PHP_HTTP_DEBUG_PHANDLES
+ fprintf(stderr, "ACCRETE: %p > %p (%s)\n", old_handle, *new_handle, name_str);
+#endif
+
+ return status;
+}
+
+PHP_HTTP_API void php_http_persistent_handle_cleanup(const char *name_str, size_t name_len, int current_ident_only TSRMLS_DC)
+{
+ php_http_persistent_handle_provider_t *provider;
+ php_http_persistent_handle_list_t *list, **listp;
+ HashPosition pos1, pos2;
+
+ LOCK();
+ if (name_str && name_len) {
+ if (SUCCESS == zend_hash_find(&php_http_persistent_handles_hash, name_str, name_len+1, (void *) &provider)) {
+ if (current_ident_only) {
+ if ((list = php_http_persistent_handle_list_find(provider TSRMLS_CC))) {
+ php_http_persistent_handle_list_dtor(list, provider->dtor);
+ php_http_persistent_handle_list_init(list);
+ }
+ } else {
+ FOREACH_HASH_VAL(pos1, &provider->list.free, listp) {
+ php_http_persistent_handle_list_dtor(*listp, provider->dtor);
+ php_http_persistent_handle_list_init(*listp);
+ }
+ }
+ }
+ } else {
+ FOREACH_HASH_VAL(pos1, &php_http_persistent_handles_hash, provider) {
+ if (current_ident_only) {
+ if ((list = php_http_persistent_handle_list_find(provider TSRMLS_CC))) {
+ php_http_persistent_handle_list_dtor(list, provider->dtor);
+ php_http_persistent_handle_list_init(list);
+ }
+ } else {
+ FOREACH_HASH_VAL(pos2, &provider->list.free, listp) {
+ php_http_persistent_handle_list_dtor(*listp, provider->dtor);
+ php_http_persistent_handle_list_init(*listp);
+ }
+ }
+ }
+ }
+ UNLOCK();
+}
+
+PHP_HTTP_API HashTable *php_http_persistent_handle_statall(HashTable *ht TSRMLS_DC)
+{
+ zval *zentry[2];
+ HashPosition pos1, pos2;
+ php_http_array_hashkey_t key1 = php_http_array_hashkey_init(0), key2 = php_http_array_hashkey_init(0);
+ php_http_persistent_handle_provider_t *provider;
+ php_http_persistent_handle_list_t **list;
+
+ LOCK();
+ if (zend_hash_num_elements(&php_http_persistent_handles_hash)) {
+ if (!ht) {
+ ALLOC_HASHTABLE(ht);
+ zend_hash_init(ht, 0, NULL, ZVAL_PTR_DTOR, 0);
+ }
+
+ FOREACH_HASH_KEYVAL(pos1, &php_http_persistent_handles_hash, key1, provider) {
+ MAKE_STD_ZVAL(zentry[0]);
+ array_init(zentry[0]);
+
+ FOREACH_HASH_KEYVAL(pos2, &provider->list.free, key2, list) {
+ MAKE_STD_ZVAL(zentry[1]);
+ array_init(zentry[1]);
+ add_assoc_long_ex(zentry[1], ZEND_STRS("used"), (*list)->used);
+ add_assoc_long_ex(zentry[1], ZEND_STRS("free"), zend_hash_num_elements(&(*list)->free));
+
+ /* use zend_hash_* not add_assoc_* (which is zend_symtable_*) as we want a string even for numbers */
+ zend_hash_add(Z_ARRVAL_P(zentry[0]), key2.str, key2.len, &zentry[1], sizeof(zval *), NULL);
+ }
+
+ zend_hash_add(ht, key1.str, key1.len, &zentry[0], sizeof(zval *), NULL);
+ }
+ } else if (ht) {
+ ht = NULL;
+ }
+ UNLOCK();
+
+ return ht;
+}
+
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
+
--- /dev/null
+/*
+ +--------------------------------------------------------------------+
+ | PECL :: http |
+ +--------------------------------------------------------------------+
+ | Redistribution and use in source and binary forms, with or without |
+ | modification, are permitted provided that the conditions mentioned |
+ | in the accompanying LICENSE file are met. |
+ +--------------------------------------------------------------------+
+ | Copyright (c) 2004-2010, Michael Wallner <mike@php.net> |
+ +--------------------------------------------------------------------+
+*/
+
+/* $Id: php_http_persistent_handle_api.h 292841 2009-12-31 08:48:57Z mike $ */
+
+#ifndef PHP_HTTP_PERSISTENT_HANDLE_H
+#define PHP_HTTP_PERSISTENT_HANDLE_H
+
+typedef void *(*php_http_persistent_handle_ctor_t)(void);
+typedef void (*php_http_persistent_handle_dtor_t)(void *handle);
+typedef void *(*php_http_persistent_handle_copy_t)(void *handle);
+
+struct php_http_persistent_handle_globals {
+ ulong limit;
+ struct {
+ ulong h;
+ char *s;
+ size_t l;
+ } ident;
+};
+
+PHP_MINIT_FUNCTION(http_persistent_handle);
+PHP_MSHUTDOWN_FUNCTION(http_persistent_handle);
+
+PHP_HTTP_API STATUS php_http_persistent_handle_provide(const char *name_str, size_t name_len, php_http_persistent_handle_ctor_t ctor, php_http_persistent_handle_dtor_t dtor, php_http_persistent_handle_copy_t copy);
+PHP_HTTP_API void php_http_persistent_handle_cleanup(const char *name_str, size_t name_len, int current_ident_only TSRMLS_DC);
+PHP_HTTP_API HashTable *php_http_persistent_handle_statall(HashTable *ht TSRMLS_DC);
+PHP_HTTP_API STATUS php_http_persistent_handle_acquire(const char *name_str, size_t name_len, void **handle TSRMLS_DC);
+PHP_HTTP_API STATUS php_http_persistent_handle_release(const char *name_str, size_t name_len, void **handle TSRMLS_DC);
+PHP_HTTP_API STATUS php_http_persistent_handle_accrete(const char *name_str, size_t name_len, void *old_handle, void **new_handle TSRMLS_DC);
+
+#endif /* PHP_HTTP_PERSISTENT_HANDLE_H */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
--- /dev/null
+
+#include "php_http.h"
+
+
+php_http_property_proxy_t *php_http_property_proxy_init(php_http_property_proxy_t *proxy, zval *object, zval *member TSRMLS_DC)
+{
+ if (!proxy) {
+ proxy = emalloc(sizeof(*proxy));
+ }
+ memset(proxy, 0, sizeof(*proxy));
+
+ MAKE_STD_ZVAL(proxy->myself);
+ ZVAL_OBJVAL(proxy->myself, php_http_property_proxy_object_new_ex(php_http_property_proxy_class_entry, proxy, NULL TSRMLS_CC), 0);
+ Z_ADDREF_P(object);
+ proxy->object = object;
+ proxy->member = php_http_zsep(IS_STRING, member);
+
+ return proxy;
+}
+
+void php_http_property_proxy_dtor(php_http_property_proxy_t *proxy)
+{
+ zval_ptr_dtor(&proxy->object);
+ zval_ptr_dtor(&proxy->member);
+ zval_ptr_dtor(&proxy->myself);
+}
+
+void php_http_property_proxy_free(php_http_property_proxy_t **proxy)
+{
+ if (*proxy) {
+ php_http_property_proxy_dtor(*proxy);
+ efree(*proxy);
+ *proxy = NULL;
+ }
+}
+
+
+#define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpPropertyProxy, method, 0, req_args)
+#define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpPropertyProxy, method, 0)
+#define PHP_HTTP_PP_ME(method, visibility) PHP_ME(HttpPropertyProxy, method, PHP_HTTP_ARGS(HttpPropertyProxy, method), visibility)
+
+PHP_HTTP_EMPTY_ARGS(__construct);
+
+zend_class_entry *php_http_property_proxy_class_entry;
+zend_function_entry php_http_property_proxy_method_entry[] = {
+ PHP_HTTP_PP_ME(__construct, ZEND_ACC_FINAL|ZEND_ACC_PRIVATE)
+ EMPTY_FUNCTION_ENTRY
+};
+static zend_object_handlers php_http_property_proxy_object_handlers;
+
+zend_object_value php_http_property_proxy_object_new(zend_class_entry *ce TSRMLS_DC)
+{
+ return php_http_property_proxy_object_new_ex(ce, NULL, NULL TSRMLS_CC);
+}
+
+zend_object_value php_http_property_proxy_object_new_ex(zend_class_entry *ce, php_http_property_proxy_t *proxy, php_http_property_proxy_object_t **ptr TSRMLS_DC)
+{
+ zend_object_value ov;
+ php_http_property_proxy_object_t *o;
+
+ o = ecalloc(1, sizeof(*o));
+ zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
+ object_properties_init((zend_object *) o, ce);
+
+ if (ptr) {
+ *ptr = o;
+ }
+ o->proxy = proxy;
+
+ ov.handle = zend_objects_store_put(o, NULL, php_http_property_proxy_object_free, NULL TSRMLS_CC);
+ ov.handlers = &php_http_property_proxy_object_handlers;
+
+ return ov;
+}
+
+void php_http_property_proxy_object_free(void *object TSRMLS_DC)
+{
+ php_http_property_proxy_object_t *o = object;
+
+ if (o->proxy) {
+ php_http_property_proxy_free(&o->proxy);
+ }
+ zend_object_std_dtor((zend_object *) o TSRMLS_CC);
+ efree(o);
+}
+
+static void php_http_property_proxy_object_set(zval **object, zval *value TSRMLS_DC)
+{
+ php_http_property_proxy_object_t *obj = zend_object_store_get_object(*object TSRMLS_CC);
+
+ zend_update_property(Z_OBJCE_P(obj->proxy->object), obj->proxy->object, Z_STRVAL_P(obj->proxy->member), Z_STRLEN_P(obj->proxy->member), value TSRMLS_CC);
+}
+
+static zval *php_http_property_proxy_object_get(zval *object TSRMLS_DC)
+{
+ php_http_property_proxy_object_t *obj = zend_object_store_get_object(object TSRMLS_CC);
+
+ return zend_read_property(Z_OBJCE_P(obj->proxy->object), obj->proxy->object, Z_STRVAL_P(obj->proxy->member), Z_STRLEN_P(obj->proxy->member), 0 TSRMLS_CC);
+}
+
+static STATUS php_http_property_proxy_object_cast(zval *object, zval *return_value, int type TSRMLS_DC)
+{
+ zval *old_value, *new_value;
+
+ old_value = php_http_property_proxy_object_get(object TSRMLS_CC);
+ new_value = php_http_zsep(type, old_value);
+
+ if (old_value != new_value) {
+ zval_ptr_dtor(&old_value);
+ }
+
+ RETVAL_ZVAL(new_value, 0, 0);
+
+ return SUCCESS;
+}
+
+static zval *php_http_property_proxy_object_read_dimension(zval *object, zval *offset, int type TSRMLS_DC)
+{
+ zval *retval = NULL, *property = php_http_property_proxy_object_get(object TSRMLS_CC);
+
+ if (Z_TYPE_P(property) == IS_ARRAY) {
+ zval **data = NULL;
+
+ if (Z_TYPE_P(offset) == IS_LONG) {
+ if (SUCCESS == zend_hash_index_find(Z_ARRVAL_P(property), Z_LVAL_P(offset), (void *) &data)) {
+ retval = *data;
+ }
+ } else {
+ offset = php_http_zsep(IS_STRING, offset);
+ if (SUCCESS == zend_hash_find(Z_ARRVAL_P(property), Z_STRVAL_P(offset), Z_STRLEN_P(offset), (void *) &data)) {
+ retval = *data;
+ }
+ zval_ptr_dtor(&offset);
+ }
+
+ if (data) {
+ Z_ADDREF_PP(data);
+ }
+ }
+ zval_ptr_dtor(&property);
+
+ return retval;
+}
+
+static void php_http_property_proxy_object_write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC)
+{
+ zval *property = php_http_property_proxy_object_get(object TSRMLS_CC);
+
+ switch (Z_TYPE_P(property)) {
+ case IS_NULL:
+ array_init(property);
+ case IS_ARRAY:
+ Z_ADDREF_P(value);
+ if (!offset) {
+ add_next_index_zval(property, value);
+ } else if (Z_TYPE_P(offset) == IS_LONG) {
+ add_index_zval(property, Z_LVAL_P(offset), value);
+ } else {
+ offset = php_http_zsep(IS_STRING, offset);
+ add_assoc_zval_ex(property, Z_STRVAL_P(offset), Z_STRLEN_P(offset) + 1, value);
+ zval_ptr_dtor(&offset);
+ }
+ php_http_property_proxy_object_set(&object, property TSRMLS_CC);
+ break;
+
+ default:
+ zval_ptr_dtor(&property);
+ break;
+ }
+}
+
+PHP_METHOD(HttpPropertyProxy, __construct)
+{
+}
+
+PHP_MINIT_FUNCTION(http_property_proxy)
+{
+ PHP_HTTP_REGISTER_CLASS(http\\object, PropertyProxy, http_property_proxy, NULL, ZEND_ACC_FINAL);
+ php_http_property_proxy_class_entry->create_object = php_http_property_proxy_object_new;
+ memcpy(&php_http_property_proxy_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
+ php_http_property_proxy_object_handlers.set = php_http_property_proxy_object_set;
+ php_http_property_proxy_object_handlers.get = php_http_property_proxy_object_get;
+ php_http_property_proxy_object_handlers.cast_object = php_http_property_proxy_object_cast;
+ php_http_property_proxy_object_handlers.read_dimension = php_http_property_proxy_object_read_dimension;
+ php_http_property_proxy_object_handlers.write_dimension = php_http_property_proxy_object_write_dimension;
+
+ return SUCCESS;
+}
+
--- /dev/null
+
+#ifndef PHP_HTTP_PROPERTY_PROXY_H
+#define PHP_HTTP_PROPERTY_PROXY_H
+
+typedef struct php_http_property_proxy {
+ zval *myself;
+ zval *object;
+ zval *member;
+} php_http_property_proxy_t;
+
+PHP_HTTP_API php_http_property_proxy_t *php_http_property_proxy_init(php_http_property_proxy_t *proxy, zval *object, zval *member TSRMLS_DC);
+PHP_HTTP_API void php_http_property_proxy_dtor(php_http_property_proxy_t *proxy);
+PHP_HTTP_API void php_http_property_proxy_free(php_http_property_proxy_t **proxy);
+
+typedef struct php_http_property_proxy_object {
+ zend_object zo;
+ php_http_property_proxy_t *proxy;
+} php_http_property_proxy_object_t;
+
+extern zend_class_entry *php_http_property_proxy_class_entry;
+extern zend_function_entry php_http_property_proxy_method_entry[];
+
+extern zend_object_value php_http_property_proxy_object_new(zend_class_entry *ce TSRMLS_DC);
+extern zend_object_value php_http_property_proxy_object_new_ex(zend_class_entry *ce, php_http_property_proxy_t *proxy, php_http_property_proxy_object_t **ptr TSRMLS_DC);
+extern void php_http_property_proxy_object_free(void *object TSRMLS_DC);
+
+PHP_METHOD(HttpPropertyProxy, __construct);
+
+PHP_MINIT_FUNCTION(http_property_proxy);
+
+#endif /* PHP_HTTP_PROPERTY_PROXY_H_ */
--- /dev/null
+/*
+ +--------------------------------------------------------------------+
+ | PECL :: http |
+ +--------------------------------------------------------------------+
+ | Redistribution and use in source and binary forms, with or without |
+ | modification, are permitted provided that the conditions mentioned |
+ | in the accompanying LICENSE file are met. |
+ +--------------------------------------------------------------------+
+ | Copyright (c) 2004-2010, Michael Wallner <mike@php.net> |
+ +--------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#include "php_http.h"
+
+/** API **/
+
+static inline int php_http_querystring_modify_array_ex(zval *qarray, int key_type, char *key, int keylen, ulong idx, zval *params_entry TSRMLS_DC);
+static inline int php_http_querystring_modify_array(zval *qarray, zval *params TSRMLS_DC);
+
+#ifdef PHP_HTTP_HAVE_ICONV
+PHP_HTTP_API int php_http_querystring_xlate(zval *array, zval *param, const char *ie, const char *oe TSRMLS_DC)
+{
+ HashPosition pos;
+ zval **entry = NULL;
+ char *xlate_str = NULL, *xkey;
+ size_t xlate_len = 0, xlen;
+ php_http_array_hashkey_t key = php_http_array_hashkey_init(0);
+
+ FOREACH_KEYVAL(pos, param, key, entry) {
+ if (key.type == HASH_KEY_IS_STRING) {
+ if (PHP_ICONV_ERR_SUCCESS != php_iconv_string(key.str, key.len-1, &xkey, &xlen, oe, ie)) {
+ php_http_error(HE_WARNING, PHP_HTTP_E_QUERYSTRING, "Failed to convert '%.*s' from '%s' to '%s'", key.len-1, key.str, ie, oe);
+ return FAILURE;
+ }
+ }
+
+ if (Z_TYPE_PP(entry) == IS_STRING) {
+ if (PHP_ICONV_ERR_SUCCESS != php_iconv_string(Z_STRVAL_PP(entry), Z_STRLEN_PP(entry), &xlate_str, &xlate_len, oe, ie)) {
+ if (key.type == HASH_KEY_IS_STRING) {
+ efree(xkey);
+ }
+ php_http_error(HE_WARNING, PHP_HTTP_E_QUERYSTRING, "Failed to convert '%.*s' from '%s' to '%s'", Z_STRLEN_PP(entry), Z_STRVAL_PP(entry), ie, oe);
+ return FAILURE;
+ }
+ if (key.type == HASH_KEY_IS_STRING) {
+ add_assoc_stringl_ex(array, xkey, xlen+1, xlate_str, xlate_len, 0);
+ } else {
+ add_index_stringl(array, key.num, xlate_str, xlate_len, 0);
+ }
+ } else if (Z_TYPE_PP(entry) == IS_ARRAY) {
+ zval *subarray;
+
+ MAKE_STD_ZVAL(subarray);
+ array_init(subarray);
+ if (key.type == HASH_KEY_IS_STRING) {
+ add_assoc_zval_ex(array, xkey, xlen+1, subarray);
+ } else {
+ add_index_zval(array, key.num, subarray);
+ }
+ if (SUCCESS != php_http_querystring_xlate(subarray, *entry, ie, oe TSRMLS_CC)) {
+ if (key.type == HASH_KEY_IS_STRING) {
+ efree(xkey);
+ }
+ return FAILURE;
+ }
+ }
+
+ if (key.type == HASH_KEY_IS_STRING) {
+ efree(xkey);
+ }
+ }
+ return SUCCESS;
+}
+#endif /* HAVE_ICONV */
+
+PHP_HTTP_API void php_http_querystring_update(zval *qarray, zval *qstring TSRMLS_DC)
+{
+ char *s = NULL;
+ size_t l = 0;
+
+ if (Z_TYPE_P(qarray) != IS_ARRAY) {
+ convert_to_array(qarray);
+ }
+ if (SUCCESS == php_http_url_encode_hash(Z_ARRVAL_P(qarray), 0, NULL, 0, &s, &l TSRMLS_CC)) {
+ if (Z_TYPE_P(qstring) == IS_STRING)
+ zval_dtor(qstring);
+ ZVAL_STRINGL(qstring, s, l, 0);
+ } else {
+ php_http_error(HE_WARNING, PHP_HTTP_E_QUERYSTRING, "Failed to update query string");
+ }
+}
+
+PHP_HTTP_API int php_http_querystring_modify(zval *qarray, zval *params TSRMLS_DC)
+{
+ if (Z_TYPE_P(params) == IS_ARRAY) {
+ return php_http_querystring_modify_array(qarray, params TSRMLS_CC);
+ } else if (Z_TYPE_P(params) == IS_OBJECT) {
+ if (instanceof_function(Z_OBJCE_P(params), php_http_querystring_class_entry TSRMLS_CC)) {
+ return php_http_querystring_modify_array(qarray, zend_read_property(php_http_querystring_class_entry, params, ZEND_STRL("queryArray"), 0 TSRMLS_CC) TSRMLS_CC);
+ } else {
+ return php_http_querystring_modify_array(qarray, params TSRMLS_CC);
+ }
+ } else {
+ int rv;
+ zval array;
+ zval *qstring = php_http_zsep(IS_STRING, params);
+
+ INIT_PZVAL(&array);
+ array_init(&array);
+
+ php_default_treat_data(PARSE_STRING, estrdup(Z_STRVAL_P(qstring)), &array TSRMLS_CC);
+ zval_ptr_dtor(&qstring);
+
+ rv = php_http_querystring_modify_array(qarray, &array TSRMLS_CC);
+ zval_dtor(&array);
+ return rv;
+ }
+}
+
+static inline int php_http_querystring_modify_array(zval *qarray, zval *params TSRMLS_DC)
+{
+ int rv = 0;
+ php_http_array_hashkey_t key = php_http_array_hashkey_init(0);
+ HashPosition pos;
+ zval **params_entry = NULL;
+
+ FOREACH_HASH_KEYVAL(pos, HASH_OF(params), key, params_entry) {
+ /* only public properties */
+ if ((key.type != HASH_KEY_IS_STRING || *key.str) && php_http_querystring_modify_array_ex(qarray, key.type, key.str, key.len, key.num, *params_entry TSRMLS_CC)) {
+ rv = 1;
+ }
+ }
+
+ return rv;
+}
+
+static inline int php_http_querystring_modify_array_ex(zval *qarray, int key_type, char *key, int keylen, ulong idx, zval *params_entry TSRMLS_DC)
+{
+ zval **qarray_entry;
+
+ /* ensure array type */
+ if (Z_TYPE_P(qarray) != IS_ARRAY) {
+ convert_to_array(qarray);
+ }
+
+ /* delete */
+ if (Z_TYPE_P(params_entry) == IS_NULL) {
+ if (key_type == HASH_KEY_IS_STRING) {
+ return (SUCCESS == zend_hash_del(Z_ARRVAL_P(qarray), key, keylen));
+ } else {
+ return (SUCCESS == zend_hash_index_del(Z_ARRVAL_P(qarray), idx));
+ }
+ }
+
+ /* update */
+ if ( ((key_type == HASH_KEY_IS_STRING) && (SUCCESS == zend_hash_find(Z_ARRVAL_P(qarray), key, keylen, (void *) &qarray_entry))) ||
+ ((key_type == HASH_KEY_IS_LONG) && (SUCCESS == zend_hash_index_find(Z_ARRVAL_P(qarray), idx, (void *) &qarray_entry)))) {
+ zval equal;
+
+ /* recursive */
+ if (Z_TYPE_P(params_entry) == IS_ARRAY || Z_TYPE_P(params_entry) == IS_OBJECT) {
+ return php_http_querystring_modify(*qarray_entry, params_entry TSRMLS_CC);
+ }
+ /* equal */
+ if ((SUCCESS == is_equal_function(&equal, *qarray_entry, params_entry TSRMLS_CC)) && Z_BVAL(equal)) {
+ return 0;
+ }
+ }
+
+ /* add */
+ if (Z_TYPE_P(params_entry) == IS_OBJECT) {
+ zval *new_array;
+
+ MAKE_STD_ZVAL(new_array);
+ array_init(new_array);
+ php_http_querystring_modify_array(new_array, params_entry TSRMLS_CC);
+ params_entry = new_array;
+ } else {
+ Z_ADDREF_P(params_entry);
+ }
+ if (key_type == HASH_KEY_IS_STRING) {
+ add_assoc_zval_ex(qarray, key, keylen, params_entry);
+ } else {
+ add_index_zval(qarray, idx, params_entry);
+ }
+ return 1;
+}
+
+/** PHP **/
+
+#define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpQueryString, method, 0, req_args)
+#define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpQueryString, method, 0)
+#define PHP_HTTP_QUERYSTRING_ME(method, visibility) PHP_ME(HttpQueryString, method, PHP_HTTP_ARGS(HttpQueryString, method), visibility)
+#define PHP_HTTP_QUERYSTRING_GME(method, visibility) PHP_ME(HttpQueryString, method, PHP_HTTP_ARGS(HttpQueryString, __getter), visibility)
+
+PHP_HTTP_BEGIN_ARGS(__construct, 0)
+ PHP_HTTP_ARG_VAL(params, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_EMPTY_ARGS(getGlobalInstance);
+
+PHP_HTTP_EMPTY_ARGS(toArray);
+PHP_HTTP_EMPTY_ARGS(toString);
+
+PHP_HTTP_BEGIN_ARGS(get, 0)
+ PHP_HTTP_ARG_VAL(name, 0)
+ PHP_HTTP_ARG_VAL(type, 0)
+ PHP_HTTP_ARG_VAL(defval, 0)
+ PHP_HTTP_ARG_VAL(delete, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(set, 1)
+ PHP_HTTP_ARG_VAL(params, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(mod, 0)
+ PHP_HTTP_ARG_VAL(params, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(__getter, 1)
+ PHP_HTTP_ARG_VAL(name, 0)
+ PHP_HTTP_ARG_VAL(defval, 0)
+ PHP_HTTP_ARG_VAL(delete, 0)
+PHP_HTTP_END_ARGS;
+
+#ifdef PHP_HTTP_HAVE_ICONV
+PHP_HTTP_BEGIN_ARGS(xlate, 2)
+ PHP_HTTP_ARG_VAL(from_encoding, 0)
+ PHP_HTTP_ARG_VAL(to_encoding, 0)
+PHP_HTTP_END_ARGS;
+#endif
+
+PHP_HTTP_EMPTY_ARGS(serialize);
+PHP_HTTP_BEGIN_ARGS(unserialize, 1)
+ PHP_HTTP_ARG_VAL(serialized, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(offsetGet, 1)
+ PHP_HTTP_ARG_VAL(offset, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(offsetSet, 2)
+ PHP_HTTP_ARG_VAL(offset, 0)
+ PHP_HTTP_ARG_VAL(value, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(offsetExists, 1)
+ PHP_HTTP_ARG_VAL(offset, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(offsetUnset, 1)
+ PHP_HTTP_ARG_VAL(offset, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_EMPTY_ARGS(getIterator);
+
+zend_class_entry *php_http_querystring_class_entry;
+zend_function_entry php_http_querystring_method_entry[] = {
+ PHP_HTTP_QUERYSTRING_ME(__construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR|ZEND_ACC_FINAL)
+
+ PHP_HTTP_QUERYSTRING_ME(toArray, ZEND_ACC_PUBLIC)
+ PHP_HTTP_QUERYSTRING_ME(toString, ZEND_ACC_PUBLIC)
+ ZEND_MALIAS(HttpQueryString, __toString, toString, PHP_HTTP_ARGS(HttpQueryString, toString), ZEND_ACC_PUBLIC)
+
+ PHP_HTTP_QUERYSTRING_ME(get, ZEND_ACC_PUBLIC)
+ PHP_HTTP_QUERYSTRING_ME(set, ZEND_ACC_PUBLIC)
+ PHP_HTTP_QUERYSTRING_ME(mod, ZEND_ACC_PUBLIC)
+
+ PHP_HTTP_QUERYSTRING_GME(getBool, ZEND_ACC_PUBLIC)
+ PHP_HTTP_QUERYSTRING_GME(getInt, ZEND_ACC_PUBLIC)
+ PHP_HTTP_QUERYSTRING_GME(getFloat, ZEND_ACC_PUBLIC)
+ PHP_HTTP_QUERYSTRING_GME(getString, ZEND_ACC_PUBLIC)
+ PHP_HTTP_QUERYSTRING_GME(getArray, ZEND_ACC_PUBLIC)
+ PHP_HTTP_QUERYSTRING_GME(getObject, ZEND_ACC_PUBLIC)
+
+ PHP_HTTP_QUERYSTRING_ME(getIterator, ZEND_ACC_PUBLIC)
+
+ PHP_HTTP_QUERYSTRING_ME(getGlobalInstance, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
+#ifdef PHP_HTTP_HAVE_ICONV
+ PHP_HTTP_QUERYSTRING_ME(xlate, ZEND_ACC_PUBLIC)
+#endif
+
+ /* Implements Serializable */
+ PHP_HTTP_QUERYSTRING_ME(serialize, ZEND_ACC_PUBLIC)
+ PHP_HTTP_QUERYSTRING_ME(unserialize, ZEND_ACC_PUBLIC)
+
+ /* Implements ArrayAccess */
+ PHP_HTTP_QUERYSTRING_ME(offsetGet, ZEND_ACC_PUBLIC)
+ PHP_HTTP_QUERYSTRING_ME(offsetSet, ZEND_ACC_PUBLIC)
+ PHP_HTTP_QUERYSTRING_ME(offsetExists, ZEND_ACC_PUBLIC)
+ PHP_HTTP_QUERYSTRING_ME(offsetUnset, ZEND_ACC_PUBLIC)
+
+ EMPTY_FUNCTION_ENTRY
+};
+
+PHP_MINIT_FUNCTION(http_querystring)
+{
+ PHP_HTTP_REGISTER_CLASS(http, QueryString, http_querystring, php_http_object_class_entry, 0);
+
+ zend_class_implements(php_http_querystring_class_entry TSRMLS_CC, 3, zend_ce_serializable, zend_ce_arrayaccess, zend_ce_aggregate);
+
+ zend_declare_property_null(php_http_querystring_class_entry, ZEND_STRL("instance"), (ZEND_ACC_STATIC|ZEND_ACC_PRIVATE) TSRMLS_CC);
+ zend_declare_property_null(php_http_querystring_class_entry, ZEND_STRL("queryArray"), ZEND_ACC_PRIVATE TSRMLS_CC);
+ zend_declare_property_null(php_http_querystring_class_entry, ZEND_STRL("queryString"), ZEND_ACC_PRIVATE TSRMLS_CC);
+
+ zend_declare_class_constant_long(php_http_querystring_class_entry, ZEND_STRL("TYPE_BOOL"), PHP_HTTP_QUERYSTRING_TYPE_BOOL TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_querystring_class_entry, ZEND_STRL("TYPE_INT"), PHP_HTTP_QUERYSTRING_TYPE_INT TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_querystring_class_entry, ZEND_STRL("TYPE_FLOAT"), PHP_HTTP_QUERYSTRING_TYPE_FLOAT TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_querystring_class_entry, ZEND_STRL("TYPE_STRING"), PHP_HTTP_QUERYSTRING_TYPE_STRING TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_querystring_class_entry, ZEND_STRL("TYPE_ARRAY"), PHP_HTTP_QUERYSTRING_TYPE_ARRAY TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_querystring_class_entry, ZEND_STRL("TYPE_OBJECT"), PHP_HTTP_QUERYSTRING_TYPE_OBJECT TSRMLS_CC);
+
+ return SUCCESS;
+}
+
+static inline void php_http_querystring_get(zval *this_ptr, int type, char *name, uint name_len, zval *defval, zend_bool del, zval *return_value TSRMLS_DC)
+{
+ zval **arrval, *qarray = zend_read_property(php_http_querystring_class_entry, getThis(), ZEND_STRL("queryArray"), 0 TSRMLS_CC);
+
+ if ((Z_TYPE_P(qarray) == IS_ARRAY) && (SUCCESS == zend_hash_find(Z_ARRVAL_P(qarray), name, name_len + 1, (void *) &arrval))) {
+ if (type) {
+ zval *value = php_http_zsep(type, *arrval);
+ RETVAL_ZVAL(value, 1, 1);
+ } else {
+ RETVAL_ZVAL(*arrval, 1, 0);
+ }
+
+ if (del && (SUCCESS == zend_hash_del(Z_ARRVAL_P(qarray), name, name_len + 1))) {
+ php_http_querystring_update(qarray, zend_read_property(php_http_querystring_class_entry, getThis(), ZEND_STRL("queryString"), 0 TSRMLS_CC) TSRMLS_CC);
+ }
+ } else if(defval) {
+ RETURN_ZVAL(defval, 1, 0);
+ }
+}
+
+static inline void php_http_querystring_set(zval *instance, zval *params TSRMLS_DC)
+{
+ zval *na = NULL, *qa = zend_read_property(php_http_querystring_class_entry, instance, ZEND_STRL("queryArray"), 0 TSRMLS_CC);
+
+ if (Z_TYPE_P(qa) != IS_ARRAY) {
+ MAKE_STD_ZVAL(qa);
+ array_init(qa);
+ zend_update_property(php_http_querystring_class_entry, instance, ZEND_STRL("queryArray"), qa TSRMLS_CC);
+ na = qa;
+ }
+
+ if (params && php_http_querystring_modify(qa, params TSRMLS_CC)) {
+ zval *ns = NULL, *qs = zend_read_property(php_http_querystring_class_entry, instance, ZEND_STRL("queryString"), 0 TSRMLS_CC);
+
+ if (Z_TYPE_P(qs) != IS_STRING) {
+ MAKE_STD_ZVAL(qs);
+ ZVAL_EMPTY_STRING(qs);
+ zend_update_property(php_http_querystring_class_entry, instance, ZEND_STRL("queryString"), qs TSRMLS_CC);
+ ns = qs;
+ }
+
+ php_http_querystring_update(qa, qs TSRMLS_CC);
+
+ if (ns) {
+ zval_ptr_dtor(&ns);
+ }
+ }
+
+ if (na) {
+ zval_ptr_dtor(&na);
+ }
+}
+
+PHP_METHOD(HttpQueryString, __construct)
+{
+ zval *params = NULL;
+
+ with_error_handling(EH_THROW, PHP_HTTP_EX_CE(runtime)) {
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z", ¶ms)) {
+ with_error_handling(EH_THROW, PHP_HTTP_EX_CE(querystring)) {
+ php_http_querystring_set(getThis(), params TSRMLS_CC);
+ } end_error_handling();
+ }
+ } end_error_handling();
+}
+
+PHP_METHOD(HttpQueryString, getGlobalInstance)
+{
+ with_error_handling(EH_THROW, PHP_HTTP_EX_CE(runtime)) {
+ if (SUCCESS == zend_parse_parameters_none()) {
+ with_error_handling(EH_THROW, PHP_HTTP_EX_CE(querystring)) {
+ zval *instance = *zend_std_get_static_property(php_http_querystring_class_entry, ZEND_STRL("instance"), 0, NULL TSRMLS_CC);
+
+ if (Z_TYPE_P(instance) != IS_OBJECT) {
+ zval **_SERVER = NULL, **_GET = NULL, **QUERY_STRING = NULL;
+
+ zend_is_auto_global("_GET", lenof("_GET") TSRMLS_CC);
+ zend_is_auto_global("_SERVER", lenof("_SERVER") TSRMLS_CC);
+
+ if ((SUCCESS == zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void *) &_SERVER))
+ && (Z_TYPE_PP(_SERVER) == IS_ARRAY)
+ && (SUCCESS == zend_hash_find(Z_ARRVAL_PP(_SERVER), "QUERY_STRING", sizeof("QUERY_STRING"), (void *) &QUERY_STRING))
+ && (SUCCESS == zend_hash_find(&EG(symbol_table), "_GET", sizeof("_GET"), (void *) &_GET))
+ && (Z_TYPE_PP(_GET) == IS_ARRAY)
+ ) {
+ zval *qstring = *QUERY_STRING, *qarray = *_GET;
+
+ if (Z_TYPE_P(qstring) != IS_STRING) {
+ convert_to_string(qstring);
+ }
+
+ MAKE_STD_ZVAL(instance);
+ ZVAL_OBJVAL(instance, php_http_querystring_object_new(php_http_querystring_class_entry TSRMLS_CC), 0);
+
+ zend_update_property(php_http_querystring_class_entry, instance, ZEND_STRL("queryArray"), qarray TSRMLS_CC);
+ zend_update_property(php_http_querystring_class_entry, instance, ZEND_STRL("queryString"), qstring TSRMLS_CC);
+
+ Z_SET_ISREF_P(zend_read_property(php_http_querystring_class_entry, instance, ZEND_STRL("queryArray"), 0 TSRMLS_CC));
+ Z_SET_ISREF_P(zend_read_property(php_http_querystring_class_entry, instance, ZEND_STRL("queryString"), 0 TSRMLS_CC));
+
+ zend_update_static_property(php_http_querystring_class_entry, ZEND_STRL("instance"), instance TSRMLS_CC);
+ zval_ptr_dtor(&instance);
+ } else {
+ php_http_error(HE_WARNING, PHP_HTTP_E_QUERYSTRING, "Could not acquire reference to superglobal GET or QUERY_STRING");
+ }
+ }
+ RETVAL_ZVAL(instance, 1, 0);
+ } end_error_handling();
+ }
+ } end_error_handling();
+}
+
+PHP_METHOD(HttpQueryString, getIterator)
+{
+ with_error_handling(EH_THROW, PHP_HTTP_EX_CE(runtime)) {
+ if (SUCCESS == zend_parse_parameters_none()) {
+ with_error_handling(EH_THROW, PHP_HTTP_EX_CE(querystring)) {
+ zval *retval = NULL, *qa = zend_read_property(php_http_querystring_class_entry, getThis(), ZEND_STRL("queryArray"), 0 TSRMLS_CC);
+
+ object_init_ex(return_value, spl_ce_RecursiveArrayIterator);
+ zend_call_method_with_1_params(&return_value, spl_ce_RecursiveArrayIterator, NULL, "__construct", &retval, qa);
+ if (retval) {
+ zval_ptr_dtor(&retval);
+ }
+ } end_error_handling();
+ }
+ } end_error_handling();
+}
+
+PHP_METHOD(HttpQueryString, toString)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ RETURN_PROP(php_http_querystring_class_entry, "queryString");
+ }
+ RETURN_EMPTY_STRING();
+}
+
+PHP_METHOD(HttpQueryString, toArray)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ RETURN_PROP(php_http_querystring_class_entry, "queryArray");
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpQueryString, get)
+{
+ char *name_str = NULL;
+ int name_len = 0;
+ long type = 0;
+ zend_bool del = 0;
+ zval *ztype = NULL, *defval = NULL;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|szzb", &name_str, &name_len, &ztype, &defval, &del)) {
+ if (name_str && name_len) {
+ if (ztype) {
+ if (Z_TYPE_P(ztype) == IS_LONG) {
+ type = Z_LVAL_P(ztype);
+ } else if(Z_TYPE_P(ztype) == IS_STRING) {
+ switch (Z_STRVAL_P(ztype)[0]) {
+ case 'B':
+ case 'b': type = PHP_HTTP_QUERYSTRING_TYPE_BOOL; break;
+ case 'L':
+ case 'l':
+ case 'I':
+ case 'i': type = PHP_HTTP_QUERYSTRING_TYPE_INT; break;
+ case 'd':
+ case 'D':
+ case 'F':
+ case 'f': type = PHP_HTTP_QUERYSTRING_TYPE_FLOAT; break;
+ case 'S':
+ case 's': type = PHP_HTTP_QUERYSTRING_TYPE_STRING; break;
+ case 'A':
+ case 'a': type = PHP_HTTP_QUERYSTRING_TYPE_ARRAY; break;
+ case 'O':
+ case 'o': type = PHP_HTTP_QUERYSTRING_TYPE_OBJECT; break;
+ }
+ }
+ }
+ php_http_querystring_get(getThis(), type, name_str, name_len, defval, del, return_value TSRMLS_CC);
+ } else {
+ RETURN_PROP(php_http_querystring_class_entry, "queryString");
+ }
+ }
+}
+
+PHP_METHOD(HttpQueryString, set)
+{
+ zval *params;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", ¶ms)) {
+ php_http_querystring_set(getThis(), params TSRMLS_CC);
+ RETURN_PROP(php_http_querystring_class_entry, "queryString");
+ }
+
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpQueryString, mod)
+{
+ zval *params;
+
+ with_error_handling(EH_THROW, PHP_HTTP_EX_CE(runtime)) {
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", ¶ms)) {
+ with_error_handling(EH_THROW, PHP_HTTP_EX_CE(querystring)) {
+ ZVAL_OBJVAL(return_value, Z_OBJ_HT_P(getThis())->clone_obj(getThis() TSRMLS_CC), 0);
+ php_http_querystring_set(return_value, params TSRMLS_CC);
+ } end_error_handling();
+ }
+ } end_error_handling();
+}
+
+#define PHP_HTTP_QUERYSTRING_GETTER(method, TYPE) \
+PHP_METHOD(HttpQueryString, method) \
+{ \
+ char *name; \
+ int name_len; \
+ zval *defval = NULL; \
+ zend_bool del = 0; \
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|zb", &name, &name_len, &defval, &del)) { \
+ php_http_querystring_get(getThis(), TYPE, name, name_len, defval, del, return_value TSRMLS_CC); \
+ } \
+}
+PHP_HTTP_QUERYSTRING_GETTER(getBool, IS_BOOL);
+PHP_HTTP_QUERYSTRING_GETTER(getInt, IS_LONG);
+PHP_HTTP_QUERYSTRING_GETTER(getFloat, IS_DOUBLE);
+PHP_HTTP_QUERYSTRING_GETTER(getString, IS_STRING);
+PHP_HTTP_QUERYSTRING_GETTER(getArray, IS_ARRAY);
+PHP_HTTP_QUERYSTRING_GETTER(getObject, IS_OBJECT);
+
+#ifdef PHP_HTTP_HAVE_ICONV
+PHP_METHOD(HttpQueryString, xlate)
+{
+ with_error_handling(EH_THROW, PHP_HTTP_EX_CE(runtime)) {
+ char *ie, *oe;
+ int ie_len, oe_len;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &ie, &ie_len, &oe, &oe_len)) {
+ with_error_handling(EH_THROW, PHP_HTTP_EX_CE(querystring)) {
+ zval *qa = zend_read_property(php_http_querystring_class_entry, getThis(), ZEND_STRL("queryArray"), 0 TSRMLS_CC);
+
+ if (Z_TYPE_P(qa) != IS_ARRAY) {
+ MAKE_STD_ZVAL(qa);
+ array_init(qa);
+ zend_update_property(php_http_querystring_class_entry, getThis(), ZEND_STRL("queryArray"), qa TSRMLS_CC);
+ zval_ptr_dtor(&qa);
+ } else {
+ zval xa;
+
+ INIT_PZVAL(&xa);
+ array_init(&xa);
+ if (SUCCESS == php_http_querystring_xlate(&xa, qa, ie, oe TSRMLS_CC)) {
+ zval *ns = NULL, *qs = zend_read_property(php_http_querystring_class_entry, getThis(), ZEND_STRL("queryString"), 0 TSRMLS_CC);
+
+ /* shitty internal zvals */
+ if (Z_TYPE_P(qs) != IS_STRING) {
+ MAKE_STD_ZVAL(qs);
+ ZVAL_EMPTY_STRING(qs);
+ zend_update_property(php_http_querystring_class_entry, getThis(), ZEND_STRL("queryString"), qs TSRMLS_CC);
+ ns = qs;
+ }
+
+ zend_hash_clean(Z_ARRVAL_P(qa));
+ array_copy(Z_ARRVAL(xa), Z_ARRVAL_P(qa));
+ php_http_querystring_update(qa, qs TSRMLS_CC);
+
+ if (ns) {
+ zval_ptr_dtor(&ns);
+ }
+ }
+ zval_dtor(&xa);
+ }
+ RETVAL_ZVAL(getThis(), 1, 0);
+ } end_error_handling();
+ }
+ } end_error_handling();
+
+}
+#endif /* HAVE_ICONV */
+
+PHP_METHOD(HttpQueryString, serialize)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ RETURN_PROP(php_http_querystring_class_entry, "queryString");
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpQueryString, unserialize)
+{
+ zval *serialized;
+
+ with_error_handling(EH_THROW, PHP_HTTP_EX_CE(runtime)) {
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &serialized)) {
+ with_error_handling(EH_THROW, PHP_HTTP_EX_CE(querystring)) {
+ if (Z_TYPE_P(serialized) == IS_STRING) {
+ php_http_querystring_set(getThis(), serialized TSRMLS_CC);
+ } else {
+ php_http_error(HE_WARNING, PHP_HTTP_E_QUERYSTRING, "Expected a string as parameter");
+ }
+ } end_error_handling();
+ }
+ } end_error_handling();
+}
+
+PHP_METHOD(HttpQueryString, offsetGet)
+{
+ char *offset_str;
+ int offset_len;
+ zval **value;
+
+ if ((SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &offset_str, &offset_len))
+ && (SUCCESS == zend_hash_find(Z_ARRVAL_P(zend_read_property(php_http_querystring_class_entry, getThis(), ZEND_STRL("queryArray"), 0 TSRMLS_CC)), offset_str, offset_len + 1, (void *) &value))
+ ) {
+ RETVAL_ZVAL(*value, 1, 0);
+ }
+}
+
+PHP_METHOD(HttpQueryString, offsetSet)
+{
+ char *offset_str;
+ int offset_len;
+ zval *value;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &offset_str, &offset_len, &value)) {
+ zval *qarr = zend_read_property(php_http_querystring_class_entry, getThis(), ZEND_STRL("queryArray"), 0 TSRMLS_CC), *qstr = zend_read_property(php_http_querystring_class_entry, getThis(), ZEND_STRL("queryString"), 0 TSRMLS_CC);
+
+ Z_ADDREF_P(value);
+ add_assoc_zval_ex(qarr, offset_str, offset_len + 1, value);
+ php_http_querystring_update(qarr, qstr TSRMLS_CC);
+ }
+}
+
+PHP_METHOD(HttpQueryString, offsetExists)
+{
+ char *offset_str;
+ int offset_len;
+ zval **value;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &offset_str, &offset_len)) {
+ RETURN_BOOL((SUCCESS == zend_hash_find(Z_ARRVAL_P(zend_read_property(php_http_querystring_class_entry, getThis(), ZEND_STRL("queryArray"), 0 TSRMLS_CC)), offset_str, offset_len + 1, (void *) &value)) && (Z_TYPE_PP(value) != IS_NULL));
+ }
+}
+
+PHP_METHOD(HttpQueryString, offsetUnset)
+{
+ char *offset_str;
+ int offset_len;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &offset_str, &offset_len)) {
+ zval *qarr = zend_read_property(php_http_querystring_class_entry, getThis(), ZEND_STRL("queryArray"), 0 TSRMLS_CC);
+
+ if (SUCCESS == zend_hash_del(Z_ARRVAL_P(qarr), offset_str, offset_len + 1)) {
+ php_http_querystring_update(qarr, zend_read_property(php_http_querystring_class_entry, getThis(), ZEND_STRL("queryString"), 0 TSRMLS_CC) TSRMLS_CC);
+ }
+ }
+}
+
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
--- /dev/null
+/*
+ +--------------------------------------------------------------------+
+ | PECL :: http |
+ +--------------------------------------------------------------------+
+ | Redistribution and use in source and binary forms, with or without |
+ | modification, are permitted provided that the conditions mentioned |
+ | in the accompanying LICENSE file are met. |
+ +--------------------------------------------------------------------+
+ | Copyright (c) 2004-2010, Michael Wallner <mike@php.net> |
+ +--------------------------------------------------------------------+
+*/
+
+/* $Id: php_http_querystring_api.h 292841 2009-12-31 08:48:57Z mike $ */
+
+#ifndef PHP_HTTP_QUERYSTRING_H
+#define PHP_HTTP_QUERYSTRING_H
+
+/* API */
+
+#ifdef PHP_HTTP_HAVE_ICONV
+PHP_HTTP_API int php_http_querystring_xlate(zval *array, zval *param, const char *ie, const char *oe TSRMLS_DC);
+#endif /* PHP_HTTP_HAVE_ICONV */
+PHP_HTTP_API void php_http_querystring_update(zval *qarray, zval *qstring TSRMLS_DC);
+PHP_HTTP_API int php_http_querystring_modify(zval *qarray, zval *params TSRMLS_DC);
+
+/* PHP */
+
+typedef struct php_http_querystring_object {
+ zend_object zo;
+} php_http_querystring_object_t;
+
+#define PHP_HTTP_QUERYSTRING_TYPE_BOOL IS_BOOL
+#define PHP_HTTP_QUERYSTRING_TYPE_INT IS_LONG
+#define PHP_HTTP_QUERYSTRING_TYPE_FLOAT IS_DOUBLE
+#define PHP_HTTP_QUERYSTRING_TYPE_STRING IS_STRING
+#define PHP_HTTP_QUERYSTRING_TYPE_ARRAY IS_ARRAY
+#define PHP_HTTP_QUERYSTRING_TYPE_OBJECT IS_OBJECT
+
+extern zend_class_entry *php_http_querystring_class_entry;
+extern zend_function_entry php_http_querystring_method_entry[];
+
+extern PHP_MINIT_FUNCTION(http_querystring);
+
+#define php_http_querystring_object_new php_http_object_new
+#define php_http_querystring_object_new_ex php_http_object_new_ex
+
+PHP_METHOD(HttpQueryString, getGlobalInstance);
+PHP_METHOD(HttpQueryString, __construct);
+PHP_METHOD(HttpQueryString, getIterator);
+PHP_METHOD(HttpQueryString, toString);
+PHP_METHOD(HttpQueryString, toArray);
+PHP_METHOD(HttpQueryString, get);
+PHP_METHOD(HttpQueryString, set);
+PHP_METHOD(HttpQueryString, mod);
+PHP_METHOD(HttpQueryString, getBool);
+PHP_METHOD(HttpQueryString, getInt);
+PHP_METHOD(HttpQueryString, getFloat);
+PHP_METHOD(HttpQueryString, getString);
+PHP_METHOD(HttpQueryString, getArray);
+PHP_METHOD(HttpQueryString, getObject);
+#ifdef PHP_HTTP_HAVE_ICONV
+PHP_METHOD(HttpQueryString, xlate);
+#endif /* PHP_HTTP_HAVE_ICONV */
+PHP_METHOD(HttpQueryString, factory);
+PHP_METHOD(HttpQueryString, singleton);
+PHP_METHOD(HttpQueryString, serialize);
+PHP_METHOD(HttpQueryString, unserialize);
+PHP_METHOD(HttpQueryString, offsetGet);
+PHP_METHOD(HttpQueryString, offsetSet);
+PHP_METHOD(HttpQueryString, offsetExists);
+PHP_METHOD(HttpQueryString, offsetUnset);
+
+#endif /* PHP_HTTP_QUERYSTRING_H */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
--- /dev/null
+/*
+ +--------------------------------------------------------------------+
+ | PECL :: http |
+ +--------------------------------------------------------------------+
+ | Redistribution and use in source and binary forms, with or without |
+ | modification, are permitted provided that the conditions mentioned |
+ | in the accompanying LICENSE file are met. |
+ +--------------------------------------------------------------------+
+ | Copyright (c) 2004-2010, Michael Wallner <mike@php.net> |
+ +--------------------------------------------------------------------+
+*/
+
+/* $Id: php_http_request_api.c 298591 2010-04-26 11:46:55Z mike $ */
+
+#include "php_http.h"
+
+#ifdef PHP_HTTP_NEED_OPENSSL_TSL
+static MUTEX_T *php_http_openssl_tsl = NULL;
+
+static void php_http_openssl_thread_lock(int mode, int n, const char * file, int line)
+{
+ if (mode & CRYPTO_LOCK) {
+ tsrm_mutex_lock(php_http_openssl_tsl[n]);
+ } else {
+ tsrm_mutex_unlock(php_http_openssl_tsl[n]);
+ }
+}
+
+static ulong php_http_openssl_thread_id(void)
+{
+ return (ulong) tsrm_thread_id();
+}
+#endif
+#ifdef PHP_HTTP_NEED_GNUTLS_TSL
+static int php_http_gnutls_mutex_create(void **m)
+{
+ if (*((MUTEX_T *) m) = tsrm_mutex_alloc()) {
+ return SUCCESS;
+ } else {
+ return FAILURE;
+ }
+}
+
+static int php_http_gnutls_mutex_destroy(void **m)
+{
+ tsrm_mutex_free(*((MUTEX_T *) m));
+ return SUCCESS;
+}
+
+static int php_http_gnutls_mutex_lock(void **m)
+{
+ return tsrm_mutex_lock(*((MUTEX_T *) m));
+}
+
+static int php_http_gnutls_mutex_unlock(void **m)
+{
+ return tsrm_mutex_unlock(*((MUTEX_T *) m));
+}
+
+static struct gcry_thread_cbs php_http_gnutls_tsl = {
+ GCRY_THREAD_OPTION_USER,
+ NULL,
+ php_http_gnutls_mutex_create,
+ php_http_gnutls_mutex_destroy,
+ php_http_gnutls_mutex_lock,
+ php_http_gnutls_mutex_unlock
+};
+#endif
+
+
+/* safe curl wrappers */
+#define init_curl_storage(ch) \
+ {\
+ php_http_request_storage_t *st = pecalloc(1, sizeof(php_http_request_storage_t), 1); \
+ curl_easy_setopt(ch, CURLOPT_PRIVATE, st); \
+ curl_easy_setopt(ch, CURLOPT_ERRORBUFFER, st->errorbuffer); \
+ }
+
+static void *safe_curl_init(void)
+{
+ CURL *ch;
+
+ if ((ch = curl_easy_init())) {
+ init_curl_storage(ch);
+ return ch;
+ }
+ return NULL;
+}
+static void *safe_curl_copy(void *p)
+{
+ CURL *ch;
+
+ if ((ch = curl_easy_duphandle(p))) {
+ init_curl_storage(ch);
+ return ch;
+ }
+ return NULL;
+}
+static void safe_curl_dtor(void *p) {
+ php_http_request_storage_t *st = php_http_request_storage_get(p);
+
+ curl_easy_cleanup(p);
+
+ if (st) {
+ if (st->url) {
+ pefree(st->url, 1);
+ }
+ if (st->cookiestore) {
+ pefree(st->cookiestore, 1);
+ }
+ pefree(st, 1);
+ }
+}
+
+static inline zval *php_http_request_option(php_http_request_t *request, HashTable *options, char *key, size_t keylen, int type);
+static inline zval *php_http_request_option_cache(php_http_request_t *r, char *key, size_t keylen, ulong h, zval *opt);
+static inline int php_http_request_cookies_enabled(php_http_request_t *r);
+
+static size_t php_http_curl_read_callback(void *, size_t, size_t, void *);
+static int php_http_curl_progress_callback(void *, double, double, double, double);
+static int php_http_curl_raw_callback(CURL *, curl_infotype, char *, size_t, void *);
+static int php_http_curl_dummy_callback(char *data, size_t n, size_t l, void *s) { return n*l; }
+static curlioerr php_http_curl_ioctl_callback(CURL *, curliocmd, void *);
+
+PHP_HTTP_API CURL * php_http_curl_init(CURL *ch, php_http_request_t *request TSRMLS_DC)
+{
+ if (ch || (SUCCESS == php_http_persistent_handle_acquire(ZEND_STRL("http_request"), &ch TSRMLS_CC))) {
+#if defined(ZTS)
+ curl_easy_setopt(ch, CURLOPT_NOSIGNAL, 1L);
+#endif
+ curl_easy_setopt(ch, CURLOPT_HEADER, 0L);
+ curl_easy_setopt(ch, CURLOPT_FILETIME, 1L);
+ curl_easy_setopt(ch, CURLOPT_AUTOREFERER, 1L);
+ curl_easy_setopt(ch, CURLOPT_VERBOSE, 1L);
+ curl_easy_setopt(ch, CURLOPT_HEADERFUNCTION, NULL);
+ curl_easy_setopt(ch, CURLOPT_DEBUGFUNCTION, php_http_curl_raw_callback);
+ curl_easy_setopt(ch, CURLOPT_READFUNCTION, php_http_curl_read_callback);
+ curl_easy_setopt(ch, CURLOPT_IOCTLFUNCTION, php_http_curl_ioctl_callback);
+ curl_easy_setopt(ch, CURLOPT_WRITEFUNCTION, php_http_curl_dummy_callback);
+
+ /* set context */
+ if (request) {
+ curl_easy_setopt(ch, CURLOPT_DEBUGDATA, request);
+
+ /* attach curl handle */
+ request->ch = ch;
+ /* set defaults (also in php_http_request_reset()) */
+ php_http_request_defaults(request);
+ }
+ }
+
+ return ch;
+}
+PHP_HTTP_API CURL *php_http_curl_copy(CURL *ch TSRMLS_DC)
+{
+ CURL *copy;
+
+ if (SUCCESS == php_http_persistent_handle_accrete(ZEND_STRL("http_request"), ch, © TSRMLS_CC)) {
+ return copy;
+ }
+ return NULL;
+}
+PHP_HTTP_API void php_http_curl_free(CURL **ch TSRMLS_DC)
+{
+ if (*ch) {
+ curl_easy_setopt(*ch, CURLOPT_NOPROGRESS, 1L);
+ curl_easy_setopt(*ch, CURLOPT_PROGRESSFUNCTION, NULL);
+ curl_easy_setopt(*ch, CURLOPT_VERBOSE, 0L);
+ curl_easy_setopt(*ch, CURLOPT_DEBUGFUNCTION, NULL);
+
+ php_http_persistent_handle_release(ZEND_STRL("http_request"), ch TSRMLS_CC);
+ }
+}
+
+PHP_HTTP_API php_http_request_t *php_http_request_init(php_http_request_t *request, CURL *ch, php_http_request_method_t meth, const char *url TSRMLS_DC)
+{
+ php_http_request_t *r;
+
+ if (request) {
+ r = request;
+ } else {
+ r = emalloc(sizeof(php_http_request_t));
+ }
+ memset(r, 0, sizeof(php_http_request_t));
+
+ r->ch = ch;
+ r->url = (url) ? php_http_url_absolute(url, 0) : NULL;
+ r->meth = (meth > 0) ? meth : PHP_HTTP_GET;
+
+ r->parser.ctx = php_http_message_parser_init(NULL TSRMLS_CC);
+ r->parser.msg = php_http_message_init(NULL, 0 TSRMLS_CC);
+ r->parser.buf = php_http_buffer_init(NULL);
+
+ php_http_buffer_init(&r->_cache.cookies);
+ zend_hash_init(&r->_cache.options, 0, NULL, ZVAL_PTR_DTOR, 0);
+
+ TSRMLS_SET_CTX(r->ts);
+
+ return r;
+}
+
+PHP_HTTP_API void php_http_request_dtor(php_http_request_t *request)
+{
+ TSRMLS_FETCH_FROM_CTX(request->ts);
+
+ php_http_request_reset(request);
+ php_http_curl_free(&request->ch);
+ php_http_message_body_free(&request->body);
+ php_http_message_parser_free(&request->parser.ctx);
+ php_http_message_free(&request->parser.msg);
+ php_http_buffer_free(&request->parser.buf);
+
+ php_http_buffer_dtor(&request->_cache.cookies);
+ zend_hash_destroy(&request->_cache.options);
+ if (request->_cache.headers) {
+ curl_slist_free_all(request->_cache.headers);
+ request->_cache.headers = NULL;
+ }
+ if (request->_progress.callback) {
+ zval_ptr_dtor(&request->_progress.callback);
+ request->_progress.callback = NULL;
+ }
+}
+
+PHP_HTTP_API void php_http_request_free(php_http_request_t **request)
+{
+ if (*request) {
+ TSRMLS_FETCH_FROM_CTX((*request)->ts);
+ php_http_request_dtor(*request);
+ efree(*request);
+ *request = NULL;
+ }
+}
+
+PHP_HTTP_API void php_http_request_reset(php_http_request_t *request)
+{
+ TSRMLS_FETCH_FROM_CTX(request->ts);
+ STR_SET(request->url, NULL);
+ php_http_message_body_dtor(request->body);
+ php_http_request_defaults(request);
+
+ if (request->ch) {
+ php_http_request_storage_t *st = php_http_request_storage_get(request->ch);
+
+ if (st) {
+ if (st->url) {
+ pefree(st->url, 1);
+ st->url = NULL;
+ }
+ if (st->cookiestore) {
+ pefree(st->cookiestore, 1);
+ st->cookiestore = NULL;
+ }
+ st->errorbuffer[0] = '\0';
+ }
+ }
+}
+
+PHP_HTTP_API STATUS php_http_request_enable_cookies(php_http_request_t *request)
+{
+ int initialized = 1;
+ TSRMLS_FETCH_FROM_CTX(request->ts);
+
+ PHP_HTTP_CHECK_CURL_INIT(request->ch, php_http_curl_init(request->ch, request TSRMLS_CC), initialized = 0);
+ if (initialized && (php_http_request_cookies_enabled(request) || (CURLE_OK == curl_easy_setopt(request->ch, CURLOPT_COOKIEFILE, "")))) {
+ return SUCCESS;
+ }
+ php_http_error(HE_WARNING, PHP_HTTP_E_REQUEST, "Could not enable cookies for this session");
+ return FAILURE;
+}
+
+PHP_HTTP_API STATUS php_http_request_reset_cookies(php_http_request_t *request, int session_only)
+{
+ int initialized = 1;
+ TSRMLS_FETCH_FROM_CTX(request->ts);
+
+ PHP_HTTP_CHECK_CURL_INIT(request->ch, php_http_curl_init(request->ch, request TSRMLS_CC), initialized = 0);
+ if (initialized) {
+ if (!php_http_request_cookies_enabled(request)) {
+ if (SUCCESS != php_http_request_enable_cookies(request)) {
+ return FAILURE;
+ }
+ }
+ if (session_only) {
+ if (CURLE_OK == curl_easy_setopt(request->ch, CURLOPT_COOKIELIST, "SESS")) {
+ return SUCCESS;
+ }
+ } else {
+ if (CURLE_OK == curl_easy_setopt(request->ch, CURLOPT_COOKIELIST, "ALL")) {
+ return SUCCESS;
+ }
+ }
+ }
+ return FAILURE;
+}
+
+PHP_HTTP_API STATUS php_http_request_flush_cookies(php_http_request_t *request)
+{
+ int initialized = 1;
+ TSRMLS_FETCH_FROM_CTX(request->ts);
+
+ PHP_HTTP_CHECK_CURL_INIT(request->ch, php_http_curl_init(request->ch, request TSRMLS_CC), initialized = 0);
+ if (initialized) {
+ if (!php_http_request_cookies_enabled(request)) {
+ return FAILURE;
+ }
+ if (CURLE_OK == curl_easy_setopt(request->ch, CURLOPT_COOKIELIST, "FLUSH")) {
+ return SUCCESS;
+ }
+ }
+ return FAILURE;
+}
+
+PHP_HTTP_API void php_http_request_defaults(php_http_request_t *request)
+{
+ if (request->ch) {
+ PHP_HTTP_CURL_OPT(CURLOPT_NOPROGRESS, 0L);
+ PHP_HTTP_CURL_OPT(CURLOPT_PROGRESSDATA, request);
+ PHP_HTTP_CURL_OPT(CURLOPT_PROGRESSFUNCTION, php_http_curl_progress_callback);
+ PHP_HTTP_CURL_OPT(CURLOPT_URL, NULL);
+#if PHP_HTTP_CURL_VERSION(7,19,4)
+ PHP_HTTP_CURL_OPT(CURLOPT_NOPROXY, NULL);
+#endif
+ PHP_HTTP_CURL_OPT(CURLOPT_PROXY, NULL);
+ PHP_HTTP_CURL_OPT(CURLOPT_PROXYPORT, 0L);
+ PHP_HTTP_CURL_OPT(CURLOPT_PROXYTYPE, 0L);
+ /* libcurl < 7.19.6 does not clear auth info with USERPWD set to NULL */
+#if PHP_HTTP_CURL_VERSION(7,19,1)
+ PHP_HTTP_CURL_OPT(CURLOPT_PROXYUSERNAME, NULL);
+ PHP_HTTP_CURL_OPT(CURLOPT_PROXYPASSWORD, NULL);
+#endif
+ PHP_HTTP_CURL_OPT(CURLOPT_PROXYAUTH, 0L);
+ PHP_HTTP_CURL_OPT(CURLOPT_HTTPPROXYTUNNEL, 0L);
+ PHP_HTTP_CURL_OPT(CURLOPT_DNS_CACHE_TIMEOUT, 60L);
+ PHP_HTTP_CURL_OPT(CURLOPT_IPRESOLVE, 0);
+ PHP_HTTP_CURL_OPT(CURLOPT_LOW_SPEED_LIMIT, 0L);
+ PHP_HTTP_CURL_OPT(CURLOPT_LOW_SPEED_TIME, 0L);
+ /* LFS weirdance
+ PHP_HTTP_CURL_OPT(CURLOPT_MAX_SEND_SPEED_LARGE, (curl_off_t) 0);
+ PHP_HTTP_CURL_OPT(CURLOPT_MAX_RECV_SPEED_LARGE, (curl_off_t) 0);
+ */
+ /* crashes
+ PHP_HTTP_CURL_OPT(CURLOPT_MAXCONNECTS, 5L); */
+ PHP_HTTP_CURL_OPT(CURLOPT_FRESH_CONNECT, 0L);
+ PHP_HTTP_CURL_OPT(CURLOPT_FORBID_REUSE, 0L);
+ PHP_HTTP_CURL_OPT(CURLOPT_INTERFACE, NULL);
+ PHP_HTTP_CURL_OPT(CURLOPT_PORT, 0L);
+#if PHP_HTTP_CURL_VERSION(7,19,0)
+ PHP_HTTP_CURL_OPT(CURLOPT_ADDRESS_SCOPE, 0L);
+#endif
+ PHP_HTTP_CURL_OPT(CURLOPT_LOCALPORT, 0L);
+ PHP_HTTP_CURL_OPT(CURLOPT_LOCALPORTRANGE, 0L);
+ /* libcurl < 7.19.6 does not clear auth info with USERPWD set to NULL */
+#if PHP_HTTP_CURL_VERSION(7,19,1)
+ PHP_HTTP_CURL_OPT(CURLOPT_USERNAME, NULL);
+ PHP_HTTP_CURL_OPT(CURLOPT_PASSWORD, NULL);
+#endif
+ PHP_HTTP_CURL_OPT(CURLOPT_HTTPAUTH, 0L);
+ PHP_HTTP_CURL_OPT(CURLOPT_ENCODING, NULL);
+ /* we do this ourself anyway */
+ PHP_HTTP_CURL_OPT(CURLOPT_HTTP_CONTENT_DECODING, 0L);
+ PHP_HTTP_CURL_OPT(CURLOPT_HTTP_TRANSFER_DECODING, 0L);
+ PHP_HTTP_CURL_OPT(CURLOPT_FOLLOWLOCATION, 0L);
+#if PHP_HTTP_CURL_VERSION(7,19,1)
+ PHP_HTTP_CURL_OPT(CURLOPT_POSTREDIR, 0L);
+#else
+ PHP_HTTP_CURL_OPT(CURLOPT_POST301, 0L);
+#endif
+ PHP_HTTP_CURL_OPT(CURLOPT_UNRESTRICTED_AUTH, 0L);
+ PHP_HTTP_CURL_OPT(CURLOPT_REFERER, NULL);
+ PHP_HTTP_CURL_OPT(CURLOPT_USERAGENT, "PECL::HTTP/" PHP_HTTP_EXT_VERSION " (PHP/" PHP_VERSION ")");
+ PHP_HTTP_CURL_OPT(CURLOPT_HTTPHEADER, NULL);
+ PHP_HTTP_CURL_OPT(CURLOPT_COOKIE, NULL);
+ PHP_HTTP_CURL_OPT(CURLOPT_COOKIESESSION, 0L);
+ /* these options would enable curl's cookie engine by default which we don't want
+ PHP_HTTP_CURL_OPT(CURLOPT_COOKIEFILE, NULL);
+ PHP_HTTP_CURL_OPT(CURLOPT_COOKIEJAR, NULL); */
+ PHP_HTTP_CURL_OPT(CURLOPT_COOKIELIST, NULL);
+ PHP_HTTP_CURL_OPT(CURLOPT_RANGE, NULL);
+ PHP_HTTP_CURL_OPT(CURLOPT_RESUME_FROM, 0L);
+ PHP_HTTP_CURL_OPT(CURLOPT_MAXFILESIZE, 0L);
+ PHP_HTTP_CURL_OPT(CURLOPT_TIMECONDITION, 0L);
+ PHP_HTTP_CURL_OPT(CURLOPT_TIMEVALUE, 0L);
+ PHP_HTTP_CURL_OPT(CURLOPT_TIMEOUT, 0L);
+ PHP_HTTP_CURL_OPT(CURLOPT_CONNECTTIMEOUT, 3);
+ PHP_HTTP_CURL_OPT(CURLOPT_SSLCERT, NULL);
+ PHP_HTTP_CURL_OPT(CURLOPT_SSLCERTTYPE, NULL);
+ PHP_HTTP_CURL_OPT(CURLOPT_SSLCERTPASSWD, NULL);
+ PHP_HTTP_CURL_OPT(CURLOPT_SSLKEY, NULL);
+ PHP_HTTP_CURL_OPT(CURLOPT_SSLKEYTYPE, NULL);
+ PHP_HTTP_CURL_OPT(CURLOPT_SSLKEYPASSWD, NULL);
+ PHP_HTTP_CURL_OPT(CURLOPT_SSLENGINE, NULL);
+ PHP_HTTP_CURL_OPT(CURLOPT_SSLVERSION, 0L);
+ PHP_HTTP_CURL_OPT(CURLOPT_SSL_VERIFYPEER, 0L);
+ PHP_HTTP_CURL_OPT(CURLOPT_SSL_VERIFYHOST, 0L);
+ PHP_HTTP_CURL_OPT(CURLOPT_SSL_CIPHER_LIST, NULL);
+#if PHP_HTTP_CURL_VERSION(7,19,0)
+ PHP_HTTP_CURL_OPT(CURLOPT_ISSUERCERT, NULL);
+ #if defined(PHP_HTTP_HAVE_OPENSSL)
+ PHP_HTTP_CURL_OPT(CURLOPT_CRLFILE, NULL);
+ #endif
+#endif
+#if PHP_HTTP_CURL_VERSION(7,19,1) && defined(PHP_HTTP_HAVE_OPENSSL)
+ PHP_HTTP_CURL_OPT(CURLOPT_CERTINFO, NULL);
+#endif
+#ifdef PHP_HTTP_CURL_CAINFO
+ PHP_HTTP_CURL_OPT(CURLOPT_CAINFO, PHP_HTTP_CURL_CAINFO);
+#else
+ PHP_HTTP_CURL_OPT(CURLOPT_CAINFO, NULL);
+#endif
+ PHP_HTTP_CURL_OPT(CURLOPT_CAPATH, NULL);
+ PHP_HTTP_CURL_OPT(CURLOPT_RANDOM_FILE, NULL);
+ PHP_HTTP_CURL_OPT(CURLOPT_EGDSOCKET, NULL);
+ PHP_HTTP_CURL_OPT(CURLOPT_POSTFIELDS, NULL);
+ PHP_HTTP_CURL_OPT(CURLOPT_POSTFIELDSIZE, 0L);
+ PHP_HTTP_CURL_OPT(CURLOPT_HTTPPOST, NULL);
+ PHP_HTTP_CURL_OPT(CURLOPT_IOCTLDATA, NULL);
+ PHP_HTTP_CURL_OPT(CURLOPT_READDATA, NULL);
+ PHP_HTTP_CURL_OPT(CURLOPT_INFILESIZE, 0L);
+ PHP_HTTP_CURL_OPT(CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_NONE);
+ PHP_HTTP_CURL_OPT(CURLOPT_CUSTOMREQUEST, NULL);
+ PHP_HTTP_CURL_OPT(CURLOPT_NOBODY, 0L);
+ PHP_HTTP_CURL_OPT(CURLOPT_POST, 0L);
+ PHP_HTTP_CURL_OPT(CURLOPT_UPLOAD, 0L);
+ PHP_HTTP_CURL_OPT(CURLOPT_HTTPGET, 1L);
+ }
+}
+
+PHP_HTTP_API void php_http_request_set_progress_callback(php_http_request_t *request, zval *cb)
+{
+ if (request->_progress.callback) {
+ zval_ptr_dtor(&request->_progress.callback);
+ }
+ if ((request->_progress.callback = cb)) {
+ Z_ADDREF_P(cb);
+ }
+}
+
+PHP_HTTP_API STATUS php_http_request_prepare(php_http_request_t *request, HashTable *options)
+{
+ zval *zoption;
+ zend_bool range_req = 0;
+ php_http_request_storage_t *storage;
+
+ TSRMLS_FETCH_FROM_CTX(request->ts);
+
+ PHP_HTTP_CHECK_CURL_INIT(request->ch, php_http_curl_init(NULL, request TSRMLS_CC), return FAILURE);
+
+ if (!(storage = php_http_request_storage_get(request->ch))) {
+ return FAILURE;
+ }
+ storage->errorbuffer[0] = '\0';
+ /* set options */
+ if (storage->url) {
+ pefree(storage->url, 1);
+ }
+ storage->url = pestrdup(request->url, 1);
+ PHP_HTTP_CURL_OPT(CURLOPT_URL, storage->url);
+
+ /* progress callback */
+ if ((zoption = php_http_request_option(request, options, ZEND_STRS("onprogress"), -1))) {
+ php_http_request_set_progress_callback(request, zoption);
+ }
+
+ /* proxy */
+ if ((zoption = php_http_request_option(request, options, ZEND_STRS("proxyhost"), IS_STRING))) {
+ PHP_HTTP_CURL_OPT(CURLOPT_PROXY, Z_STRVAL_P(zoption));
+ /* type */
+ if ((zoption = php_http_request_option(request, options, ZEND_STRS("proxytype"), IS_LONG))) {
+ PHP_HTTP_CURL_OPT(CURLOPT_PROXYTYPE, Z_LVAL_P(zoption));
+ }
+ /* port */
+ if ((zoption = php_http_request_option(request, options, ZEND_STRS("proxyport"), IS_LONG))) {
+ PHP_HTTP_CURL_OPT(CURLOPT_PROXYPORT, Z_LVAL_P(zoption));
+ }
+ /* user:pass */
+ if ((zoption = php_http_request_option(request, options, ZEND_STRS("proxyauth"), IS_STRING)) && Z_STRLEN_P(zoption)) {
+ PHP_HTTP_CURL_OPT(CURLOPT_PROXYUSERPWD, Z_STRVAL_P(zoption));
+ }
+ /* auth method */
+ if ((zoption = php_http_request_option(request, options, ZEND_STRS("proxyauthtype"), IS_LONG))) {
+ PHP_HTTP_CURL_OPT(CURLOPT_PROXYAUTH, Z_LVAL_P(zoption));
+ }
+ /* tunnel */
+ if ((zoption = php_http_request_option(request, options, ZEND_STRS("proxytunnel"), IS_BOOL)) && Z_BVAL_P(zoption)) {
+ PHP_HTTP_CURL_OPT(CURLOPT_HTTPPROXYTUNNEL, 1L);
+ }
+ }
+#if PHP_HTTP_CURL_VERSION(7,19,4)
+ if ((zoption = php_http_request_option(request, options, ZEND_STRS("noproxy"), IS_STRING))) {
+ PHP_HTTP_CURL_OPT(CURLOPT_NOPROXY, Z_STRVAL_P(zoption));
+ }
+#endif
+
+ /* dns */
+ if ((zoption = php_http_request_option(request, options, ZEND_STRS("dns_cache_timeout"), IS_LONG))) {
+ PHP_HTTP_CURL_OPT(CURLOPT_DNS_CACHE_TIMEOUT, Z_LVAL_P(zoption));
+ }
+ if ((zoption = php_http_request_option(request, options, ZEND_STRS("ipresolve"), IS_LONG)) && Z_LVAL_P(zoption)) {
+ PHP_HTTP_CURL_OPT(CURLOPT_IPRESOLVE, Z_LVAL_P(zoption));
+ }
+
+ /* limits */
+ if ((zoption = php_http_request_option(request, options, ZEND_STRS("low_speed_limit"), IS_LONG))) {
+ PHP_HTTP_CURL_OPT(CURLOPT_LOW_SPEED_LIMIT, Z_LVAL_P(zoption));
+ }
+ if ((zoption = php_http_request_option(request, options, ZEND_STRS("low_speed_time"), IS_LONG))) {
+ PHP_HTTP_CURL_OPT(CURLOPT_LOW_SPEED_TIME, Z_LVAL_P(zoption));
+ }
+ /* LSF weirdance
+ if ((zoption = php_http_request_option(request, options, ZEND_STRS("max_send_speed"), IS_LONG))) {
+ PHP_HTTP_CURL_OPT(CURLOPT_MAX_SEND_SPEED_LARGE, (curl_off_t) Z_LVAL_P(zoption));
+ }
+ if ((zoption = php_http_request_option(request, options, ZEND_STRS("max_recv_speed"), IS_LONG))) {
+ PHP_HTTP_CURL_OPT(CURLOPT_MAX_RECV_SPEED_LARGE, (curl_off_t) Z_LVAL_P(zoption));
+ }
+ */
+ /* crashes
+ if ((zoption = php_http_request_option(request, options, ZEND_STRS("maxconnects"), IS_LONG))) {
+ PHP_HTTP_CURL_OPT(CURLOPT_MAXCONNECTS, Z_LVAL_P(zoption));
+ } */
+ if ((zoption = php_http_request_option(request, options, ZEND_STRS("fresh_connect"), IS_BOOL)) && Z_BVAL_P(zoption)) {
+ PHP_HTTP_CURL_OPT(CURLOPT_FRESH_CONNECT, 1L);
+ }
+ if ((zoption = php_http_request_option(request, options, ZEND_STRS("forbid_reuse"), IS_BOOL)) && Z_BVAL_P(zoption)) {
+ PHP_HTTP_CURL_OPT(CURLOPT_FORBID_REUSE, 1L);
+ }
+
+ /* outgoing interface */
+ if ((zoption = php_http_request_option(request, options, ZEND_STRS("interface"), IS_STRING))) {
+ PHP_HTTP_CURL_OPT(CURLOPT_INTERFACE, Z_STRVAL_P(zoption));
+
+ if ((zoption = php_http_request_option(request, options, ZEND_STRS("portrange"), IS_ARRAY))) {
+ zval **prs, **pre;
+
+ zend_hash_internal_pointer_reset(Z_ARRVAL_P(zoption));
+ if (SUCCESS == zend_hash_get_current_data(Z_ARRVAL_P(zoption), (void *) &prs)) {
+ zend_hash_move_forward(Z_ARRVAL_P(zoption));
+ if (SUCCESS == zend_hash_get_current_data(Z_ARRVAL_P(zoption), (void *) &pre)) {
+ zval *prs_cpy = php_http_zsep(IS_LONG, *prs);
+ zval *pre_cpy = php_http_zsep(IS_LONG, *pre);
+
+ if (Z_LVAL_P(prs_cpy) && Z_LVAL_P(pre_cpy)) {
+ PHP_HTTP_CURL_OPT(CURLOPT_LOCALPORT, MIN(Z_LVAL_P(prs_cpy), Z_LVAL_P(pre_cpy)));
+ PHP_HTTP_CURL_OPT(CURLOPT_LOCALPORTRANGE, labs(Z_LVAL_P(prs_cpy)-Z_LVAL_P(pre_cpy))+1L);
+ }
+ zval_ptr_dtor(&prs_cpy);
+ zval_ptr_dtor(&pre_cpy);
+ }
+ }
+ }
+ }
+
+ /* another port */
+ if ((zoption = php_http_request_option(request, options, ZEND_STRS("port"), IS_LONG))) {
+ PHP_HTTP_CURL_OPT(CURLOPT_PORT, Z_LVAL_P(zoption));
+ }
+
+ /* RFC4007 zone_id */
+#if PHP_HTTP_CURL_VERSION(7,19,0)
+ if ((zoption = php_http_request_option(request, options, ZEND_STRS("address_scope"), IS_LONG))) {
+ PHP_HTTP_CURL_OPT(CURLOPT_ADDRESS_SCOPE, Z_LVAL_P(zoption));
+ }
+#endif
+
+ /* auth */
+ if ((zoption = php_http_request_option(request, options, ZEND_STRS("httpauth"), IS_STRING)) && Z_STRLEN_P(zoption)) {
+ PHP_HTTP_CURL_OPT(CURLOPT_USERPWD, Z_STRVAL_P(zoption));
+ }
+ if ((zoption = php_http_request_option(request, options, ZEND_STRS("httpauthtype"), IS_LONG))) {
+ PHP_HTTP_CURL_OPT(CURLOPT_HTTPAUTH, Z_LVAL_P(zoption));
+ }
+
+ /* redirects, defaults to 0 */
+ if ((zoption = php_http_request_option(request, options, ZEND_STRS("redirect"), IS_LONG))) {
+ PHP_HTTP_CURL_OPT(CURLOPT_FOLLOWLOCATION, Z_LVAL_P(zoption) ? 1L : 0L);
+ PHP_HTTP_CURL_OPT(CURLOPT_MAXREDIRS, Z_LVAL_P(zoption));
+ if ((zoption = php_http_request_option(request, options, ZEND_STRS("unrestrictedauth"), IS_BOOL))) {
+ PHP_HTTP_CURL_OPT(CURLOPT_UNRESTRICTED_AUTH, Z_LVAL_P(zoption));
+ }
+ if ((zoption = php_http_request_option(request, options, ZEND_STRS("postredir"), IS_BOOL))) {
+#if PHP_HTTP_CURL_VERSION(7,19,1)
+ PHP_HTTP_CURL_OPT(CURLOPT_POSTREDIR, Z_BVAL_P(zoption) ? 1L : 0L);
+#else
+ PHP_HTTP_CURL_OPT(CURLOPT_POST301, Z_BVAL_P(zoption) ? 1L : 0L);
+#endif
+ }
+ }
+
+ /* retries, defaults to 0 */
+ if ((zoption = php_http_request_option(request, options, ZEND_STRS("retrycount"), IS_LONG))) {
+ request->_retry.count = Z_LVAL_P(zoption);
+ if ((zoption = php_http_request_option(request, options, ZEND_STRS("retrydelay"), IS_DOUBLE))) {
+ request->_retry.delay = Z_DVAL_P(zoption);
+ } else {
+ request->_retry.delay = 0;
+ }
+ } else {
+ request->_retry.count = 0;
+ }
+
+ /* referer */
+ if ((zoption = php_http_request_option(request, options, ZEND_STRS("referer"), IS_STRING)) && Z_STRLEN_P(zoption)) {
+ PHP_HTTP_CURL_OPT(CURLOPT_REFERER, Z_STRVAL_P(zoption));
+ }
+
+ /* useragent, default "PECL::HTTP/version (PHP/version)" */
+ if ((zoption = php_http_request_option(request, options, ZEND_STRS("useragent"), IS_STRING))) {
+ /* allow to send no user agent, not even default one */
+ if (Z_STRLEN_P(zoption)) {
+ PHP_HTTP_CURL_OPT(CURLOPT_USERAGENT, Z_STRVAL_P(zoption));
+ } else {
+ PHP_HTTP_CURL_OPT(CURLOPT_USERAGENT, NULL);
+ }
+ }
+
+ /* resume */
+ if ((zoption = php_http_request_option(request, options, ZEND_STRS("resume"), IS_LONG)) && (Z_LVAL_P(zoption) > 0)) {
+ range_req = 1;
+ PHP_HTTP_CURL_OPT(CURLOPT_RESUME_FROM, Z_LVAL_P(zoption));
+ }
+ /* or range of kind array(array(0,499), array(100,1499)) */
+ else if ((zoption = php_http_request_option(request, options, ZEND_STRS("range"), IS_ARRAY)) && zend_hash_num_elements(Z_ARRVAL_P(zoption))) {
+ HashPosition pos1, pos2;
+ zval **rr, **rb, **re;
+ php_http_buffer rs;
+
+ php_http_buffer_init(&rs);
+ FOREACH_VAL(pos1, zoption, rr) {
+ if (Z_TYPE_PP(rr) == IS_ARRAY) {
+ zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(rr), &pos2);
+ if (SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_PP(rr), (void *) &rb, &pos2)) {
+ zend_hash_move_forward_ex(Z_ARRVAL_PP(rr), &pos2);
+ if (SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_PP(rr), (void *) &re, &pos2)) {
+ if ( ((Z_TYPE_PP(rb) == IS_LONG) || ((Z_TYPE_PP(rb) == IS_STRING) && is_numeric_string(Z_STRVAL_PP(rb), Z_STRLEN_PP(rb), NULL, NULL, 1))) &&
+ ((Z_TYPE_PP(re) == IS_LONG) || ((Z_TYPE_PP(re) == IS_STRING) && is_numeric_string(Z_STRVAL_PP(re), Z_STRLEN_PP(re), NULL, NULL, 1)))) {
+ zval *rbl = php_http_zsep(IS_LONG, *rb);
+ zval *rel = php_http_zsep(IS_LONG, *re);
+
+ if ((Z_LVAL_P(rbl) >= 0) && (Z_LVAL_P(rel) >= 0)) {
+ php_http_buffer_appendf(&rs, "%ld-%ld,", Z_LVAL_P(rbl), Z_LVAL_P(rel));
+ }
+ zval_ptr_dtor(&rbl);
+ zval_ptr_dtor(&rel);
+ }
+ }
+ }
+ }
+ }
+
+ if (PHP_HTTP_BUFFER_LEN(&rs)) {
+ zval *cached_range;
+
+ /* ditch last comma */
+ PHP_HTTP_BUFFER_VAL(&rs)[PHP_HTTP_BUFFER_LEN(&rs)-- -1] = '\0';
+ /* cache string */
+ MAKE_STD_ZVAL(cached_range);
+ ZVAL_STRINGL(cached_range, PHP_HTTP_BUFFER_VAL(&rs), PHP_HTTP_BUFFER_LEN(&rs), 0);
+ PHP_HTTP_CURL_OPT(CURLOPT_RANGE, Z_STRVAL_P(php_http_request_option_cache(request, ZEND_STRS("range"), 0, cached_range)));
+ zval_ptr_dtor(&cached_range);
+ }
+ }
+
+ /* additional headers, array('name' => 'value') */
+ if (request->_cache.headers) {
+ curl_slist_free_all(request->_cache.headers);
+ request->_cache.headers = NULL;
+ }
+ if ((zoption = php_http_request_option(request, options, ZEND_STRS("headers"), IS_ARRAY))) {
+ php_http_array_hashkey_t header_key = php_http_array_hashkey_init(0);
+ zval **header_val;
+ HashPosition pos;
+ php_http_buffer header;
+
+ php_http_buffer_init(&header);
+ FOREACH_KEYVAL(pos, zoption, header_key, header_val) {
+ if (header_key.type == HASH_KEY_IS_STRING) {
+ zval *header_cpy = php_http_zsep(IS_STRING, *header_val);
+
+ if (!strcasecmp(header_key.str, "range")) {
+ range_req = 1;
+ }
+
+ php_http_buffer_appendf(&header, "%s: %s", header_key.str, Z_STRVAL_P(header_cpy));
+ php_http_buffer_fix(&header);
+ request->_cache.headers = curl_slist_append(request->_cache.headers, PHP_HTTP_BUFFER_VAL(&header));
+ php_http_buffer_reset(&header);
+
+ zval_ptr_dtor(&header_cpy);
+ }
+ }
+ php_http_buffer_dtor(&header);
+ }
+ /* etag */
+ if ((zoption = php_http_request_option(request, options, ZEND_STRS("etag"), IS_STRING)) && Z_STRLEN_P(zoption)) {
+ zend_bool is_quoted = !((Z_STRVAL_P(zoption)[0] != '"') || (Z_STRVAL_P(zoption)[Z_STRLEN_P(zoption)-1] != '"'));
+ php_http_buffer header;
+
+ php_http_buffer_init(&header);
+ php_http_buffer_appendf(&header, is_quoted?"%s: %s":"%s: \"%s\"", range_req?"If-Match":"If-None-Match", Z_STRVAL_P(zoption));
+ php_http_buffer_fix(&header);
+ request->_cache.headers = curl_slist_append(request->_cache.headers, PHP_HTTP_BUFFER_VAL(&header));
+ php_http_buffer_dtor(&header);
+ }
+ /* compression */
+ if ((zoption = php_http_request_option(request, options, ZEND_STRS("compress"), IS_BOOL)) && Z_LVAL_P(zoption)) {
+ request->_cache.headers = curl_slist_append(request->_cache.headers, "Accept-Encoding: gzip;q=1.0,deflate;q=0.5");
+ }
+ PHP_HTTP_CURL_OPT(CURLOPT_HTTPHEADER, request->_cache.headers);
+
+ /* lastmodified */
+ if ((zoption = php_http_request_option(request, options, ZEND_STRS("lastmodified"), IS_LONG))) {
+ if (Z_LVAL_P(zoption)) {
+ if (Z_LVAL_P(zoption) > 0) {
+ PHP_HTTP_CURL_OPT(CURLOPT_TIMEVALUE, Z_LVAL_P(zoption));
+ } else {
+ PHP_HTTP_CURL_OPT(CURLOPT_TIMEVALUE, (long) PHP_HTTP_G->env.request.time + Z_LVAL_P(zoption));
+ }
+ PHP_HTTP_CURL_OPT(CURLOPT_TIMECONDITION, (long) (range_req ? CURL_TIMECOND_IFUNMODSINCE : CURL_TIMECOND_IFMODSINCE));
+ } else {
+ PHP_HTTP_CURL_OPT(CURLOPT_TIMECONDITION, CURL_TIMECOND_NONE);
+ }
+ }
+
+ /* cookies, array('name' => 'value') */
+ if ((zoption = php_http_request_option(request, options, ZEND_STRS("cookies"), IS_ARRAY))) {
+ php_http_buffer_dtor(&request->_cache.cookies);
+ if (zend_hash_num_elements(Z_ARRVAL_P(zoption))) {
+ zval *urlenc_cookies = NULL;
+ /* check whether cookies should not be urlencoded; default is to urlencode them */
+ if ((!(urlenc_cookies = php_http_request_option(request, options, ZEND_STRS("encodecookies"), IS_BOOL))) || Z_BVAL_P(urlenc_cookies)) {
+ if (SUCCESS == php_http_url_encode_hash_recursive(HASH_OF(zoption), &request->_cache.cookies, "; ", lenof("; "), NULL, 0 TSRMLS_CC)) {
+ php_http_buffer_fix(&request->_cache.cookies);
+ PHP_HTTP_CURL_OPT(CURLOPT_COOKIE, request->_cache.cookies.data);
+ }
+ } else {
+ HashPosition pos;
+ php_http_array_hashkey_t cookie_key = php_http_array_hashkey_init(0);
+ zval **cookie_val;
+
+ FOREACH_KEYVAL(pos, zoption, cookie_key, cookie_val) {
+ if (cookie_key.type == HASH_KEY_IS_STRING) {
+ zval *val = php_http_zsep(IS_STRING, *cookie_val);
+ php_http_buffer_appendf(&request->_cache.cookies, "%s=%s; ", cookie_key.str, Z_STRVAL_P(val));
+ zval_ptr_dtor(&val);
+ }
+ }
+
+ php_http_buffer_fix(&request->_cache.cookies);
+ if (PHP_HTTP_BUFFER_LEN(&request->_cache.cookies)) {
+ PHP_HTTP_CURL_OPT(CURLOPT_COOKIE, PHP_HTTP_BUFFER_VAL(&request->_cache.cookies));
+ }
+ }
+ }
+ }
+
+ /* don't load session cookies from cookiestore */
+ if ((zoption = php_http_request_option(request, options, ZEND_STRS("cookiesession"), IS_BOOL)) && Z_BVAL_P(zoption)) {
+ PHP_HTTP_CURL_OPT(CURLOPT_COOKIESESSION, 1L);
+ }
+
+ /* cookiestore, read initial cookies from that file and store cookies back into that file */
+ if ((zoption = php_http_request_option(request, options, ZEND_STRS("cookiestore"), IS_STRING))) {
+ if (Z_STRLEN_P(zoption)) {
+ if (SUCCESS != php_check_open_basedir(Z_STRVAL_P(zoption) TSRMLS_CC)) {
+ return FAILURE;
+ }
+ }
+ if (storage->cookiestore) {
+ pefree(storage->cookiestore, 1);
+ }
+ storage->cookiestore = pestrndup(Z_STRVAL_P(zoption), Z_STRLEN_P(zoption), 1);
+ PHP_HTTP_CURL_OPT(CURLOPT_COOKIEFILE, storage->cookiestore);
+ PHP_HTTP_CURL_OPT(CURLOPT_COOKIEJAR, storage->cookiestore);
+ }
+
+ /* maxfilesize */
+ if ((zoption = php_http_request_option(request, options, ZEND_STRS("maxfilesize"), IS_LONG))) {
+ PHP_HTTP_CURL_OPT(CURLOPT_MAXFILESIZE, Z_LVAL_P(zoption));
+ }
+
+ /* http protocol */
+ if ((zoption = php_http_request_option(request, options, ZEND_STRS("protocol"), IS_LONG))) {
+ PHP_HTTP_CURL_OPT(CURLOPT_HTTP_VERSION, Z_LVAL_P(zoption));
+ }
+
+ /* timeout, defaults to 0 */
+ if ((zoption = php_http_request_option(request, options, ZEND_STRS("timeout"), IS_DOUBLE))) {
+ PHP_HTTP_CURL_OPT(CURLOPT_TIMEOUT_MS, (long)(Z_DVAL_P(zoption)*1000));
+ }
+ /* connecttimeout, defaults to 0 */
+ if ((zoption = php_http_request_option(request, options, ZEND_STRS("connecttimeout"), IS_DOUBLE))) {
+ PHP_HTTP_CURL_OPT(CURLOPT_CONNECTTIMEOUT_MS, (long)(Z_DVAL_P(zoption)*1000));
+ }
+
+ /* ssl */
+ if ((zoption = php_http_request_option(request, options, ZEND_STRS("ssl"), IS_ARRAY))) {
+ php_http_array_hashkey_t key = php_http_array_hashkey_init(0);
+ zval **param;
+ HashPosition pos;
+
+ FOREACH_KEYVAL(pos, zoption, key, param) {
+ if (key.type == HASH_KEY_IS_STRING) {
+ PHP_HTTP_CURL_OPT_STRING(CURLOPT_SSLCERT, 0, 1);
+ PHP_HTTP_CURL_OPT_STRING(CURLOPT_SSLCERTTYPE, 0, 0);
+ PHP_HTTP_CURL_OPT_STRING(CURLOPT_SSLCERTPASSWD, 0, 0);
+
+ PHP_HTTP_CURL_OPT_STRING(CURLOPT_SSLKEY, 0, 0);
+ PHP_HTTP_CURL_OPT_STRING(CURLOPT_SSLKEYTYPE, 0, 0);
+ PHP_HTTP_CURL_OPT_STRING(CURLOPT_SSLKEYPASSWD, 0, 0);
+
+ PHP_HTTP_CURL_OPT_STRING(CURLOPT_SSLENGINE, 0, 0);
+ PHP_HTTP_CURL_OPT_LONG(CURLOPT_SSLVERSION, 0);
+
+ PHP_HTTP_CURL_OPT_LONG(CURLOPT_SSL_VERIFYPEER, 1);
+ PHP_HTTP_CURL_OPT_LONG(CURLOPT_SSL_VERIFYHOST, 1);
+ PHP_HTTP_CURL_OPT_STRING(CURLOPT_SSL_CIPHER_LIST, 1, 0);
+
+ PHP_HTTP_CURL_OPT_STRING(CURLOPT_CAINFO, -3, 1);
+ PHP_HTTP_CURL_OPT_STRING(CURLOPT_CAPATH, -3, 1);
+ PHP_HTTP_CURL_OPT_STRING(CURLOPT_RANDOM_FILE, -3, 1);
+ PHP_HTTP_CURL_OPT_STRING(CURLOPT_EGDSOCKET, -3, 1);
+#if PHP_HTTP_CURL_VERSION(7,19,0)
+ PHP_HTTP_CURL_OPT_STRING(CURLOPT_ISSUERCERT, -3, 1);
+ #if defined(PHP_HTTP_HAVE_OPENSSL)
+ PHP_HTTP_CURL_OPT_STRING(CURLOPT_CRLFILE, -3, 1);
+ #endif
+#endif
+#if PHP_HTTP_CURL_VERSION(7,19,1) && defined(PHP_HTTP_HAVE_OPENSSL)
+ PHP_HTTP_CURL_OPT_LONG(CURLOPT_CERTINFO, -3);
+#endif
+ }
+ }
+ }
+
+ /* request method */
+ switch (request->meth) {
+ case PHP_HTTP_GET:
+ PHP_HTTP_CURL_OPT(CURLOPT_HTTPGET, 1L);
+ break;
+
+ case PHP_HTTP_HEAD:
+ PHP_HTTP_CURL_OPT(CURLOPT_NOBODY, 1L);
+ break;
+
+ case PHP_HTTP_POST:
+ PHP_HTTP_CURL_OPT(CURLOPT_POST, 1L);
+ break;
+
+ case PHP_HTTP_PUT:
+ PHP_HTTP_CURL_OPT(CURLOPT_UPLOAD, 1L);
+ break;
+
+ default: {
+ const char *meth = php_http_request_method_name(request->meth);
+
+ if (meth) {
+ PHP_HTTP_CURL_OPT(CURLOPT_CUSTOMREQUEST, meth);
+ } else {
+ php_http_error(HE_WARNING, PHP_HTTP_E_REQUEST_METHOD, "Unsupported request method: %d (%s)", request->meth, request->url);
+ return FAILURE;
+ }
+ break;
+ }
+ }
+
+ /* attach request body */
+ if (request->body && (request->meth != PHP_HTTP_GET) && (request->meth != PHP_HTTP_HEAD) && (request->meth != PHP_HTTP_OPTIONS)) {
+ if (1 || request->meth == PHP_HTTP_PUT) {
+ /* PUT/UPLOAD _needs_ READDATA */
+ PHP_HTTP_CURL_OPT(CURLOPT_IOCTLDATA, request);
+ PHP_HTTP_CURL_OPT(CURLOPT_READDATA, request);
+ PHP_HTTP_CURL_OPT(CURLOPT_INFILESIZE, php_http_message_body_size(request->body));
+ } else {
+ abort();
+ //PHP_HTTP_CURL_OPT(CURLOPT_POSTFIELDS, request->body->real->data);
+ PHP_HTTP_CURL_OPT(CURLOPT_POSTFIELDSIZE, php_http_message_body_size(request->body));
+ }
+ }
+
+ return SUCCESS;
+}
+
+PHP_HTTP_API void php_http_request_exec(php_http_request_t *request)
+{
+ uint tries = 0;
+ CURLcode result;
+ TSRMLS_FETCH_FROM_CTX(request->ts);
+
+retry:
+ if (CURLE_OK != (result = curl_easy_perform(request->ch))) {
+ php_http_error(HE_WARNING, PHP_HTTP_E_REQUEST, "%s; %s (%s)", curl_easy_strerror(result), php_http_request_storage_get(request->ch)->errorbuffer, request->url);
+ if (EG(exception)) {
+ add_property_long(EG(exception), "curlCode", result);
+ }
+
+ if (request->_retry.count > tries++) {
+ switch (result) {
+ case CURLE_COULDNT_RESOLVE_PROXY:
+ case CURLE_COULDNT_RESOLVE_HOST:
+ case CURLE_COULDNT_CONNECT:
+ case CURLE_WRITE_ERROR:
+ case CURLE_READ_ERROR:
+ case CURLE_OPERATION_TIMEDOUT:
+ case CURLE_SSL_CONNECT_ERROR:
+ case CURLE_GOT_NOTHING:
+ case CURLE_SSL_ENGINE_SETFAILED:
+ case CURLE_SEND_ERROR:
+ case CURLE_RECV_ERROR:
+ case CURLE_SSL_ENGINE_INITFAILED:
+ case CURLE_LOGIN_DENIED:
+ if (request->_retry.delay >= PHP_HTTP_DIFFSEC) {
+ php_http_sleep(request->_retry.delay);
+ }
+ goto retry;
+ default:
+ break;
+ }
+ }
+ }
+}
+
+static size_t php_http_curl_read_callback(void *data, size_t len, size_t n, void *ctx)
+{
+ php_http_request_t *request = (php_http_request_t *) ctx;
+ TSRMLS_FETCH_FROM_CTX(request->ts);
+
+ if (request->body) {
+ return php_stream_read(php_http_message_body_stream(request->body), data, len * n);
+ }
+ return 0;
+}
+
+static int php_http_curl_progress_callback(void *ctx, double dltotal, double dlnow, double ultotal, double ulnow)
+{
+ php_http_request_t *request = (php_http_request_t *) ctx;
+
+ request->_progress.state.dl.total = dltotal;
+ request->_progress.state.dl.now = dlnow;
+ request->_progress.state.ul.total = ultotal;
+ request->_progress.state.ul.now = ulnow;
+
+ if (request->_progress.callback) {
+ zval *param, retval;
+ TSRMLS_FETCH_FROM_CTX(request->ts);
+
+ INIT_PZVAL(&retval);
+ ZVAL_NULL(&retval);
+
+ MAKE_STD_ZVAL(param);
+ array_init(param);
+ add_assoc_double(param, "dltotal", request->_progress.state.dl.total);
+ add_assoc_double(param, "dlnow", request->_progress.state.dl.now);
+ add_assoc_double(param, "ultotal", request->_progress.state.ul.total);
+ add_assoc_double(param, "ulnow", request->_progress.state.ul.now);
+
+ with_error_handling(EH_NORMAL, NULL) {
+ request->_progress.in_cb = 1;
+ call_user_function(EG(function_table), NULL, request->_progress.callback, &retval, 1, ¶m TSRMLS_CC);
+ request->_progress.in_cb = 0;
+ } end_error_handling();
+
+ zval_ptr_dtor(¶m);
+ zval_dtor(&retval);
+ }
+
+ return 0;
+}
+
+static curlioerr php_http_curl_ioctl_callback(CURL *ch, curliocmd cmd, void *ctx)
+{
+ php_http_request_t *request = (php_http_request_t *) ctx;
+ TSRMLS_FETCH_FROM_CTX(request->ts);
+
+ if (cmd != CURLIOCMD_RESTARTREAD) {
+ return CURLIOE_UNKNOWNCMD;
+ }
+
+ if (request->body) {
+ if (SUCCESS == php_stream_rewind(php_http_message_body_stream(request->body))) {
+ return CURLIOE_OK;
+ }
+ }
+
+ return CURLIOE_FAILRESTART;
+}
+
+static int php_http_curl_raw_callback(CURL *ch, curl_infotype type, char *data, size_t length, void *ctx)
+{
+ php_http_request_t *request = (php_http_request_t *) ctx;
+
+ /* process data */
+ switch (type) {
+ case CURLINFO_HEADER_IN:
+ case CURLINFO_DATA_IN:
+ case CURLINFO_HEADER_OUT:
+ case CURLINFO_DATA_OUT:
+ php_http_buffer_append(request->parser.buf, data, length);
+ if (PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE == php_http_message_parser_parse(request->parser.ctx, request->parser.buf, 0, &request->parser.msg)) {
+ return -1;
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* debug */
+#if 0
+ {
+ const char _sym[] = "><><><";
+ if (type) {
+ for (fprintf(stderr, "%c ", _sym[type-1]); length--; data++) {
+ fprintf(stderr, PHP_HTTP_IS_CTYPE(print, *data)?"%c":"\\x%02X", (int) *data);
+ if (*data == '\n' && length) {
+ fprintf(stderr, "\n%c ", _sym[type-1]);
+ }
+ }
+ fprintf(stderr, "\n");
+ } else {
+ fprintf(stderr, "# %s", data);
+ }
+ }
+#endif
+
+ return 0;
+}
+
+static inline zval *php_http_request_option(php_http_request_t *r, HashTable *options, char *key, size_t keylen, int type)
+{
+ TSRMLS_FETCH_FROM_CTX(r->ts);
+
+ if (options) {
+ zval **zoption;
+ ulong h = zend_hash_func(key, keylen);
+
+ if (SUCCESS == zend_hash_quick_find(options, key, keylen, h, (void *) &zoption)) {
+ zval *option, *cached;
+
+ option = php_http_zsep(type, *zoption);
+ cached = php_http_request_option_cache(r, key, keylen, h, option);
+
+ zval_ptr_dtor(&option);
+ return cached;
+ }
+ }
+
+ return NULL;
+}
+
+static inline zval *php_http_request_option_cache(php_http_request_t *r, char *key, size_t keylen, ulong h, zval *opt)
+{
+ TSRMLS_FETCH_FROM_CTX(r->ts);
+ Z_ADDREF_P(opt);
+
+ if (h) {
+ zend_hash_quick_update(&r->_cache.options, key, keylen, h, &opt, sizeof(zval *), NULL);
+ } else {
+ zend_hash_update(&r->_cache.options, key, keylen, &opt, sizeof(zval *), NULL);
+ }
+
+ return opt;
+}
+
+static inline int php_http_request_cookies_enabled(php_http_request_t *request) {
+ php_http_request_storage_t *st;
+
+ if (request->ch && (st = php_http_request_storage_get(request->ch)) && st->cookiestore) {
+ /* cookies are enabled */
+ return 1;
+ }
+ return 0;
+}
+
+/* USERLAND */
+
+#define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpRequest, method, 0, req_args)
+#define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpRequest, method, 0)
+#define PHP_HTTP_REQUEST_ME(method, visibility) PHP_ME(HttpRequest, method, PHP_HTTP_ARGS(HttpRequest, method), visibility)
+#define PHP_HTTP_REQUEST_ALIAS(method, func) PHP_HTTP_STATIC_ME_ALIAS(method, func, PHP_HTTP_ARGS(HttpRequest, method))
+#define PHP_HTTP_REQUEST_MALIAS(me, al, vis) ZEND_FENTRY(me, ZEND_MN(HttpRequest_##al), PHP_HTTP_ARGS(HttpRequest, al), vis)
+
+PHP_HTTP_BEGIN_ARGS(__construct, 0)
+ PHP_HTTP_ARG_VAL(url, 0)
+ PHP_HTTP_ARG_VAL(method, 0)
+ PHP_HTTP_ARG_VAL(options, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(factory, 0)
+ PHP_HTTP_ARG_VAL(url, 0)
+ PHP_HTTP_ARG_VAL(method, 0)
+ PHP_HTTP_ARG_VAL(options, 0)
+ PHP_HTTP_ARG_VAL(class_name, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_EMPTY_ARGS(getOptions);
+PHP_HTTP_BEGIN_ARGS(setOptions, 0)
+ PHP_HTTP_ARG_VAL(options, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_EMPTY_ARGS(getSslOptions);
+PHP_HTTP_BEGIN_ARGS(setSslOptions, 0)
+ PHP_HTTP_ARG_VAL(ssl_options, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(addSslOptions, 0)
+ PHP_HTTP_ARG_VAL(ssl_optins, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_EMPTY_ARGS(getHeaders);
+PHP_HTTP_BEGIN_ARGS(setHeaders, 0)
+ PHP_HTTP_ARG_VAL(headers, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(addHeaders, 1)
+ PHP_HTTP_ARG_VAL(headers, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_EMPTY_ARGS(getCookies);
+PHP_HTTP_BEGIN_ARGS(setCookies, 0)
+ PHP_HTTP_ARG_VAL(cookies, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(addCookies, 1)
+ PHP_HTTP_ARG_VAL(cookies, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_EMPTY_ARGS(enableCookies);
+PHP_HTTP_BEGIN_ARGS(resetCookies, 0)
+ PHP_HTTP_ARG_VAL(session_only, 0)
+PHP_HTTP_END_ARGS;
+PHP_HTTP_EMPTY_ARGS(flushCookies);
+
+PHP_HTTP_EMPTY_ARGS(getUrl);
+PHP_HTTP_BEGIN_ARGS(setUrl, 1)
+ PHP_HTTP_ARG_VAL(url, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_EMPTY_ARGS(getMethod);
+PHP_HTTP_BEGIN_ARGS(setMethod, 1)
+ PHP_HTTP_ARG_VAL(request_method, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_EMPTY_ARGS(getContentType);
+PHP_HTTP_BEGIN_ARGS(setContentType, 1)
+ PHP_HTTP_ARG_VAL(content_type, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_EMPTY_ARGS(getQueryData);
+PHP_HTTP_BEGIN_ARGS(setQueryData, 0)
+ PHP_HTTP_ARG_VAL(query_data, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(addQueryData, 1)
+ PHP_HTTP_ARG_VAL(query_data, 0)
+PHP_HTTP_END_ARGS;
+
+
+PHP_HTTP_EMPTY_ARGS(getBody);
+PHP_HTTP_BEGIN_ARGS(setBody, 0)
+ PHP_HTTP_ARG_OBJ(http\\message\\Body, body, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(addBody, 1)
+ PHP_HTTP_ARG_OBJ(http\\message\\Body, body, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(getResponseCookies, 0)
+ PHP_HTTP_ARG_VAL(flags, 0)
+ PHP_HTTP_ARG_VAL(allowed_extras, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_EMPTY_ARGS(getResponseBody);
+PHP_HTTP_EMPTY_ARGS(getResponseCode);
+PHP_HTTP_EMPTY_ARGS(getResponseStatus);
+PHP_HTTP_BEGIN_ARGS(getResponseInfo, 0)
+ PHP_HTTP_ARG_VAL(name, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(getResponseHeader, 0)
+ PHP_HTTP_ARG_VAL(header_name, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_EMPTY_ARGS(getMessageClass);
+PHP_HTTP_BEGIN_ARGS(setMessageClass, 1)
+ PHP_HTTP_ARG_VAL(message_class_name, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_EMPTY_ARGS(getResponseMessage);
+PHP_HTTP_EMPTY_ARGS(getRawResponseMessage);
+PHP_HTTP_EMPTY_ARGS(getRequestMessage);
+PHP_HTTP_EMPTY_ARGS(getRawRequestMessage);
+PHP_HTTP_EMPTY_ARGS(getHistory);
+PHP_HTTP_EMPTY_ARGS(clearHistory);
+PHP_HTTP_EMPTY_ARGS(send);
+
+PHP_HTTP_BEGIN_ARGS(get, 1)
+ PHP_HTTP_ARG_VAL(url, 0)
+ PHP_HTTP_ARG_VAL(options, 0)
+ PHP_HTTP_ARG_VAL(info, 1)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(head, 1)
+ PHP_HTTP_ARG_VAL(url, 0)
+ PHP_HTTP_ARG_VAL(options, 0)
+ PHP_HTTP_ARG_VAL(info, 1)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(postData, 2)
+ PHP_HTTP_ARG_VAL(url, 0)
+ PHP_HTTP_ARG_VAL(data, 0)
+ PHP_HTTP_ARG_VAL(options, 0)
+ PHP_HTTP_ARG_VAL(info, 1)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(postFields, 2)
+ PHP_HTTP_ARG_VAL(url, 0)
+ PHP_HTTP_ARG_VAL(data, 0)
+ PHP_HTTP_ARG_VAL(options, 0)
+ PHP_HTTP_ARG_VAL(info, 1)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(putData, 2)
+ PHP_HTTP_ARG_VAL(url, 0)
+ PHP_HTTP_ARG_VAL(data, 0)
+ PHP_HTTP_ARG_VAL(options, 0)
+ PHP_HTTP_ARG_VAL(info, 1)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(putFile, 2)
+ PHP_HTTP_ARG_VAL(url, 0)
+ PHP_HTTP_ARG_VAL(file, 0)
+ PHP_HTTP_ARG_VAL(options, 0)
+ PHP_HTTP_ARG_VAL(info, 1)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(putStream, 2)
+ PHP_HTTP_ARG_VAL(url, 0)
+ PHP_HTTP_ARG_VAL(stream, 0)
+ PHP_HTTP_ARG_VAL(options, 0)
+ PHP_HTTP_ARG_VAL(info, 1)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(methodRegister, 1)
+ PHP_HTTP_ARG_VAL(method_name, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(methodUnregister, 1)
+ PHP_HTTP_ARG_VAL(method, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(methodName, 1)
+ PHP_HTTP_ARG_VAL(method_id, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(methodExists, 1)
+ PHP_HTTP_ARG_VAL(method, 0)
+PHP_HTTP_END_ARGS;
+
+#ifdef HAVE_CURL_FORMGET
+PHP_HTTP_BEGIN_ARGS(encodeBody, 2)
+ PHP_HTTP_ARG_VAL(fields, 0)
+ PHP_HTTP_ARG_VAL(files, 0)
+PHP_HTTP_END_ARGS;
+#endif
+
+zend_class_entry *php_http_request_class_entry;
+zend_function_entry php_http_request_method_entry[] = {
+ PHP_HTTP_REQUEST_ME(__construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
+
+ PHP_HTTP_REQUEST_ME(setOptions, ZEND_ACC_PUBLIC)
+ PHP_HTTP_REQUEST_ME(getOptions, ZEND_ACC_PUBLIC)
+ PHP_HTTP_REQUEST_ME(setSslOptions, ZEND_ACC_PUBLIC)
+ PHP_HTTP_REQUEST_ME(getSslOptions, ZEND_ACC_PUBLIC)
+ PHP_HTTP_REQUEST_ME(addSslOptions, ZEND_ACC_PUBLIC)
+
+ PHP_HTTP_REQUEST_ME(addHeaders, ZEND_ACC_PUBLIC)
+ PHP_HTTP_REQUEST_ME(getHeaders, ZEND_ACC_PUBLIC)
+ PHP_HTTP_REQUEST_ME(setHeaders, ZEND_ACC_PUBLIC)
+
+ PHP_HTTP_REQUEST_ME(addCookies, ZEND_ACC_PUBLIC)
+ PHP_HTTP_REQUEST_ME(getCookies, ZEND_ACC_PUBLIC)
+ PHP_HTTP_REQUEST_ME(setCookies, ZEND_ACC_PUBLIC)
+
+ PHP_HTTP_REQUEST_ME(enableCookies, ZEND_ACC_PUBLIC)
+ PHP_HTTP_REQUEST_ME(resetCookies, ZEND_ACC_PUBLIC)
+ PHP_HTTP_REQUEST_ME(flushCookies, ZEND_ACC_PUBLIC)
+
+ PHP_HTTP_REQUEST_ME(setMethod, ZEND_ACC_PUBLIC)
+ PHP_HTTP_REQUEST_ME(getMethod, ZEND_ACC_PUBLIC)
+
+ PHP_HTTP_REQUEST_ME(setUrl, ZEND_ACC_PUBLIC)
+ PHP_HTTP_REQUEST_ME(getUrl, ZEND_ACC_PUBLIC)
+
+ PHP_HTTP_REQUEST_ME(setContentType, ZEND_ACC_PUBLIC)
+ PHP_HTTP_REQUEST_ME(getContentType, ZEND_ACC_PUBLIC)
+
+ PHP_HTTP_REQUEST_ME(setQueryData, ZEND_ACC_PUBLIC)
+ PHP_HTTP_REQUEST_ME(getQueryData, ZEND_ACC_PUBLIC)
+ PHP_HTTP_REQUEST_ME(addQueryData, ZEND_ACC_PUBLIC)
+
+ PHP_HTTP_REQUEST_ME(setBody, ZEND_ACC_PUBLIC)
+ PHP_HTTP_REQUEST_ME(getBody, ZEND_ACC_PUBLIC)
+ PHP_HTTP_REQUEST_ME(addBody, ZEND_ACC_PUBLIC)
+
+ PHP_HTTP_REQUEST_ME(send, ZEND_ACC_PUBLIC)
+
+ PHP_HTTP_REQUEST_ME(getResponseHeader, ZEND_ACC_PUBLIC)
+ PHP_HTTP_REQUEST_ME(getResponseCookies, ZEND_ACC_PUBLIC)
+ PHP_HTTP_REQUEST_ME(getResponseCode, ZEND_ACC_PUBLIC)
+ PHP_HTTP_REQUEST_ME(getResponseStatus, ZEND_ACC_PUBLIC)
+ PHP_HTTP_REQUEST_ME(getResponseBody, ZEND_ACC_PUBLIC)
+ PHP_HTTP_REQUEST_ME(getResponseInfo, ZEND_ACC_PUBLIC)
+ PHP_HTTP_REQUEST_ME(getResponseMessage, ZEND_ACC_PUBLIC)
+ PHP_HTTP_REQUEST_ME(getRequestMessage, ZEND_ACC_PUBLIC)
+ PHP_HTTP_REQUEST_ME(getHistory, ZEND_ACC_PUBLIC)
+ PHP_HTTP_REQUEST_ME(clearHistory, ZEND_ACC_PUBLIC)
+
+ PHP_HTTP_REQUEST_ME(getMessageClass, ZEND_ACC_PUBLIC)
+ PHP_HTTP_REQUEST_ME(setMessageClass, ZEND_ACC_PUBLIC)
+
+ EMPTY_FUNCTION_ENTRY
+};
+static zend_object_handlers php_http_request_object_handlers;
+
+zend_object_value php_http_request_object_new(zend_class_entry *ce TSRMLS_DC)
+{
+ return php_http_request_object_new_ex(ce, NULL, NULL);
+}
+
+zend_object_value php_http_request_object_new_ex(zend_class_entry *ce, CURL *ch, php_http_request_object_t **ptr TSRMLS_DC)
+{
+ zend_object_value ov;
+ php_http_request_object_t *o;
+
+ o = ecalloc(1, sizeof(php_http_request_object_t));
+ zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
+ object_properties_init((zend_object *) o, ce);
+
+ o->request = php_http_request_init(NULL, ch, 0, NULL TSRMLS_CC);
+
+ if (ptr) {
+ *ptr = o;
+ }
+
+ ov.handle = zend_objects_store_put(o, NULL, php_http_request_object_free, NULL TSRMLS_CC);
+ ov.handlers = &php_http_request_object_handlers;
+
+ return ov;
+}
+
+zend_object_value php_http_request_object_clone(zval *this_ptr TSRMLS_DC)
+{
+ zend_object_value new_ov;
+ php_http_request_object_t *new_obj, *old_obj = zend_object_store_get_object(this_ptr TSRMLS_CC);
+
+ new_ov = php_http_request_object_new_ex(old_obj->zo.ce, NULL, &new_obj TSRMLS_CC);
+ if (old_obj->request->ch) {
+ php_http_curl_init(php_http_curl_copy(old_obj->request->ch), new_obj->request TSRMLS_CC);
+ }
+
+ zend_objects_clone_members(&new_obj->zo, new_ov, &old_obj->zo, Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC);
+ /* FIXME */
+
+ return new_ov;
+}
+
+void php_http_request_object_free(void *object TSRMLS_DC)
+{
+ php_http_request_object_t *o = (php_http_request_object_t *) object;
+
+ php_http_request_free(&o->request);
+ zend_object_std_dtor((zend_object *) o TSRMLS_CC);
+ efree(o);
+}
+
+static inline void php_http_request_object_check_request_content_type(zval *this_ptr TSRMLS_DC)
+{
+ zval *ctype = zend_read_property(php_http_request_class_entry, getThis(), ZEND_STRL("contentType"), 0 TSRMLS_CC);
+
+ if (Z_STRLEN_P(ctype)) {
+ zval **headers, *opts = zend_read_property(php_http_request_class_entry, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC);
+
+ if ( (Z_TYPE_P(opts) == IS_ARRAY) &&
+ (SUCCESS == zend_hash_find(Z_ARRVAL_P(opts), ZEND_STRS("headers"), (void *) &headers)) &&
+ (Z_TYPE_PP(headers) == IS_ARRAY)) {
+ zval **ct_header;
+
+ /* only override if not already set */
+ if ((SUCCESS != zend_hash_find(Z_ARRVAL_PP(headers), ZEND_STRS("Content-Type"), (void *) &ct_header))) {
+ add_assoc_stringl(*headers, "Content-Type", Z_STRVAL_P(ctype), Z_STRLEN_P(ctype), 1);
+ } else
+ /* or not a string, zero length string or a string of spaces */
+ if ((Z_TYPE_PP(ct_header) != IS_STRING) || !Z_STRLEN_PP(ct_header)) {
+ add_assoc_stringl(*headers, "Content-Type", Z_STRVAL_P(ctype), Z_STRLEN_P(ctype), 1);
+ } else {
+ int i, only_space = 1;
+
+ /* check for spaces only */
+ for (i = 0; i < Z_STRLEN_PP(ct_header); ++i) {
+ if (!PHP_HTTP_IS_CTYPE(space, Z_STRVAL_PP(ct_header)[i])) {
+ only_space = 0;
+ break;
+ }
+ }
+ if (only_space) {
+ add_assoc_stringl(*headers, "Content-Type", Z_STRVAL_P(ctype), Z_STRLEN_P(ctype), 1);
+ }
+ }
+ } else {
+ zval *headers;
+
+ MAKE_STD_ZVAL(headers);
+ array_init(headers);
+ add_assoc_stringl(headers, "Content-Type", Z_STRVAL_P(ctype), Z_STRLEN_P(ctype), 1);
+ zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "addheaders", NULL, headers);
+ zval_ptr_dtor(&headers);
+ }
+ }
+}
+
+static inline zend_object_value php_http_request_object_message(zval *this_ptr, php_http_message_t *msg TSRMLS_DC)
+{
+ zend_object_value ov;
+ zval *zcn = zend_read_property(php_http_request_class_entry, getThis(), ZEND_STRL("messageClass"), 0 TSRMLS_CC);
+ zend_class_entry *class_entry;
+
+ if (Z_STRLEN_P(zcn)
+ && (class_entry = zend_fetch_class(Z_STRVAL_P(zcn), Z_STRLEN_P(zcn), 0 TSRMLS_CC))
+ && (SUCCESS == php_http_new(&ov, class_entry, (php_http_new_t) php_http_message_object_new_ex, php_http_message_class_entry, msg, NULL TSRMLS_CC))) {
+ return ov;
+ } else {
+ return php_http_message_object_new_ex(php_http_message_class_entry, msg, NULL TSRMLS_CC);
+ }
+}
+
+STATUS php_http_request_object_requesthandler(php_http_request_object_t *obj, zval *this_ptr TSRMLS_DC)
+{
+ STATUS status = SUCCESS;
+ zval *zurl, *zmeth, *zbody, *zqdata, *zoptions;
+ php_http_message_body_t *body = NULL;
+ php_url *tmp, qdu = {0};
+
+ php_http_request_reset(obj->request);
+ PHP_HTTP_CHECK_CURL_INIT(obj->request->ch, php_http_curl_init(NULL, obj->request TSRMLS_CC), return FAILURE);
+ php_http_request_object_check_request_content_type(getThis() TSRMLS_CC);
+
+ zmeth = zend_read_property(php_http_request_class_entry, getThis(), ZEND_STRL("method"), 0 TSRMLS_CC);
+ obj->request->meth = Z_LVAL_P(zmeth);
+
+ zurl = zend_read_property(php_http_request_class_entry, getThis(), ZEND_STRL("url"), 0 TSRMLS_CC);
+ zqdata = zend_read_property(php_http_request_class_entry, getThis(), ZEND_STRL("queryData"), 0 TSRMLS_CC);
+ if (Z_STRLEN_P(zqdata)) {
+ qdu.query = Z_STRVAL_P(zqdata);
+ }
+ php_http_url(0, tmp = php_url_parse(Z_STRVAL_P(zurl)), &qdu, NULL, &obj->request->url, NULL TSRMLS_CC);
+ php_url_free(tmp);
+
+ zbody = zend_read_property(php_http_request_class_entry, getThis(), ZEND_STRL("requestBody"), 0 TSRMLS_CC);
+ if (Z_TYPE_P(zbody) == IS_OBJECT) {
+ body = ((php_http_message_body_object_t *)zend_object_store_get_object(zbody TSRMLS_CC))->body;
+ }
+ obj->request->body = body;
+
+ zoptions = zend_read_property(php_http_request_class_entry, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC);
+ php_http_request_prepare(obj->request, Z_ARRVAL_P(zoptions));
+
+ /* check if there's a onProgress method and add it as progress callback if one isn't already set */
+ if (zend_hash_exists(&Z_OBJCE_P(getThis())->function_table, ZEND_STRS("onprogress"))) {
+ zval **entry, *pcb;
+
+ if ((Z_TYPE_P(zoptions) != IS_ARRAY)
+ || (SUCCESS != zend_hash_find(Z_ARRVAL_P(zoptions), ZEND_STRS("onprogress"), (void *) &entry)
+ || (!zend_is_callable(*entry, 0, NULL TSRMLS_CC)))) {
+ MAKE_STD_ZVAL(pcb);
+ array_init(pcb);
+ Z_ADDREF_P(getThis());
+ add_next_index_zval(pcb, getThis());
+ add_next_index_stringl(pcb, "onprogress", lenof("onprogress"), 1);
+ php_http_request_set_progress_callback(obj->request, pcb);
+ zval_ptr_dtor(&pcb);
+ }
+ }
+
+ return status;
+}
+
+STATUS php_http_request_object_responsehandler(php_http_request_object_t *obj, zval *this_ptr TSRMLS_DC)
+{
+ STATUS ret = SUCCESS;
+ zval *info;
+ php_http_message_t *msg;
+
+ /* always fetch info */
+ MAKE_STD_ZVAL(info);
+ array_init(info);
+ php_http_request_info(obj->request, Z_ARRVAL_P(info));
+ zend_update_property(php_http_request_class_entry, getThis(), ZEND_STRL("responseInfo"), info TSRMLS_CC);
+ zval_ptr_dtor(&info);
+
+ /* update history * /
+ if (i_zend_is_true(zend_read_property(php_http_request_class_entry, getThis(), ZEND_STRL("recordHistory"), 0 TSRMLS_CC))) {
+ zval *new_hist, *old_hist = zend_read_property(php_http_request_class_entry, getThis(), ZEND_STRL("history"), 0 TSRMLS_CC);
+ zend_object_value ov = php_http_request_object_message(getThis(), obj->request->message_parser.message TSRMLS_CC);
+
+ MAKE_STD_ZVAL(new_hist);
+ ZVAL_OBJVAL(new_hist, ov, 0);
+
+ if (Z_TYPE_P(old_hist) == IS_OBJECT) {
+ php_http_message_object_prepend(new_hist, old_hist, 0 TSRMLS_CC);
+ }
+
+ zend_update_property(php_http_request_class_entry, getThis(), ZEND_STRL("history"), new_hist TSRMLS_CC);
+ zval_ptr_dtor(&new_hist);
+ }
+*/
+// if ((msg = obj->request->_current.request)) {
+// /* update request message */
+// zval *message;
+//
+// MAKE_STD_ZVAL(message);
+// ZVAL_OBJVAL(message, php_http_request_object_message(getThis(), msg TSRMLS_CC), 1);
+// zend_update_property(php_http_request_class_entry, getThis(), ZEND_STRL("requestMessage"), message TSRMLS_CC);
+// }
+// fprintf(stderr, "RESPONSE MESSAGE: %p\n", obj->request->parser.msg);
+ if ((msg = obj->request->parser.msg)) {
+ /* update properties with response info */
+ zval *message;
+
+ zend_update_property_long(php_http_request_class_entry, getThis(), ZEND_STRL("responseCode"), msg->http.info.response.code TSRMLS_CC);
+ zend_update_property_string(php_http_request_class_entry, getThis(), ZEND_STRL("responseStatus"), STR_PTR(msg->http.info.response.status) TSRMLS_CC);
+
+ MAKE_STD_ZVAL(message);
+ ZVAL_OBJVAL(message, php_http_request_object_message(getThis(), msg TSRMLS_CC), 0);
+ zend_update_property(php_http_request_class_entry, getThis(), ZEND_STRL("responseMessage"), message TSRMLS_CC);
+ zval_ptr_dtor(&message);
+ obj->request->parser.msg = php_http_message_init(NULL, 0 TSRMLS_CC);
+ } else {
+ /* update properties with empty values */
+ zval *znull;
+
+ MAKE_STD_ZVAL(znull);
+ ZVAL_NULL(znull);
+ zend_update_property(php_http_request_class_entry, getThis(), ZEND_STRL("responseMessage"), znull TSRMLS_CC);
+ zval_ptr_dtor(&znull);
+
+ zend_update_property_long(php_http_request_class_entry, getThis(), ZEND_STRL("responseCode"), 0 TSRMLS_CC);
+ zend_update_property_string(php_http_request_class_entry, getThis(), ZEND_STRL("responseStatus"), "" TSRMLS_CC);
+ }
+
+ php_http_request_set_progress_callback(obj->request, NULL);
+
+ if (!EG(exception) && zend_hash_exists(&Z_OBJCE_P(getThis())->function_table, ZEND_STRS("onfinish"))) {
+ zval *param;
+
+ MAKE_STD_ZVAL(param);
+ ZVAL_BOOL(param, ret == SUCCESS);
+ with_error_handling(EH_NORMAL, NULL) {
+ zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "onfinish", NULL, param);
+ } end_error_handling();
+ zval_ptr_dtor(¶m);
+ }
+
+ return ret;
+}
+
+static int apply_pretty_key(void *pDest, int num_args, va_list args, zend_hash_key *hash_key)
+{
+ if (hash_key->arKey && hash_key->nKeyLength > 1) {
+ hash_key->h = zend_hash_func(php_http_pretty_key(hash_key->arKey, hash_key->nKeyLength - 1, 1, 0), hash_key->nKeyLength);
+ }
+ return ZEND_HASH_APPLY_KEEP;
+}
+
+static inline void php_http_request_object_set_options_subr(INTERNAL_FUNCTION_PARAMETERS, char *key, size_t len, int overwrite, int prettify_keys)
+{
+ zval *old_opts, *new_opts, *opts = NULL, **entry = NULL;
+
+ if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a/!", &opts)) {
+ RETURN_FALSE;
+ }
+
+ MAKE_STD_ZVAL(new_opts);
+ array_init(new_opts);
+ old_opts = zend_read_property(php_http_request_class_entry, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC);
+ if (Z_TYPE_P(old_opts) == IS_ARRAY) {
+ array_copy(Z_ARRVAL_P(old_opts), Z_ARRVAL_P(new_opts));
+ }
+
+ if (SUCCESS == zend_hash_find(Z_ARRVAL_P(new_opts), key, len, (void *) &entry)) {
+ if (overwrite) {
+ zend_hash_clean(Z_ARRVAL_PP(entry));
+ }
+ if (opts && zend_hash_num_elements(Z_ARRVAL_P(opts))) {
+ if (overwrite) {
+ array_copy(Z_ARRVAL_P(opts), Z_ARRVAL_PP(entry));
+ } else {
+ array_join(Z_ARRVAL_P(opts), Z_ARRVAL_PP(entry), 0, prettify_keys ? ARRAY_JOIN_PRETTIFY : 0);
+ }
+ }
+ } else if (opts) {
+ if (prettify_keys) {
+ zend_hash_apply_with_arguments(Z_ARRVAL_P(opts) TSRMLS_CC, apply_pretty_key, 0, NULL);
+ }
+ Z_ADDREF_P(opts);
+ add_assoc_zval_ex(new_opts, key, len, opts);
+ }
+ zend_update_property(php_http_request_class_entry, getThis(), ZEND_STRL("options"), new_opts TSRMLS_CC);
+ zval_ptr_dtor(&new_opts);
+
+ RETURN_TRUE;
+}
+
+static inline void php_http_request_object_get_options_subr(INTERNAL_FUNCTION_PARAMETERS, char *key, size_t len)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ zval *opts, **options;
+
+ opts = zend_read_property(php_http_request_class_entry, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC);
+ array_init(return_value);
+
+ if ( (Z_TYPE_P(opts) == IS_ARRAY) &&
+ (SUCCESS == zend_hash_find(Z_ARRVAL_P(opts), key, len, (void *) &options))) {
+ convert_to_array(*options);
+ array_copy(Z_ARRVAL_PP(options), Z_ARRVAL_P(return_value));
+ }
+ }
+}
+
+
+PHP_METHOD(HttpRequest, __construct)
+{
+ char *url_str = NULL;
+ int url_len;
+ long meth = -1;
+ zval *options = NULL;
+
+ with_error_handling(EH_THROW, PHP_HTTP_EX_CE(runtime)) {
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sla!", &url_str, &url_len, &meth, &options)) {
+ if (url_str) {
+ zend_update_property_stringl(php_http_request_class_entry, getThis(), ZEND_STRL("url"), url_str, url_len TSRMLS_CC);
+ }
+ if (meth > -1) {
+ zend_update_property_long(php_http_request_class_entry, getThis(), ZEND_STRL("method"), meth TSRMLS_CC);
+ }
+ if (options) {
+ zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "setoptions", NULL, options);
+ }
+ }
+ } end_error_handling();
+}
+
+PHP_METHOD(HttpRequest, setOptions)
+{
+ php_http_array_hashkey_t key = php_http_array_hashkey_init(0);
+ HashPosition pos;
+ zval *opts = NULL, *old_opts, *new_opts, *add_opts, **opt;
+
+ if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!/", &opts)) {
+ RETURN_FALSE;
+ }
+
+ MAKE_STD_ZVAL(new_opts);
+ array_init(new_opts);
+
+ if (!opts || !zend_hash_num_elements(Z_ARRVAL_P(opts))) {
+ zend_update_property(php_http_request_class_entry, getThis(), ZEND_STRL("options"), new_opts TSRMLS_CC);
+ zval_ptr_dtor(&new_opts);
+ RETURN_TRUE;
+ }
+
+ MAKE_STD_ZVAL(add_opts);
+ array_init(add_opts);
+ /* some options need extra attention -- thus cannot use array_merge() directly */
+ FOREACH_KEYVAL(pos, opts, key, opt) {
+ if (key.type == HASH_KEY_IS_STRING) {
+#define KEYMATCH(k, s) ((sizeof(s)==k.len) && !strcasecmp(k.str, s))
+ if (KEYMATCH(key, "headers")) {
+ zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "addheaders", NULL, *opt);
+ } else if (KEYMATCH(key, "cookies")) {
+ zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "addcookies", NULL, *opt);
+ } else if (KEYMATCH(key, "ssl")) {
+ zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "addssloptions", NULL, *opt);
+ } else if (KEYMATCH(key, "url") || KEYMATCH(key, "uri")) {
+ zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "seturl", NULL, *opt);
+ } else if (KEYMATCH(key, "method")) {
+ zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "setmethod", NULL, *opt);
+ } else if (KEYMATCH(key, "flushcookies")) {
+ if (i_zend_is_true(*opt)) {
+ php_http_request_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ php_http_request_flush_cookies(obj->request);
+ }
+ } else if (KEYMATCH(key, "resetcookies")) {
+ php_http_request_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ php_http_request_reset_cookies(obj->request, (zend_bool) i_zend_is_true(*opt));
+ } else if (KEYMATCH(key, "enablecookies")) {
+ php_http_request_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ php_http_request_enable_cookies(obj->request);
+ } else if (KEYMATCH(key, "recordHistory")) {
+ zend_update_property(php_http_request_class_entry, getThis(), ZEND_STRL("recordHistory"), *opt TSRMLS_CC);
+ } else if (KEYMATCH(key, "messageClass")) {
+ zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "setmessageclass", NULL, *opt);
+ } else if (Z_TYPE_PP(opt) == IS_NULL) {
+ old_opts = zend_read_property(php_http_request_class_entry, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC);
+ if (Z_TYPE_P(old_opts) == IS_ARRAY) {
+ zend_hash_del(Z_ARRVAL_P(old_opts), key.str, key.len);
+ }
+ } else {
+ Z_ADDREF_P(*opt);
+ add_assoc_zval_ex(add_opts, key.str, key.len, *opt);
+ }
+ }
+ }
+
+ old_opts = zend_read_property(php_http_request_class_entry, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC);
+ if (Z_TYPE_P(old_opts) == IS_ARRAY) {
+ array_copy(Z_ARRVAL_P(old_opts), Z_ARRVAL_P(new_opts));
+ }
+ array_join(Z_ARRVAL_P(add_opts), Z_ARRVAL_P(new_opts), 0, 0);
+ zend_update_property(php_http_request_class_entry, getThis(), ZEND_STRL("options"), new_opts TSRMLS_CC);
+ zval_ptr_dtor(&new_opts);
+ zval_ptr_dtor(&add_opts);
+
+ RETURN_TRUE;
+}
+
+
+
+PHP_METHOD(HttpRequest, getOptions)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ RETURN_PROP(php_http_request_class_entry, "options");
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpRequest, setSslOptions)
+{
+ php_http_request_object_set_options_subr(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRS("ssl"), 1, 0);
+}
+
+PHP_METHOD(HttpRequest, addSslOptions)
+{
+ php_http_request_object_set_options_subr(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRS("ssl"), 0, 0);
+}
+
+PHP_METHOD(HttpRequest, getSslOptions)
+{
+ php_http_request_object_get_options_subr(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRS("ssl"));
+}
+
+PHP_METHOD(HttpRequest, addHeaders)
+{
+ php_http_request_object_set_options_subr(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRS("headers"), 0, 1);
+}
+
+PHP_METHOD(HttpRequest, setHeaders)
+{
+ php_http_request_object_set_options_subr(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRS("headers"), 1, 1);
+}
+
+PHP_METHOD(HttpRequest, getHeaders)
+{
+ php_http_request_object_get_options_subr(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRS("headers"));
+}
+
+PHP_METHOD(HttpRequest, setCookies)
+{
+ php_http_request_object_set_options_subr(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRS("cookies"), 1, 0);
+}
+
+PHP_METHOD(HttpRequest, addCookies)
+{
+ php_http_request_object_set_options_subr(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRS("cookies"), 0, 0);
+}
+
+PHP_METHOD(HttpRequest, getCookies)
+{
+ php_http_request_object_get_options_subr(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRS("cookies"));
+}
+
+PHP_METHOD(HttpRequest, enableCookies)
+{
+ if (SUCCESS == zend_parse_parameters_none()){
+ php_http_request_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ RETURN_SUCCESS(php_http_request_enable_cookies(obj->request));
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpRequest, resetCookies)
+{
+ zend_bool session_only = 0;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &session_only)) {
+ php_http_request_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+ RETURN_SUCCESS(php_http_request_reset_cookies(obj->request, session_only));
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpRequest, flushCookies)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ php_http_request_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ RETURN_SUCCESS(php_http_request_flush_cookies(obj->request));
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpRequest, setUrl)
+{
+ char *url_str = NULL;
+ int url_len;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &url_len, &url_len)) {
+ zend_update_property_stringl(php_http_request_class_entry, getThis(), ZEND_STRL("url"), url_str, url_len TSRMLS_CC);
+ RETURN_TRUE;
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpRequest, getUrl)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ RETURN_PROP(php_http_request_class_entry, "url");
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpRequest, setMethod)
+{
+ long meth;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &meth)) {
+ zend_update_property_long(php_http_request_class_entry, getThis(), ZEND_STRL("method"), meth TSRMLS_CC);
+ RETURN_TRUE;
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpRequest, getMethod)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ RETURN_PROP(php_http_request_class_entry, "method");
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpRequest, setContentType)
+{
+ char *ctype;
+ int ct_len;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &ctype, &ct_len)) {
+ if (ct_len) {
+ PHP_HTTP_CHECK_CONTENT_TYPE(ctype, RETURN_FALSE);
+ }
+ zend_update_property_stringl(php_http_request_class_entry, getThis(), ZEND_STRL("contentType"), ctype, ct_len TSRMLS_CC);
+ RETURN_TRUE;
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpRequest, getContentType)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ RETURN_PROP(php_http_request_class_entry, "contentType");
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpRequest, setQueryData)
+{
+ zval *qdata = NULL;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z!", &qdata)) {
+ if ((!qdata) || Z_TYPE_P(qdata) == IS_NULL) {
+ zend_update_property_stringl(php_http_request_class_entry, getThis(), ZEND_STRL("queryData"), "", 0 TSRMLS_CC);
+ } else if ((Z_TYPE_P(qdata) == IS_ARRAY) || (Z_TYPE_P(qdata) == IS_OBJECT)) {
+ char *query_data_str = NULL;
+ size_t query_data_len;
+
+ if (SUCCESS != php_http_url_encode_hash(HASH_OF(qdata), 0, NULL, 0, &query_data_str, &query_data_len TSRMLS_CC)) {
+ RETURN_FALSE;
+ }
+
+ zend_update_property_stringl(php_http_request_class_entry, getThis(), ZEND_STRL("queryData"), query_data_str, query_data_len TSRMLS_CC);
+ efree(query_data_str);
+ } else {
+ zval *data = php_http_zsep(IS_STRING, qdata);
+
+ zend_update_property_stringl(php_http_request_class_entry, getThis(), ZEND_STRL("queryData"), Z_STRVAL_P(data), Z_STRLEN_P(data) TSRMLS_CC);
+ zval_ptr_dtor(&data);
+ }
+ RETURN_TRUE;
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpRequest, getQueryData)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ RETURN_PROP(php_http_request_class_entry, "queryData");
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpRequest, addQueryData)
+{
+ zval *qdata;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/", &qdata)) {
+ char *query_data_str = NULL;
+ size_t query_data_len = 0;
+ zval *old_qdata = zend_read_property(php_http_request_class_entry, getThis(), ZEND_STRL("queryData"), 0 TSRMLS_CC);
+
+ if (SUCCESS != php_http_url_encode_hash(HASH_OF(qdata), 1, Z_STRVAL_P(old_qdata), Z_STRLEN_P(old_qdata), &query_data_str, &query_data_len TSRMLS_CC)) {
+ RETURN_FALSE;
+ }
+
+ zend_update_property_stringl(php_http_request_class_entry, getThis(), ZEND_STRL("queryData"), query_data_str, query_data_len TSRMLS_CC);
+ efree(query_data_str);
+
+ RETURN_TRUE;
+ }
+ RETURN_FALSE;
+
+}
+
+PHP_METHOD(HttpRequest, setBody)
+{
+ zval *body = NULL;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|O!", &body, php_http_message_body_class_entry)) {
+ if (body && Z_TYPE_P(body) != IS_NULL) {
+ zend_update_property(php_http_request_class_entry, getThis(), ZEND_STRL("requestBody"), body TSRMLS_CC);
+ } else {
+ zend_update_property_null(php_http_request_class_entry, getThis(), ZEND_STRL("requestBody") TSRMLS_CC);
+ }
+ RETURN_TRUE;
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpRequest, addBody)
+{
+ zval *new_body;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &new_body, php_http_message_body_class_entry)) {
+ zval *old_body = zend_read_property(php_http_request_class_entry, getThis(), ZEND_STRL("requestBody"), 0 TSRMLS_CC);
+
+ if (Z_TYPE_P(old_body) == IS_OBJECT) {
+ php_http_message_body_object_t *old_obj = zend_object_store_get_object(old_body TSRMLS_CC);
+ php_http_message_body_object_t *new_obj = zend_object_store_get_object(new_body TSRMLS_CC);
+
+ php_http_message_body_to_callback(old_obj->body, (php_http_pass_callback_t) php_http_message_body_append, new_obj->body, 0, 0);
+ } else {
+ zend_update_property(php_http_request_class_entry, getThis(), ZEND_STRL("requestBody"), new_body TSRMLS_CC);
+ }
+ RETURN_TRUE;
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpRequest, getBody)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ RETURN_PROP(php_http_request_class_entry, "requestBody");
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpRequest, getResponseHeader)
+{
+ zval *header;
+ char *header_name = NULL;
+ int header_len = 0;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &header_name, &header_len)) {
+ zval *message = zend_read_property(php_http_request_class_entry, getThis(), ZEND_STRL("responseMessage"), 0 TSRMLS_CC);
+
+ if (Z_TYPE_P(message) == IS_OBJECT) {
+ php_http_message_object_t *msg = zend_object_store_get_object(message TSRMLS_CC);
+
+ if (header_len) {
+ if ((header = php_http_message_header(msg->message, header_name, header_len + 1, 0))) {
+ RETURN_ZVAL(header, 1, 1);
+ }
+ } else {
+ array_init(return_value);
+ zend_hash_copy(Z_ARRVAL_P(return_value), &msg->message->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
+ return;
+ }
+ }
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpRequest, getResponseCookies)
+{
+ long flags = 0;
+ zval *allowed_extras_array = NULL;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|la!", &flags, &allowed_extras_array)) {
+ int i = 0;
+ php_http_array_hashkey_t key = php_http_array_hashkey_init(0);
+ char **allowed_extras = NULL;
+ zval **header = NULL, **entry = NULL, *message = zend_read_property(php_http_request_class_entry, getThis(), ZEND_STRL("responseMessage"), 0 TSRMLS_CC);
+ HashPosition pos, pos1, pos2;
+
+ if (Z_TYPE_P(message) == IS_OBJECT) {
+ php_http_message_object_t *msg = zend_object_store_get_object(message TSRMLS_CC);
+
+ array_init(return_value);
+
+ if (allowed_extras_array) {
+ allowed_extras = ecalloc(zend_hash_num_elements(Z_ARRVAL_P(allowed_extras_array)) + 1, sizeof(char *));
+ FOREACH_VAL(pos, allowed_extras_array, entry) {
+ zval *data = php_http_zsep(IS_STRING, *entry);
+ allowed_extras[i++] = estrndup(Z_STRVAL_P(data), Z_STRLEN_P(data));
+ zval_ptr_dtor(&data);
+ }
+ }
+
+ FOREACH_HASH_KEYVAL(pos1, &msg->message->hdrs, key, header) {
+ if (key.type == HASH_KEY_IS_STRING && !strcasecmp(key.str, "Set-Cookie")) {
+ php_http_cookie_list_t *list;
+
+ if (Z_TYPE_PP(header) == IS_ARRAY) {
+ zval **single_header;
+
+ FOREACH_VAL(pos2, *header, single_header) {
+ zval *data = php_http_zsep(IS_STRING, *single_header);
+
+ if ((list = php_http_cookie_list_parse(NULL, Z_STRVAL_P(data), flags, allowed_extras TSRMLS_CC))) {
+ zval *cookie;
+
+ MAKE_STD_ZVAL(cookie);
+ ZVAL_OBJVAL(cookie, php_http_cookie_object_new_ex(php_http_cookie_class_entry, list, NULL TSRMLS_CC), 0);
+ add_next_index_zval(return_value, cookie);
+ }
+ zval_ptr_dtor(&data);
+ }
+ } else {
+ zval *data = php_http_zsep(IS_STRING, *header);
+ if ((list = php_http_cookie_list_parse(NULL, Z_STRVAL_P(data), flags, allowed_extras TSRMLS_CC))) {
+ zval *cookie;
+
+ MAKE_STD_ZVAL(cookie);
+ ZVAL_OBJVAL(cookie, php_http_cookie_object_new_ex(php_http_cookie_class_entry, list, NULL TSRMLS_CC), 0);
+ add_next_index_zval(return_value, cookie);
+ }
+ zval_ptr_dtor(&data);
+ }
+ }
+ }
+
+ if (allowed_extras) {
+ for (i = 0; allowed_extras[i]; ++i) {
+ efree(allowed_extras[i]);
+ }
+ efree(allowed_extras);
+ }
+
+ return;
+ }
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpRequest, getResponseBody)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ zval *message = zend_read_property(php_http_request_class_entry, getThis(), ZEND_STRL("responseMessage"), 0 TSRMLS_CC);
+ zval *body = zend_read_property(php_http_message_class_entry, message, ZEND_STRL("body"), 0 TSRMLS_CC);
+
+ RETURN_ZVAL(body, 1, 0);
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpRequest, getResponseCode)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ RETURN_PROP(php_http_request_class_entry, "responseCode");
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpRequest, getResponseStatus)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ RETURN_PROP(php_http_request_class_entry, "responseStatus");
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpRequest, getResponseInfo)
+{
+ char *info_name = NULL;
+ int info_len = 0;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &info_name, &info_len)) {
+ zval **infop, *info = zend_read_property(php_http_request_class_entry, getThis(), ZEND_STRL("responseInfo"), 0 TSRMLS_CC);
+
+ if (Z_TYPE_P(info) != IS_ARRAY) {
+ RETURN_FALSE;
+ }
+
+ if (info_len && info_name) {
+ if (SUCCESS == zend_hash_find(Z_ARRVAL_P(info), php_http_pretty_key(info_name, info_len, 0, 0), info_len + 1, (void *) &infop)) {
+ RETURN_ZVAL(*infop, 1, 0);
+ } else {
+ php_http_error(HE_NOTICE, PHP_HTTP_E_INVALID_PARAM, "Could not find response info named %s", info_name);
+ RETURN_FALSE;
+ }
+ } else {
+ RETURN_ZVAL(info, 1, 0);
+ }
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpRequest, getResponseMessage)
+{
+ with_error_handling(EH_THROW, PHP_HTTP_EX_CE(runtime)) {
+ if (SUCCESS == zend_parse_parameters_none()) {
+ zval *message = zend_read_property(php_http_request_class_entry, getThis(), ZEND_STRL("responseMessage"), 0 TSRMLS_CC);
+
+ if (Z_TYPE_P(message) == IS_OBJECT) {
+ RETVAL_OBJECT(message, 1);
+ } else {
+ php_http_error(HE_WARNING, PHP_HTTP_E_RUNTIME, "HttpRequest does not contain a response message");
+ }
+ }
+ } end_error_handling();
+}
+
+PHP_METHOD(HttpRequest, getRequestMessage)
+{
+ with_error_handling(EH_THROW, PHP_HTTP_EX_CE(runtime)) {
+ if (SUCCESS == zend_parse_parameters_none()) {
+ zval *message = zend_read_property(php_http_request_class_entry, getThis(), ZEND_STRL("requestMessage"), 0 TSRMLS_CC);
+
+ if (Z_TYPE_P(message) == IS_OBJECT) {
+ RETVAL_OBJECT(message, 1);
+ } else {
+ php_http_error(HE_WARNING, PHP_HTTP_E_RUNTIME, "HttpRequest does not contain a request message");
+ }
+ }
+ } end_error_handling();
+}
+
+PHP_METHOD(HttpRequest, getHistory)
+{
+ with_error_handling(EH_THROW, PHP_HTTP_EX_CE(runtime)) {
+ if (SUCCESS == zend_parse_parameters_none()) {
+ zval *hist = zend_read_property(php_http_request_class_entry, getThis(), ZEND_STRL("history"), 0 TSRMLS_CC);
+
+ if (Z_TYPE_P(hist) == IS_OBJECT) {
+ RETVAL_OBJECT(hist, 1);
+ } else {
+ php_http_error(HE_WARNING, PHP_HTTP_E_RUNTIME, "The history is empty");
+ }
+ }
+ } end_error_handling();
+}
+
+PHP_METHOD(HttpRequest, clearHistory)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ zend_update_property_null(php_http_request_class_entry, getThis(), ZEND_STRL("history") TSRMLS_CC);
+ RETURN_TRUE;
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpRequest, getMessageClass)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ RETURN_PROP(php_http_request_class_entry, "messageClass");
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpRequest, setMessageClass)
+{
+ char *cn;
+ int cl;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &cn, &cl)) {
+ zend_update_property_stringl(php_http_request_class_entry, getThis(), ZEND_STRL("messageClass"), cn, cl TSRMLS_CC);
+ }
+}
+
+PHP_METHOD(HttpRequest, send)
+{
+ RETVAL_FALSE;
+
+ with_error_handling(EH_THROW, PHP_HTTP_EX_CE(runtime)) {
+ if (SUCCESS == zend_parse_parameters_none()) {
+ php_http_request_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (obj->pool) {
+ php_http_error(HE_WARNING, PHP_HTTP_E_RUNTIME, "Cannot perform HttpRequest::send() while attached to an HttpRequestPool");
+ } else if (SUCCESS == php_http_request_object_requesthandler(obj, getThis() TSRMLS_CC)) {
+ php_http_request_exec(obj->request);
+ if (SUCCESS == php_http_request_object_responsehandler(obj, getThis() TSRMLS_CC)) {
+ RETVAL_PROP(php_http_request_class_entry, "responseMessage");
+ } else {
+ php_http_error(HE_WARNING, PHP_HTTP_E_REQUEST, "Failed to handle response");
+ }
+ } else {
+ php_http_error(HE_WARNING, PHP_HTTP_E_REQUEST, "Failed to handle request");
+ }
+ }
+ } end_error_handling();
+}
+
+PHP_MINIT_FUNCTION(http_request)
+{
+#ifdef PHP_HTTP_NEED_OPENSSL_TSL
+ /* mod_ssl, libpq or ext/curl might already have set thread lock callbacks */
+ if (!CRYPTO_get_id_callback()) {
+ int i, c = CRYPTO_num_locks();
+
+ php_http_openssl_tsl = malloc(c * sizeof(MUTEX_T));
+
+ for (i = 0; i < c; ++i) {
+ php_http_openssl_tsl[i] = tsrm_mutex_alloc();
+ }
+
+ CRYPTO_set_id_callback(php_http_openssl_thread_id);
+ CRYPTO_set_locking_callback(php_http_openssl_thread_lock);
+ }
+#endif
+#ifdef PHP_HTTP_NEED_GNUTLS_TSL
+ gcry_control(GCRYCTL_SET_THREAD_CBS, &php_http_gnutls_tsl);
+#endif
+
+ if (CURLE_OK != curl_global_init(CURL_GLOBAL_ALL)) {
+ return FAILURE;
+ }
+
+ if (SUCCESS != php_http_persistent_handle_provide(ZEND_STRL("http_request"), safe_curl_init, safe_curl_dtor, safe_curl_copy)) {
+ return FAILURE;
+ }
+
+ PHP_HTTP_REGISTER_CLASS(http, Request, http_request, php_http_object_class_entry, 0);
+ php_http_request_class_entry->create_object = php_http_request_object_new;
+ memcpy(&php_http_request_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
+ php_http_request_object_handlers.clone_obj = php_http_request_object_clone;
+
+ zend_declare_property_null(php_http_request_class_entry, ZEND_STRL("options"), ZEND_ACC_PRIVATE TSRMLS_CC);
+ zend_declare_property_null(php_http_request_class_entry, ZEND_STRL("responseInfo"), ZEND_ACC_PRIVATE TSRMLS_CC);
+ zend_declare_property_null(php_http_request_class_entry, ZEND_STRL("responseMessage"), ZEND_ACC_PRIVATE TSRMLS_CC);
+ zend_declare_property_long(php_http_request_class_entry, ZEND_STRL("responseCode"), 0, ZEND_ACC_PRIVATE TSRMLS_CC);
+ zend_declare_property_string(php_http_request_class_entry, ZEND_STRL("responseStatus"), "", ZEND_ACC_PRIVATE TSRMLS_CC);
+ zend_declare_property_null(php_http_request_class_entry, ZEND_STRL("requestMessage"), ZEND_ACC_PRIVATE TSRMLS_CC);
+ zend_declare_property_long(php_http_request_class_entry, ZEND_STRL("method"), PHP_HTTP_GET, ZEND_ACC_PRIVATE TSRMLS_CC);
+ zend_declare_property_string(php_http_request_class_entry, ZEND_STRL("url"), "", ZEND_ACC_PRIVATE TSRMLS_CC);
+ zend_declare_property_string(php_http_request_class_entry, ZEND_STRL("contentType"), "", ZEND_ACC_PRIVATE TSRMLS_CC);
+ zend_declare_property_string(php_http_request_class_entry, ZEND_STRL("requestBody"), "", ZEND_ACC_PRIVATE TSRMLS_CC);
+ zend_declare_property_string(php_http_request_class_entry, ZEND_STRL("queryData"), "", ZEND_ACC_PRIVATE TSRMLS_CC);
+ zend_declare_property_null(php_http_request_class_entry, ZEND_STRL("history"), ZEND_ACC_PRIVATE TSRMLS_CC);
+ zend_declare_property_bool(php_http_request_class_entry, ZEND_STRL("recordHistory"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
+ zend_declare_property_string(php_http_request_class_entry, ZEND_STRL("messageClass"), "", ZEND_ACC_PRIVATE TSRMLS_CC);
+
+ /*
+ * HTTP Protocol Version Constants
+ */
+ zend_declare_class_constant_long(php_http_request_class_entry, ZEND_STRL("VERSION_1_0"), CURL_HTTP_VERSION_1_0 TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_request_class_entry, ZEND_STRL("VERSION_1_1"), CURL_HTTP_VERSION_1_1 TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_request_class_entry, ZEND_STRL("VERSION_NONE"), CURL_HTTP_VERSION_NONE TSRMLS_CC); /* to be removed */
+ zend_declare_class_constant_long(php_http_request_class_entry, ZEND_STRL("VERSION_ANY"), CURL_HTTP_VERSION_NONE TSRMLS_CC);
+
+ /*
+ * SSL Version Constants
+ */
+ zend_declare_class_constant_long(php_http_request_class_entry, ZEND_STRL("SSL_VERSION_TLSv1"), CURL_SSLVERSION_TLSv1 TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_request_class_entry, ZEND_STRL("SSL_VERSION_SSLv2"), CURL_SSLVERSION_SSLv2 TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_request_class_entry, ZEND_STRL("SSL_VERSION_SSLv3"), CURL_SSLVERSION_SSLv3 TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_request_class_entry, ZEND_STRL("SSL_VERSION_ANY"), CURL_SSLVERSION_DEFAULT TSRMLS_CC);
+
+ /*
+ * DNS IPvX resolving
+ */
+ zend_declare_class_constant_long(php_http_request_class_entry, ZEND_STRL("IPRESOLVE_V4"), CURL_IPRESOLVE_V4 TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_request_class_entry, ZEND_STRL("IPRESOLVE_V6"), CURL_IPRESOLVE_V6 TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_request_class_entry, ZEND_STRL("IPRESOLVE_ANY"), CURL_IPRESOLVE_WHATEVER TSRMLS_CC);
+
+ /*
+ * Auth Constants
+ */
+ zend_declare_class_constant_long(php_http_request_class_entry, ZEND_STRL("AUTH_BASIC"), CURLAUTH_BASIC TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_request_class_entry, ZEND_STRL("AUTH_DIGEST"), CURLAUTH_DIGEST TSRMLS_CC);
+#if PHP_HTTP_CURL_VERSION(7,19,3)
+ zend_declare_class_constant_long(php_http_request_class_entry, ZEND_STRL("AUTH_DIGEST_IE"), CURLAUTH_DIGEST_IE TSRMLS_CC);
+#endif
+ zend_declare_class_constant_long(php_http_request_class_entry, ZEND_STRL("AUTH_NTLM"), CURLAUTH_NTLM TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_request_class_entry, ZEND_STRL("AUTH_GSSNEG"), CURLAUTH_GSSNEGOTIATE TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_request_class_entry, ZEND_STRL("AUTH_ANY"), CURLAUTH_ANY TSRMLS_CC);
+
+ /*
+ * Proxy Type Constants
+ */
+ zend_declare_class_constant_long(php_http_request_class_entry, ZEND_STRL("PROXY_SOCKS4"), CURLPROXY_SOCKS4 TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_request_class_entry, ZEND_STRL("PROXY_SOCKS4A"), CURLPROXY_SOCKS5 TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_request_class_entry, ZEND_STRL("PROXY_SOCKS5_HOSTNAME"), CURLPROXY_SOCKS5 TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_request_class_entry, ZEND_STRL("PROXY_SOCKS5"), CURLPROXY_SOCKS5 TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_request_class_entry, ZEND_STRL("PROXY_HTTP"), CURLPROXY_HTTP TSRMLS_CC);
+# if PHP_HTTP_CURL_VERSION(7,19,4)
+ zend_declare_class_constant_long(php_http_request_class_entry, ZEND_STRL("PROXY_HTTP_1_0"), CURLPROXY_HTTP_1_0 TSRMLS_CC);
+# endif
+
+ /*
+ * Post Redirection Constants
+ */
+#if PHP_HTTP_CURL_VERSION(7,19,1)
+ zend_declare_class_constant_long(php_http_request_class_entry, ZEND_STRL("POSTREDIR_301"), CURL_REDIR_POST_301 TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_request_class_entry, ZEND_STRL("POSTREDIR_302"), CURL_REDIR_POST_302 TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_request_class_entry, ZEND_STRL("POSTREDIR_ALL"), CURL_REDIR_POST_ALL TSRMLS_CC);
+#endif
+
+ return SUCCESS;
+}
+
+PHP_MSHUTDOWN_FUNCTION(http_request)
+{
+ curl_global_cleanup();
+#ifdef PHP_HTTP_NEED_OPENSSL_TSL
+ if (php_http_openssl_tsl) {
+ int i, c = CRYPTO_num_locks();
+
+ CRYPTO_set_id_callback(NULL);
+ CRYPTO_set_locking_callback(NULL);
+
+ for (i = 0; i < c; ++i) {
+ tsrm_mutex_free(php_http_openssl_tsl[i]);
+ }
+
+ free(php_http_openssl_tsl);
+ php_http_openssl_tsl = NULL;
+ }
+#endif
+ return SUCCESS;
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
+
--- /dev/null
+/*
+ +--------------------------------------------------------------------+
+ | PECL :: http |
+ +--------------------------------------------------------------------+
+ | Redistribution and use in source and binary forms, with or without |
+ | modification, are permitted provided that the conditions mentioned |
+ | in the accompanying LICENSE file are met. |
+ +--------------------------------------------------------------------+
+ | Copyright (c) 2004-2010, Michael Wallner <mike@php.net> |
+ +--------------------------------------------------------------------+
+*/
+
+/* $Id: php_http_request_api.h 292841 2009-12-31 08:48:57Z mike $ */
+
+#ifndef PHP_HTTP_REQUEST_H
+#define PHP_HTTP_REQUEST_H
+
+#include "php_http_request_method.h"
+#include "php_http_request_pool.h"
+
+extern PHP_MINIT_FUNCTION(http_request);
+extern PHP_MSHUTDOWN_FUNCTION(http_request);
+
+typedef struct php_http_request_progress_state_counter {
+ double now;
+ double total;
+} php_http_request_progress_state_counter_t;
+
+typedef struct php_http_request_progress_state {
+ php_http_request_progress_state_counter_t ul;
+ php_http_request_progress_state_counter_t dl;
+} php_http_request_progress_state_t;
+
+typedef struct php_http_request {
+ CURL *ch;
+ char *url;
+ php_http_request_method_t meth;
+ php_http_message_body_t *body;
+ struct {
+ php_http_message_parser_t *ctx;
+ php_http_message_t *msg;
+ php_http_buffer *buf;
+ } parser;
+
+ struct {
+ php_http_buffer cookies;
+ HashTable options;
+ struct curl_slist *headers;
+ } _cache;
+
+ struct {
+ uint count;
+ double delay;
+ } _retry;
+
+ struct {
+ struct {
+ struct {
+ double now;
+ double total;
+ } ul;
+ struct {
+ double now;
+ double total;
+ } dl;
+ } state;
+ zval *callback;
+ unsigned in_cb:1;
+ } _progress;
+
+#ifdef ZTS
+ void ***ts;
+#endif
+
+} php_http_request_t;
+
+/* CURLOPT_PRIVATE storage living as long as a CURL handle */
+typedef struct php_http_request_storage {
+ char *url;
+ char *cookiestore;
+ char errorbuffer[CURL_ERROR_SIZE];
+} php_http_request_storage_t;
+
+
+static inline php_http_request_storage_t *php_http_request_storage_get(CURL *ch)
+{
+ php_http_request_storage_t *st = NULL;
+ curl_easy_getinfo(ch, CURLINFO_PRIVATE, &st);
+ return st;
+}
+
+PHP_HTTP_API CURL *php_http_curl_init(CURL *ch, php_http_request_t *request TSRMLS_DC);
+PHP_HTTP_API void php_http_curl_free(CURL **ch TSRMLS_DC);
+PHP_HTTP_API CURL *php_http_curl_copy(CURL *ch TSRMLS_DC);
+
+#define PHP_HTTP_CHECK_CURL_INIT(ch, init, action) \
+ if ((!(ch)) && (!((ch) = init))) { \
+ php_http_error(HE_WARNING, PHP_HTTP_E_REQUEST, "Could not initialize curl"); \
+ action; \
+ }
+
+
+PHP_HTTP_API php_http_request_t *php_http_request_init(php_http_request_t *request, CURL *ch, php_http_request_method_t meth, const char *url TSRMLS_DC);
+PHP_HTTP_API void php_http_request_dtor(php_http_request_t *request);
+PHP_HTTP_API void php_http_request_free(php_http_request_t **request);
+PHP_HTTP_API void php_http_request_reset(php_http_request_t *r);
+PHP_HTTP_API STATUS php_http_request_enable_cookies(php_http_request_t *request);
+PHP_HTTP_API STATUS php_http_request_reset_cookies(php_http_request_t *request, int session_only);
+PHP_HTTP_API STATUS php_http_request_flush_cookies(php_http_request_t *request);
+PHP_HTTP_API void php_http_request_defaults(php_http_request_t *request);
+PHP_HTTP_API STATUS php_http_request_prepare(php_http_request_t *request, HashTable *options);
+PHP_HTTP_API void php_http_request_exec(php_http_request_t *request);
+PHP_HTTP_API void php_http_request_info(php_http_request_t *request, HashTable *info);
+PHP_HTTP_API void php_http_request_set_progress_callback(php_http_request_t *request, zval *cb);
+
+
+typedef struct php_http_request_object {
+ zend_object zo;
+ php_http_request_t *request;
+ php_http_request_pool_t *pool;
+ php_http_request_datashare_t *share;
+} php_http_request_object_t;
+
+extern zend_class_entry *php_http_request_class_entry;
+extern zend_function_entry php_http_request_method_entry[];
+
+extern zend_object_value php_http_request_object_new(zend_class_entry *ce TSRMLS_DC);
+extern zend_object_value php_http_request_object_new_ex(zend_class_entry *ce, CURL *ch, php_http_request_object_t **ptr TSRMLS_DC);
+extern zend_object_value php_http_request_object_clone(zval *zobject TSRMLS_DC);
+extern void php_http_request_object_free(void *object TSRMLS_DC);
+
+extern STATUS php_http_request_object_requesthandler(php_http_request_object_t *obj, zval *this_ptr TSRMLS_DC);
+extern STATUS php_http_request_object_responsehandler(php_http_request_object_t *obj, zval *this_ptr TSRMLS_DC);
+
+PHP_METHOD(HttpRequest, __construct);
+PHP_METHOD(HttpRequest, setOptions);
+PHP_METHOD(HttpRequest, getOptions);
+PHP_METHOD(HttpRequest, addSslOptions);
+PHP_METHOD(HttpRequest, setSslOptions);
+PHP_METHOD(HttpRequest, getSslOptions);
+PHP_METHOD(HttpRequest, addHeaders);
+PHP_METHOD(HttpRequest, getHeaders);
+PHP_METHOD(HttpRequest, setHeaders);
+PHP_METHOD(HttpRequest, addCookies);
+PHP_METHOD(HttpRequest, getCookies);
+PHP_METHOD(HttpRequest, setCookies);
+PHP_METHOD(HttpRequest, enableCookies);
+PHP_METHOD(HttpRequest, resetCookies);
+PHP_METHOD(HttpRequest, flushCookies);
+PHP_METHOD(HttpRequest, setMethod);
+PHP_METHOD(HttpRequest, getMethod);
+PHP_METHOD(HttpRequest, setUrl);
+PHP_METHOD(HttpRequest, getUrl);
+PHP_METHOD(HttpRequest, setContentType);
+PHP_METHOD(HttpRequest, getContentType);
+PHP_METHOD(HttpRequest, setQueryData);
+PHP_METHOD(HttpRequest, getQueryData);
+PHP_METHOD(HttpRequest, addQueryData);
+PHP_METHOD(HttpRequest, getBody);
+PHP_METHOD(HttpRequest, setBody);
+PHP_METHOD(HttpRequest, addBody);
+PHP_METHOD(HttpRequest, send);
+PHP_METHOD(HttpRequest, getResponseData);
+PHP_METHOD(HttpRequest, getResponseHeader);
+PHP_METHOD(HttpRequest, getResponseCookies);
+PHP_METHOD(HttpRequest, getResponseCode);
+PHP_METHOD(HttpRequest, getResponseStatus);
+PHP_METHOD(HttpRequest, getResponseBody);
+PHP_METHOD(HttpRequest, getResponseInfo);
+PHP_METHOD(HttpRequest, getResponseMessage);
+PHP_METHOD(HttpRequest, getRawResponseMessage);
+PHP_METHOD(HttpRequest, getRequestMessage);
+PHP_METHOD(HttpRequest, getRawRequestMessage);
+PHP_METHOD(HttpRequest, getHistory);
+PHP_METHOD(HttpRequest, clearHistory);
+PHP_METHOD(HttpRequest, getMessageClass);
+PHP_METHOD(HttpRequest, setMessageClass);
+
+#endif
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
+
--- /dev/null
+
+#include "php_http.h"
+
+static HashTable php_http_request_datashare_options;
+static php_http_request_datashare_t php_http_request_datashare_global;
+static int php_http_request_datashare_compare_handles(void *h1, void *h2);
+static void php_http_request_datashare_destroy_handles(void *el);
+
+#ifdef ZTS
+static void *php_http_request_datashare_locks_init(void);
+static void php_http_request_datashare_locks_dtor(void *l);
+static void php_http_request_datashare_lock_func(CURL *handle, curl_lock_data data, curl_lock_access locktype, void *userptr);
+static void php_http_request_datashare_unlock_func(CURL *handle, curl_lock_data data, void *userptr);
+#endif
+
+php_http_request_datashare_t *php_http_request_datashare_global_get(void)
+{
+ return &php_http_request_datashare_global;
+}
+
+PHP_HTTP_API php_http_request_datashare_t *php_http_request_datashare_init(php_http_request_datashare_t *share, zend_bool persistent TSRMLS_DC)
+{
+ zend_bool free_share;
+
+ if ((free_share = !share)) {
+ share = pemalloc(sizeof(php_http_request_datashare_t), persistent);
+ }
+ memset(share, 0, sizeof(php_http_request_datashare_t));
+
+ if (SUCCESS != php_http_persistent_handle_acquire(ZEND_STRL("http_request_datashare"), &share->ch TSRMLS_CC)) {
+ if (free_share) {
+ pefree(share, persistent);
+ }
+ return NULL;
+ }
+
+ if (!(share->persistent = persistent)) {
+ share->handle.list = emalloc(sizeof(zend_llist));
+ zend_llist_init(share->handle.list, sizeof(zval *), ZVAL_PTR_DTOR, 0);
+#ifdef ZTS
+ } else {
+ if (SUCCESS == php_http_persistent_handle_acquire(ZEND_STRL("http_request_datashare_lock"), (void *) &share->handle.locks)) {
+ curl_share_setopt(share->ch, CURLSHOPT_LOCKFUNC, php_http_request_datashare_lock_func);
+ curl_share_setopt(share->ch, CURLSHOPT_UNLOCKFUNC, php_http_request_datashare_unlock_func);
+ curl_share_setopt(share->ch, CURLSHOPT_USERDATA, share->handle.locks);
+ }
+#endif
+ }
+
+ TSRMLS_SET_CTX(share->ts);
+
+ return share;
+}
+
+PHP_HTTP_API STATUS php_http_request_datashare_attach(php_http_request_datashare_t *share, zval *request)
+{
+ CURLcode rc;
+ TSRMLS_FETCH_FROM_CTX(share->ts);
+ php_http_request_object_t *obj = zend_object_store_get_object(request TSRMLS_CC);
+
+ if (obj->share) {
+ if (obj->share == share) {
+ return SUCCESS;
+ } else if (SUCCESS != php_http_request_datashare_detach(obj->share, request)) {
+ return FAILURE;
+ }
+ }
+
+ PHP_HTTP_CHECK_CURL_INIT(obj->request->ch, php_http_curl_init(obj->request->ch, obj->request TSRMLS_CC), return FAILURE);
+ if (CURLE_OK != (rc = curl_easy_setopt(obj->request->ch, CURLOPT_SHARE, share->ch))) {
+ php_http_error(HE_WARNING, PHP_HTTP_E_REQUEST, "Could not attach HttpRequest object(#%d) to the HttpRequestDataShare: %s", Z_OBJ_HANDLE_P(request), curl_easy_strerror(rc));
+ return FAILURE;
+ }
+
+ obj->share = share;
+ Z_ADDREF_P(request);
+ zend_llist_add_element(PHP_HTTP_RSHARE_HANDLES(share), (void *) &request);
+
+ return SUCCESS;
+}
+
+PHP_HTTP_API STATUS php_http_request_datashare_detach(php_http_request_datashare_t *share, zval *request)
+{
+ CURLcode rc;
+ TSRMLS_FETCH_FROM_CTX(share->ts);
+ php_http_request_object_t *obj = zend_object_store_get_object(request TSRMLS_CC);
+
+ if (!obj->share) {
+ php_http_error(HE_WARNING, PHP_HTTP_E_REQUEST, "HttpRequest object(#%d) is not attached to any HttpRequestDataShare", Z_OBJ_HANDLE_P(request));
+ } else if (obj->share != share) {
+ php_http_error(HE_WARNING, PHP_HTTP_E_REQUEST, "HttpRequest object(#%d) is not attached to this HttpRequestDataShare", Z_OBJ_HANDLE_P(request));
+ } else if (CURLE_OK != (rc = curl_easy_setopt(obj->request->ch, CURLOPT_SHARE, NULL))) {
+ php_http_error(HE_WARNING, PHP_HTTP_E_REQUEST, "Could not detach HttpRequest object(#%d) from the HttpRequestDataShare: %s", Z_OBJ_HANDLE_P(request), curl_share_strerror(rc));
+ } else {
+ obj->share = NULL;
+ zend_llist_del_element(PHP_HTTP_RSHARE_HANDLES(share), request, php_http_request_datashare_compare_handles);
+ return SUCCESS;
+ }
+ return FAILURE;
+}
+
+PHP_HTTP_API void php_http_request_datashare_detach_all(php_http_request_datashare_t *share)
+{
+ zval **r;
+
+ while ((r = zend_llist_get_first(PHP_HTTP_RSHARE_HANDLES(share)))) {
+ php_http_request_datashare_detach(share, *r);
+ }
+}
+
+PHP_HTTP_API void php_http_request_datashare_dtor(php_http_request_datashare_t *share)
+{
+ TSRMLS_FETCH_FROM_CTX(share->ts);
+
+ if (!share->persistent) {
+ zend_llist_destroy(share->handle.list);
+ efree(share->handle.list);
+ }
+ php_http_persistent_handle_release(ZEND_STRL("http_request_datashare"), &share->ch TSRMLS_CC);
+#ifdef ZTS
+ if (share->persistent) {
+ php_http_persistent_handle_release(ZEND_STRL("http_request_datashare_lock"), (void *) &share->handle.locks TSRMLS_CC);
+ }
+#endif
+}
+
+PHP_HTTP_API void php_http_request_datashare_free(php_http_request_datashare_t **share)
+{
+ php_http_request_datashare_dtor(*share);
+ pefree(*share, (*share)->persistent);
+ *share = NULL;
+}
+
+PHP_HTTP_API STATUS php_http_request_datashare_set(php_http_request_datashare_t *share, const char *option, size_t option_len, zend_bool enable)
+{
+ curl_lock_data *opt;
+ CURLSHcode rc;
+ TSRMLS_FETCH_FROM_CTX(share->ts);
+
+ if (SUCCESS == zend_hash_find(&php_http_request_datashare_options, (char *) option, option_len + 1, (void *) &opt)) {
+ if (CURLSHE_OK == (rc = curl_share_setopt(share->ch, enable ? CURLSHOPT_SHARE : CURLSHOPT_UNSHARE, *opt))) {
+ return SUCCESS;
+ }
+ php_http_error(HE_WARNING, PHP_HTTP_E_REQUEST, "Could not %s sharing of %s data: %s", enable ? "enable" : "disable", option, curl_share_strerror(rc));
+ }
+ return FAILURE;
+}
+
+static int php_http_request_datashare_compare_handles(void *h1, void *h2)
+{
+ return (Z_OBJ_HANDLE_PP((zval **) h1) == Z_OBJ_HANDLE_P((zval *) h2));
+}
+
+static void php_http_request_datashare_destroy_handles(void *el)
+{
+ zval **r = (zval **) el;
+ TSRMLS_FETCH();
+
+ { /* gcc 2.95 needs these braces */
+ php_http_request_object_t *obj = zend_object_store_get_object(*r TSRMLS_CC);
+
+ curl_easy_setopt(obj->request->ch, CURLOPT_SHARE, NULL);
+ zval_ptr_dtor(r);
+ }
+}
+
+#ifdef ZTS
+static void *php_http_request_datashare_locks_init(void)
+{
+ int i;
+ php_http_request_datashare_lock_t *locks = pecalloc(CURL_LOCK_DATA_LAST, sizeof(php_http_request_datashare_lock_t), 1);
+
+ if (locks) {
+ for (i = 0; i < CURL_LOCK_DATA_LAST; ++i) {
+ locks[i].mx = tsrm_mutex_alloc();
+ }
+ }
+
+ return locks;
+}
+
+static void php_http_request_datashare_locks_dtor(void *l)
+{
+ int i;
+ php_http_request_datashare_lock_t *locks = (php_http_request_datashare_lock_t *) l;
+
+ for (i = 0; i < CURL_LOCK_DATA_LAST; ++i) {
+ tsrm_mutex_free(locks[i].mx);
+ }
+ pefree(locks, 1);
+}
+
+static void php_http_request_datashare_lock_func(CURL *handle, curl_lock_data data, curl_lock_access locktype, void *userptr)
+{
+ php_http_request_datashare_lock_t *locks = (php_http_request_datashare_lock_t *) userptr;
+
+ /* TSRM can't distinguish shared/exclusive locks */
+ tsrm_mutex_lock(locks[data].mx);
+ locks[data].ch = handle;
+}
+
+static void php_http_request_datashare_unlock_func(CURL *handle, curl_lock_data data, void *userptr)
+{
+ php_http_request_datashare_lock_t *locks = (php_http_request_datashare_lock_t *) userptr;
+
+ if (locks[data].ch == handle) {
+ tsrm_mutex_unlock(locks[data].mx);
+ }
+}
+#endif
+
+
+#define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpRequestDataShare, method, 0, req_args)
+#define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpRequestDataShare, method, 0)
+#define PHP_HTTP_RSHARE_ME(method, visibility) PHP_ME(HttpRequestDataShare, method, PHP_HTTP_ARGS(HttpRequestDataShare, method), visibility)
+
+PHP_HTTP_EMPTY_ARGS(__destruct);
+PHP_HTTP_EMPTY_ARGS(count);
+
+PHP_HTTP_BEGIN_ARGS(attach, 1)
+ PHP_HTTP_ARG_OBJ(http\\Request, request, 0)
+PHP_HTTP_END_ARGS;
+PHP_HTTP_BEGIN_ARGS(detach, 1)
+ PHP_HTTP_ARG_OBJ(http\\Request, request, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_EMPTY_ARGS(reset);
+
+PHP_HTTP_EMPTY_ARGS(getGlobalInstance);
+
+
+static zval *php_http_request_datashare_object_read_prop(zval *object, zval *member, int type, const zend_literal *literal_key TSRMLS_DC);
+static void php_http_request_datashare_object_write_prop(zval *object, zval *member, zval *value, const zend_literal *literal_key TSRMLS_DC);
+
+#define THIS_CE php_http_request_datashare_class_entry
+zend_class_entry *php_http_request_datashare_class_entry;
+zend_function_entry php_http_request_datashare_method_entry[] = {
+ PHP_HTTP_RSHARE_ME(__destruct, ZEND_ACC_PUBLIC|ZEND_ACC_DTOR)
+ PHP_HTTP_RSHARE_ME(count, ZEND_ACC_PUBLIC)
+ PHP_HTTP_RSHARE_ME(attach, ZEND_ACC_PUBLIC)
+ PHP_HTTP_RSHARE_ME(detach, ZEND_ACC_PUBLIC)
+ PHP_HTTP_RSHARE_ME(reset, ZEND_ACC_PUBLIC)
+ PHP_HTTP_RSHARE_ME(getGlobalInstance, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
+ EMPTY_FUNCTION_ENTRY
+};
+static zend_object_handlers php_http_request_datashare_object_handlers;
+
+zend_object_value php_http_request_datashare_object_new(zend_class_entry *ce TSRMLS_DC)
+{
+ return php_http_request_datashare_object_new_ex(ce, NULL, NULL TSRMLS_CC);
+}
+
+zend_object_value php_http_request_datashare_object_new_ex(zend_class_entry *ce, php_http_request_datashare_t *share, php_http_request_datashare_object_t **ptr TSRMLS_DC)
+{
+ zend_object_value ov;
+ php_http_request_datashare_object_t *o;
+
+ o = ecalloc(1, sizeof(*o));
+ zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
+ object_properties_init((zend_object *) o, ce);
+
+ if (share) {
+ o->share = share;
+ } else {
+ o->share = php_http_request_datashare_init(NULL, 0 TSRMLS_CC);
+ }
+
+ if (ptr) {
+ *ptr = o;
+ }
+
+ ov.handle = zend_objects_store_put(o, NULL, php_http_request_datashare_object_free, NULL TSRMLS_CC);
+ ov.handlers = &php_http_request_datashare_object_handlers;
+
+ return ov;
+}
+
+void php_http_request_datashare_object_free(void *object TSRMLS_DC)
+{
+ php_http_request_datashare_object_t *o = (php_http_request_datashare_object_t *) object;
+
+ if (!o->share->persistent) {
+ php_http_request_datashare_free(&o->share);
+ }
+ zend_object_std_dtor((zend_object *) o);
+ efree(o);
+}
+
+static zval *php_http_request_datashare_object_read_prop(zval *object, zval *member, int type, const zend_literal *literal_key TSRMLS_DC)
+{
+ if (type == BP_VAR_W && zend_get_property_info(THIS_CE, member, 1 TSRMLS_CC)) {
+ zend_error(E_ERROR, "Cannot access HttpRequestDataShare default properties by reference or array key/index");
+ return NULL;
+ }
+
+ return zend_get_std_object_handlers()->read_property(object, member, type, literal_key TSRMLS_CC);
+}
+
+static void php_http_request_datashare_object_write_prop(zval *object, zval *member, zval *value, const zend_literal *literal_key TSRMLS_DC)
+{
+ if (zend_get_property_info(THIS_CE, member, 1 TSRMLS_CC)) {
+ int status;
+ php_http_request_datashare_object_t *obj = zend_object_store_get_object(object TSRMLS_CC);
+
+ status = php_http_request_datashare_set(obj->share, Z_STRVAL_P(member), Z_STRLEN_P(member), (zend_bool) i_zend_is_true(value));
+ if (SUCCESS != status) {
+ return;
+ }
+ }
+
+ zend_get_std_object_handlers()->write_property(object, member, value, literal_key TSRMLS_CC);
+}
+
+PHP_METHOD(HttpRequestDataShare, __destruct)
+{
+ php_http_request_datashare_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (SUCCESS == zend_parse_parameters_none()) {
+ ; /* we always want to clean up */
+ }
+
+ php_http_request_datashare_detach_all(obj->share);
+}
+
+PHP_METHOD(HttpRequestDataShare, count)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ php_http_request_datashare_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ RETURN_LONG(zend_llist_count(PHP_HTTP_RSHARE_HANDLES(obj->share)));
+ }
+ RETURN_FALSE;
+}
+
+
+PHP_METHOD(HttpRequestDataShare, attach)
+{
+ zval *request;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &request, php_http_request_class_entry)) {
+ php_http_request_datashare_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ RETURN_SUCCESS(php_http_request_datashare_attach(obj->share, request));
+ }
+ RETURN_FALSE;
+
+}
+
+PHP_METHOD(HttpRequestDataShare, detach)
+{
+ zval *request;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &request, php_http_request_class_entry)) {
+ php_http_request_datashare_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ RETURN_SUCCESS(php_http_request_datashare_detach(obj->share, request));
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpRequestDataShare, reset)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ php_http_request_datashare_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ php_http_request_datashare_detach_all(obj->share);
+ RETURN_TRUE;
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpRequestDataShare, getGlobalInstance)
+{
+ with_error_handling(EH_THROW, PHP_HTTP_EX_CE(runtime)) {
+ if (SUCCESS == zend_parse_parameters_none()) {
+ zval *instance = *zend_std_get_static_property(THIS_CE, ZEND_STRL("instance"), 0, NULL TSRMLS_CC);
+
+ if (Z_TYPE_P(instance) != IS_OBJECT) {
+ MAKE_STD_ZVAL(instance);
+ ZVAL_OBJVAL(instance, php_http_request_datashare_object_new_ex(THIS_CE, php_http_request_datashare_global_get(), NULL TSRMLS_CC), 1);
+ zend_update_static_property(THIS_CE, ZEND_STRL("instance"), instance TSRMLS_CC);
+
+ if (PHP_HTTP_G->request_datashare.cookie) {
+ zend_update_property_bool(THIS_CE, instance, ZEND_STRL("cookie"), PHP_HTTP_G->request_datashare.cookie TSRMLS_CC);
+ }
+ if (PHP_HTTP_G->request_datashare.dns) {
+ zend_update_property_bool(THIS_CE, instance, ZEND_STRL("dns"), PHP_HTTP_G->request_datashare.dns TSRMLS_CC);
+ }
+ if (PHP_HTTP_G->request_datashare.ssl) {
+ zend_update_property_bool(THIS_CE, instance, ZEND_STRL("ssl"), PHP_HTTP_G->request_datashare.ssl TSRMLS_CC);
+ }
+ if (PHP_HTTP_G->request_datashare.connect) {
+ zend_update_property_bool(THIS_CE, instance, ZEND_STRL("connect"), PHP_HTTP_G->request_datashare.connect TSRMLS_CC);
+ }
+ }
+
+ RETVAL_ZVAL(instance, 0, 0);
+ }
+ }end_error_handling();
+}
+
+PHP_MINIT_FUNCTION(http_request_datashare)
+{
+ curl_lock_data val;
+
+ if (SUCCESS != php_http_persistent_handle_provide(ZEND_STRL("http_request_datashare"), curl_share_init, (php_http_persistent_handle_dtor_t) curl_share_cleanup, NULL)) {
+ return FAILURE;
+ }
+#ifdef ZTS
+ if (SUCCESS != php_http_persistent_handle_provide(ZEND_STRL("http_request_datashare_lock"), php_http_request_datashare_locks_init, php_http_request_datashare_locks_dtor, NULL)) {
+ return FAILURE;
+ }
+#endif
+
+ if (!php_http_request_datashare_init(&php_http_request_datashare_global, 1 TSRMLS_CC)) {
+ return FAILURE;
+ }
+
+ zend_hash_init(&php_http_request_datashare_options, 4, NULL, NULL, 1);
+#define ADD_DATASHARE_OPT(name, opt) \
+ val = opt; \
+ zend_hash_add(&php_http_request_datashare_options, name, sizeof(name), &val, sizeof(curl_lock_data), NULL)
+ ADD_DATASHARE_OPT("cookie", CURL_LOCK_DATA_COOKIE);
+ ADD_DATASHARE_OPT("dns", CURL_LOCK_DATA_DNS);
+ ADD_DATASHARE_OPT("ssl", CURL_LOCK_DATA_SSL_SESSION);
+ ADD_DATASHARE_OPT("connect", CURL_LOCK_DATA_CONNECT);
+
+ PHP_HTTP_REGISTER_CLASS(http\\request, DataShare, http_request_datashare, php_http_object_class_entry, 0);
+ php_http_request_datashare_class_entry->create_object = php_http_request_datashare_object_new;
+ memcpy(&php_http_request_datashare_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
+ php_http_request_datashare_object_handlers.clone_obj = NULL;
+ php_http_request_datashare_object_handlers.read_property = php_http_request_datashare_object_read_prop;
+ php_http_request_datashare_object_handlers.write_property = php_http_request_datashare_object_write_prop;
+ php_http_request_datashare_object_handlers.get_property_ptr_ptr = NULL;
+
+ zend_class_implements(php_http_request_datashare_class_entry TSRMLS_CC, 1, spl_ce_Countable);
+
+ zend_declare_property_null(THIS_CE, ZEND_STRL("instance"), (ZEND_ACC_STATIC|ZEND_ACC_PRIVATE) TSRMLS_CC);
+ zend_declare_property_bool(THIS_CE, ZEND_STRL("cookie"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
+ zend_declare_property_bool(THIS_CE, ZEND_STRL("dns"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
+ zend_declare_property_bool(THIS_CE, ZEND_STRL("ssl"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
+ zend_declare_property_bool(THIS_CE, ZEND_STRL("connect"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
+
+ return SUCCESS;
+}
+
+PHP_MSHUTDOWN_FUNCTION(http_request_datashare)
+{
+ php_http_request_datashare_dtor(&php_http_request_datashare_global);
+ zend_hash_destroy(&php_http_request_datashare_options);
+
+ return SUCCESS;
+}
+
+PHP_RINIT_FUNCTION(http_request_datashare)
+{
+ zend_llist_init(&PHP_HTTP_G->request_datashare.handles, sizeof(zval *), php_http_request_datashare_destroy_handles, 0);
+
+ return SUCCESS;
+}
+
+PHP_RSHUTDOWN_FUNCTION(http_request_datashare)
+{
+ zend_llist_destroy(&PHP_HTTP_G->request_datashare.handles);
+
+ return SUCCESS;
+}
+
--- /dev/null
+#ifndef PHP_HTTP_REQUEST_DATASHARE_H
+#define PHP_HTTP_REQUEST_DATASHARE_H
+
+#ifdef ZTS
+typedef struct php_http_request_datashare_lock {
+ CURL *ch;
+ MUTEX_T mx;
+} php_http_request_datashare_lock_t;
+#endif
+
+typedef union php_http_request_datashare_handle {
+ zend_llist *list;
+#ifdef ZTS
+ php_http_request_datashare_lock_t *locks;
+#endif
+} php_http_request_datashare_handle_t;
+
+typedef struct php_http_request_datashare_t {
+ CURLSH *ch;
+ php_http_request_datashare_handle_t handle;
+ unsigned persistent:1;
+#ifdef ZTS
+ void ***ts;
+#endif
+} php_http_request_datashare_t;
+
+struct php_http_request_datashare_globals {
+ zend_llist handles;
+ zend_bool cookie;
+ zend_bool dns;
+ zend_bool ssl;
+ zend_bool connect;
+};
+
+#define PHP_HTTP_RSHARE_HANDLES(s) ((s)->persistent ? &PHP_HTTP_G->request_datashare.handles : (s)->handle.list)
+
+extern php_http_request_datashare_t *php_http_request_datashare_global_get(void);
+
+extern PHP_MINIT_FUNCTION(http_request_datashare);
+extern PHP_MSHUTDOWN_FUNCTION(http_request_datashare);
+extern PHP_RINIT_FUNCTION(http_request_datashare);
+extern PHP_RSHUTDOWN_FUNCTION(http_request_datashare);
+
+PHP_HTTP_API php_http_request_datashare_t *php_http_request_datashare_init(php_http_request_datashare_t *share, zend_bool persistent TSRMLS_DC);
+PHP_HTTP_API STATUS php_http_request_datashare_attach(php_http_request_datashare_t *share, zval *request);
+PHP_HTTP_API STATUS php_http_request_datashare_detach(php_http_request_datashare_t *share, zval *request);
+PHP_HTTP_API void php_http_request_datashare_detach_all(php_http_request_datashare_t *share);
+PHP_HTTP_API void php_http_request_datashare_dtor(php_http_request_datashare_t *share);
+PHP_HTTP_API void php_http_request_datashare_free(php_http_request_datashare_t **share);
+PHP_HTTP_API STATUS php_http_request_datashare_set(php_http_request_datashare_t *share, const char *option, size_t option_len, zend_bool enable);
+
+typedef struct php_http_request_datashare_object {
+ zend_object zo;
+ php_http_request_datashare_t *share;
+} php_http_request_datashare_object_t;
+
+extern zend_class_entry *php_http_request_datashare_class_entry;
+extern zend_function_entry php_http_request_datashare_method_entry[];
+
+extern zend_object_value php_http_request_datashare_object_new(zend_class_entry *ce TSRMLS_DC);
+extern zend_object_value php_http_request_datashare_object_new_ex(zend_class_entry *ce, php_http_request_datashare_t *share, php_http_request_datashare_object_t **ptr TSRMLS_DC);
+extern void php_http_request_datashare_object_free(void *object TSRMLS_DC);
+
+PHP_METHOD(HttpRequestDataShare, __destruct);
+PHP_METHOD(HttpRequestDataShare, count);
+PHP_METHOD(HttpRequestDataShare, attach);
+PHP_METHOD(HttpRequestDataShare, detach);
+PHP_METHOD(HttpRequestDataShare, reset);
+PHP_METHOD(HttpRequestDataShare, getGlobalInstance);
+
+#endif /* PHP_HTTP_REQUEST_DATASHARE_H */
--- /dev/null
+/*
+ +--------------------------------------------------------------------+
+ | PECL :: http |
+ +--------------------------------------------------------------------+
+ | Redistribution and use in source and binary forms, with or without |
+ | modification, are permitted provided that the conditions mentioned |
+ | in the accompanying LICENSE file are met. |
+ +--------------------------------------------------------------------+
+ | Copyright (c) 2004-2010, Michael Wallner <mike@php.net> |
+ +--------------------------------------------------------------------+
+*/
+
+/* $Id: http_request_info.c 293136 2010-01-05 08:48:52Z mike $ */
+
+#include "php_http.h"
+
+PHP_HTTP_API void php_http_request_info(php_http_request_t *request, HashTable *info)
+{
+ char *c;
+ long l;
+ double d;
+ struct curl_slist *s, *p;
+ zval *subarray, array;
+ INIT_PZVAL_ARRAY(&array, info);
+
+ /* BEGIN */
+ if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_EFFECTIVE_URL, &c)) {
+ add_assoc_string_ex(&array, "effective_url", sizeof("effective_url"), c ? c : "", 1);
+ }
+ if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_RESPONSE_CODE, &l)) {
+ add_assoc_long_ex(&array, "response_code", sizeof("response_code"), l);
+ }
+ if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_TOTAL_TIME, &d)) {
+ add_assoc_double_ex(&array, "total_time", sizeof("total_time"), d);
+ }
+ if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_NAMELOOKUP_TIME, &d)) {
+ add_assoc_double_ex(&array, "namelookup_time", sizeof("namelookup_time"), d);
+ }
+ if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_CONNECT_TIME, &d)) {
+ add_assoc_double_ex(&array, "connect_time", sizeof("connect_time"), d);
+ }
+ if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_PRETRANSFER_TIME, &d)) {
+ add_assoc_double_ex(&array, "pretransfer_time", sizeof("pretransfer_time"), d);
+ }
+ if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_SIZE_UPLOAD, &d)) {
+ add_assoc_double_ex(&array, "size_upload", sizeof("size_upload"), d);
+ }
+ if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_SIZE_DOWNLOAD, &d)) {
+ add_assoc_double_ex(&array, "size_download", sizeof("size_download"), d);
+ }
+ if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_SPEED_DOWNLOAD, &d)) {
+ add_assoc_double_ex(&array, "speed_download", sizeof("speed_download"), d);
+ }
+ if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_SPEED_UPLOAD, &d)) {
+ add_assoc_double_ex(&array, "speed_upload", sizeof("speed_upload"), d);
+ }
+ if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_HEADER_SIZE, &l)) {
+ add_assoc_long_ex(&array, "header_size", sizeof("header_size"), l);
+ }
+ if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_REQUEST_SIZE, &l)) {
+ add_assoc_long_ex(&array, "request_size", sizeof("request_size"), l);
+ }
+ if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_SSL_VERIFYRESULT, &l)) {
+ add_assoc_long_ex(&array, "ssl_verifyresult", sizeof("ssl_verifyresult"), l);
+ }
+ if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_FILETIME, &l)) {
+ add_assoc_long_ex(&array, "filetime", sizeof("filetime"), l);
+ }
+ if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &d)) {
+ add_assoc_double_ex(&array, "content_length_download", sizeof("content_length_download"), d);
+ }
+ if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_CONTENT_LENGTH_UPLOAD, &d)) {
+ add_assoc_double_ex(&array, "content_length_upload", sizeof("content_length_upload"), d);
+ }
+ if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_STARTTRANSFER_TIME, &d)) {
+ add_assoc_double_ex(&array, "starttransfer_time", sizeof("starttransfer_time"), d);
+ }
+ if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_CONTENT_TYPE, &c)) {
+ add_assoc_string_ex(&array, "content_type", sizeof("content_type"), c ? c : "", 1);
+ }
+ if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_REDIRECT_TIME, &d)) {
+ add_assoc_double_ex(&array, "redirect_time", sizeof("redirect_time"), d);
+ }
+ if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_REDIRECT_COUNT, &l)) {
+ add_assoc_long_ex(&array, "redirect_count", sizeof("redirect_count"), l);
+ }
+ if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_HTTP_CONNECTCODE, &l)) {
+ add_assoc_long_ex(&array, "connect_code", sizeof("connect_code"), l);
+ }
+ if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_HTTPAUTH_AVAIL, &l)) {
+ add_assoc_long_ex(&array, "httpauth_avail", sizeof("httpauth_avail"), l);
+ }
+ if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_PROXYAUTH_AVAIL, &l)) {
+ add_assoc_long_ex(&array, "proxyauth_avail", sizeof("proxyauth_avail"), l);
+ }
+ if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_OS_ERRNO, &l)) {
+ add_assoc_long_ex(&array, "os_errno", sizeof("os_errno"), l);
+ }
+ if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_NUM_CONNECTS, &l)) {
+ add_assoc_long_ex(&array, "num_connects", sizeof("num_connects"), l);
+ }
+ if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_SSL_ENGINES, &s)) {
+ MAKE_STD_ZVAL(subarray);
+ array_init(subarray);
+ for (p = s; p; p = p->next) {
+ if (p->data) {
+ add_next_index_string(subarray, p->data, 1);
+ }
+ }
+ add_assoc_zval_ex(&array, "ssl_engines", sizeof("ssl_engines"), subarray);
+ curl_slist_free_all(s);
+ }
+#if PHP_HTTP_CURL_VERSION(7,14,1)
+ if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_COOKIELIST, &s)) {
+ MAKE_STD_ZVAL(subarray);
+ array_init(subarray);
+ for (p = s; p; p = p->next) {
+ if (p->data) {
+ add_next_index_string(subarray, p->data, 1);
+ }
+ }
+ add_assoc_zval_ex(&array, "cookies", sizeof("cookies"), subarray);
+ curl_slist_free_all(s);
+ }
+#endif
+#if PHP_HTTP_CURL_VERSION(7,18,2)
+ if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_REDIRECT_URL, &c)) {
+ add_assoc_string_ex(&array, "redirect_url", sizeof("redirect_url"), c ? c : "", 1);
+ }
+#endif
+#if PHP_HTTP_CURL_VERSION(7,19,0)
+ if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_PRIMARY_IP, &c)) {
+ add_assoc_string_ex(&array, "primary_ip", sizeof("primary_ip"), c ? c : "", 1);
+ }
+#endif
+#if PHP_HTTP_CURL_VERSION(7,19,0)
+ if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_APPCONNECT_TIME, &d)) {
+ add_assoc_double_ex(&array, "appconnect_time", sizeof("appconnect_time"), d);
+ }
+#endif
+#if PHP_HTTP_CURL_VERSION(7,19,4)
+ if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_CONDITION_UNMET, &l)) {
+ add_assoc_long_ex(&array, "condition_unmet", sizeof("condition_unmet"), l);
+ }
+#endif
+/* END */
+#if PHP_HTTP_CURL_VERSION(7,19,1) && defined(PHP_HTTP_HAVE_OPENSSL)
+ {
+ int i;
+ zval *ci_array;
+ struct curl_certinfo *ci;
+ char *colon, *keyname;
+
+ if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_CERTINFO, &ci)) {
+ MAKE_STD_ZVAL(ci_array);
+ array_init(ci_array);
+
+ for (i = 0; i < ci->num_of_certs; ++i) {
+ s = ci->certinfo[i];
+
+ MAKE_STD_ZVAL(subarray);
+ array_init(subarray);
+ for (p = s; p; p = p->next) {
+ if (p->data) {
+ if ((colon = strchr(p->data, ':'))) {
+ keyname = estrndup(p->data, colon - p->data);
+ add_assoc_string_ex(subarray, keyname, colon - p->data + 1, colon + 1, 1);
+ efree(keyname);
+ } else {
+ add_next_index_string(subarray, p->data, 1);
+ }
+ }
+ }
+ add_next_index_zval(ci_array, subarray);
+ }
+ add_assoc_zval_ex(&array, "certinfo", sizeof("certinfo"), ci_array);
+ }
+ }
+#endif
+ add_assoc_string_ex(&array, "error", sizeof("error"), php_http_request_storage_get(request->ch)->errorbuffer, 1);
+}
+
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
--- /dev/null
+/*
+ +--------------------------------------------------------------------+
+ | PECL :: http |
+ +--------------------------------------------------------------------+
+ | Redistribution and use in source and binary forms, with or without |
+ | modification, are permitted provided that the conditions mentioned |
+ | in the accompanying LICENSE file are met. |
+ +--------------------------------------------------------------------+
+ | Copyright (c) 2004-2010, Michael Wallner <mike@php.net> |
+ +--------------------------------------------------------------------+
+*/
+
+/* $Id: http_request_method_api.c 292841 2009-12-31 08:48:57Z mike $ */
+
+#include "php_http.h"
+
+static PHP_HTTP_STRLIST(php_http_request_methods) =
+ PHP_HTTP_STRLIST_ITEM("UNKNOWN")
+ /* HTTP/1.1 */
+ PHP_HTTP_STRLIST_ITEM("GET")
+ PHP_HTTP_STRLIST_ITEM("HEAD")
+ PHP_HTTP_STRLIST_ITEM("POST")
+ PHP_HTTP_STRLIST_ITEM("PUT")
+ PHP_HTTP_STRLIST_ITEM("DELETE")
+ PHP_HTTP_STRLIST_ITEM("OPTIONS")
+ PHP_HTTP_STRLIST_ITEM("TRACE")
+ PHP_HTTP_STRLIST_ITEM("CONNECT")
+ /* WebDAV - RFC 2518 */
+ PHP_HTTP_STRLIST_ITEM("PROPFIND")
+ PHP_HTTP_STRLIST_ITEM("PROPPATCH")
+ PHP_HTTP_STRLIST_ITEM("MKCOL")
+ PHP_HTTP_STRLIST_ITEM("COPY")
+ PHP_HTTP_STRLIST_ITEM("MOVE")
+ PHP_HTTP_STRLIST_ITEM("LOCK")
+ PHP_HTTP_STRLIST_ITEM("UNLOCK")
+ /* WebDAV Versioning - RFC 3253 */
+ PHP_HTTP_STRLIST_ITEM("VERSION-CONTROL")
+ PHP_HTTP_STRLIST_ITEM("REPORT")
+ PHP_HTTP_STRLIST_ITEM("CHECKOUT")
+ PHP_HTTP_STRLIST_ITEM("CHECKIN")
+ PHP_HTTP_STRLIST_ITEM("UNCHECKOUT")
+ PHP_HTTP_STRLIST_ITEM("MKWORKSPACE")
+ PHP_HTTP_STRLIST_ITEM("UPDATE")
+ PHP_HTTP_STRLIST_ITEM("LABEL")
+ PHP_HTTP_STRLIST_ITEM("MERGE")
+ PHP_HTTP_STRLIST_ITEM("BASELINE-CONTROL")
+ PHP_HTTP_STRLIST_ITEM("MKACTIVITY")
+ /* WebDAV Access Control - RFC 3744 */
+ PHP_HTTP_STRLIST_ITEM("ACL")
+ PHP_HTTP_STRLIST_STOP
+;
+
+PHP_HTTP_API const char *php_http_request_method_name(php_http_request_method_t meth)
+{
+ if (meth > PHP_HTTP_NO_REQUEST_METHOD && meth < PHP_HTTP_MAX_REQUEST_METHOD) {
+ return php_http_strlist_find(php_http_request_methods, 1, meth);
+ } else {
+ zval **val, *cmp, res;
+ HashPosition pos;
+ php_http_array_hashkey_t key = php_http_array_hashkey_init(0);
+
+ INIT_PZVAL(&res);
+ FOREACH_HASH_KEYVAL(pos, &php_http_request_class_entry->constants_table, key, val) {
+ MAKE_STD_ZVAL(cmp);
+ ZVAL_LONG(cmp, meth);
+ is_equal_function(&res, *val, cmp TSRMLS_CC);
+ zval_ptr_dtor(&cmp);
+
+ if (Z_LVAL(res)) {
+ return key.str;
+ }
+ }
+ }
+ return NULL;
+}
+
+PHP_HTTP_API STATUS php_http_request_method_register(const char *meth_str, size_t meth_len, long *id TSRMLS_DC)
+{
+ long num = zend_hash_num_elements(&php_http_request_class_entry->constants_table);
+
+ if (SUCCESS == zend_declare_class_constant_long(php_http_request_method_class_entry, meth_str, meth_len, num TSRMLS_CC)) {
+ if (id) {
+ *id = num;
+ }
+ return SUCCESS;
+ }
+ return FAILURE;
+}
+
+zend_class_entry *php_http_request_method_class_entry;
+
+#define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpRequestMethod, method, 0, req_args)
+#define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpRequestMethod, method, 0)
+#define PHP_HTTP_REQMETH_ME(method, visibility) PHP_ME(HttpRequestMethod, method, PHP_HTTP_ARGS(HttpRequestMethod, method), visibility)
+
+#ifdef register
+# undef register
+#endif
+
+PHP_HTTP_BEGIN_ARGS(__construct, 1)
+ PHP_HTTP_ARG_VAL(name, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_EMPTY_ARGS(__toString);
+
+PHP_HTTP_EMPTY_ARGS(getId);
+
+PHP_HTTP_BEGIN_ARGS(exists, 1)
+ PHP_HTTP_ARG_VAL(method, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(register, 1)
+ PHP_HTTP_ARG_VAL(method, 0)
+PHP_HTTP_END_ARGS;
+
+zend_function_entry php_http_request_method_method_entry[] = {
+ PHP_HTTP_REQMETH_ME(__construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
+ PHP_HTTP_REQMETH_ME(__toString, ZEND_ACC_PUBLIC)
+ PHP_HTTP_REQMETH_ME(getId, ZEND_ACC_PUBLIC)
+ PHP_HTTP_REQMETH_ME(exists, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
+ PHP_HTTP_REQMETH_ME(register, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
+
+ EMPTY_FUNCTION_ENTRY
+};
+
+PHP_METHOD(HttpRequestMethod, __construct)
+{
+ with_error_handling(EH_THROW, PHP_HTTP_EX_CE(runtime)) {
+ char *meth_str;
+ int meth_len;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &meth_str, &meth_len)) {
+ with_error_handling(EH_THROW, PHP_HTTP_EX_CE(request_method)) {
+ zval *zarg, *zret;
+
+ if (SUCCESS == zend_get_parameters(ZEND_NUM_ARGS(), 1, &zarg)) {
+ if (zend_call_method_with_1_params(&getThis(), php_http_request_method_class_entry, NULL, "exists", &zret, zarg)) {
+ if (i_zend_is_true(zret)) {
+ zend_update_property_stringl(php_http_request_method_class_entry, getThis(), ZEND_STRL("name"), meth_str, meth_len TSRMLS_CC);
+ } else {
+ php_http_error(HE_THROW, PHP_HTTP_E_REQUEST_METHOD, "Unknown request method '%s'", meth_str);
+ }
+ zval_ptr_dtor(&zret);
+ }
+ }
+ } end_error_handling();
+ }
+ } end_error_handling();
+}
+
+PHP_METHOD(HttpRequestMethod, __toString)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ zval *retval = php_http_zsep(IS_STRING, zend_read_property(php_http_request_method_class_entry, getThis(), ZEND_STRL("name"), 0 TSRMLS_CC));
+
+ RETURN_ZVAL(retval, 0, 0);
+ }
+ RETURN_EMPTY_STRING();
+}
+
+PHP_METHOD(HttpRequestMethod, getId)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ zval **data, *meth = php_http_zsep(IS_STRING, zend_read_property(php_http_request_method_class_entry, getThis(), ZEND_STRL("name"), 0 TSRMLS_CC));
+
+ if (SUCCESS == zend_hash_find(&php_http_request_method_class_entry->constants_table, Z_STRVAL_P(meth), Z_STRLEN_P(meth) + 1, (void *) &data)) {
+ zval_ptr_dtor(&meth);
+ RETURN_ZVAL(*data, 1, 0);
+ }
+ zval_ptr_dtor(&meth);
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpRequestMethod, exists)
+{
+ char *meth_str;
+ int meth_len;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &meth_str, &meth_len)) {
+ zval **data;
+
+ if (SUCCESS == zend_hash_find(&php_http_request_method_class_entry->constants_table, meth_str, meth_len + 1, (void *) &data)) {
+ RETURN_ZVAL(*data, 1, 0);
+ }
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpRequestMethod, register)
+{
+ char *meth_str;
+ int meth_len;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &meth_str, &meth_len)) {
+ RETURN_SUCCESS(zend_declare_class_constant_long(php_http_request_method_class_entry, meth_str, meth_len, zend_hash_num_elements(&php_http_request_class_entry->constants_table) TSRMLS_CC));
+ }
+ RETURN_FALSE;
+}
+
+PHP_MINIT_FUNCTION(http_request_method)
+{
+ php_http_strlist_iterator_t std;
+
+ PHP_HTTP_REGISTER_CLASS(http\\request, Method, http_request_method, php_http_object_class_entry, 0);
+
+ zend_declare_property_null(php_http_request_method_class_entry, ZEND_STRL("name"), ZEND_ACC_PROTECTED TSRMLS_CC);
+
+ php_http_strlist_iterator_init(&std, php_http_request_methods, 1);
+ do {
+ unsigned id;
+ const char *meth = php_http_strlist_iterator_this(&std, &id);
+
+ zend_declare_class_constant_long(php_http_request_method_class_entry, meth, strlen(meth), id TSRMLS_CC);
+ } while (*php_http_strlist_iterator_next(&std));
+
+ return SUCCESS;
+}
+
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
+
--- /dev/null
+/*
+ +--------------------------------------------------------------------+
+ | PECL :: http |
+ +--------------------------------------------------------------------+
+ | Redistribution and use in source and binary forms, with or without |
+ | modification, are permitted provided that the conditions mentioned |
+ | in the accompanying LICENSE file are met. |
+ +--------------------------------------------------------------------+
+ | Copyright (c) 2004-2010, Michael Wallner <mike@php.net> |
+ +--------------------------------------------------------------------+
+*/
+
+/* $Id: php_http_request_method_api.h 292841 2009-12-31 08:48:57Z mike $ */
+
+#ifndef PHP_HTTP_REQUEST_METHOD_H
+#define PHP_HTTP_REQUEST_METHOD_H
+
+typedef enum php_http_request_method {
+ /* force the enum to be signed */
+ PHP_HTTP_NEG_REQUEST_METHOD =-1,
+ PHP_HTTP_NO_REQUEST_METHOD = 0,
+ /* HTTP/1.1 */
+ PHP_HTTP_GET = 1,
+ PHP_HTTP_HEAD = 2,
+ PHP_HTTP_POST = 3,
+ PHP_HTTP_PUT = 4,
+ PHP_HTTP_DELETE = 5,
+ PHP_HTTP_OPTIONS = 6,
+ PHP_HTTP_TRACE = 7,
+ PHP_HTTP_CONNECT = 8,
+ /* WebDAV - RFC 2518 */
+ PHP_HTTP_PROPFIND = 9,
+ PHP_HTTP_PROPPATCH = 10,
+ PHP_HTTP_MKCOL = 11,
+ PHP_HTTP_COPY = 12,
+ PHP_HTTP_MOVE = 13,
+ PHP_HTTP_LOCK = 14,
+ PHP_HTTP_UNLOCK = 15,
+ /* WebDAV Versioning - RFC 3253 */
+ PHP_HTTP_VERSION_CONTROL = 16,
+ PHP_HTTP_REPORT = 17,
+ PHP_HTTP_CHECKOUT = 18,
+ PHP_HTTP_CHECKIN = 19,
+ PHP_HTTP_UNCHECKOUT = 20,
+ PHP_HTTP_MKWORKSPACE = 21,
+ PHP_HTTP_UPDATE = 22,
+ PHP_HTTP_LABEL = 23,
+ PHP_HTTP_MERGE = 24,
+ PHP_HTTP_BASELINE_CONTROL = 25,
+ PHP_HTTP_MKACTIVITY = 26,
+ /* WebDAV Access Control - RFC 3744 */
+ PHP_HTTP_ACL = 27,
+ PHP_HTTP_MAX_REQUEST_METHOD = 28
+} php_http_request_method_t;
+
+PHP_HTTP_API const char *php_http_request_method_name(php_http_request_method_t meth);
+PHP_HTTP_API STATUS php_http_request_method_register(const char *meth_str, size_t meth_len, long *id TSRMLS_DC);
+
+extern zend_class_entry *php_http_request_method_class_entry;
+extern zend_function_entry php_http_request_method_method_entry[];
+
+extern PHP_METHOD(HttpRequestMethod, __construct);
+extern PHP_METHOD(HttpRequestMethod, __toString);
+extern PHP_METHOD(HttpRequestMethod, getId);
+
+extern PHP_METHOD(HttpRequestMethod, exists);
+extern PHP_METHOD(HttpRequestMethod, register);
+
+extern PHP_MINIT_FUNCTION(http_request_method);
+
+#endif
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
+
--- /dev/null
+
+#include "php_http.h"
+
+
+#ifndef PHP_HTTP_DEBUG_REQPOOLS
+# define PHP_HTTP_DEBUG_REQPOOLS 0
+#endif
+
+#ifdef PHP_HTTP_HAVE_EVENT
+typedef struct php_http_request_pool_event {
+ struct event evnt;
+ php_http_request_pool_t *pool;
+} php_http_request_pool_event_t;
+
+static void php_http_request_pool_timeout_callback(int socket, short action, void *event_data);
+static void php_http_request_pool_event_callback(int socket, short action, void *event_data);
+static int php_http_request_pool_socket_callback(CURL *easy, curl_socket_t s, int action, void *, void *);
+static void php_http_request_pool_timer_callback(CURLM *multi, long timeout_ms, void *timer_data);
+#endif
+
+static int php_http_request_pool_compare_handles(void *h1, void *h2);
+
+PHP_HTTP_API php_http_request_pool_t *php_http_request_pool_init(php_http_request_pool_t *pool TSRMLS_DC)
+{
+ zend_bool free_pool;
+
+#if PHP_HTTP_DEBUG_REQPOOLS
+ fprintf(stderr, "Initializing request pool %p\n", pool);
+#endif
+
+ if ((free_pool = (!pool))) {
+ pool = emalloc(sizeof(php_http_request_pool_t));
+ pool->ch = NULL;
+ }
+
+ if (SUCCESS != php_http_persistent_handle_acquire(ZEND_STRL("http_request_pool"), &pool->ch TSRMLS_CC)) {
+ if (free_pool) {
+ efree(pool);
+ }
+ return NULL;
+ }
+
+ TSRMLS_SET_CTX(pool->ts);
+
+#ifdef PHP_HTTP_HAVE_EVENT
+ pool->timeout = ecalloc(1, sizeof(struct event));
+ curl_multi_setopt(pool->ch, CURLMOPT_SOCKETDATA, pool);
+ curl_multi_setopt(pool->ch, CURLMOPT_SOCKETFUNCTION, php_http_request_pool_socket_callback);
+ curl_multi_setopt(pool->ch, CURLMOPT_TIMERDATA, pool);
+ curl_multi_setopt(pool->ch, CURLMOPT_TIMERFUNCTION, php_http_request_pool_timer_callback);
+#endif
+
+ pool->unfinished = 0;
+ zend_llist_init(&pool->finished, sizeof(zval *), (llist_dtor_func_t) ZVAL_PTR_DTOR, 0);
+ zend_llist_init(&pool->handles, sizeof(zval *), (llist_dtor_func_t) ZVAL_PTR_DTOR, 0);
+
+#if PHP_HTTP_DEBUG_REQPOOLS
+ fprintf(stderr, "Initialized request pool %p\n", pool);
+#endif
+
+ return pool;
+}
+
+PHP_HTTP_API STATUS php_http_request_pool_attach(php_http_request_pool_t *pool, zval *request)
+{
+#ifdef ZTS
+ TSRMLS_FETCH_FROM_CTX(pool->ts);
+#endif
+ php_http_request_object_t *req = zend_object_store_get_object(request TSRMLS_CC);
+
+#if PHP_HTTP_DEBUG_REQPOOLS
+ fprintf(stderr, "Attaching HttpRequest(#%d) %p to pool %p\n", Z_OBJ_HANDLE_P(request), req, pool);
+#endif
+
+ if (req->pool) {
+ php_http_error(HE_WARNING, PHP_HTTP_E_INVALID_PARAM, "HttpRequest object(#%d) is already member of %s HttpRequestPool", Z_OBJ_HANDLE_P(request), req->pool == pool ? "this" : "another");
+ } else if (SUCCESS != php_http_request_object_requesthandler(req, request)) {
+ php_http_error(HE_WARNING, PHP_HTTP_E_REQUEST, "Could not initialize HttpRequest object(#%d) for attaching to the HttpRequestPool", Z_OBJ_HANDLE_P(request));
+ } else {
+ CURLMcode code = curl_multi_add_handle(pool->ch, req->request->ch);
+
+ if (CURLM_OK != code) {
+ php_http_error(HE_WARNING, PHP_HTTP_E_REQUEST_POOL, "Could not attach HttpRequest object(#%d) to the HttpRequestPool: %s", Z_OBJ_HANDLE_P(request), curl_multi_strerror(code));
+ } else {
+ req->pool = pool;
+
+ Z_ADDREF_P(request);
+ zend_llist_add_element(&pool->handles, &request);
+ ++pool->unfinished;
+
+#if PHP_HTTP_DEBUG_REQPOOLS
+ fprintf(stderr, "> %d HttpRequests attached to pool %p\n", zend_llist_count(&pool->handles), pool);
+#endif
+ return SUCCESS;
+ }
+ }
+ return FAILURE;
+}
+
+PHP_HTTP_API STATUS php_http_request_pool_detach(php_http_request_pool_t *pool, zval *request)
+{
+ CURLMcode code;
+#ifdef ZTS
+ TSRMLS_FETCH_FROM_CTX(pool->ts);
+#endif
+ php_http_request_object_t *req = zend_object_store_get_object(request TSRMLS_CC);
+
+#if PHP_HTTP_DEBUG_REQPOOLS
+ fprintf(stderr, "Detaching HttpRequest(#%d) %p from pool %p\n", Z_OBJ_HANDLE_P(request), req, pool);
+#endif
+
+ if (!req->pool) {
+ /* not attached to any pool */
+#if PHP_HTTP_DEBUG_REQPOOLS
+ fprintf(stderr, "HttpRequest object(#%d) %p is not attached to any HttpRequestPool\n", Z_OBJ_HANDLE_P(request), req);
+#endif
+ } else if (req->pool != pool) {
+ php_http_error(HE_WARNING, PHP_HTTP_E_INVALID_PARAM, "HttpRequest object(#%d) is not attached to this HttpRequestPool", Z_OBJ_HANDLE_P(request));
+ } else if (req->request->_progress.in_cb) {
+ php_http_error(HE_WARNING, PHP_HTTP_E_REQUEST_POOL, "HttpRequest object(#%d) cannot be detached from the HttpRequestPool while executing the progress callback", Z_OBJ_HANDLE_P(request));
+ } else if (CURLM_OK != (code = curl_multi_remove_handle(pool->ch, req->request->ch))) {
+ php_http_error(HE_WARNING, PHP_HTTP_E_REQUEST_POOL, "Could not detach HttpRequest object(#%d) from the HttpRequestPool: %s", Z_OBJ_HANDLE_P(request), curl_multi_strerror(code));
+ } else {
+ req->pool = NULL;
+ zend_llist_del_element(&pool->finished, request, php_http_request_pool_compare_handles);
+ zend_llist_del_element(&pool->handles, request, php_http_request_pool_compare_handles);
+
+#if PHP_HTTP_DEBUG_REQPOOLS
+ fprintf(stderr, "> %d HttpRequests remaining in pool %p\n", zend_llist_count(&pool->handles), pool);
+#endif
+
+ return SUCCESS;
+ }
+ return FAILURE;
+}
+
+PHP_HTTP_API void php_http_request_pool_apply(php_http_request_pool_t *pool, php_http_request_pool_apply_func_t cb)
+{
+ int count = zend_llist_count(&pool->handles);
+
+ if (count) {
+ int i = 0;
+ zend_llist_position pos;
+ zval **handle, **handles = emalloc(count * sizeof(zval *));
+
+ for (handle = zend_llist_get_first_ex(&pool->handles, &pos); handle; handle = zend_llist_get_next_ex(&pool->handles, &pos)) {
+ handles[i++] = *handle;
+ }
+
+ /* should never happen */
+ if (i != count) {
+ zend_error(E_ERROR, "number of fetched request handles do not match overall count");
+ count = i;
+ }
+
+ for (i = 0; i < count; ++i) {
+ if (cb(pool, handles[i])) {
+ break;
+ }
+ }
+ efree(handles);
+ }
+}
+
+PHP_HTTP_API void php_http_request_pool_apply_with_arg(php_http_request_pool_t *pool, php_http_request_pool_apply_with_arg_func_t cb, void *arg)
+{
+ int count = zend_llist_count(&pool->handles);
+
+ if (count) {
+ int i = 0;
+ zend_llist_position pos;
+ zval **handle, **handles = emalloc(count * sizeof(zval *));
+
+ for (handle = zend_llist_get_first_ex(&pool->handles, &pos); handle; handle = zend_llist_get_next_ex(&pool->handles, &pos)) {
+ handles[i++] = *handle;
+ }
+
+ /* should never happen */
+ if (i != count) {
+ zend_error(E_ERROR, "number of fetched request handles do not match overall count");
+ count = i;
+ }
+
+ for (i = 0; i < count; ++i) {
+ if (cb(pool, handles[i], arg)) {
+ break;
+ }
+ }
+ efree(handles);
+ }
+}
+
+PHP_HTTP_API void php_http_request_pool_detach_all(php_http_request_pool_t *pool)
+{
+#if PHP_HTTP_DEBUG_REQPOOLS
+ fprintf(stderr, "Detaching %d requests from pool %p\n", zend_llist_count(&pool->handles), pool);
+#endif
+ php_http_request_pool_apply(pool, php_http_request_pool_detach);
+}
+
+PHP_HTTP_API STATUS php_http_request_pool_send(php_http_request_pool_t *pool)
+{
+ TSRMLS_FETCH_FROM_CTX(pool->ts);
+
+#if PHP_HTTP_DEBUG_REQPOOLS
+ fprintf(stderr, "Attempt to send %d requests of pool %p\n", zend_llist_count(&pool->handles), pool);
+#endif
+
+#ifdef PHP_HTTP_HAVE_EVENT
+ if (pool->useevents) {
+ do {
+#if PHP_HTTP_DEBUG_REQPOOLS
+ fprintf(stderr, "& Starting event dispatcher of pool %p\n", pool);
+#endif
+ event_base_dispatch(PHP_HTTP_G->request_pool.event_base);
+ } while (pool->unfinished);
+ } else
+#endif
+ {
+ while (php_http_request_pool_perform(pool)) {
+ if (SUCCESS != php_http_request_pool_select(pool, NULL)) {
+#ifdef PHP_WIN32
+ /* see http://msdn.microsoft.com/library/en-us/winsock/winsock/windows_sockets_error_codes_2.asp */
+ php_http_error(HE_WARNING, PHP_HTTP_E_SOCKET, "WinSock error: %d", WSAGetLastError());
+#else
+ php_http_error(HE_WARNING, PHP_HTTP_E_SOCKET, strerror(errno));
+#endif
+ return FAILURE;
+ }
+ }
+ }
+
+#if PHP_HTTP_DEBUG_REQPOOLS
+ fprintf(stderr, "Finished sending %d HttpRequests of pool %p (still unfinished: %d)\n", zend_llist_count(&pool->handles), pool, pool->unfinished);
+#endif
+
+ return SUCCESS;
+}
+
+PHP_HTTP_API void php_http_request_pool_dtor(php_http_request_pool_t *pool)
+{
+ TSRMLS_FETCH_FROM_CTX(pool->ts);
+
+#if PHP_HTTP_DEBUG_REQPOOLS
+ fprintf(stderr, "Destructing request pool %p\n", pool);
+#endif
+
+#ifdef PHP_HTTP_HAVE_EVENT
+ efree(pool->timeout);
+#endif
+
+ php_http_request_pool_detach_all(pool);
+
+ pool->unfinished = 0;
+ zend_llist_clean(&pool->finished);
+ zend_llist_clean(&pool->handles);
+ php_http_persistent_handle_release(ZEND_STRL("php_http_request_pool_t"), &pool->ch TSRMLS_CC);
+}
+
+PHP_HTTP_API void php_http_request_pool_free(php_http_request_pool_t **pool) {
+ if (*pool) {
+ php_http_request_pool_dtor(*pool);
+ efree(*pool);
+ *pool = NULL;
+ }
+}
+
+#ifdef PHP_WIN32
+# define SELECT_ERROR SOCKET_ERROR
+#else
+# define SELECT_ERROR -1
+#endif
+
+PHP_HTTP_API STATUS php_http_request_pool_select(php_http_request_pool_t *pool, struct timeval *custom_timeout)
+{
+ int MAX;
+ fd_set R, W, E;
+ struct timeval timeout;
+
+#ifdef PHP_HTTP_HAVE_EVENT
+ if (pool->useevents) {
+ TSRMLS_FETCH_FROM_CTX(pool->ts);
+ php_http_error(HE_WARNING, PHP_HTTP_E_RUNTIME, "not implemented; use HttpRequest callbacks");
+ return FAILURE;
+ }
+#endif
+
+ if (custom_timeout && timerisset(custom_timeout)) {
+ timeout = *custom_timeout;
+ } else {
+ php_http_request_pool_timeout(pool, &timeout);
+ }
+
+ FD_ZERO(&R);
+ FD_ZERO(&W);
+ FD_ZERO(&E);
+
+ if (CURLM_OK == curl_multi_fdset(pool->ch, &R, &W, &E, &MAX)) {
+ if (MAX == -1) {
+ php_http_sleep((double) timeout.tv_sec + (double) (timeout.tv_usec / PHP_HTTP_MCROSEC));
+ return SUCCESS;
+ } else if (SELECT_ERROR != select(MAX + 1, &R, &W, &E, &timeout)) {
+ return SUCCESS;
+ }
+ }
+ return FAILURE;
+}
+
+PHP_HTTP_API int php_http_request_pool_perform(php_http_request_pool_t *pool)
+{
+ TSRMLS_FETCH_FROM_CTX(pool->ts);
+
+#ifdef PHP_HTTP_HAVE_EVENT
+ if (pool->useevents) {
+ php_http_error(HE_WARNING, PHP_HTTP_E_RUNTIME, "not implemented; use HttpRequest callbacks");
+ return FAILURE;
+ }
+#endif
+
+ while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(pool->ch, &pool->unfinished));
+
+#if PHP_HTTP_DEBUG_REQPOOLS
+ fprintf(stderr, "%u unfinished requests of pool %p remaining\n", pool->unfinished, pool);
+#endif
+
+ php_http_request_pool_responsehandler(pool);
+
+ return pool->unfinished;
+}
+
+void php_http_request_pool_responsehandler(php_http_request_pool_t *pool)
+{
+ CURLMsg *msg;
+ int remaining = 0;
+ TSRMLS_FETCH_FROM_CTX(pool->ts);
+
+ do {
+ msg = curl_multi_info_read(pool->ch, &remaining);
+ if (msg && CURLMSG_DONE == msg->msg) {
+ if (CURLE_OK != msg->data.result) {
+ php_http_request_storage_t *st = php_http_request_storage_get(msg->easy_handle);
+ php_http_error(HE_WARNING, PHP_HTTP_E_REQUEST, "%s; %s (%s)", curl_easy_strerror(msg->data.result), STR_PTR(st->errorbuffer), STR_PTR(st->url));
+ }
+ php_http_request_pool_apply_with_arg(pool, php_http_request_pool_apply_responsehandler, msg->easy_handle);
+ }
+ } while (remaining);
+}
+
+int php_http_request_pool_apply_responsehandler(php_http_request_pool_t *pool, zval *req, void *ch)
+{
+#ifdef ZTS
+ TSRMLS_FETCH_FROM_CTX(pool->ts);
+#endif
+ php_http_request_object_t *obj = zend_object_store_get_object(req TSRMLS_CC);
+
+ if ((!ch) || obj->request->ch == (CURL *) ch) {
+
+#if PHP_HTTP_DEBUG_REQPOOLS
+ fprintf(stderr, "Fetching data from HttpRequest(#%d) %p of pool %p\n", Z_OBJ_HANDLE_P(req), obj, obj->pool);
+#endif
+
+ Z_ADDREF_P(req);
+ zend_llist_add_element(&obj->pool->finished, &req);
+ php_http_request_object_responsehandler(obj, req);
+ return 1;
+ }
+ return 0;
+}
+
+struct timeval *php_http_request_pool_timeout(php_http_request_pool_t *pool, struct timeval *timeout)
+{
+#ifdef HAVE_CURL_MULTI_TIMEOUT
+ long max_tout = 1000;
+
+ if ((CURLM_OK == curl_multi_timeout(pool->ch, &max_tout)) && (max_tout > 0)) {
+ timeout->tv_sec = max_tout / 1000;
+ timeout->tv_usec = (max_tout % 1000) * 1000;
+ } else {
+#endif
+ timeout->tv_sec = 0;
+ timeout->tv_usec = 1000;
+#ifdef HAVE_CURL_MULTI_TIMEOUT
+ }
+#endif
+
+#if PHP_HTTP_DEBUG_REQPOOLS
+ fprintf(stderr, "Calculating timeout (%lu, %lu) of pool %p\n", (ulong) timeout->tv_sec, (ulong) timeout->tv_usec, pool);
+#endif
+
+ return timeout;
+}
+
+/*#*/
+
+static int php_http_request_pool_compare_handles(void *h1, void *h2)
+{
+ return (Z_OBJ_HANDLE_PP((zval **) h1) == Z_OBJ_HANDLE_P((zval *) h2));
+}
+
+#ifdef PHP_HTTP_HAVE_EVENT
+
+static void php_http_request_pool_timeout_callback(int socket, short action, void *event_data)
+{
+ php_http_request_pool_t *pool = event_data;
+
+ if (pool->useevents) {
+ CURLMcode rc;
+ TSRMLS_FETCH_FROM_CTX(pool->ts);
+
+#if PHP_HTTP_DEBUG_REQPOOLS
+ fprintf(stderr, "Timeout occurred of pool %p\n", pool);
+#endif
+
+ while (CURLM_CALL_MULTI_PERFORM == (rc = curl_multi_socket(pool->ch, CURL_SOCKET_TIMEOUT, &pool->unfinished)));
+
+ if (CURLM_OK != rc) {
+ php_http_error(HE_WARNING, PHP_HTTP_E_SOCKET, curl_multi_strerror(rc));
+ }
+
+ php_http_request_pool_responsehandler(pool);
+ }
+}
+
+static void php_http_request_pool_event_callback(int socket, short action, void *event_data)
+{
+ php_http_request_pool_event_t *ev = event_data;
+ php_http_request_pool_t *pool = ev->pool;
+
+ if (pool->useevents) {
+ CURLMcode rc = CURLE_OK;
+ TSRMLS_FETCH_FROM_CTX(ev->pool->ts);
+
+#if PHP_HTTP_DEBUG_REQPOOLS
+ {
+ static const char event_strings[][20] = {"NONE","TIMEOUT","READ","TIMEOUT|READ","WRITE","TIMEOUT|WRITE","READ|WRITE","TIMEOUT|READ|WRITE","SIGNAL"};
+ fprintf(stderr, "Event on socket %d (%s) event %p of pool %p\n", socket, event_strings[action], ev, pool);
+ }
+#endif
+
+ /* don't use 'ev' below this loop as it might 've been freed in the socket callback */
+ do {
+#ifdef HAVE_CURL_MULTI_SOCKET_ACTION
+ switch (action & (EV_READ|EV_WRITE)) {
+ case EV_READ:
+ rc = curl_multi_socket_action(pool->ch, socket, CURL_CSELECT_IN, &pool->unfinished);
+ break;
+ case EV_WRITE:
+ rc = curl_multi_socket_action(pool->ch, socket, CURL_CSELECT_OUT, &pool->unfinished);
+ break;
+ case EV_READ|EV_WRITE:
+ rc = curl_multi_socket_action(pool->ch, socket, CURL_CSELECT_IN|CURL_CSELECT_OUT, &pool->unfinished);
+ break;
+ default:
+ php_http_error(HE_WARNING, PHP_HTTP_E_SOCKET, "Unknown event %d", (int) action);
+ return;
+ }
+#else
+ rc = curl_multi_socket(pool->ch, socket, &pool->unfinished);
+#endif
+ } while (CURLM_CALL_MULTI_PERFORM == rc);
+
+ switch (rc) {
+ case CURLM_BAD_SOCKET:
+#if 0
+ fprintf(stderr, "!!! Bad socket: %d (%d)\n", socket, (int) action);
+#endif
+ case CURLM_OK:
+ break;
+ default:
+ php_http_error(HE_WARNING, PHP_HTTP_E_SOCKET, curl_multi_strerror(rc));
+ break;
+ }
+
+ php_http_request_pool_responsehandler(pool);
+
+ /* remove timeout if there are no transfers left */
+ if (!pool->unfinished && event_initialized(pool->timeout) && event_pending(pool->timeout, EV_TIMEOUT, NULL)) {
+ event_del(pool->timeout);
+#if PHP_HTTP_DEBUG_REQPOOLS
+ fprintf(stderr, "Removed timeout of pool %p\n", pool);
+#endif
+ }
+ }
+}
+
+static int php_http_request_pool_socket_callback(CURL *easy, curl_socket_t sock, int action, void *socket_data, void *assign_data)
+{
+ php_http_request_pool_t *pool = socket_data;
+
+ if (pool->useevents) {
+ int events = EV_PERSIST;
+ php_http_request_pool_event_t *ev = assign_data;
+ TSRMLS_FETCH_FROM_CTX(pool->ts);
+
+ if (!ev) {
+ ev = ecalloc(1, sizeof(php_http_request_pool_event_t));
+ ev->pool = pool;
+ curl_multi_assign(pool->ch, sock, ev);
+ event_base_set(PHP_HTTP_G->request_pool.event_base, &ev->evnt);
+ } else {
+ event_del(&ev->evnt);
+ }
+
+#if PHP_HTTP_DEBUG_REQPOOLS
+ {
+ static const char action_strings[][8] = {"NONE", "IN", "OUT", "INOUT", "REMOVE"};
+ php_http_request_t *r;
+ curl_easy_getinfo(easy, CURLINFO_PRIVATE, &r);
+ fprintf(stderr, "Callback on socket %2d (%8s) event %p of pool %p (%d)\n", (int) sock, action_strings[action], ev, pool, pool->unfinished);
+ }
+#endif
+
+ switch (action) {
+ case CURL_POLL_IN:
+ events |= EV_READ;
+ break;
+ case CURL_POLL_OUT:
+ events |= EV_WRITE;
+ break;
+ case CURL_POLL_INOUT:
+ events |= EV_READ|EV_WRITE;
+ break;
+
+ case CURL_POLL_REMOVE:
+ efree(ev);
+ case CURL_POLL_NONE:
+ return 0;
+
+ default:
+ php_http_error(HE_WARNING, PHP_HTTP_E_SOCKET, "Unknown socket action %d", action);
+ return -1;
+ }
+
+ event_set(&ev->evnt, sock, events, php_http_request_pool_event_callback, ev);
+ event_add(&ev->evnt, NULL);
+ }
+
+ return 0;
+}
+
+static void php_http_request_pool_timer_callback(CURLM *multi, long timeout_ms, void *timer_data)
+{
+ php_http_request_pool_t *pool = timer_data;
+
+ if (pool->useevents) {
+ TSRMLS_FETCH_FROM_CTX(pool->ts);
+ struct timeval timeout;
+
+ if (!event_initialized(pool->timeout)) {
+ event_set(pool->timeout, -1, 0, php_http_request_pool_timeout_callback, pool);
+ event_base_set(PHP_HTTP_G->request_pool.event_base, pool->timeout);
+ } else if (event_pending(pool->timeout, EV_TIMEOUT, NULL)) {
+ event_del(pool->timeout);
+ }
+
+ if (timeout_ms > 0) {
+ timeout.tv_sec = timeout_ms / 1000;
+ timeout.tv_usec = (timeout_ms % 1000) * 1000;
+ } else {
+ php_http_request_pool_timeout(pool, &timeout);
+ }
+
+ event_add(pool->timeout, &timeout);
+
+#if PHP_HTTP_DEBUG_REQPOOLS
+ fprintf(stderr, "Updating timeout %lu (%lu, %lu) of pool %p\n", (ulong) timeout_ms, (ulong) timeout.tv_sec, (ulong) timeout.tv_usec, pool);
+#endif
+ }
+}
+#endif /* HAVE_EVENT */
+
+#define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpRequestPool, method, 0, req_args)
+#define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpRequestPool, method, 0)
+#define PHP_HTTP_REQPOOL_ME(method, visibility) PHP_ME(HttpRequestPool, method, PHP_HTTP_ARGS(HttpRequestPool, method), visibility)
+
+PHP_HTTP_EMPTY_ARGS(__construct);
+
+PHP_HTTP_EMPTY_ARGS(__destruct);
+PHP_HTTP_EMPTY_ARGS(reset);
+
+PHP_HTTP_BEGIN_ARGS(attach, 1)
+ PHP_HTTP_ARG_OBJ(http\\Request, request, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(detach, 1)
+ PHP_HTTP_ARG_OBJ(http\\Request, request, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_EMPTY_ARGS(send);
+PHP_HTTP_EMPTY_ARGS(socketPerform);
+PHP_HTTP_BEGIN_ARGS(socketSelect, 0)
+ PHP_HTTP_ARG_VAL(timeout, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_EMPTY_ARGS(valid);
+PHP_HTTP_EMPTY_ARGS(current);
+PHP_HTTP_EMPTY_ARGS(key);
+PHP_HTTP_EMPTY_ARGS(next);
+PHP_HTTP_EMPTY_ARGS(rewind);
+
+PHP_HTTP_EMPTY_ARGS(count);
+
+PHP_HTTP_EMPTY_ARGS(getAttachedRequests);
+PHP_HTTP_EMPTY_ARGS(getFinishedRequests);
+
+PHP_HTTP_BEGIN_ARGS(enablePipelining, 0)
+ PHP_HTTP_ARG_VAL(enable, 0)
+PHP_HTTP_END_ARGS;
+
+PHP_HTTP_BEGIN_ARGS(enableEvents, 0)
+ PHP_HTTP_ARG_VAL(enable, 0)
+PHP_HTTP_END_ARGS;
+
+zend_class_entry *php_http_request_pool_class_entry;
+zend_function_entry php_http_request_pool_method_entry[] = {
+ PHP_HTTP_REQPOOL_ME(__construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
+ PHP_HTTP_REQPOOL_ME(__destruct, ZEND_ACC_PUBLIC|ZEND_ACC_DTOR)
+ PHP_HTTP_REQPOOL_ME(attach, ZEND_ACC_PUBLIC)
+ PHP_HTTP_REQPOOL_ME(detach, ZEND_ACC_PUBLIC)
+ PHP_HTTP_REQPOOL_ME(send, ZEND_ACC_PUBLIC)
+ PHP_HTTP_REQPOOL_ME(reset, ZEND_ACC_PUBLIC)
+
+ PHP_HTTP_REQPOOL_ME(socketPerform, ZEND_ACC_PROTECTED)
+ PHP_HTTP_REQPOOL_ME(socketSelect, ZEND_ACC_PROTECTED)
+
+ /* implements Iterator */
+ PHP_HTTP_REQPOOL_ME(valid, ZEND_ACC_PUBLIC)
+ PHP_HTTP_REQPOOL_ME(current, ZEND_ACC_PUBLIC)
+ PHP_HTTP_REQPOOL_ME(key, ZEND_ACC_PUBLIC)
+ PHP_HTTP_REQPOOL_ME(next, ZEND_ACC_PUBLIC)
+ PHP_HTTP_REQPOOL_ME(rewind, ZEND_ACC_PUBLIC)
+
+ /* implmenents Countable */
+ PHP_HTTP_REQPOOL_ME(count, ZEND_ACC_PUBLIC)
+
+ PHP_HTTP_REQPOOL_ME(getAttachedRequests, ZEND_ACC_PUBLIC)
+ PHP_HTTP_REQPOOL_ME(getFinishedRequests, ZEND_ACC_PUBLIC)
+
+ PHP_HTTP_REQPOOL_ME(enablePipelining, ZEND_ACC_PUBLIC)
+ PHP_HTTP_REQPOOL_ME(enableEvents, ZEND_ACC_PUBLIC)
+
+ EMPTY_FUNCTION_ENTRY
+};
+static zend_object_handlers php_http_request_pool_object_handlers;
+
+zend_object_value php_http_request_pool_object_new(zend_class_entry *ce TSRMLS_DC)
+{
+ zend_object_value ov;
+ php_http_request_pool_object_t *o;
+
+ o = ecalloc(1, sizeof(php_http_request_pool_object_t));
+ zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
+ object_properties_init((zend_object *) o, ce);
+
+ php_http_request_pool_init(&o->pool TSRMLS_CC);
+
+ ov.handle = zend_objects_store_put(o, NULL, php_http_request_pool_object_free, NULL TSRMLS_CC);
+ ov.handlers = &php_http_request_pool_object_handlers;
+
+ return ov;
+}
+
+void php_http_request_pool_object_free(void *object TSRMLS_DC)
+{
+ php_http_request_pool_object_t *o = (php_http_request_pool_object_t *) object;
+
+ php_http_request_pool_dtor(&o->pool);
+ zend_object_std_dtor((zend_object *) o TSRMLS_CC);
+ efree(o);
+}
+
+static void php_http_request_pool_object_llist2array(zval **req, zval *array TSRMLS_DC)
+{
+ Z_ADDREF_P(*req);
+ add_next_index_zval(array, *req);
+}
+
+/* ### USERLAND ### */
+
+PHP_METHOD(HttpRequestPool, __construct)
+{
+ with_error_handling(EH_THROW, PHP_HTTP_EX_CE(runtime)) {
+ int argc;
+ zval ***argv;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "*", &argv, &argc)) {
+ with_error_handling(EH_THROW, PHP_HTTP_EX_CE(request_pool)) {
+ int i;
+ php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ for (i = 0; i < argc; ++i) {
+ if (Z_TYPE_PP(argv[i]) == IS_OBJECT && instanceof_function(Z_OBJCE_PP(argv[i]), php_http_request_class_entry TSRMLS_CC)) {
+ php_http_request_pool_attach(&obj->pool, *(argv[i]));
+ }
+ }
+ } end_error_handling();
+ }
+ } end_error_handling();
+}
+
+PHP_METHOD(HttpRequestPool, __destruct)
+{
+ php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (SUCCESS != zend_parse_parameters_none()) {
+ ; /* we always want to clean up */
+ }
+
+ php_http_request_pool_detach_all(&obj->pool);
+}
+
+PHP_METHOD(HttpRequestPool, reset)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ obj->iterator.pos = 0;
+ php_http_request_pool_detach_all(&obj->pool);
+ RETURN_TRUE;
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpRequestPool, attach)
+{
+ RETVAL_FALSE;
+
+ with_error_handling(EH_THROW, PHP_HTTP_EX_CE(runtime)) {
+ zval *request;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &request, php_http_request_class_entry)) {
+ with_error_handling(EH_THROW, PHP_HTTP_EX_CE(runtime)) {
+ php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (obj->iterator.pos > 0 && obj->iterator.pos < zend_llist_count(&obj->pool.handles)) {
+ php_http_error(HE_THROW, PHP_HTTP_E_REQUEST_POOL, "Cannot attach to the HttpRequestPool while the iterator is active");
+ } else {
+ RETVAL_SUCCESS(php_http_request_pool_attach(&obj->pool, request));
+ }
+ } end_error_handling();
+ }
+ } end_error_handling();
+}
+
+PHP_METHOD(HttpRequestPool, detach)
+{
+ RETVAL_FALSE;
+
+ with_error_handling(EH_THROW, PHP_HTTP_EX_CE(runtime)) {
+ zval *request;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &request, php_http_request_class_entry)) {
+ with_error_handling(EH_THROW, PHP_HTTP_EX_CE(request_pool)) {
+ php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ obj->iterator.pos = -1;
+ RETVAL_SUCCESS(php_http_request_pool_detach(&obj->pool, request));
+ } end_error_handling();
+ }
+ } end_error_handling();
+}
+
+PHP_METHOD(HttpRequestPool, send)
+{
+ RETVAL_FALSE;
+
+ with_error_handling(EH_THROW, PHP_HTTP_EX_CE(runtime)) {
+ if (SUCCESS == zend_parse_parameters_none()) {
+ with_error_handling(EH_THROW, PHP_HTTP_EX_CE(request_pool)) {
+ php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ RETVAL_SUCCESS(php_http_request_pool_send(&obj->pool));
+ } end_error_handling();
+ }
+ } end_error_handling();
+}
+
+PHP_METHOD(HttpRequestPool, socketPerform)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (0 < php_http_request_pool_perform(&obj->pool)) {
+ RETURN_TRUE;
+ }
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpRequestPool, socketSelect)
+{
+ double timeout = 0;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|d", &timeout)) {
+ struct timeval timeout_val;
+ php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ timeout_val.tv_sec = (time_t) timeout;
+ timeout_val.tv_usec = PHP_HTTP_USEC(timeout) % PHP_HTTP_MCROSEC;
+
+ RETURN_SUCCESS(php_http_request_pool_select(&obj->pool, timeout ? &timeout_val : NULL));
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpRequestPool, valid)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ RETURN_BOOL(obj->iterator.pos >= 0 && obj->iterator.pos < zend_llist_count(&obj->pool.handles));
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpRequestPool, current)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (obj->iterator.pos < zend_llist_count(&obj->pool.handles)) {
+ long pos = 0;
+ zval **current = NULL;
+ zend_llist_position lpos;
+
+ for ( current = zend_llist_get_first_ex(&obj->pool.handles, &lpos);
+ current && obj->iterator.pos != pos++;
+ current = zend_llist_get_next_ex(&obj->pool.handles, &lpos));
+ if (current) {
+ RETURN_OBJECT(*current, 1);
+ }
+ }
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpRequestPool, key)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ RETURN_LONG(obj->iterator.pos);
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpRequestPool, next)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ ++obj->iterator.pos;
+ }
+}
+
+PHP_METHOD(HttpRequestPool, rewind)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ obj->iterator.pos = 0;
+ }
+}
+
+PHP_METHOD(HttpRequestPool, count)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ RETURN_LONG((long) zend_llist_count(&obj->pool.handles));
+ }
+}
+
+PHP_METHOD(HttpRequestPool, getAttachedRequests)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ array_init(return_value);
+ zend_llist_apply_with_argument(&obj->pool.handles,
+ (llist_apply_with_arg_func_t) php_http_request_pool_object_llist2array,
+ return_value TSRMLS_CC);
+ return;
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpRequestPool, getFinishedRequests)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ array_init(return_value);
+ zend_llist_apply_with_argument(&obj->pool.finished,
+ (llist_apply_with_arg_func_t) php_http_request_pool_object_llist2array,
+ return_value TSRMLS_CC);
+ return;
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpRequestPool, enablePipelining)
+{
+ zend_bool enable = 1;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &enable)) {
+ php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (CURLM_OK == curl_multi_setopt(obj->pool.ch, CURLMOPT_PIPELINING, (long) enable)) {
+ RETURN_TRUE;
+ }
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(HttpRequestPool, enableEvents)
+{
+ zend_bool enable = 1;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &enable)) {
+#if PHP_HTTP_HAVE_EVENT
+ php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ obj->pool.useevents = enable;
+ RETURN_TRUE;
+#endif
+ }
+ RETURN_FALSE;
+}
+
+PHP_MINIT_FUNCTION(http_request_pool)
+{
+ if (SUCCESS != php_http_persistent_handle_provide(ZEND_STRL("http_request_pool"), curl_multi_init, (php_http_persistent_handle_dtor_t) curl_multi_cleanup, NULL TSRMLS_CC)) {
+ return FAILURE;
+ }
+
+ PHP_HTTP_REGISTER_CLASS(http\\request, Pool, http_request_pool, php_http_object_class_entry, 0);
+ php_http_request_pool_class_entry->create_object = php_http_request_pool_object_new;
+ memcpy(&php_http_request_pool_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
+ php_http_request_pool_object_handlers.clone_obj = NULL;
+
+ zend_class_implements(php_http_request_pool_class_entry TSRMLS_CC, 2, spl_ce_Countable, zend_ce_iterator);
+
+ return SUCCESS;
+}
+
+PHP_RINIT_FUNCTION(http_request_pool)
+{
+#ifdef PHP_HTTP_HAVE_EVENT
+ if (!PHP_HTTP_G->request_pool.event_base && !(PHP_HTTP_G->request_pool.event_base = event_init())) {
+ return FAILURE;
+ }
+#endif
+
+ return SUCCESS;
+}
+
+
--- /dev/null
+
+#ifndef PHP_HTTP_REQUESTPOOL_H
+#define PHP_HTTP_REQUESTPOOL_H
+
+struct php_http_request_pool_globals {
+ void *event_base;
+};
+
+typedef struct php_http_request_pool {
+ CURLM *ch;
+ zend_llist finished;
+ zend_llist handles;
+ int unfinished; /* int because of curl_multi_perform() */
+#ifdef ZTS
+ void ***ts;
+#endif
+#ifdef PHP_HTTP_HAVE_EVENT
+ struct event *timeout;
+ unsigned useevents:1;
+ unsigned runsocket:1;
+#endif
+} php_http_request_pool_t;
+
+typedef int (*php_http_request_pool_apply_func_t)(php_http_request_pool_t *pool, zval *request);
+typedef int (*php_http_request_pool_apply_with_arg_func_t)(php_http_request_pool_t *pool, zval *request, void *arg);
+
+#ifdef PHP_HTTP_HAVE_EVENT
+PHP_RINIT_FUNCTION(php_http_request_pool);
+#endif
+
+extern struct timeval *php_http_request_pool_timeout(php_http_request_pool_t *pool, struct timeval *timeout);
+extern void php_http_request_pool_responsehandler(php_http_request_pool_t *pool);
+extern int php_http_request_pool_apply_responsehandler(php_http_request_pool_t *pool, zval *req, void *ch);
+
+PHP_HTTP_API php_http_request_pool_t *php_http_request_pool_init(php_http_request_pool_t *pool TSRMLS_DC);
+PHP_HTTP_API STATUS php_http_request_pool_attach(php_http_request_pool_t *pool, zval *request);
+PHP_HTTP_API STATUS php_http_request_pool_detach(php_http_request_pool_t *pool, zval *request);
+PHP_HTTP_API void php_http_request_pool_apply(php_http_request_pool_t *pool, php_http_request_pool_apply_func_t cb);
+PHP_HTTP_API void php_http_request_pool_apply_with_arg(php_http_request_pool_t *pool, php_http_request_pool_apply_with_arg_func_t cb, void *arg);
+PHP_HTTP_API void php_http_request_pool_detach_all(php_http_request_pool_t *pool);
+PHP_HTTP_API STATUS php_http_request_pool_send(php_http_request_pool_t *pool);
+PHP_HTTP_API STATUS php_http_request_pool_select(php_http_request_pool_t *pool, struct timeval *custom_timeout);
+PHP_HTTP_API int php_http_request_pool_perform(php_http_request_pool_t *pool);
+PHP_HTTP_API void php_http_request_pool_dtor(php_http_request_pool_t *pool);
+PHP_HTTP_API void php_http_request_pool_free(php_http_request_pool_t **pool);
+
+typedef struct php_http_request_pool_object {
+ zend_object zo;
+ php_http_request_pool_t pool;
+ struct {
+ long pos;
+ } iterator;
+} php_http_request_pool_object_t;
+
+extern zend_class_entry *php_http_request_pool_class_entry;
+extern zend_function_entry php_http_request_pool_method_entry[];
+
+extern zend_object_value php_http_request_pool_object_new(zend_class_entry *ce TSRMLS_DC);
+extern void php_http_request_pool_object_free(void *object TSRMLS_DC);
+
+PHP_METHOD(HttpRequestPool, __construct);
+PHP_METHOD(HttpRequestPool, __destruct);
+PHP_METHOD(HttpRequestPool, attach);
+PHP_METHOD(HttpRequestPool, detach);
+PHP_METHOD(HttpRequestPool, send);
+PHP_METHOD(HttpRequestPool, reset);
+PHP_METHOD(HttpRequestPool, socketPerform);
+PHP_METHOD(HttpRequestPool, socketSelect);
+PHP_METHOD(HttpRequestPool, valid);
+PHP_METHOD(HttpRequestPool, current);
+PHP_METHOD(HttpRequestPool, key);
+PHP_METHOD(HttpRequestPool, next);
+PHP_METHOD(HttpRequestPool, rewind);
+PHP_METHOD(HttpRequestPool, count);
+PHP_METHOD(HttpRequestPool, getAttachedRequests);
+PHP_METHOD(HttpRequestPool, getFinishedRequests);
+PHP_METHOD(HttpRequestPool, enablePipelining);
+PHP_METHOD(HttpRequestPool, enableEvents);
+
+PHP_MINIT_FUNCTION(http_request_pool);
+PHP_RINIT_FUNCTION(http_request_pool);
+
+#endif /* PHP_HTTP_REQUESTPOOL_H */
--- /dev/null
+
+#include "php_http.h"
+
+PHP_HTTP_API php_http_strlist_iterator_t *php_http_strlist_iterator_init(php_http_strlist_iterator_t *iter, const char list[], unsigned factor)
+{
+ if (!iter) {
+ iter = emalloc(sizeof(*iter));
+ }
+ memset(iter, 0, sizeof(*iter));
+
+ iter->p = &list[0];
+ iter->factor = factor;
+
+ return iter;
+}
+
+PHP_HTTP_API const char *php_http_strlist_iterator_this(php_http_strlist_iterator_t *iter, unsigned *id)
+{
+ if (id) {
+ *id = iter->major * iter->factor + iter->minor;
+ }
+
+ return iter->p;
+}
+
+PHP_HTTP_API const char *php_http_strlist_iterator_next(php_http_strlist_iterator_t *iter)
+{
+ if (*iter->p) {
+ while (*iter->p) {
+ ++iter->p;
+ }
+ ++iter->p;
+ ++iter->minor;
+
+ if (!*iter->p) {
+ ++iter->p;
+ ++iter->major;
+ }
+ }
+
+ return iter->p;
+}
+
+PHP_HTTP_API void php_http_strlist_iterator_dtor(php_http_strlist_iterator_t *iter)
+{
+
+}
+
+PHP_HTTP_API void php_http_strlist_iterator_free(php_http_strlist_iterator_t **iter)
+{
+ if (*iter) {
+ efree(*iter);
+ *iter = NULL;
+ }
+}
+
+PHP_HTTP_API const char *php_http_strlist_find(const char list[], unsigned factor, unsigned item)
+{
+ unsigned M = 0, m = 0, major = (item / factor) - 1, minor = (item % factor);
+ const char *p = &list[0];
+
+ while (*p && major != M++) {
+ while (*p) {
+ while (*p) {
+ ++p;
+ }
+ ++p;
+ }
+ ++p;
+ }
+
+ while (*p && minor != m++) {
+ while (*p) {
+ ++p;
+ }
+ ++p;
+ }
+
+ return p;
+}
--- /dev/null
+#ifndef PHP_HTTP_STRLIST_H
+#define PHP_HTTP_STRLIST_H
+
+#ifdef NUL
+# undef NUL
+#endif
+#define NUL "\0"
+
+#define PHP_HTTP_STRLIST(name) const char name[]
+#define PHP_HTTP_STRLIST_ITEM(item) item NUL
+#define PHP_HTTP_STRLIST_NEXT NUL
+#define PHP_HTTP_STRLIST_STOP NUL NUL
+
+PHP_HTTP_API const char *php_http_strlist_find(const char list[], unsigned factor, unsigned item);
+
+typedef struct php_http_strlist_iterator {
+ const char *p;
+ unsigned factor, major, minor;
+} php_http_strlist_iterator_t;
+
+PHP_HTTP_API php_http_strlist_iterator_t *php_http_strlist_iterator_init(php_http_strlist_iterator_t *iter, const char list[], unsigned factor);
+PHP_HTTP_API const char *php_http_strlist_iterator_this(php_http_strlist_iterator_t *iter, unsigned *id);
+PHP_HTTP_API const char *php_http_strlist_iterator_next(php_http_strlist_iterator_t *iter);
+PHP_HTTP_API void php_http_strlist_iterator_dtor(php_http_strlist_iterator_t *iter);
+PHP_HTTP_API void php_http_strlist_iterator_free(php_http_strlist_iterator_t **iter);
+
+#endif /* PHP_HTTP_STRLIST_H */
--- /dev/null
+/*
+ +--------------------------------------------------------------------+
+ | PECL :: http |
+ +--------------------------------------------------------------------+
+ | Redistribution and use in source and binary forms, with or without |
+ | modification, are permitted provided that the conditions mentioned |
+ | in the accompanying LICENSE file are met. |
+ +--------------------------------------------------------------------+
+ | Copyright (c) 2004-2010, Michael Wallner <mike@php.net> |
+ +--------------------------------------------------------------------+
+*/
+
+/* $Id: http_url_api.c 292841 2009-12-31 08:48:57Z mike $ */
+
+#include "php_http.h"
+
+static inline char *localhostname(void)
+{
+ char hostname[1024] = {0};
+
+#ifdef PHP_WIN32
+ if (SUCCESS == gethostname(hostname, lenof(hostname))) {
+ return estrdup(hostname);
+ }
+#elif defined(HAVE_GETHOSTNAME)
+ if (SUCCESS == gethostname(hostname, lenof(hostname))) {
+# if defined(HAVE_GETDOMAINNAME)
+ size_t hlen = strlen(hostname);
+ if (hlen <= lenof(hostname) - lenof("(none)")) {
+ hostname[hlen++] = '.';
+ if (SUCCESS == getdomainname(&hostname[hlen], lenof(hostname) - hlen)) {
+ if (!strcmp(&hostname[hlen], "(none)")) {
+ hostname[hlen - 1] = '\0';
+ }
+ return estrdup(hostname);
+ }
+ }
+# endif
+ if (strcmp(hostname, "(none)")) {
+ return estrdup(hostname);
+ }
+ }
+#endif
+ return estrndup("localhost", lenof("localhost"));
+}
+
+PHP_HTTP_API char *php_http_url_absolute(const char *url, int flags TSRMLS_DC)
+{
+ char *abs = NULL;
+ php_url *purl = NULL;
+
+ if (url) {
+ purl = php_url_parse(abs = estrdup(url));
+ STR_SET(abs, NULL);
+ if (!purl) {
+ php_http_error(HE_WARNING, PHP_HTTP_E_URL, "Could not parse URL (%s)", url);
+ return NULL;
+ }
+ }
+
+ php_http_url(flags, purl, NULL, NULL, &abs, NULL TSRMLS_CC);
+
+ if (purl) {
+ php_url_free(purl);
+ }
+
+ return abs;
+}
+
+PHP_HTTP_API void php_http_url(int flags, const php_url *old_url, const php_url *new_url, php_url **url_ptr, char **url_str, size_t *url_len TSRMLS_DC)
+{
+#if defined(HAVE_GETSERVBYPORT) || defined(HAVE_GETSERVBYNAME)
+ struct servent *se;
+#endif
+ php_url *url = ecalloc(1, sizeof(php_url));
+
+#define __URLSET(u,n) \
+ ((u)&&(u)->n)
+#define __URLCPY(n) \
+ url->n = __URLSET(new_url,n) ? estrdup(new_url->n) : (__URLSET(old_url,n) ? estrdup(old_url->n) : NULL)
+
+ if (!(flags & PHP_HTTP_URL_STRIP_PORT)) {
+ url->port = __URLSET(new_url, port) ? new_url->port : ((old_url) ? old_url->port : 0);
+ }
+ if (!(flags & PHP_HTTP_URL_STRIP_USER)) {
+ __URLCPY(user);
+ }
+ if (!(flags & PHP_HTTP_URL_STRIP_PASS)) {
+ __URLCPY(pass);
+ }
+
+ __URLCPY(scheme);
+ __URLCPY(host);
+
+ if (!(flags & PHP_HTTP_URL_STRIP_PATH)) {
+ if ((flags & PHP_HTTP_URL_JOIN_PATH) && __URLSET(old_url, path) && __URLSET(new_url, path) && *new_url->path != '/') {
+ size_t old_path_len = strlen(old_url->path), new_path_len = strlen(new_url->path);
+
+ url->path = ecalloc(1, old_path_len + new_path_len + 1 + 1);
+
+ strcat(url->path, old_url->path);
+ if (url->path[old_path_len - 1] != '/') {
+ php_dirname(url->path, old_path_len);
+ strcat(url->path, "/");
+ }
+ strcat(url->path, new_url->path);
+ } else {
+ __URLCPY(path);
+ }
+ }
+ if (!(flags & PHP_HTTP_URL_STRIP_QUERY)) {
+ if ((flags & PHP_HTTP_URL_JOIN_QUERY) && __URLSET(new_url, query) && __URLSET(old_url, query)) {
+ zval qarr, qstr;
+
+ INIT_PZVAL(&qstr);
+ INIT_PZVAL(&qarr);
+ array_init(&qarr);
+
+ ZVAL_STRING(&qstr, old_url->query, 0);
+ php_http_querystring_modify(&qarr, &qstr TSRMLS_CC);
+ ZVAL_STRING(&qstr, new_url->query, 0);
+ php_http_querystring_modify(&qarr, &qstr TSRMLS_CC);
+
+ ZVAL_NULL(&qstr);
+ php_http_querystring_update(&qarr, &qstr TSRMLS_CC);
+ url->query = Z_STRVAL(qstr);
+ zval_dtor(&qarr);
+ } else {
+ __URLCPY(query);
+ }
+ }
+ if (!(flags & PHP_HTTP_URL_STRIP_FRAGMENT)) {
+ __URLCPY(fragment);
+ }
+
+ if (!url->scheme) {
+ if (flags & PHP_HTTP_URL_FROM_ENV) {
+ zval *https = php_http_env_get_server_var(ZEND_STRL("HTTPS"), 1 TSRMLS_CC);
+ if (https && !strcasecmp(Z_STRVAL_P(https), "ON")) {
+ url->scheme = estrndup("https", lenof("https"));
+ } else switch (url->port) {
+ case 443:
+ url->scheme = estrndup("https", lenof("https"));
+ break;
+
+#ifndef HAVE_GETSERVBYPORT
+ default:
+#endif
+ case 80:
+ case 0:
+ url->scheme = estrndup("http", lenof("http"));
+ break;
+
+#ifdef HAVE_GETSERVBYPORT
+ default:
+ if ((se = getservbyport(htons(url->port), "tcp")) && se->s_name) {
+ url->scheme = estrdup(se->s_name);
+ } else {
+ url->scheme = estrndup("http", lenof("http"));
+ }
+ break;
+#endif
+ }
+ } else {
+ url->scheme = estrndup("http", lenof("http"));
+ }
+ }
+
+ if (!url->host) {
+ if (flags & PHP_HTTP_URL_FROM_ENV) {
+ zval *zhost;
+
+ if ((((zhost = php_http_env_get_server_var(ZEND_STRL("HTTP_HOST"), 1 TSRMLS_CC)) ||
+ (zhost = php_http_env_get_server_var(ZEND_STRL("SERVER_NAME"), 1 TSRMLS_CC)))) && Z_STRLEN_P(zhost)) {
+ url->host = estrndup(Z_STRVAL_P(zhost), Z_STRLEN_P(zhost));
+ } else {
+ url->host = localhostname();
+ }
+ } else {
+ url->host = estrndup("localhost", lenof("localhost"));
+ }
+ }
+
+ if (!url->path) {
+ if ((flags & PHP_HTTP_URL_FROM_ENV) && SG(request_info).request_uri && SG(request_info).request_uri[0]) {
+ const char *q = strchr(SG(request_info).request_uri, '?');
+
+ if (q) {
+ url->path = estrndup(SG(request_info).request_uri, q - SG(request_info).request_uri);
+ } else {
+ url->path = estrdup(SG(request_info).request_uri);
+ }
+ } else {
+ url->path = estrndup("/", 1);
+ }
+ } else if (url->path[0] != '/') {
+ if ((flags & PHP_HTTP_URL_FROM_ENV) && SG(request_info).request_uri && SG(request_info).request_uri[0]) {
+ size_t ulen = strlen(SG(request_info).request_uri);
+ size_t plen = strlen(url->path);
+ char *path;
+
+ if (SG(request_info).request_uri[ulen-1] != '/') {
+ for (--ulen; ulen && SG(request_info).request_uri[ulen - 1] != '/'; --ulen);
+ }
+
+ path = emalloc(ulen + plen + 1);
+ memcpy(path, SG(request_info).request_uri, ulen);
+ memcpy(path + ulen, url->path, plen);
+ path[ulen + plen] = '\0';
+ STR_SET(url->path, path);
+ } else {
+ size_t plen = strlen(url->path);
+ char *path = emalloc(plen + 1 + 1);
+
+ path[0] = '/';
+ memcpy(&path[1], url->path, plen + 1);
+ STR_SET(url->path, path);
+ }
+ }
+ /* replace directory references if path is not a single slash */
+ if (url->path[0] && (url->path[0] != '/' || url->path[1])) {
+ char *ptr, *end = url->path + strlen(url->path) + 1;
+
+ for (ptr = strstr(url->path, "/."); ptr; ptr = strstr(ptr, "/.")) {
+ switch (ptr[2]) {
+ case '\0':
+ ptr[1] = '\0';
+ break;
+
+ case '/':
+ memmove(&ptr[1], &ptr[3], end - &ptr[3]);
+ break;
+
+ case '.':
+ if (ptr[3] == '/') {
+ char *pos = &ptr[4];
+ while (ptr != url->path) {
+ if (*--ptr == '/') {
+ break;
+ }
+ }
+ memmove(&ptr[1], pos, end - pos);
+ break;
+ } else if (!ptr[3]) {
+ /* .. at the end */
+ ptr[1] = '\0';
+ }
+ /* fallthrough */
+
+ default:
+ /* something else */
+ ++ptr;
+ break;
+ }
+ }
+ }
+
+ if (url->port) {
+ if ( ((url->port == 80) && !strcmp(url->scheme, "http"))
+ || ((url->port ==443) && !strcmp(url->scheme, "https"))
+#ifdef HAVE_GETSERVBYNAME
+ || ((se = getservbyname(url->scheme, "tcp")) && se->s_port &&
+ (url->port == ntohs(se->s_port)))
+#endif
+ ) {
+ url->port = 0;
+ }
+ }
+
+ if (url_str) {
+ size_t len;
+
+ *url_str = emalloc(PHP_HTTP_URL_MAXLEN + 1);
+
+ **url_str = '\0';
+ strlcat(*url_str, url->scheme, PHP_HTTP_URL_MAXLEN);
+ strlcat(*url_str, "://", PHP_HTTP_URL_MAXLEN);
+
+ if (url->user && *url->user) {
+ strlcat(*url_str, url->user, PHP_HTTP_URL_MAXLEN);
+ if (url->pass && *url->pass) {
+ strlcat(*url_str, ":", PHP_HTTP_URL_MAXLEN);
+ strlcat(*url_str, url->pass, PHP_HTTP_URL_MAXLEN);
+ }
+ strlcat(*url_str, "@", PHP_HTTP_URL_MAXLEN);
+ }
+
+ strlcat(*url_str, url->host, PHP_HTTP_URL_MAXLEN);
+
+ if (url->port) {
+ char port_str[8];
+
+ snprintf(port_str, sizeof(port_str), "%d", (int) url->port);
+ strlcat(*url_str, ":", PHP_HTTP_URL_MAXLEN);
+ strlcat(*url_str, port_str, PHP_HTTP_URL_MAXLEN);
+ }
+
+ strlcat(*url_str, url->path, PHP_HTTP_URL_MAXLEN);
+
+ if (url->query && *url->query) {
+ strlcat(*url_str, "?", PHP_HTTP_URL_MAXLEN);
+ strlcat(*url_str, url->query, PHP_HTTP_URL_MAXLEN);
+ }
+
+ if (url->fragment && *url->fragment) {
+ strlcat(*url_str, "#", PHP_HTTP_URL_MAXLEN);
+ strlcat(*url_str, url->fragment, PHP_HTTP_URL_MAXLEN);
+ }
+
+ if (PHP_HTTP_URL_MAXLEN == (len = strlen(*url_str))) {
+ php_http_error(HE_NOTICE, PHP_HTTP_E_URL, "Length of URL exceeds PHP_HTTP_URL_MAXLEN");
+ }
+ if (url_len) {
+ *url_len = len;
+ }
+ }
+
+ if (url_ptr) {
+ *url_ptr = url;
+ } else {
+ php_url_free(url);
+ }
+}
+
+PHP_HTTP_API STATUS php_http_url_encode_hash(HashTable *hash, zend_bool override_argsep, char *pre_encoded_data, size_t pre_encoded_len, char **encoded_data, size_t *encoded_len TSRMLS_DC)
+{
+ char *arg_sep;
+ size_t arg_sep_len;
+ php_http_buffer *qstr = php_http_buffer_new();
+
+ if (override_argsep || !(arg_sep_len = strlen(arg_sep = INI_STR("arg_separator.output")))) {
+ arg_sep = PHP_HTTP_URL_ARGSEP;
+ arg_sep_len = lenof(PHP_HTTP_URL_ARGSEP);
+ }
+
+ if (pre_encoded_len && pre_encoded_data) {
+ php_http_buffer_append(qstr, pre_encoded_data, pre_encoded_len);
+ }
+
+ if (SUCCESS != php_http_url_encode_hash_recursive(hash, qstr, arg_sep, arg_sep_len, NULL, 0)) {
+ php_http_buffer_free(&qstr);
+ return FAILURE;
+ }
+
+ php_http_buffer_data(qstr, encoded_data, encoded_len);
+ php_http_buffer_free(&qstr);
+
+ return SUCCESS;
+}
+
+PHP_HTTP_API STATUS php_http_url_encode_hash_recursive(HashTable *ht, php_http_buffer *str, const char *arg_sep, size_t arg_sep_len, const char *prefix, size_t prefix_len TSRMLS_DC)
+{
+ php_http_array_hashkey_t key = php_http_array_hashkey_init(0);
+ zval **data = NULL;
+ HashPosition pos;
+
+ if (!ht || !str) {
+ php_http_error(HE_WARNING, PHP_HTTP_E_INVALID_PARAM, "Invalid parameters");
+ return FAILURE;
+ }
+ if (ht->nApplyCount > 0) {
+ return SUCCESS;
+ }
+
+ FOREACH_HASH_KEYVAL(pos, ht, key, data) {
+ char *encoded_key;
+ int encoded_len;
+ php_http_buffer new_prefix;
+
+ if (!data || !*data) {
+ php_http_buffer_dtor(str);
+ return FAILURE;
+ }
+
+ if (key.type == HASH_KEY_IS_STRING) {
+ if (!*key.str) {
+ /* only public properties */
+ continue;
+ }
+ if (key.len && key.str[key.len - 1] == '\0') {
+ --key.len;
+ }
+ encoded_key = php_url_encode(key.str, key.len, &encoded_len);
+ } else {
+ encoded_len = spprintf(&encoded_key, 0, "%ld", key.num);
+ }
+
+ {
+ php_http_buffer_init(&new_prefix);
+ if (prefix && prefix_len) {
+ php_http_buffer_append(&new_prefix, prefix, prefix_len);
+ php_http_buffer_appends(&new_prefix, "%5B");
+ }
+
+ php_http_buffer_append(&new_prefix, encoded_key, encoded_len);
+ efree(encoded_key);
+
+ if (prefix && prefix_len) {
+ php_http_buffer_appends(&new_prefix, "%5D");
+ }
+ php_http_buffer_fix(&new_prefix);
+ }
+
+ if (Z_TYPE_PP(data) == IS_ARRAY || Z_TYPE_PP(data) == IS_OBJECT) {
+ STATUS status;
+ ++ht->nApplyCount;
+ status = php_http_url_encode_hash_recursive(HASH_OF(*data), str, arg_sep, arg_sep_len, PHP_HTTP_BUFFER_VAL(&new_prefix), PHP_HTTP_BUFFER_LEN(&new_prefix) TSRMLS_CC);
+ --ht->nApplyCount;
+ if (SUCCESS != status) {
+ php_http_buffer_dtor(&new_prefix);
+ php_http_buffer_dtor(str);
+ return FAILURE;
+ }
+ } else {
+ zval *val = php_http_zsep(IS_STRING, *data);
+
+ if (PHP_HTTP_BUFFER_LEN(str)) {
+ php_http_buffer_append(str, arg_sep, arg_sep_len);
+ }
+ php_http_buffer_append(str, PHP_HTTP_BUFFER_VAL(&new_prefix), PHP_HTTP_BUFFER_LEN(&new_prefix));
+ php_http_buffer_appends(str, "=");
+
+ if (Z_STRLEN_P(val) && Z_STRVAL_P(val)) {
+ char *encoded_val;
+ int encoded_len;
+
+ encoded_val = php_url_encode(Z_STRVAL_P(val), Z_STRLEN_P(val), &encoded_len);
+ php_http_buffer_append(str, encoded_val, encoded_len);
+ efree(encoded_val);
+ }
+
+ zval_ptr_dtor(&val);
+ }
+ php_http_buffer_dtor(&new_prefix);
+ }
+ return SUCCESS;
+}
+
+#define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpUrl, method, 0, req_args)
+#define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpUrl, method, 0)
+#define PHP_HTTP_URL_ME(method, visibility) PHP_ME(HttpUrl, method, PHP_HTTP_ARGS(HttpUrl, method), visibility)
+
+PHP_HTTP_BEGIN_ARGS(__construct, 0)
+ PHP_HTTP_ARG_VAL(old_url, 0)
+ PHP_HTTP_ARG_VAL(new_url, 0)
+ PHP_HTTP_ARG_VAL(flags, 0)
+PHP_HTTP_END_ARGS;
+PHP_HTTP_EMPTY_ARGS(toString);
+
+zend_class_entry *php_http_url_class_entry;
+zend_function_entry php_http_url_method_entry[] = {
+ PHP_HTTP_URL_ME(__construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
+ PHP_HTTP_URL_ME(toString, ZEND_ACC_PUBLIC)
+ ZEND_MALIAS(HttpUrl, __toString, toString, PHP_HTTP_ARGS(HttpUrl, toString), ZEND_ACC_PUBLIC)
+ EMPTY_FUNCTION_ENTRY
+};
+
+PHP_METHOD(HttpUrl, __construct)
+{
+ with_error_handling(EH_THROW, PHP_HTTP_EX_CE(runtime)) {
+ zval *new_url = NULL, *old_url = NULL;
+ long flags = PHP_HTTP_URL_FROM_ENV;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z!z!l", &old_url, &new_url, &flags)) {
+ with_error_handling(EH_THROW, PHP_HTTP_EX_CE(url)) {
+ php_url *res_purl, *new_purl = NULL, *old_purl = NULL;
+
+ if (new_url) {
+ switch (Z_TYPE_P(new_url)) {
+ case IS_OBJECT:
+ case IS_ARRAY:
+ new_purl = php_http_url_from_struct(NULL, HASH_OF(new_url) TSRMLS_CC);
+ break;
+ default: {
+ zval *cpy = php_http_zsep(IS_STRING, new_url);
+
+ new_purl = php_url_parse(Z_STRVAL_P(new_url));
+ zval_ptr_dtor(&cpy);
+ break;
+ }
+ }
+ if (!new_purl) {
+ return;
+ }
+ }
+ if (old_url) {
+ switch (Z_TYPE_P(old_url)) {
+ case IS_OBJECT:
+ case IS_ARRAY:
+ old_purl = php_http_url_from_struct(NULL, HASH_OF(old_url) TSRMLS_CC);
+ break;
+ default: {
+ zval *cpy = php_http_zsep(IS_STRING, old_url);
+
+ old_purl = php_url_parse(Z_STRVAL_P(old_url));
+ zval_ptr_dtor(&cpy);
+ break;
+ }
+ }
+ if (!old_purl) {
+ if (new_purl) {
+ php_url_free(new_purl);
+ }
+ return;
+ }
+ }
+
+ php_http_url(flags, old_purl, new_purl, &res_purl, NULL, NULL TSRMLS_CC);
+ php_http_url_to_struct(res_purl, getThis() TSRMLS_CC);
+
+ php_url_free(res_purl);
+ if (old_purl) {
+ php_url_free(old_purl);
+ }
+ if (new_purl) {
+ php_url_free(new_purl);
+ }
+ } end_error_handling();
+ }
+ } end_error_handling();
+}
+
+PHP_METHOD(HttpUrl, toString)
+{
+ if (SUCCESS == zend_parse_parameters_none()) {
+ php_url *purl;
+
+ if ((purl = php_http_url_from_struct(NULL, HASH_OF(getThis()) TSRMLS_CC))) {
+ char *str;
+ size_t len;
+
+ php_http_url(0, purl, NULL, NULL, &str, &len TSRMLS_CC);
+ php_url_free(purl);
+ RETURN_STRINGL(str, len, 0);
+ }
+ }
+ RETURN_EMPTY_STRING();
+}
+
+PHP_MINIT_FUNCTION(http_url)
+{
+ PHP_HTTP_REGISTER_CLASS(http, Url, http_url, php_http_object_class_entry, 0);
+
+ zend_declare_property_null(php_http_url_class_entry, ZEND_STRL("scheme"), ZEND_ACC_PUBLIC TSRMLS_CC);
+ zend_declare_property_null(php_http_url_class_entry, ZEND_STRL("user"), ZEND_ACC_PUBLIC TSRMLS_CC);
+ zend_declare_property_null(php_http_url_class_entry, ZEND_STRL("pass"), ZEND_ACC_PUBLIC TSRMLS_CC);
+ zend_declare_property_null(php_http_url_class_entry, ZEND_STRL("host"), ZEND_ACC_PUBLIC TSRMLS_CC);
+ zend_declare_property_null(php_http_url_class_entry, ZEND_STRL("port"), ZEND_ACC_PUBLIC TSRMLS_CC);
+ zend_declare_property_null(php_http_url_class_entry, ZEND_STRL("path"), ZEND_ACC_PUBLIC TSRMLS_CC);
+ zend_declare_property_null(php_http_url_class_entry, ZEND_STRL("query"), ZEND_ACC_PUBLIC TSRMLS_CC);
+ zend_declare_property_null(php_http_url_class_entry, ZEND_STRL("fragment"), ZEND_ACC_PUBLIC TSRMLS_CC);
+
+ zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("REPLACE"), PHP_HTTP_URL_REPLACE TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("JOIN_PATH"), PHP_HTTP_URL_JOIN_PATH TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("JOIN_QUERY"), PHP_HTTP_URL_JOIN_QUERY TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STRIP_USER"), PHP_HTTP_URL_STRIP_USER TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STRIP_PASS"), PHP_HTTP_URL_STRIP_PASS TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STRIP_AUTH"), PHP_HTTP_URL_STRIP_AUTH TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STRIP_PORT"), PHP_HTTP_URL_STRIP_PORT TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STRIP_PATH"), PHP_HTTP_URL_STRIP_PATH TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STRIP_QUERY"), PHP_HTTP_URL_STRIP_QUERY TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STRIP_FRAGMENT"), PHP_HTTP_URL_STRIP_FRAGMENT TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STRIP_ALL"), PHP_HTTP_URL_STRIP_ALL TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("FROM_ENV"), PHP_HTTP_URL_FROM_ENV TSRMLS_CC);
+
+ return SUCCESS;
+}
+
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
+
--- /dev/null
+/*
+ +--------------------------------------------------------------------+
+ | PECL :: http |
+ +--------------------------------------------------------------------+
+ | Redistribution and use in source and binary forms, with or without |
+ | modification, are permitted provided that the conditions mentioned |
+ | in the accompanying LICENSE file are met. |
+ +--------------------------------------------------------------------+
+ | Copyright (c) 2004-2010, Michael Wallner <mike@php.net> |
+ +--------------------------------------------------------------------+
+*/
+
+/* $Id: php_http_url_api.h 292841 2009-12-31 08:48:57Z mike $ */
+
+#ifndef PHP_HTTP_URL_H
+#define PHP_HTTP_URL_H
+
+#define PHP_HTTP_URL_REPLACE 0x000
+#define PHP_HTTP_URL_JOIN_PATH 0x001
+#define PHP_HTTP_URL_JOIN_QUERY 0x002
+#define PHP_HTTP_URL_STRIP_USER 0x004
+#define PHP_HTTP_URL_STRIP_PASS 0x008
+#define PHP_HTTP_URL_STRIP_AUTH (PHP_HTTP_URL_STRIP_USER|PHP_HTTP_URL_STRIP_PASS)
+#define PHP_HTTP_URL_STRIP_PORT 0x020
+#define PHP_HTTP_URL_STRIP_PATH 0x040
+#define PHP_HTTP_URL_STRIP_QUERY 0x080
+#define PHP_HTTP_URL_STRIP_FRAGMENT 0x100
+#define PHP_HTTP_URL_STRIP_ALL ( \
+ PHP_HTTP_URL_STRIP_AUTH | \
+ PHP_HTTP_URL_STRIP_PORT | \
+ PHP_HTTP_URL_STRIP_PATH | \
+ PHP_HTTP_URL_STRIP_QUERY | \
+ PHP_HTTP_URL_STRIP_FRAGMENT \
+)
+#define PHP_HTTP_URL_FROM_ENV 0x1000
+
+PHP_HTTP_API void php_http_url(int flags, const php_url *old_url, const php_url *new_url, php_url **url_ptr, char **url_str, size_t *url_len TSRMLS_DC);
+PHP_HTTP_API char *php_http_url_absolute(const char *url, int flags TSRMLS_DC);
+
+PHP_HTTP_API STATUS php_http_url_encode_hash(HashTable *hash, zend_bool override_argsep, char *pre_encoded_data, size_t pre_encoded_len, char **encoded_data, size_t *encoded_len TSRMLS_DC);
+PHP_HTTP_API STATUS php_http_url_encode_hash_recursive(HashTable *ht, php_http_buffer *str, const char *arg_sep, size_t arg_sep_len, const char *prefix, size_t prefix_len TSRMLS_DC);
+
+static inline php_url *php_http_url_from_struct(php_url *url, HashTable *ht TSRMLS_DC)
+{
+ zval **e;
+
+ if (!url) {
+ url = emalloc(sizeof(*url));
+ }
+ memset(url, 0, sizeof(*url));
+
+ if (SUCCESS == zend_hash_find(ht, "scheme", sizeof("scheme"), (void *) &e)) {
+ zval *cpy = php_http_zsep(IS_STRING, *e);
+ url->scheme = estrndup(Z_STRVAL_P(cpy), Z_STRLEN_P(cpy));
+ zval_ptr_dtor(&cpy);
+ }
+ if (SUCCESS == zend_hash_find(ht, "user", sizeof("user"), (void *) &e)) {
+ zval *cpy = php_http_zsep(IS_STRING, *e);
+ url->user = estrndup(Z_STRVAL_P(cpy), Z_STRLEN_P(cpy));
+ zval_ptr_dtor(&cpy);
+ }
+ if (SUCCESS == zend_hash_find(ht, "pass", sizeof("pass"), (void *) &e)) {
+ zval *cpy = php_http_zsep(IS_STRING, *e);
+ url->pass = estrndup(Z_STRVAL_P(cpy), Z_STRLEN_P(cpy));
+ zval_ptr_dtor(&cpy);
+ }
+ if (SUCCESS == zend_hash_find(ht, "host", sizeof("host"), (void *) &e)) {
+ zval *cpy = php_http_zsep(IS_STRING, *e);
+ url->host = estrndup(Z_STRVAL_P(cpy), Z_STRLEN_P(cpy));
+ zval_ptr_dtor(&cpy);
+ }
+ if (SUCCESS == zend_hash_find(ht, "path", sizeof("path"), (void *) &e)) {
+ zval *cpy = php_http_zsep(IS_STRING, *e);
+ url->path = estrndup(Z_STRVAL_P(cpy), Z_STRLEN_P(cpy));
+ zval_ptr_dtor(&cpy);
+ }
+ if (SUCCESS == zend_hash_find(ht, "query", sizeof("query"), (void *) &e)) {
+ zval *cpy = php_http_zsep(IS_STRING, *e);
+ url->query = estrndup(Z_STRVAL_P(cpy), Z_STRLEN_P(cpy));
+ zval_ptr_dtor(&cpy);
+ }
+ if (SUCCESS == zend_hash_find(ht, "fragment", sizeof("fragment"), (void *) &e)) {
+ zval *cpy = php_http_zsep(IS_STRING, *e);
+ url->fragment = estrndup(Z_STRVAL_P(cpy), Z_STRLEN_P(cpy));
+ zval_ptr_dtor(&cpy);
+ }
+ if (SUCCESS == zend_hash_find(ht, "port", sizeof("port"), (void *) &e)) {
+ zval *cpy = php_http_zsep(IS_LONG, *e);
+ url->port = (unsigned short) Z_LVAL_P(cpy);
+ zval_ptr_dtor(&cpy);
+ }
+
+ return url;
+}
+
+static inline HashTable *php_http_url_to_struct(php_url *url, zval *strct TSRMLS_DC)
+{
+ zval arr;
+
+ if (strct) {
+ switch (Z_TYPE_P(strct)) {
+ default:
+ zval_dtor(strct);
+ array_init(strct);
+ case IS_ARRAY:
+ case IS_OBJECT:
+ INIT_PZVAL_ARRAY((&arr), HASH_OF(strct));
+ }
+ } else {
+ INIT_PZVAL(&arr);
+ array_init(&arr);
+ }
+
+ if (url) {
+ if (url->scheme) {
+ add_assoc_string(&arr, "scheme", url->scheme, 1);
+ }
+ if (url->user) {
+ add_assoc_string(&arr, "user", url->user, 1);
+ }
+ if (url->pass) {
+ add_assoc_string(&arr, "pass", url->pass, 1);
+ }
+ if (url->host) {
+ add_assoc_string(&arr, "host", url->host, 1);
+ }
+ if (url->port) {
+ add_assoc_long(&arr, "port", (long) url->port);
+ }
+ if (url->path) {
+ add_assoc_string(&arr, "path", url->path, 1);
+ }
+ if (url->query) {
+ add_assoc_string(&arr, "query", url->query, 1);
+ }
+ if (url->fragment) {
+ add_assoc_string(&arr, "fragment", url->fragment, 1);
+ }
+ }
+
+ return Z_ARRVAL(arr);
+}
+
+extern zend_class_entry *php_http_url_class_entry;
+extern zend_function_entry php_http_url_method_entry[];
+
+#define php_http_url_object_new php_http_object_new
+#define php_http_url_object_new_ex php_http_object_new_ex
+
+PHP_METHOD(HttpUrl, __construct);
+PHP_METHOD(HttpUrl, toString);
+
+extern PHP_MINIT_FUNCTION(http_url);
+
+#endif
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
+
--- /dev/null
+#include "php_http.h"
+
+PHP_HTTP_API php_http_version_t *php_http_version_init(php_http_version_t *v, unsigned major, unsigned minor TSRMLS_DC)
+{
+ if (!v) {
+ v = emalloc(sizeof(*v));
+ }
+
+ v->major = major;
+ v->minor = minor;
+
+ return v;
+}
+
+PHP_HTTP_API 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;
+
+ 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_http_error(HE_WARNING, PHP_HTTP_E_MALFORMED_HEADERS, "Could not parse HTTP protocol version '%s'", str);
+ return NULL;
+ }
+
+ if (separator && separator != '.' && separator != ',') {
+ php_http_error(HE_NOTICE, PHP_HTTP_E_MALFORMED_HEADERS, "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_HTTP_API void php_http_version_to_string(php_http_version_t *v, char **str, size_t *len, const char *pre, const char *post TSRMLS_DC)
+{
+ *len = spprintf(str, 0, "%s%u.%u%s", pre ? pre : "", v->major, v->minor, post ? post : "");
+}
+
+PHP_HTTP_API void php_http_version_to_struct(php_http_version_t *v, HashTable *strct TSRMLS_DC)
+{
+ zval tmp;
+
+ INIT_PZVAL_ARRAY(&tmp, strct);
+ add_assoc_long(&tmp, "major", v->major);
+ add_assoc_long(&tmp, "minor", v->minor);
+}
+
+PHP_HTTP_API void php_http_version_dtor(php_http_version_t *v)
+{
+ (void) v;
+}
+
+PHP_HTTP_API void php_http_version_free(php_http_version_t **v)
+{
+ if (*v) {
+ php_http_version_dtor(*v);
+ efree(*v);
+ *v = NULL;
+ }
+}
--- /dev/null
+
+#ifndef PHP_HTTP_VERSION_H
+#define PHP_HTTP_VERSION_H
+
+typedef struct php_http_version {
+ unsigned major;
+ unsigned minor;
+} php_http_version_t;
+
+PHP_HTTP_API php_http_version_t *php_http_version_init(php_http_version_t *v, unsigned major, unsigned minor TSRMLS_DC);
+PHP_HTTP_API php_http_version_t *php_http_version_parse(php_http_version_t *v, const char *str TSRMLS_DC);
+PHP_HTTP_API void php_http_version_to_string(php_http_version_t *v, char **str, size_t *len, const char *pre, const char *post TSRMLS_DC);
+PHP_HTTP_API void php_http_version_to_struct(php_http_version_t *v, HashTable *strct TSRMLS_DC);
+PHP_HTTP_API void php_http_version_dtor(php_http_version_t *v);
+PHP_HTTP_API void php_http_version_free(php_http_version_t **v);
+
+#endif /* PHP_HTTP_VERSION_H */
+