--- /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);
+ &