package.xml0000644000076500000240000010203714117626035011753 0ustar Mikestaff pecl_http pecl.php.net Extended HTTP Support This HTTP extension aims to provide a convenient and powerful set of functionality for one of PHPs major applications. It eases handling of HTTP urls, headers and messages, provides means for negotiation of a client's preferred content type, language and charset, as well as a convenient way to send any arbitrary data with caching and resuming capabilities. It provides powerful request functionality with support for parallel requests. Documentation: https://mdref.m6w6.name/http Michael Wallner mike mike@php.net yes 2021-09-13 4.2.1 4.2.0 stable stable BSD-2-Clause * Fixed failing tests with PHP-8.1 (see gh issue #120) * Fixed configure reliably finding the right libcurl features available * Fixed cookie handling with libcurl 7.77+ and consistently across all supported libcurl versions (follow-up to gh issue #116) 8.0.0 1.4.1 raphf pecl.php.net 2.0.0dev raphf hash iconv http pecl_http-4.2.1/autoconf/pecl/pecl.m40000644000076500000240000002577514117626035016223 0ustar Mikestaff yes() { true } no() { false } dnl dnl PECL_INIT(name) dnl dnl Start configuring the PECL extension. dnl AC_DEFUN([PECL_INIT], [dnl m4_define([PECL_NAME],[$1])dnl ])dnl dnl dnl dnl PECL_VAR(name) dnl AC_DEFUN([PECL_VAR], [dnl AS_TR_CPP([PHP_]PECL_NAME[_$1])dnl ])dnl dnl dnl PECL_CACHE_VAR(name) dnl AC_DEFUN([PECL_CACHE_VAR], [dnl AS_TR_SH([PECL_cv_$1])dnl ])dnl dnl dnl PECL_SAVE_VAR(name) dnl AC_DEFUN([PECL_SAVE_VAR], [dnl AS_TR_SH([PECL_sv_$1])dnl ])dnl dnl dnl PECL_DEFINE(what, to[, desc]) dnl AC_DEFUN([PECL_DEFINE], [dnl AC_DEFINE(PECL_VAR([$1]), ifelse([$2],,1,[$2]), ifelse([$3],,[ ],[$3])) ])dnl dnl dnl PECL_DEFINE_UQ(what, to[, desc]) dnl AC_DEFUN([PECL_DEFINE_UQ], [dnl AC_DEFINE_UNQUOTED(PECL_VAR([$1]), [$2], ifelse([$3],,[ ],[$3])) ])dnl dnl dnl PECL_DEFINE_SH(what, to[, desc]) dnl AC_DEFUN([PECL_DEFINE_SH], [dnl PECL_VAR([$1])=$2 PECL_DEFINE_UQ([$1], [$2], [$3]) ]) dnl dnl PECL_DEFINE_FN(fn) dnl AC_DEFUN([PECL_DEFINE_FN], [ AC_DEFINE(AS_TR_CPP([HAVE_$1]), [1], [ ]) ]) dnl dnl PECL_SAVE_ENV(var, ns) dnl AC_DEFUN([PECL_SAVE_ENV], [ PECL_SAVE_VAR([$2_$1])=[$]$1 ]) dnl dnl PECL_RESTORE_ENV(var, ns) dnl AC_DEFUN([PECL_RESTORE_ENV], [ $1=$PECL_SAVE_VAR([$2_$1]) ]) dnl dnl PECL_COUNT_CHECKS(incdec) dnl AC_DEFUN([PECL_COUNT_CHECKS], [ PECL_VAR([_checks])=$(($PECL_VAR([_checks])$1)) ]) dnl dnl PECL_EVAL_LIBLINE(libline) dnl AC_DEFUN([PECL_EVAL_LIBLINE], [ PECL_SAVE_ENV(ext_shared, pecl) ext_shared=no PHP_EVAL_LIBLINE([$1], _pecl_eval_libline_dummy) PECL_RESTORE_ENV(ext_shared, pecl) ]) dnl dnl PECL_PROG_EGREP dnl dnl Checks for an egrep. Defines $EGREP. dnl AC_DEFUN([PECL_PROG_EGREP], [ ifdef([AC_PROG_EGREP], [ AC_PROG_EGREP ], [ AC_CHECK_PROG(EGREP, egrep, egrep) ]) ]) dnl dnl PECL_PROG_AWK dnl dnl Checks for an awk. Defines $AWK. dnl AC_DEFUN([PECL_PROG_AWK], [ ifdef([AC_PROG_AWK], [ AC_PROG_AWK ], [ AC_CHECK_PROG(AWK, awk, awk) ]) ]) dnl dnl PECL_PROG_SED dnl dnl Checks for the sed program. Defines $SED. dnl AC_DEFUN([PECL_PROG_SED], [ ifdef([AC_PROG_SED], [ AC_PROG_SED ], [ ifdef([LT_AC_PROG_SED], [ LT_AC_PROG_SED ], [ AC_CHECK_PROG(SED, sed, sed) ]) ]) ]) dnl dnl PECL_PROG_PKGCONFIG dnl dnl Checks for pkg-config program and defines $PKG_CONFIG (to false if not found). dnl AC_DEFUN([PECL_PROG_PKGCONFIG], [ if test -z "$PKG_CONFIG"; then AC_PATH_PROG([PKG_CONFIG], [pkg-config], [false]) fi ]) dnl dnl PECL_HAVE_PHP_EXT(name[, code-if-yes[, code-if-not]]) dnl dnl Check whether ext/$name is enabled in $PHP_EXECUTABLE (PECL build) dnl or if $PHP_ is defined to anything else than "no" (in-tree build). dnl Defines shell var PECL_VAR(HAVE_EXT_) to true or false. dnl AC_DEFUN([PECL_HAVE_PHP_EXT], [ AC_REQUIRE([PECL_PROG_EGREP])dnl AC_CACHE_CHECK([whether ext/$1 is enabled], PECL_CACHE_VAR([HAVE_EXT_$1]), [ PECL_CACHE_VAR([HAVE_EXT_$1])=no if test -x "$PHP_EXECUTABLE"; then if $PHP_EXECUTABLE -m | $EGREP -q ^$1\$; then PECL_CACHE_VAR([HAVE_EXT_$1])=yes fi elif test -n "$AS_TR_CPP([PHP_$1])" && test "$AS_TR_CPP([PHP_$1])" != "no"; then PECL_CACHE_VAR([HAVE_EXT_$1])=yes fi ]) if $PECL_CACHE_VAR([HAVE_EXT_$1]); then PECL_VAR([HAVE_EXT_$1])=true PECL_DEFINE([HAVE_EXT_$1]) $2 else PECL_VAR([HAVE_EXT_$1])=false $3 fi ]) dnl dnl PECL_HAVE_PHP_EXT_HEADER(ext[, header]) dnl dnl Check where to find a header for ext and add the found dir to $INCLUDES. dnl If header is not specified php_.h is assumed. dnl Defines shell var PHP__EXT__INCDIR to the found dir. dnl Defines PHP__HAVE_
to the found path. dnl AC_DEFUN([PECL_HAVE_PHP_EXT_HEADER], [dnl AC_REQUIRE([PECL_PROG_SED])dnl m4_define([EXT_HEADER], ifelse([$2],,php_$1.h,[$2]))dnl AC_CACHE_CHECK([for EXT_HEADER of ext/$1], PECL_CACHE_VAR([EXT_$1]_INCDIR), [ for i in $(printf "%s" "$INCLUDES" | $SED -e's/-I//g') $abs_srcdir ../$1; do if test -d $i; then for j in $i/EXT_HEADER $i/ext/$1/EXT_HEADER; do if test -f $j; then PECL_CACHE_VAR([EXT_$1]_INCDIR)=$(dirname "$j") break fi done fi done ]) PECL_VAR([EXT_$1]_INCDIR)=$PECL_CACHE_VAR([EXT_$1]_INCDIR) PHP_ADD_INCLUDE([$PECL_VAR([EXT_$1]_INCDIR)]) PECL_DEFINE_UQ([HAVE_]EXT_HEADER, "$PECL_VAR([EXT_$1]_INCDIR)/EXT_HEADER") ]) dnl dnl PECL_HAVE_CONST(header, const[, type=int[, code-if-yes[, code-if-mno]]]) dnl AC_DEFUN([PECL_HAVE_CONST], [dnl AC_REQUIRE([PECL_PROG_EGREP])dnl AC_CACHE_CHECK([for $2 in $1], PECL_CACHE_VAR([HAVE_$1_$2]), [ AC_TRY_COMPILE([ #include "$1" ], [ ]ifelse([$3],,int,[$3])[ _c = $2; (void) _c; ], [ PECL_CACHE_VAR([HAVE_$1_$2])=yes ], [ PECL_CACHE_VAR([HAVE_$1_$2])=no ]) ]) if $PECL_CACHE_VAR([HAVE_$1_$2]); then PECL_DEFINE([HAVE_$2]) $4 else ifelse([$5],,:,[$5]) fi ]) dnl dnl _PECL_TR_VERSION(version) dnl AC_DEFUN([_PECL_TR_VERSION], [dnl AC_REQUIRE([PECL_PROG_AWK])dnl $(printf "%s" $1 | $AWK -F "[.]" '{print $[]1*1000000 + $[]2*10000 + $[]3*100 + $[]4}') ]) dnl dnl PECL_CHECKED_VERSION(name) dnl dnl Shell var name of an already checked version. dnl AC_DEFUN([PECL_CHECKED_VERSION], [PECL_VAR([$1][_VERSION])]) dnl dnl PECL_HAVE_VERSION(name, min-version[, code-if-yes[, code-if-not]]) dnl dnl Perform a min-version check while in an PECL_CHECK_* block. dnl Expands AC_MSG_ERROR when code-if-not is empty and the version check fails. dnl AC_DEFUN([PECL_HAVE_VERSION], [ aversion=_PECL_TR_VERSION([$PECL_CHECKED_VERSION([$1])]) mversion=_PECL_TR_VERSION([$2]) AC_MSG_CHECKING([whether $1 version $PECL_CHECKED_VERSION([$1]) >= $2]) if test -z "$aversion" || test "$aversion" -lt "$mversion"; then ifelse($4,,AC_MSG_ERROR([no]), [ AC_MSG_RESULT([no]) $4 ]) else AC_MSG_RESULT([ok]) $3 fi ]) dnl dnl PECL_CHECK_CUSTOM(name, path, header, lib, version) dnl AC_DEFUN([PECL_CHECK_CUSTOM], [ PECL_COUNT_CHECKS([+1]) PECL_SAVE_ENV([CPPFLAGS], [$1]) PECL_SAVE_ENV([LDFLAGS], [$1]) PECL_SAVE_ENV([LIBS], [$1]) AC_MSG_CHECKING([for $1]) AC_CACHE_VAL(PECL_CACHE_VAR([$1_prefix]), [ for path in $2 /usr/local /usr /opt; do if test "$path" = "" || test "$path" = "yes" || test "$path" = "no"; then continue elif test -f "$path/include/$3"; then PECL_CACHE_VAR([$1_prefix])="$path" break fi done ]) if test -n "$PECL_CACHE_VAR([$1_prefix])"; then CPPFLAGS="$CPPFLAGS -I$PECL_CACHE_VAR([$1_prefix])/include" LDFLAGS="$LDFLAGS -L$PECL_CACHE_VAR([$1_prefix])/$PHP_LIBDIR" LIBS="$LIBS -l$4" dnl PECL_EVAL_LIBLINE([$LDFLAGS $LIBS]) AC_CACHE_VAL(PECL_CACHE_VAR([$1_version]), [ pushd $PECL_CACHE_VAR([$1_prefix]) >/dev/null PECL_CACHE_VAR([$1_version])=$5 popd >/dev/null ]) PECL_CHECKED_VERSION([$1])=$PECL_CACHE_VAR([$1_version]) if test -n "$PECL_CHECKED_VERSION([$1])"; then PECL_VAR([HAVE_$1])=true PECL_DEFINE([HAVE_$1]) PECL_DEFINE_UQ($1[_VERSION], "$PECL_CHECKED_VERSION([$1])") else PECL_VAR([HAVE_$1])=false fi else PECL_VAR([HAVE_$1])=false fi AC_MSG_RESULT([${PECL_CHECKED_VERSION([$1]):-no}]) ]) dnl dnl PECL_CHECK_CONFIG(name, prog-config, version-flag, cppflags-flag, ldflags-flag, libs-flag) dnl AC_DEFUN([PECL_CHECK_CONFIG], [ PECL_COUNT_CHECKS([+1]) PECL_SAVE_ENV([CPPFLAGS], [$1]) PECL_SAVE_ENV([LDFLAGS], [$1]) PECL_SAVE_ENV([LIBS], [$1]) AC_MSG_CHECKING([for $1]) ifelse($2, [$PKG_CONFIG $1], [ AC_CACHE_VAL(PECL_CACHE_VAR([$1_exists]), [ if $($2 --exists); then PECL_CACHE_VAR([$1_exists])=yes else PECL_CACHE_VAR([$1_exists])=no fi ]) if $PECL_CACHE_VAR([$1_exists]); then ]) AC_CACHE_VAL(PECL_CACHE_VAR([$1_version]), [ PECL_CACHE_VAR([$1_version])=$($2 $3) ]) PECL_CHECKED_VERSION([$1])=$PECL_CACHE_VAR([$1_version]) AC_CACHE_VAL(PECL_CACHE_VAR([$1_cppflags]), [ PECL_CACHE_VAR([$1_cppflags])=$($2 $4) ]) CPPFLAGS="$CPPFLAGS $PECL_CACHE_VAR([$1_cppflags])" AC_CACHE_VAL(PECL_CACHE_VAR([$1_ldflags]), [ PECL_CACHE_VAR([$1_ldflags])=$($2 $5) ]) LDFLAGS="$LDFLAGS $PECL_CACHE_VAR([$1_ldflags])" AC_CACHE_VAL(PECL_CACHE_VAR([$1_libs]), [ PECL_CACHE_VAR([$1_libs])=$($2 $6) ]) LIBS="$LIBS $PECL_CACHE_VAR([$1_libs])" dnl PECL_EVAL_LIBLINE([$LDFLAGS $LIBS]) ifelse($2, [$PKG_CONFIG $1], [ fi ]) AC_MSG_RESULT([${PECL_CHECKED_VERSION([$1]):-no}]) if test -n "$PECL_CHECKED_VERSION([$1])"; then PECL_VAR([HAVE_$1])=true PECL_DEFINE([HAVE_$1]) PECL_DEFINE_UQ([$1_VERSION], "$PECL_CHECKED_VERSION([$1])") else PECL_VAR([HAVE_$1])=false fi ]) dnl dnl PECL_CHECK_PKGCONFIG(pkg[, additional-pkg-config-path]) dnl AC_DEFUN([PECL_CHECK_PKGCONFIG], [dnl AC_REQUIRE([PECL_PROG_PKGCONFIG])dnl ifelse($2,,, [ PECL_SAVE_VAR(pkgconfig_path)="$PKG_CONFIG_PATH" if test -d "$2"; then export PKG_CONFIG_PATH="$2/lib/pkgconfig:$PKG_CONFIG_PATH" fi ]) PECL_CHECK_CONFIG([$1], [$PKG_CONFIG $1], [--modversion], [--cflags-only-I], [--libs-only-L], [--libs-only-l]) ifelse($2,,, [ PKG_CONFIG_PATH="$PECL_SAVE_VAR(pkgconfig_path)" ]) ]) dnl dnl PECL_CHECK_DONE(name, success[, incline, libline]) dnl AC_DEFUN([PECL_CHECK_DONE], [ PECL_COUNT_CHECKS([-1]) success=$2 if $success && test -n "$LDFLAGS$LIBS"; then AC_MSG_CHECKING([whether $1 can be linked]) AC_TRY_LINK([], [], [success=yes], [success=no]) AC_MSG_RESULT([$success]) if ! $success; then AC_MSG_WARN([$1 was found, but fails to link with:]) AC_MSG_WARN([ LDFLAGS='$LDFLAGS']) AC_MSG_WARN([ LIBS='$LIBS']) AC_MSG_WARN([Missing or updated library paths?]) fi fi if $success; then _cppflags=$PECL_SAVE_VAR([$1_CPPFLAGS]) _ldflags=$PECL_SAVE_VAR([$1_LDFLAGS]) _libs=$PECL_SAVE_VAR([$1_LIBS]) incline=${CPPFLAGS:${#_cppflags}} libline=["${LDFLAGS:${#_ldflags}} ${LIBS:${#_libs}}"] PECL_DEFINE([HAVE_$1]) else incline=$3 libline=$4 fi PECL_RESTORE_ENV([CPPFLAGS], [$1]) PECL_RESTORE_ENV([LDFLAGS], [$1]) PECL_RESTORE_ENV([LIBS], [$1]) PHP_EVAL_INCLINE([$incline]) PHP_EVAL_LIBLINE([$libline], AS_TR_CPP(PECL_NAME[_SHARED_LIBADD])) ]) dnl dnl PECL_CHECK_CA([additional-ca-paths,[ additional-ca-bundles]]) dnl AC_DEFUN([PECL_CHECK_CA], [ AC_CACHE_CHECK([for default CA path], PECL_CACHE_VAR([CAPATH]), [ PECL_VAR([CAPATH])= for ca_path in $1 \ /etc/ssl/certs \ /System/Library/OpenSSL do # check if it's actually a hashed directory if test -d "$ca_path" && ls "$ca_path"/@<:@0-9a-f@:>@@<:@0-9a-f@:>@@<:@0-9a-f@:>@@<:@0-9a-f@:>@@<:@0-9a-f@:>@@<:@0-9a-f@:>@@<:@0-9a-f@:>@@<:@0-9a-f@:>@.0 >/dev/null 2>&1; then PECL_CACHE_VAR([CAPATH])=$ca_path break fi done ]) if test -n "$PECL_CACHE_VAR([CAPATH])"; then PECL_DEFINE_SH([CAPATH], "$PECL_CACHE_VAR([CAPATH])") fi AC_CACHE_CHECK([for default CA info], PECL_CACHE_VAR([CAINFO]), [ for ca_info in $2 \ /etc/ssl/{cert,ca-bundle}.pem \ /{etc,usr/share}/ssl/certs/ca-{bundle,ceritifcates}.crt \ /etc/{pki/ca-trust,ca-certificates}/extracted/pem/tls-ca-bundle.pem \ /etc/pki/tls/certs/ca-bundle{,.trust}.crt \ /usr/local/etc/{,open}ssl/cert.pem \ /usr/local/share/certs/ca-root-nss.crt \ /{usr,usr/local,opt}/local/share/curl/curl-ca-bundle.crt do if test -f "$ca_info"; then PECL_CACHE_VAR([CAINFO])=$ca_info break fi done ]) if test -n "$PECL_CACHE_VAR([CAINFO])"; then PECL_DEFINE_SH([CAINFO], "$PECL_CACHE_VAR([CAINFO])") fi ]) pecl_http-4.2.1/autoconf/pecl/libbrotli.m40000644000076500000240000000265414117626035017251 0ustar Mikestaff AC_DEFUN([PECL_CHECK_LIBBROTLI], [ dnl config.m4 calls PECL_CHECK_DONE once more PECL_COUNT_CHECKS([+1]) PECL_SAVE_ENV([CPPFLAGS], [libbrotli]) PECL_SAVE_ENV([LDFLAGS], [libbrotli]) PECL_SAVE_ENV([LIBS], [libbrotli]) PECL_CHECK_LIBBROTLI_COMMON([$1], [$2]) PECL_CHECK_DONE(libbrotlicommon, [$PECL_VAR([HAVE_LIBBROTLI_COMMON])]) PECL_CHECK_LIBBROTLI_DEC([$1], [$2]) PECL_CHECK_DONE(libbrotlidec, [$PECL_VAR([HAVE_LIBBROTLI_DEC])]) PECL_CHECK_LIBBROTLI_ENC([$1], [$2]) PECL_CHECK_DONE(libbrotlienc, [$PECL_VAR([HAVE_LIBBROTLI_ENC])]) if $PECL_VAR([HAVE_LIBBROTLI_COMMON]) \ && $PECL_VAR([HAVE_LIBBROTLI_DEC]) \ && $PECL_VAR([HAVE_LIBBROTLI_ENC]); then PECL_VAR([HAVE_LIBBROTLI])=true else PECL_VAR([HAVE_LIBBROTLI])=false fi ]) AC_DEFUN([PECL_CHECK_LIBBROTLI_COMMON], [ PECL_CHECK_PKGCONFIG(libbrotlicommon, [$1]) PECL_HAVE_VERSION(libbrotlicommon, ifelse($2,,1.0,$2), [ PECL_VAR([HAVE_LIBBROTLI_COMMON])=true ], [ PECL_VAR([HAVE_LIBBROTLI_COMMON])=false ]) ]) AC_DEFUN([PECL_CHECK_LIBBROTLI_DEC], [ PECL_CHECK_PKGCONFIG(libbrotlidec, [$1]) PECL_HAVE_VERSION(libbrotlidec, ifelse($2,,1.0,$2), [ PECL_VAR([HAVE_LIBBROTLI_DEC])=true ], [ PECL_VAR([HAVE_LIBBROTLI_DEC])=false ]) ]) AC_DEFUN([PECL_CHECK_LIBBROTLI_ENC], [ PECL_CHECK_PKGCONFIG(libbrotlienc, [$1]) PECL_HAVE_VERSION(libbrotlienc, ifelse($2,,1.0,$2), [ PECL_VAR([HAVE_LIBBROTLI_ENC])=true ], [ PECL_VAR([HAVE_LIBBROTLI_ENC])=false ]) ]) pecl_http-4.2.1/autoconf/pecl/libcurl.m40000644000076500000240000002060414117626035016716 0ustar Mikestaffdnl dnl PECL_HAVE_LIBCURL_FEATURE(feature[, code-if-yes[, code-if-no]]) dnl dnl Checks $CURL_CONFIG --feature. dnl Defines PHP__HAVE_LIBCURL_ dnl AC_DEFUN([PECL_HAVE_LIBCURL_FEATURE], [dnl AC_REQUIRE([PECL_PROG_EGREP])dnl AC_CACHE_CHECK([for $1 feature in libcurl], PECL_CACHE_VAR([HAVE_LIBCURL_FEATURE_$1]), [ if $CURL_CONFIG --feature | $EGREP -qi $1; then PECL_CACHE_VAR([HAVE_LIBCURL_FEATURE_$1])=yes else PECL_CACHE_VAR([HAVE_LIBCURL_FEATURE_$1])=no fi ]) PECL_VAR([HAVE_LIBCURL_FEATURE_$1])=$PECL_CACHE_VAR([HAVE_LIBCURL_FEATURE_$1]) if $PECL_VAR([HAVE_LIBCURL_FEATURE_$1]); then PECL_DEFINE([HAVE_LIBCURL_$1]) $2 else ifelse([$3],,:,[$3]) fi ]) dnl dnl PECL_HAVE_LIBCURL_PROTOCOL(protocol[, code-if-yes[, code-if-no]]) dnl AC_DEFUN([PECL_HAVE_LIBCURL_PROTOCOL], [ AC_CACHE_CHECK([for $1 protocol in libcurl], PECL_CACHE_VAR([HAVE_LIBCURL_PROTOCOL_$1]), [ if $CURL_CONFIG --protocols | $EGREP -q $1; then PECL_CACHE_VAR([HAVE_LIBCURL_PROTOCOL_$1])=yes else PECL_CACHE_VAR([HAVE_LIBCURL_PROTOCOL_$1])=no fi ]) PECL_VAR([HAVE_LIBCURL_PROTOCOL_$1])=$PECL_CACHE_VAR([HAVE_LIBCURL_PROTOCOL_$1]) if $PECL_VAR([HAVE_LIBCURL_PROTOCOL_$1]); then PECL_DEFINE([HAVE_LIBCURL_$1]) $2 else ifelse([$3],,:,[$3]) fi ]) dnl dnl PECL_HAVE_LIBCURL_SSLLIB(ssllib-name, headers, libs) dnl AC_DEFUN([PECL_HAVE_LIBCURL_SSLLIB], [ if test -z "$PECL_VAR([LIBCURL_SSLLIB])"; then AC_CACHE_CHECK([for $1 providing SSL in libcurl], PECL_CACHE_VAR([HAVE_LIBCURL_$1]), [ AC_TRY_RUN([ #include #include 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, "$1", sizeof("$1")-1); } return 1; } ], [ PECL_CACHE_VAR([HAVE_LIBCURL_$1])=yes ], [ PECL_CACHE_VAR([HAVE_LIBCURL_$1])=no ]) ]) PECL_VAR([HAVE_LIBCURL_$1])=$PECL_CACHE_VAR([HAVE_LIBCURL_$1]) if $PECL_VAR([HAVE_LIBCURL_$1]); then PECL_VAR([LIBCURL_SSLLIB])="$1" PECL_DEFINE([HAVE_LIBCURL_$1]) m4_foreach_w(header, $2, [AC_CHECK_HEADER(header,, [ PECL_VAR([HAVE_LIBCURL_$1])=false ])]) ifelse([$3],,,[ if $PECL_VAR([HAVE_LIBCURL_$1]); then m4_foreach_w(lib, $3, [ PHP_ADD_LIBRARY(lib, true, [AS_TR_CPP(PECL_NAME[_SHARED_LIBADD])]) ]) fi ]) fi fi ]) dnl dnl PECL_HAVE_LIBCURL_SSL dnl AC_DEFUN([PECL_HAVE_LIBCURL_SSL], [dnl AC_REQUIRE([PECL_HAVE_LIBCURL_CA])dnl PECL_HAVE_LIBCURL_FEATURE([SSL], [ PECL_HAVE_LIBCURL_SSLLIB([OpenSSL], [openssl/ssl.h openssl/crypto.h], [ssl crypto]) PECL_HAVE_LIBCURL_SSLLIB([GnuTLS], [gnutls/gnutls.h gcrypt.h], [gnutls gcrypt]) PECL_HAVE_LIBCURL_SSLLIB([NSS]) PECL_HAVE_LIBCURL_SSLLIB([SecureTransport]) PECL_HAVE_LIBCURL_SSLLIB([GSKit]) PECL_HAVE_LIBCURL_SSLLIB([PolarSSL]) PECL_HAVE_LIBCURL_SSLLIB([WolfSSL]) PECL_HAVE_LIBCURL_SSLLIB([mbedTLS]) PECL_HAVE_LIBCURL_SSLLIB([axTLS]) case "$PECL_VAR([LIBCURL_SSLLIB])" in OpenSSL|GnuTLS|PolarSSL) PECL_DEFINE([HAVE_LIBCURL_CAPATH]) PECL_DEFINE([HAVE_LIBCURL_CAINFO]) ;; NSS) AC_CACHE_CHECK([whether NSS PEM is available], [PECL_CACHE_VAR([HAVE_LIBCURL_NSSPEM])], [ PECL_SAVE_ENV([LIBS], [NSSPEM]) LIBS="$LIBS -lnsspem" AC_TRY_LINK([], [(void)0;], [ PECL_CACHE_VAR([HAVE_LIBCURL_NSSPEM])=yes ], [ PECL_CACHE_VAR([HAVE_LIBCURL_NSSPEM])=no ]) PECL_RESTORE_ENV([LIBS], [NSSPEM]) ]) if $PECL_CACHE_VAR([HAVE_LIBCURL_NSSPEM]); then PECL_DEFINE([HAVE_LIBCURL_CAINFO]) else PECL_DEFINE([HAVE_LIBCURL_CAINFO], [0]) fi PECL_DEFINE([HAVE_LIBCURL_CAPATH], [0]) ;; *) PECL_DEFINE([HAVE_LIBCURL_CAPATH], [0]) PECL_DEFINE([HAVE_LIBCURL_CAINFO], [0]) ;; esac PECL_HAVE_CONST([curl/curl.h], [CURLOPT_TLSAUTH_TYPE], int, [ AC_CACHE_CHECK([whether CURLOPT_TLSAUTH_TYPE expects CURL_TLSAUTH_SRP], PECL_CACHE_VAR([LIBCURL_TLSAUTH_SRP]), [ PECL_CACHE_VAR([LIBCURL_TLSAUTH_SRP])= AC_TRY_RUN([ #include int main(int argc, char *argv[]) { CURL *ch = curl_easy_init(); return curl_easy_setopt(ch, CURLOPT_TLSAUTH_TYPE, CURL_TLSAUTH_SRP); } ], [ PECL_CACHE_VAR([LIBCURL_TLSAUTH_SRP])=yes ], [ AC_TRY_RUN([ #include int main(int argc, char *argv[]) { CURL *ch = curl_easy_init(); return curl_easy_setopt(ch, CURLOPT_TLSAUTH_TYPE, "SRP"); } ], [ PECL_CACHE_VAR([LIBCURL_TLSAUTH_SRP])=no ]) ]) ]) if test -n "$PECL_CACHE_VAR([LIBCURL_TLSAUTH_SRP])"; then PECL_DEFINE([HAVE_LIBCURL_TLSAUTH_TYPE]) if $PECL_CACHE_VAR([LIBCURL_TLSAUTH_SRP]); then PECL_DEFINE([LIBCURL_TLSAUTH_SRP], [CURL_TLSAUTH_SRP]) PECL_DEFINE([LIBCURL_TLSAUTH_DEF], [CURL_TLSAUTH_NONE]) else PECL_DEFINE([LIBCURL_TLSAUTH_SRP], ["SRP"]) PECL_DEFINE([LIBCURL_TLSAUTH_DEF], [""]) fi fi ]) PECL_HAVE_CONST([curl/curl.h], [CURL_LOCK_DATA_SSL_SESSION], int, [ AC_CACHE_CHECK([whether curl_share accepts CURL_LOCK_DATA_SSL_SESSION], PECL_CACHE_VAR([LIBCURL_SHARE_SSL]), [ PECL_CACHE_VAR([LIBCURL_SHARE_SSL])= AC_TRY_RUN([ #include int main(int argc, char *argv[]) { CURLSH *ch = curl_share_init(); return curl_share_setopt(ch, CURLSHOPT_SHARE, CURL_LOCK_DATA_SSL_SESSION); } ], [ PECL_CACHE_VAR([LIBCURL_SHARE_SSL])=yes ], [ PECL_CACHE_VAR([LIBCURL_SHARE_SSL])=no ]) ]) if test "$PECL_CACHE_VAR([LIBCURL_SHARE_SSL])" = yes; then PECL_DEFINE([HAVE_LIBCURL_SHARE_SSL], [1]) fi ]) if test "$PECL_VAR([LIBCURL_SSLLIB])" == "OpenSSL"; then PECL_HAVE_CONST([curl/curl.h], [CURLOPT_TLS13_CIPHERS], int, [ AC_CACHE_CHECK([whether curl_easy_setopt accepts CURLOPT_TLS13_CIPHERS], PECL_CACHE_VAR([LIBCURL_TLS13_CIPHERS]), [ PECL_CACHE_VAR([LIBCURL_TLS13_CIPHERS])= AC_TRY_RUN([ #include int main(int argc, char *argv[]) { CURL *ch = curl_easy_init(); return curl_easy_setopt(ch, CURLSHOPT_TLS13_CIPHERS, ""); } ], [ PECL_CACHE_VAR([LIBCURL_TLS13_CIPHERS])=yes ], [ PECL_CACHE_VAR([LIBCURL_TLS13_CIPHERS])=no ]) ]) if test "$PECL_CACHE_VAR([LIBCURL_TLS13_CIPHERS])" = yes; then PECL_DEFINE([HAVE_LIBCURL_TLS13_CIPHERS], [1]) fi ]) fi ]) ]) dnl dnl PECL_HAVE_LIBCURL_ARES dnl AC_DEFUN([PECL_HAVE_LIBCURL_ARES], [ AC_CACHE_CHECK([for c-ares providing AsynchDNS in libcurl], PECL_CACHE_VAR([HAVE_LIBCURL_ARES]), [ AC_TRY_RUN([ #include int main(int argc, char *argv[]) { curl_version_info_data *data = curl_version_info(CURLVERSION_NOW); if (data && data->ares && data->ares_num) { return 0; } return 1; } ], [ PECL_CACHE_VAR([HAVE_LIBCURL_ARES])=yes ], [ PECL_CACHE_VAR([HAVE_LIBCURL_ARES])=no ]) ]) PECL_VAR([HAVE_LIBCURL_ARES])=$PECL_CACHE_VAR([HAVE_LIBCURL_ARES]) if $PECL_VAR([HAVE_LIBCURL_ARES]); then PECL_DEFINE([HAVE_LIBCURL_ARES]) fi ]) dnl dnl PECL_HAVE_LIBCURL_CA dnl dnl Checks for any installed default CA path/info with PECL_CHECK_CA providing curl's ca config. dnl Defines shell vars PHP__LIBCURL_CAPATH and PHP__LIBCURL_CAINFO dnl additionally to those defined in PECL_CHECK_CA. dnl AC_DEFUN([PECL_HAVE_LIBCURL_CA], [ CURL_CONFIG_CA=$($CURL_CONFIG --ca) if test -z "$CURL_CONFIG_CA"; then CURL_CONFIG_CA=$($CURL_CONFIG --configure | $EGREP -o -- "--with-ca@<:@^\'@:>@*" | $SED 's/.*=//') fi PECL_CHECK_CA($CURL_CONFIG_CA, $CURL_CONFIG_CA) PECL_VAR([LIBCURL_CAPATH])=$PECL_VAR([CAPATH]) PECL_VAR([LIBCURL_CAINFO])=$PECL_VAR([CAINFO]) ]) dnl dnl PECL_CHECK_LIBCURL(search-dir[, min-version]) dnl dnl Defines shell var $CURL_CONFIG (false if curl-config could not be found). dnl dnl Calls PECL_CHECK_CONFIG(libcurl ...) for its tests. dnl Call PECL_CHECK_DONE(libcurl[, success]) yourself when you're done dnl with any subtests. This is IMPORTANT! dnl AC_DEFUN([PECL_CHECK_LIBCURL], [dnl AC_REQUIRE([PECL_PROG_SED])dnl AC_REQUIRE([PECL_PROG_EGREP])dnl AC_PATH_PROG([CURL_CONFIG], [curl-config], false, [$1/bin:$PATH:/usr/local/bin]) PECL_CHECK_CONFIG(libcurl, $CURL_CONFIG, [--version | $SED -e 's/@<:@^0-9\.@:>@//g'], [--cflags], [--libs | $EGREP -o -- '(^|\s)-L@<:@^ @:>@* ?' | xargs], [--libs | $EGREP -o -- '(^|\s)-l@<:@^ @:>@* ?' | xargs]dnl ) ifelse([$2],,,[ PECL_HAVE_VERSION([libcurl], [$2]) ]) ]) pecl_http-4.2.1/autoconf/pecl/libevent.m40000644000076500000240000000112414117626035017066 0ustar Mikestaff AC_DEFUN([PECL_CHECK_LIBEVENT], [ PECL_CHECK_PKGCONFIG(libevent, [$1]) if test -n "$PECL_CHECKED_VERSION(libevent)"; then PECL_HAVE_VERSION(libevent, 2.0, [ PECL_DEFINE([HAVE_LIBEVENT2]) ], [ ]) ifelse([$2],,,[PECL_HAVE_VERSION(libevent, [$2])]) AC_CHECK_FUNC(event_base_new,,[ AC_DEFINE([event_base_new], [event_init], [missing event_base_new() in libevent1]) ]) AC_CHECK_FUNC(event_assign,,[ AC_DEFINE([event_assign(e, b, s, a, cb, d)], [do {\ event_set(e, s, a, cb, d); \ event_base_set(b, e);\ } while(0)], [missing event_assign() in libevent1]) ]) fi ])pecl_http-4.2.1/autoconf/pecl/zlib.m40000644000076500000240000000066614117626035016230 0ustar Mikestaffdnl dnl PECL_CHECK_ZLIB( dnl dnl Calls PECL_CHECK_CUSTOM(zlib ...) for its tests. dnl Call PECL_CHECK_DONE(zlib[, success]) yourself when you're done dnl with any subtests. This is IMPORTANT! dnl AC_DEFUN([PECL_CHECK_ZLIB], [ PECL_CHECK_CUSTOM(zlib, ["$1" "$PHP_ZLIB_DIR" "$PHP_ZLIB"], zlib.h, z, [$($EGREP "define ZLIB_VERSION" "$path/include/zlib.h" | $SED -e 's/@<:@^0-9\.@:>@//g')]) ifelse([$2],,,[PECL_HAVE_VERSION(zlib, $2)]) ])pecl_http-4.2.1/src/php_http_api.h0000644000076500000240000001004014117626035015667 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_HTTP_API_H #define PHP_HTTP_API_H #ifdef __COVERITY_GCC_VERSION_AT_LEAST # define _Float128 float # define _Float64 float # define _Float32 float # define _Float64x float # define _Float32x float #endif #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef PHP_WIN32 #include "php_config.h" #endif #include "php.h" #include "SAPI.h" #include "ext/raphf/php_raphf_api.h" #include "ext/standard/php_string.h" #include "ext/spl/spl_iterators.h" #include "ext/date/php_date.h" #include "zend_interfaces.h" #include "zend_exceptions.h" #if PHP_WIN32 # define PHP_HTTP_API __declspec(dllexport) #elif __GNUC__ >= 4 # define PHP_HTTP_API extern __attribute__ ((visibility("default"))) #else # define PHP_HTTP_API extern #endif #if (HAVE_ICONV || PHP_HTTP_HAVE_EXT_ICONV) && (PHP_HTTP_SHARED_DEPS || !COMPILE_DL_ICONV) # define PHP_HTTP_HAVE_ICONV 1 #endif #if (HAVE_HASH_EXT || PHP_HTTP_HAVE_EXT_HASH) && (PHP_HTTP_SHARED_DEPS || !COMPILE_DL_HASH) # define PHP_HTTP_HAVE_HASH 1 #endif #include #if PHP_WIN32 # define CURL_STATICLIB # include #else # if HAVE_NETDB_H # include # endif # if HAVE_UNISTD_H # include # endif #endif #if HAVE_WCHAR_H && HAVE_WCTYPE_H && HAVE_ISWALNUM && (HAVE_MBRTOWC || HAVE_MBTOWC) # define PHP_HTTP_HAVE_WCHAR 1 #endif #include #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)) #include "php_http.h" #include "php_http_buffer.h" #include "php_http_misc.h" #include "php_http_options.h" #include "php_http.h" #include "php_http_cookie.h" #include "php_http_encoding.h" #include "php_http_encoding_zlib.h" #include "php_http_encoding_brotli.h" #include "php_http_info.h" #include "php_http_message.h" #include "php_http_env.h" #include "php_http_env_request.h" #include "php_http_env_response.h" #include "php_http_etag.h" #include "php_http_exception.h" #include "php_http_filter.h" #include "php_http_header_parser.h" #include "php_http_header.h" #include "php_http_message_body.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_querystring.h" #include "php_http_client.h" #include "php_http_curl.h" #include "php_http_client_request.h" #include "php_http_client_response.h" #include "php_http_client_curl.h" #include "php_http_client_curl_event.h" #include "php_http_client_curl_user.h" #include "php_http_url.h" #include "php_http_version.h" ZEND_BEGIN_MODULE_GLOBALS(php_http) struct php_http_env_globals env; #if PHP_HTTP_HAVE_CLIENT struct { # if PHP_HTTP_HAVE_LIBCURL struct php_http_client_curl_globals curl; # endif } client; #endif ZEND_END_MODULE_GLOBALS(php_http) ZEND_EXTERN_MODULE_GLOBALS(php_http); #if ZTS # include "TSRM/TSRM.h" # define PHP_HTTP_G ((zend_php_http_globals *) (*((void ***) tsrm_get_ls_cache()))[TSRM_UNSHUFFLE_RSRC_ID(php_http_globals_id)]) # undef TSRMLS_FETCH_FROM_CTX # define TSRMLS_FETCH_FROM_CTX(ctx) ERROR #else # define PHP_HTTP_G (&php_http_globals) #endif #if PHP_DEBUG # define _DPF_STR 0 # define _DPF_IN 1 # define _DPF_OUT 2 extern void _dpf(int type, const char *data, size_t length); #else # define _dpf(t,s,l); #endif #endif /* PHP_HTTP_API_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 */ pecl_http-4.2.1/src/php_http_buffer.c0000644000076500000240000002774614117626035016407 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #include "php_http_api.h" #include "php_http_buffer.h" PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_init_ex( php_http_buffer_t *buf, size_t chunk_size, unsigned flags) { if (!buf) { buf = pemalloc(sizeof(*buf), 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_t *php_http_buffer_from_string_ex( php_http_buffer_t *buf, const char *str, size_t len) { int free_buf = !!buf; if (EXPECTED(buf = php_http_buffer_init(buf))) { if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_append(buf, str, len)) { if (free_buf) { pefree(buf, buf->pmem); } buf = NULL; } } return buf; } PHP_HTTP_BUFFER_API size_t php_http_buffer_resize_ex( php_http_buffer_t *buf, size_t len, size_t override_size, zend_bool allow_error) { char *ptr = NULL; #if 0 fprintf(stderr, "RESIZE: len=%lu, size=%lu, used=%lu, free=%lu, total=%lu\n", len, buf->size, buf->used, buf->free, buf->free+buf->used); #endif if (buf->free < len) { size_t size = override_size ? override_size : buf->size; while (UNEXPECTED((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 char *php_http_buffer_account( php_http_buffer_t *buf, size_t to_account) { assert(to_account <= buf->free); buf->free -= to_account; buf->used += to_account; return buf->data + buf->used; } PHP_HTTP_BUFFER_API size_t php_http_buffer_shrink(php_http_buffer_t *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_t *buf, const char *append, size_t append_len) { if ( buf->free < append_len && PHP_HTTP_BUFFER_NOMEM == php_http_buffer_resize(buf, append_len) ) { return PHP_HTTP_BUFFER_NOMEM; } if (append_len) { 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_t *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 char *php_http_buffer_data(const php_http_buffer_t *buf, char **into, size_t *len) { char *copy = ecalloc(1, buf->used + 1); if (buf->data) { memcpy(copy, buf->data, buf->used); } if (into) { *into = copy; } if (len) { *len = buf->used; } return copy; } PHP_HTTP_BUFFER_API size_t php_http_buffer_cut(php_http_buffer_t *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_t *php_http_buffer_fix( php_http_buffer_t *buf) { if ( buf->free < 1 && 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 void php_http_buffer_reset(php_http_buffer_t *buf) { buf->free += buf->used; buf->used = 0; } PHP_HTTP_BUFFER_API void php_http_buffer_dtor(php_http_buffer_t *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_t **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_t **s, const char *data, size_t data_len, char **chunk, size_t chunk_size) { php_http_buffer_t *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) { *chunk = estrndup(storage->data, chunk_size); php_http_buffer_cut(storage, 0, chunk_size); return chunk_size; } return 0; } PHP_HTTP_BUFFER_API size_t php_http_buffer_chunked_output(php_http_buffer_t **s, const char *data, size_t data_len, size_t chunk_len, php_http_buffer_pass_func_t passout, void *opaque) { char *chunk = NULL; size_t passed = 0, got = 0; while ((got = php_http_buffer_chunk_buffer(s, data, data_len, &chunk, chunk_len))) { if (PHP_HTTP_BUFFER_PASS0 == passout(opaque, chunk, got)) { PTR_SET(chunk, NULL); return PHP_HTTP_BUFFER_PASS0; } ++passed; if (!chunk_len) { /* we already got the last chunk, and freed all resources */ break; } data = NULL; data_len = 0; PTR_SET(chunk, NULL); } PTR_FREE(chunk); return passed; } PHP_HTTP_BUFFER_API ssize_t php_http_buffer_passthru(php_http_buffer_t **s, size_t chunk_size, php_http_buffer_pass_func_t passin, void *passin_arg, php_http_buffer_pass_func_t passon, void *passon_arg) { size_t passed_on = 0, passed_in; passed_in = php_http_buffer_chunked_input(s, chunk_size, passin, passin_arg); if (passed_in == PHP_HTTP_BUFFER_PASS0) { return passed_in; } if (passed_in || (*s)->used) { passed_on = passon(passon_arg, (*s)->data, (*s)->used); 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_t **s, size_t chunk_size, php_http_buffer_pass_func_t passin, void *opaque) { php_http_buffer_t *str; size_t passed; if (UNEXPECTED(!*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); if (passed != PHP_HTTP_BUFFER_PASS0) { str->used += passed; str->free -= passed; } php_http_buffer_fix(str); return passed; } #ifdef PHP_HTTP_BUFFER_EXTENDED PHP_HTTP_BUFFER_API int php_http_buffer_cmp(php_http_buffer_t *left, php_http_buffer_t *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 php_http_buffer_t *php_http_buffer_copy( const php_http_buffer_t *from, php_http_buffer_t *to) { int free_to = !to; to = php_http_buffer_clone(from, to); if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_append(to, from->data, from->used)) { if (free_to) { php_http_buffer_free(&to); } else { php_http_buffer_dtor(to); } } return to; } PHP_HTTP_BUFFER_API size_t php_http_buffer_insert(php_http_buffer_t *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_t *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_t *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_t *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 php_http_buffer_t *php_http_buffer_sub( const php_http_buffer_t *buf, size_t offset, size_t length) { if (offset >= buf->used) { return NULL; } else { php_http_buffer_t *sub; size_t need = 1 + ((length + offset) > buf->used ? (buf->used - offset) : (length - offset)); unsigned flags = buf->pmem ? PHP_HTTP_BUFFER_INIT_PERSISTENT : 0; sub = php_http_buffer_init_ex(NULL, need, PHP_HTTP_BUFFER_INIT_PREALLOC | flags); 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_t *php_http_buffer_right( const php_http_buffer_t *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_t *php_http_buffer_merge_va( php_http_buffer_t *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_t *current = va_arg(argv, php_http_buffer_t *); php_http_buffer_append(buf, current->data, current->used); FREE_PHP_HTTP_BUFFER(f, current); } } return buf; } PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_merge_ex( php_http_buffer_t *buf, unsigned argc, ...) { va_list argv; php_http_buffer_t *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_t *php_http_buffer_merge(unsigned argc, ...) { va_list argv; php_http_buffer_t *ret; va_start(argv, argc); ret = php_http_buffer_merge_va(NULL, argc, argv); va_end(argv); return ret; } #endif /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: sw=4 ts=4 fdm=marker * vim<600: sw=4 ts=4 */ pecl_http-4.2.1/src/php_http_buffer.h0000644000076500000240000002442114117626035016377 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #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 PTR_FREE # define PTR_FREE(PTR) \ { \ if (EXPECTED(PTR)) { \ efree(PTR); \ } \ } #endif #ifndef PTR_SET # define PTR_SET(PTR, SET) \ { \ PTR_FREE(PTR); \ PTR = SET; \ } #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_t *) (p)) #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_t *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 { char *data; size_t used; size_t free; size_t size; unsigned pmem:1; unsigned reserved:31; } php_http_buffer_t; typedef enum php_http_buffer_free { 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_t */ #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(from, to) php_http_buffer_init_ex((to), (from)->size, (from)->pmem ? PHP_HTTP_BUFFER_INIT_PERSISTENT:0) PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_init_ex(php_http_buffer_t *buf, size_t chunk_size, unsigned flags); /* create a php_http_buffer_t 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_t *php_http_buffer_from_string_ex(php_http_buffer_t *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_t *buf, size_t len, size_t override_size, zend_bool allow_error); PHP_HTTP_BUFFER_API char *php_http_buffer_account(php_http_buffer_t *buf, size_t to_account); /* shrink memory chunk to actually used size (+1) */ PHP_HTTP_BUFFER_API size_t php_http_buffer_shrink(php_http_buffer_t *buf); /* append data to the php_http_buffer_t */ #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)) #define php_http_buffer_appendz(b, z) php_http_buffer_append((b), (z)->val, (z)->len) PHP_HTTP_BUFFER_API size_t php_http_buffer_append(php_http_buffer_t *buf, const char *append, size_t append_len); PHP_HTTP_BUFFER_API size_t php_http_buffer_appendf(php_http_buffer_t *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_t *buf, char **into, size_t *len); /* remove a substring */ PHP_HTTP_BUFFER_API size_t php_http_buffer_cut(php_http_buffer_t *buf, size_t offset, size_t length); /* sets a trailing NUL byte */ PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_fix(php_http_buffer_t *buf); /* reset php_http_buffer_t object */ PHP_HTTP_BUFFER_API void php_http_buffer_reset(php_http_buffer_t *buf); /* free a php_http_buffer_t objects contents */ PHP_HTTP_BUFFER_API void php_http_buffer_dtor(php_http_buffer_t *buf); /* free a php_http_buffer_t object completely */ PHP_HTTP_BUFFER_API void php_http_buffer_free(php_http_buffer_t **buf); /* stores data in a php_http_buffer_t until it reaches chunk_size */ PHP_HTTP_BUFFER_API size_t php_http_buffer_chunk_buffer(php_http_buffer_t **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, char *, size_t); PHP_HTTP_BUFFER_API ssize_t php_http_buffer_passthru(php_http_buffer_t **s, size_t chunk_size, php_http_buffer_pass_func_t passin, void *passin_arg, php_http_buffer_pass_func_t passon, void *passon_arg); /* wrapper around php_http_buffer_chunk_buffer, which passes available chunks to passthru() */ PHP_HTTP_BUFFER_API size_t php_http_buffer_chunked_output(php_http_buffer_t **s, const char *data, size_t data_len, size_t chunk_size, php_http_buffer_pass_func_t passout, void *opaque); /* write chunks directly into php_http_buffer_t buffer */ PHP_HTTP_BUFFER_API size_t php_http_buffer_chunked_input(php_http_buffer_t **s, size_t chunk_size, php_http_buffer_pass_func_t passin, void *opaque); # ifdef PHP_HTTP_BUFFER_EXTENDED /* memcmp for php_http_buffer_t objects */ PHP_HTTP_BUFFER_API int php_http_buffer_cmp(php_http_buffer_t *left, php_http_buffer_t *right); /* get a complete php_http_buffer_t duplicate */ PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_copy(const php_http_buffer_t *from, php_http_buffer_t *to); /* merge several php_http_buffer_t objects use like: php_http_buffer_t *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_t *php_http_buffer_merge(unsigned argc, ...); PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_merge_ex(php_http_buffer_t *buf, unsigned argc, ...); PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_merge_va(php_http_buffer_t *buf, unsigned argc, va_list argv); /* insert data at a specific position of the php_http_buffer_t */ #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_t *buf, const char *insert, size_t insert_len, size_t offset); PHP_HTTP_BUFFER_API size_t php_http_buffer_insertf(php_http_buffer_t *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_t *buf, const char *prepend, size_t prepend_len); PHP_HTTP_BUFFER_API size_t php_http_buffer_prependf(php_http_buffer_t *buf, const char *format, ...) PHP_HTTP_BUFFER_ATTRIBUTE_FORMAT(printf, 2, 3); /* get a part of the php_http_buffer_t */ #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_t *php_http_buffer_right(const php_http_buffer_t *buf, size_t length); PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_sub(const php_http_buffer_t *buf, size_t offset, size_t len); # endif /* PHP_HTTP_BUFFER_EXTENDED */ #endif /* PHP_HTTP_BUFFER_H */ /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: sw=4 ts=4 fdm=marker * vim<600: sw=4 ts=4 */ pecl_http-4.2.1/src/php_http.c0000644000076500000240000001640014117626035015037 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #include "php_http_api.h" #include "php_ini.h" #include "ext/standard/info.h" #include #if PHP_HTTP_HAVE_LIBCURL # include # if PHP_HTTP_HAVE_LIBEVENT # if PHP_HTTP_HAVE_LIBEVENT2 # include # include # else # include # endif # endif #endif #if PHP_HTTP_HAVE_LIBICU # include #endif #if PHP_HTTP_HAVE_LIBIDN # include #endif #if PHP_HTTP_HAVE_LIBIDN2 # include #endif #if PHP_HTTP_HAVE_LIBIDNKIT2 || PHP_HTTP_HAVE_LIBIDNKIT #include "idn/version.h" #endif ZEND_DECLARE_MODULE_GLOBALS(php_http); #if 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_RSHUTDOWN_FUNCTION(http); PHP_MINFO_FUNCTION(http); static zend_module_dep http_module_deps[] = { ZEND_MOD_REQUIRED("raphf") ZEND_MOD_REQUIRED("spl") #if PHP_HTTP_HAVE_HASH ZEND_MOD_REQUIRED("hash") #endif #if PHP_HTTP_HAVE_ICONV ZEND_MOD_REQUIRED("iconv") #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), NULL, PHP_RSHUTDOWN(http), PHP_MINFO(http), PHP_PECL_HTTP_VERSION, STANDARD_MODULE_PROPERTIES }; int http_module_number; #if PHP_DEBUG && !HAVE_GCOV void _dpf(int type, const char *data, size_t length) { static const char _sym[] = "><><><"; if (type) { int nwp = 0; for (fprintf(stderr, "%c ", _sym[type-1]); length--; data++) { int ip = PHP_HTTP_IS_CTYPE(print, *data); if (!ip && *data != '\r' && *data != '\n') nwp = 1; fprintf(stderr, ip?"%c":"\\x%02x", (int) (*data & 0xff)); if (!nwp && *data == '\n' && length) { fprintf(stderr, "\n%c ", _sym[type-1]); } } fprintf(stderr, "\n"); } else { fprintf(stderr, "# %.*s\n", (int) length, data); } } #endif static void php_http_globals_init_once(zend_php_http_globals *G) { memset(G, 0, sizeof(*G)); } #if 0 static inline void php_http_globals_init(zend_php_http_globals *G) { } static inline void php_http_globals_free(zend_php_http_globals *G) { } #endif PHP_INI_BEGIN() STD_PHP_INI_ENTRY("http.etag.mode", "crc32b", PHP_INI_ALL, OnUpdateString, env.etag_mode, zend_php_http_globals, php_http_globals) 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_encoding_zlib) #if PHP_HTTP_HAVE_LIBBROTLI || SUCCESS != PHP_MINIT_CALL(http_encoding_brotli) #endif || SUCCESS != PHP_MINIT_CALL(http_filter) || SUCCESS != PHP_MINIT_CALL(http_header) || SUCCESS != PHP_MINIT_CALL(http_header_parser) || SUCCESS != PHP_MINIT_CALL(http_message) || SUCCESS != PHP_MINIT_CALL(http_message_parser) || SUCCESS != PHP_MINIT_CALL(http_message_body) || SUCCESS != PHP_MINIT_CALL(http_querystring) || SUCCESS != PHP_MINIT_CALL(http_client) || SUCCESS != PHP_MINIT_CALL(http_client_request) || SUCCESS != PHP_MINIT_CALL(http_client_response) #if PHP_HTTP_HAVE_LIBCURL || SUCCESS != PHP_MINIT_CALL(http_curl) || SUCCESS != PHP_MINIT_CALL(http_client_curl) || SUCCESS != PHP_MINIT_CALL(http_client_curl_user) #endif || SUCCESS != PHP_MINIT_CALL(http_url) || SUCCESS != PHP_MINIT_CALL(http_env) || SUCCESS != PHP_MINIT_CALL(http_env_request) || SUCCESS != PHP_MINIT_CALL(http_env_response) || SUCCESS != PHP_MINIT_CALL(http_params) ) { return FAILURE; } return SUCCESS; } PHP_MSHUTDOWN_FUNCTION(http) { UNREGISTER_INI_ENTRIES(); if (0 || SUCCESS != PHP_MSHUTDOWN_CALL(http_message) #if PHP_HTTP_HAVE_LIBCURL || SUCCESS != PHP_MSHUTDOWN_CALL(http_client_curl) || SUCCESS != PHP_MSHUTDOWN_CALL(http_curl) #endif || SUCCESS != PHP_MSHUTDOWN_CALL(http_client) ) { return FAILURE; } return SUCCESS; } PHP_RSHUTDOWN_FUNCTION(http) { if (0 || SUCCESS != PHP_RSHUTDOWN_CALL(http_env) ) { return FAILURE; } return SUCCESS; } PHP_MINFO_FUNCTION(http) { php_http_buffer_t buf; php_http_buffer_init(&buf); php_info_print_table_start(); php_info_print_table_header(2, "HTTP Support", "enabled"); php_info_print_table_row(2, "Extension Version", PHP_PECL_HTTP_VERSION); php_info_print_table_end(); php_info_print_table_start(); php_info_print_table_header(3, "Used Library", "Compiled", "Linked"); php_info_print_table_row(3, "libz", ZLIB_VERSION, zlibVersion()); #if PHP_HTTP_HAVE_LIBCURL { 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 #if PHP_HTTP_HAVE_LIBEVENT php_info_print_table_row(3, "libevent", # ifdef LIBEVENT_VERSION LIBEVENT_VERSION, # else PHP_HTTP_LIBEVENT_VERSION, # endif event_get_version()); #else php_info_print_table_row(3, "libevent", "disabled", "disabled"); #endif #if PHP_HTTP_HAVE_LIBICU { UVersionInfo uv = {0}; char us[U_MAX_VERSION_STRING_LENGTH] = {0}; u_getVersion(uv); u_versionToString(uv, us); php_info_print_table_row(3, "libicu " #if HAVE_UIDNA_NAMETOASCII_UTF8 && HAVE_UIDNA_IDNTOASCII "(IDNA2008/IDNA2003)" #elif HAVE_UIDNA_NAMETOASCII_UTF8 "(IDNA2008)" #elif HAVE_UIDNA_IDNTOASCII "(IDNA2003)" #endif , U_ICU_VERSION, us); } #else php_info_print_table_row(3, "libicu (IDNA2008/IDNA2003)", "disabled", "disabled"); #endif #if PHP_HTTP_HAVE_LIBIDN2 php_info_print_table_row(3, "libidn2 (IDNA2008)", IDN2_VERSION, idn2_check_version(NULL)); #else php_info_print_table_row(3, "libidn2 (IDNA2008)", "disabled", "disabled"); #endif #if PHP_HTTP_HAVE_LIBIDN php_info_print_table_row(3, "libidn (IDNA2003)", PHP_HTTP_LIBIDN_VERSION, "unknown"); #else php_info_print_table_row(3, "libidn (IDNA2003)", "disabled", "disabled"); #endif #if PHP_HTTP_HAVE_LIBIDNKIT2 php_info_print_table_row(3, "libidnkit2 (IDNA2008)", IDNKIT_VERSION_LIBIDN, idn_version_libidn()); #else php_info_print_table_row(3, "libidnkit2 (IDNA2008)", "disabled", "disabled"); #endif #if PHP_HTTP_HAVE_LIBIDNKIT php_info_print_table_row(3, "libidnkit (IDNA2003)", IDNKIT_VERSION, idn_version_getstring()); #else php_info_print_table_row(3, "libidnkit (IDNA2003)", "disabled", "disabled"); #endif 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 */ pecl_http-4.2.1/src/php_http_client.c0000644000076500000240000013326514117626035016406 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #include "php_http_api.h" #include "php_http_client.h" #include "ext/spl/spl_observer.h" /* * array of name => php_http_client_driver_t* */ static HashTable php_http_client_drivers; static void php_http_client_driver_hash_dtor(zval *pData) { pefree(Z_PTR_P(pData), 1); } ZEND_RESULT_CODE php_http_client_driver_add(php_http_client_driver_t *driver) { return zend_hash_add_mem(&php_http_client_drivers, driver->driver_name, (void *) driver, sizeof(php_http_client_driver_t)) ? SUCCESS : FAILURE; } php_http_client_driver_t *php_http_client_driver_get(zend_string *name) { zval *ztmp; php_http_client_driver_t *tmp; if (name && (tmp = zend_hash_find_ptr(&php_http_client_drivers, name))) { return tmp; } if ((ztmp = zend_hash_get_current_data(&php_http_client_drivers))) { return Z_PTR_P(ztmp); } return NULL; } static int apply_driver_list(zval *p, void *arg) { php_http_client_driver_t *d = Z_PTR_P(p); zval zname; ZVAL_STR_COPY(&zname, d->driver_name); zend_hash_next_index_insert(arg, &zname); return ZEND_HASH_APPLY_KEEP; } void php_http_client_driver_list(HashTable *ht) { zend_hash_apply_with_argument(&php_http_client_drivers, apply_driver_list, ht); } static zend_class_entry *php_http_client_class_entry; zend_class_entry *php_http_client_get_class_entry(void) { return php_http_client_class_entry; } void php_http_client_options_set_subr(zval *instance, char *key, size_t len, zval *opts, int overwrite) { if (overwrite || (opts && zend_hash_num_elements(Z_ARRVAL_P(opts)))) { zend_class_entry *this_ce = Z_OBJCE_P(instance); zval old_opts_tmp, *old_opts, new_opts, *entry = NULL; array_init(&new_opts); old_opts = zend_read_property(this_ce, Z_OBJ_P(instance), ZEND_STRL("options"), 0, &old_opts_tmp); if (Z_TYPE_P(old_opts) == IS_ARRAY) { array_copy(Z_ARRVAL_P(old_opts), Z_ARRVAL(new_opts)); } if (overwrite) { if (opts && zend_hash_num_elements(Z_ARRVAL_P(opts))) { Z_ADDREF_P(opts); zend_symtable_str_update(Z_ARRVAL(new_opts), key, len, opts); } else { zend_symtable_str_del(Z_ARRVAL(new_opts), key, len); } } else if (opts && zend_hash_num_elements(Z_ARRVAL_P(opts))) { if ((entry = zend_symtable_str_find(Z_ARRVAL(new_opts), key, len))) { SEPARATE_ZVAL(entry); array_join(Z_ARRVAL_P(opts), Z_ARRVAL_P(entry), 0, 0); } else { Z_ADDREF_P(opts); zend_symtable_str_update(Z_ARRVAL(new_opts), key, len, opts); } } zend_update_property(this_ce, Z_OBJ_P(instance), ZEND_STRL("options"), &new_opts); zval_ptr_dtor(&new_opts); } } void php_http_client_options_set(zval *instance, zval *opts) { php_http_arrkey_t key; zval new_opts; zend_class_entry *this_ce = Z_OBJCE_P(instance); zend_bool is_client = instanceof_function(this_ce, php_http_client_class_entry); array_init(&new_opts); if (!opts || !zend_hash_num_elements(Z_ARRVAL_P(opts))) { zend_update_property(this_ce, Z_OBJ_P(instance), ZEND_STRL("options"), &new_opts); zval_ptr_dtor(&new_opts); } else { zval old_opts_tmp, *old_opts, add_opts, *opt; array_init(&add_opts); /* some options need extra attention -- thus cannot use array_merge() directly */ ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(opts), key.h, key.key, opt) { if (key.key) { if (Z_TYPE_P(opt) == IS_ARRAY && (zend_string_equals_literal(key.key, "ssl") || zend_string_equals_literal(key.key, "cookies"))) { php_http_client_options_set_subr(instance, key.key->val, key.key->len, opt, 0); } else if (is_client && (zend_string_equals_literal(key.key, "recordHistory") || zend_string_equals_literal(key.key, "responseMessageClass"))) { zend_update_property(this_ce, Z_OBJ_P(instance), key.key->val, key.key->len, opt); } else if (Z_TYPE_P(opt) == IS_NULL) { old_opts = zend_read_property(this_ce, Z_OBJ_P(instance), ZEND_STRL("options"), 0, &old_opts_tmp); if (Z_TYPE_P(old_opts) == IS_ARRAY) { zend_symtable_del(Z_ARRVAL_P(old_opts), key.key); } } else { Z_TRY_ADDREF_P(opt); add_assoc_zval_ex(&add_opts, key.key->val, key.key->len, opt); } } } ZEND_HASH_FOREACH_END(); old_opts = zend_read_property(this_ce, Z_OBJ_P(instance), ZEND_STRL("options"), 0, &old_opts_tmp); if (Z_TYPE_P(old_opts) == IS_ARRAY) { array_copy(Z_ARRVAL_P(old_opts), Z_ARRVAL(new_opts)); } array_join(Z_ARRVAL(add_opts), Z_ARRVAL(new_opts), 0, 0); zend_update_property(this_ce, Z_OBJ_P(instance), ZEND_STRL("options"), &new_opts); zval_ptr_dtor(&new_opts); zval_ptr_dtor(&add_opts); } } void php_http_client_options_get_subr(zval *instance, char *key, size_t len, zval *return_value) { zend_class_entry *this_ce = Z_OBJCE_P(instance); zval *options, opts_tmp, *opts = zend_read_property(this_ce, Z_OBJ_P(instance), ZEND_STRL("options"), 0, &opts_tmp); if ((Z_TYPE_P(opts) == IS_ARRAY) && (options = zend_symtable_str_find(Z_ARRVAL_P(opts), key, len))) { RETVAL_ZVAL(options, 1, 0); } } static void queue_dtor(void *enqueued) { php_http_client_enqueue_t *e = enqueued; if (e->dtor) { e->dtor(e); } } php_http_client_t *php_http_client_init(php_http_client_t *h, php_http_client_ops_t *ops, php_resource_factory_t *rf, void *init_arg) { php_http_client_t *free_h = NULL; if (!h) { free_h = h = emalloc(sizeof(*h)); } memset(h, 0, sizeof(*h)); h->ops = ops; if (rf) { h->rf = rf; } else if (ops->rsrc) { h->rf = php_resource_factory_init(NULL, h->ops->rsrc, h, NULL); } zend_llist_init(&h->requests, sizeof(php_http_client_enqueue_t), queue_dtor, 0); zend_llist_init(&h->responses, sizeof(void *), NULL, 0); if (h->ops->init) { if (!(h = h->ops->init(h, init_arg))) { php_error_docref(NULL, E_WARNING, "Could not initialize client"); PTR_FREE(free_h); } } return h; } php_http_client_t *php_http_client_copy(php_http_client_t *from, php_http_client_t *to) { if (from->ops->copy) { return from->ops->copy(from, to); } return NULL; } void php_http_client_dtor(php_http_client_t *h) { php_http_client_reset(h); if (h->ops->dtor) { h->ops->dtor(h); } h->callback.debug.func = NULL; h->callback.debug.arg = NULL; php_resource_factory_free(&h->rf); } void php_http_client_free(php_http_client_t **h) { if (*h) { php_http_client_dtor(*h); efree(*h); *h = NULL; } } ZEND_RESULT_CODE php_http_client_enqueue(php_http_client_t *h, php_http_client_enqueue_t *enqueue) { if (h->ops->enqueue) { if (php_http_client_enqueued(h, enqueue->request, NULL)) { php_error_docref(NULL, E_WARNING, "Failed to enqueue request; request already in queue"); return FAILURE; } return h->ops->enqueue(h, enqueue); } return FAILURE; } ZEND_RESULT_CODE php_http_client_dequeue(php_http_client_t *h, php_http_message_t *request) { if (h->ops->dequeue) { php_http_client_enqueue_t *enqueue = php_http_client_enqueued(h, request, NULL); if (!enqueue) { php_error_docref(NULL, E_WARNING, "Failed to dequeue request; request not in queue"); return FAILURE; } return h->ops->dequeue(h, enqueue); } return FAILURE; } ZEND_RESULT_CODE php_http_client_requeue(php_http_client_t *h, php_http_message_t *request) { if (h->ops->dequeue) { php_http_client_enqueue_t *enqueue = php_http_client_enqueued(h, request, NULL); if (!enqueue) { php_error_docref(NULL, E_WARNING, "Failed to requeue request; request not in queue"); return FAILURE; } return h->ops->requeue(h, enqueue); } return FAILURE; } php_http_client_enqueue_t *php_http_client_enqueued(php_http_client_t *h, void *compare_arg, php_http_client_enqueue_cmp_func_t compare_func) { zend_llist_element *el = NULL; if (compare_func) { for (el = h->requests.head; el; el = el->next) { if (compare_func((php_http_client_enqueue_t *) el->data, compare_arg)) { break; } } } else { for (el = h->requests.head; el; el = el->next) { if (((php_http_client_enqueue_t *) el->data)->request == compare_arg) { break; } } } return el ? (php_http_client_enqueue_t *) el->data : NULL; } ZEND_RESULT_CODE php_http_client_wait(php_http_client_t *h, struct timeval *custom_timeout) { if (h->ops->wait) { return h->ops->wait(h, custom_timeout); } return FAILURE; } int php_http_client_once(php_http_client_t *h) { if (h->ops->once) { return h->ops->once(h); } return FAILURE; } ZEND_RESULT_CODE php_http_client_exec(php_http_client_t *h) { if (h->ops->exec) { return h->ops->exec(h); } return FAILURE; } void php_http_client_reset(php_http_client_t *h) { if (h->ops->reset) { h->ops->reset(h); } zend_llist_clean(&h->requests); zend_llist_clean(&h->responses); } ZEND_RESULT_CODE php_http_client_setopt(php_http_client_t *h, php_http_client_setopt_opt_t opt, void *arg) { if (h->ops->setopt) { return h->ops->setopt(h, opt, arg); } return FAILURE; } ZEND_RESULT_CODE php_http_client_getopt(php_http_client_t *h, php_http_client_getopt_opt_t opt, void *arg, void *res_ptr) { if (h->ops->getopt) { return h->ops->getopt(h, opt, arg, res_ptr); } return FAILURE; } static zend_object_handlers php_http_client_object_handlers; void php_http_client_object_free(zend_object *object) { php_http_client_object_t *o = PHP_HTTP_OBJ(object, NULL); PTR_FREE(o->gc); php_http_client_free(&o->client); if (o->debug.fci.size > 0) { zend_fcall_info_args_clear(&o->debug.fci, 1); zval_ptr_dtor(&o->debug.fci.function_name); o->debug.fci.size = 0; } php_http_object_method_dtor(&o->notify); php_http_object_method_free(&o->update); zend_object_std_dtor(object); } php_http_client_object_t *php_http_client_object_new_ex(zend_class_entry *ce, php_http_client_t *client) { php_http_client_object_t *o; o = ecalloc(1, sizeof(*o) + zend_object_properties_size(ce)); zend_object_std_init(&o->zo, ce); object_properties_init(&o->zo, ce); o->client = client; o->zo.handlers = &php_http_client_object_handlers; return o; } zend_object *php_http_client_object_new(zend_class_entry *ce) { return &php_http_client_object_new_ex(ce, NULL)->zo; } static HashTable *php_http_client_object_get_gc(zend_object *object, zval **table, int *n) { php_http_client_object_t *obj = PHP_HTTP_OBJ(object, NULL); zend_llist_element *el = NULL; HashTable *props = object->handlers->get_properties(object); uint32_t count = zend_hash_num_elements(props) + zend_llist_count(&obj->client->responses) + zend_llist_count(&obj->client->requests) + 2; zval *val; *n = 0; *table = obj->gc = erealloc(obj->gc, sizeof(zval) * count); #if PHP_HTTP_HAVE_LIBCURL if (obj->client->ops == php_http_client_curl_get_ops()) { php_http_client_curl_t *curl = obj->client->ctx; if (curl->ev_ops == php_http_client_curl_user_ops_get()) { php_http_client_curl_user_context_t *ctx = curl->ev_ctx; ZVAL_COPY_VALUE(&obj->gc[(*n)++], &ctx->user); } } #endif if (obj->debug.fci.size > 0) { ZVAL_COPY_VALUE(&obj->gc[(*n)++], &obj->debug.fci.function_name); } for (el = obj->client->responses.head; el; el = el->next) { php_http_message_object_t *response_obj = *(php_http_message_object_t **) el->data; ZVAL_OBJ(&obj->gc[(*n)++], &response_obj->zo); } for (el = obj->client->requests.head; el; el = el->next) { php_http_client_enqueue_t *q = (php_http_client_enqueue_t *) el->data; if (q->request_obj) { ZVAL_OBJ(&obj->gc[(*n)++], &q->request_obj->zo); } } ZEND_HASH_FOREACH_VAL(props, val) { ZVAL_COPY_VALUE(&obj->gc[(*n)++], val); } ZEND_HASH_FOREACH_END(); return NULL; } static void handle_history(zval *zclient, php_http_message_t *request, php_http_message_t *response) { zval new_hist, old_hist_tmp, *old_hist = zend_read_property(php_http_client_class_entry, Z_OBJ_P(zclient), ZEND_STRL("history"), 0, &old_hist_tmp); php_http_message_t *req_copy = php_http_message_copy(request, NULL); php_http_message_t *res_copy = php_http_message_copy(response, NULL); php_http_message_t *zipped = php_http_message_zip(res_copy, req_copy); php_http_message_object_t *obj = php_http_message_object_new_ex(php_http_message_get_class_entry(), zipped); ZVAL_OBJ(&new_hist, &obj->zo); if (Z_TYPE_P(old_hist) == IS_OBJECT) { php_http_message_object_prepend(&new_hist, old_hist, 1); } zend_update_property(php_http_client_class_entry, Z_OBJ_P(zclient), ZEND_STRL("history"), &new_hist); zval_ptr_dtor(&new_hist); } static ZEND_RESULT_CODE handle_response(void *arg, php_http_client_t *client, php_http_client_enqueue_t *e, php_http_message_t **response) { zend_bool dequeue = 0; zval zclient; php_http_message_t *msg; php_http_client_progress_state_t *progress; ZVAL_OBJ(&zclient, &((php_http_client_object_t*) arg)->zo); if ((msg = *response)) { php_http_message_object_t *msg_obj; zval info, zresponse, zrequest, rec_hist_tmp; HashTable *info_ht; /* ensure the message is of type response (could be uninitialized in case of early error, like DNS) */ php_http_message_set_type(msg, PHP_HTTP_RESPONSE); if (zend_is_true(zend_read_property(php_http_client_class_entry, Z_OBJ(zclient), ZEND_STRL("recordHistory"), 0, &rec_hist_tmp))) { handle_history(&zclient, e->request, *response); } /* hard detach, redirects etc. are in the history */ php_http_message_free(&msg->parent); *response = NULL; msg_obj = php_http_message_object_new_ex(php_http_get_client_response_class_entry(), msg); ZVAL_OBJECT(&zresponse, &msg_obj->zo, 1); ZVAL_OBJECT(&zrequest, &((php_http_message_object_t *) e->opaque)->zo, 1); php_http_message_object_prepend(&zresponse, &zrequest, 1); object_init(&info); info_ht = HASH_OF(&info); php_http_client_getopt(client, PHP_HTTP_CLIENT_OPT_TRANSFER_INFO, e->request, &info_ht); zend_update_property(php_http_get_client_response_class_entry(), Z_OBJ(zresponse), ZEND_STRL("transferInfo"), &info); zval_ptr_dtor(&info); zend_llist_add_element(&client->responses, &msg_obj); if (e->closure.fci.size) { zval retval; zend_error_handling zeh; ZVAL_UNDEF(&retval); zend_fcall_info_argn(&e->closure.fci, 1, &zresponse); zend_replace_error_handling(EH_NORMAL, NULL, &zeh); ++client->callback.depth; zend_fcall_info_call(&e->closure.fci, &e->closure.fcc, &retval, NULL); --client->callback.depth; zend_restore_error_handling(&zeh); zend_fcall_info_argn(&e->closure.fci, 0); if (Z_TYPE(retval) == IS_TRUE) { dequeue = 1; } zval_ptr_dtor(&retval); } zval_ptr_dtor(&zresponse); zval_ptr_dtor(&zrequest); } if (SUCCESS == php_http_client_getopt(client, PHP_HTTP_CLIENT_OPT_PROGRESS_INFO, e->request, &progress)) { progress->info = "finished"; progress->finished = 1; client->callback.progress.func(client->callback.progress.arg, client, e, progress); } if (dequeue) { php_http_client_dequeue(client, e->request); } return SUCCESS; } static void handle_progress(void *arg, php_http_client_t *client, php_http_client_enqueue_t *e, php_http_client_progress_state_t *progress) { zval zclient, args[2]; php_http_client_object_t *client_obj = arg; zend_error_handling zeh; ZVAL_OBJECT(&zclient, &client_obj->zo, 1); ZVAL_OBJECT(&args[0], &((php_http_message_object_t *) e->opaque)->zo, 1); object_init(&args[1]); add_property_bool(&args[1], "started", progress->started); add_property_bool(&args[1], "finished", progress->finished); add_property_string(&args[1], "info", STR_PTR(progress->info)); add_property_double(&args[1], "dltotal", progress->dl.total); add_property_double(&args[1], "dlnow", progress->dl.now); add_property_double(&args[1], "ultotal", progress->ul.total); add_property_double(&args[1], "ulnow", progress->ul.now); zend_replace_error_handling(EH_NORMAL, NULL, &zeh); ++client->callback.depth; php_http_object_method_call(&client_obj->notify, &zclient, NULL, 2, args); --client->callback.depth; zend_restore_error_handling(&zeh); zval_ptr_dtor(&zclient); zval_ptr_dtor(&args[0]); zval_ptr_dtor(&args[1]); } static void handle_debug(void *arg, php_http_client_t *client, php_http_client_enqueue_t *e, unsigned type, const char *data, size_t size) { zval ztype, zdata, zreq, zclient; php_http_client_object_t *client_obj = arg; zend_error_handling zeh; ZVAL_OBJECT(&zclient, &client_obj->zo, 1); ZVAL_OBJECT(&zreq, &((php_http_message_object_t *) e->opaque)->zo, 1); ZVAL_LONG(&ztype, type); ZVAL_STRINGL(&zdata, data, size); zend_replace_error_handling(EH_NORMAL, NULL, &zeh); zend_fcall_info_argn(&client_obj->debug.fci, 4, &zclient, &zreq, &ztype, &zdata); ++client->callback.depth; zend_fcall_info_call(&client_obj->debug.fci, &client_obj->debug.fcc, NULL, NULL); --client->callback.depth; zend_fcall_info_args_clear(&client_obj->debug.fci, 0); zend_restore_error_handling(&zeh); zval_ptr_dtor(&zclient); zval_ptr_dtor(&zreq); zval_ptr_dtor(&ztype); zval_ptr_dtor(&zdata); } static void response_dtor(void *data) { php_http_message_object_t *msg_obj = *(php_http_message_object_t **) data; zend_object_release(&msg_obj->zo); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_construct, 0, 0, 0) ZEND_ARG_INFO(0, driver) ZEND_ARG_INFO(0, persistent_handle_id) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClient, __construct) { zend_string *driver_name = NULL, *persistent_handle_name = NULL; php_http_client_driver_t *driver; php_resource_factory_t *rf = NULL; php_http_client_object_t *obj; zval os; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|S!S!", &driver_name, &persistent_handle_name), invalid_arg, return); if (!zend_hash_num_elements(&php_http_client_drivers)) { php_http_throw(unexpected_val, "No http\\Client drivers available"); return; } if (!(driver = php_http_client_driver_get(driver_name))) { php_http_throw(unexpected_val, "Failed to locate \"%s\" client request handler", driver_name ? driver_name->val : "default"); return; } object_init_ex(&os, spl_ce_SplObjectStorage); zend_update_property(php_http_client_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("observers"), &os); zval_ptr_dtor(&os); if (persistent_handle_name) { php_persistent_handle_factory_t *pf; if ((pf = php_persistent_handle_concede(NULL, driver->client_name, persistent_handle_name, NULL, NULL))) { rf = php_persistent_handle_resource_factory_init(NULL, pf); } } obj = PHP_HTTP_OBJ(NULL, getThis()); php_http_expect(obj->client = php_http_client_init(NULL, driver->client_ops, rf, NULL), runtime, return); php_http_object_method_init(&obj->notify, getThis(), ZEND_STRL("notify")); obj->client->callback.response.func = handle_response; obj->client->callback.response.arg = obj; obj->client->callback.progress.func = handle_progress; obj->client->callback.progress.arg = obj; obj->client->responses.dtor = response_dtor; } ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_reset, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClient, reset) { php_http_client_object_t *obj; php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return); obj = PHP_HTTP_OBJ(NULL, getThis()); obj->iterator = 0; php_http_client_reset(obj->client); RETVAL_ZVAL(getThis(), 1, 0); } static HashTable *combined_options(HashTable *options, zval *client, zval *request) { unsigned num_options = 0; zval z_roptions, z_options_tmp, *z_coptions = zend_read_property(php_http_client_class_entry, Z_OBJ_P(client), ZEND_STRL("options"), 0, &z_options_tmp); if (Z_TYPE_P(z_coptions) == IS_ARRAY) { num_options = zend_hash_num_elements(Z_ARRVAL_P(z_coptions)); } ZVAL_UNDEF(&z_roptions); zend_call_method_with_0_params(Z_OBJ_P(request), NULL, NULL, "getOptions", &z_roptions); if (Z_TYPE(z_roptions) == IS_ARRAY) { unsigned num = zend_hash_num_elements(Z_ARRVAL(z_roptions)); if (num > num_options) { num_options = num; } } if (options) { zend_hash_clean(options); } else { ALLOC_HASHTABLE(options); ZEND_INIT_SYMTABLE_EX(options, num_options, 0); } if (Z_TYPE_P(z_coptions) == IS_ARRAY) { array_copy(Z_ARRVAL_P(z_coptions), options); } if (Z_TYPE(z_roptions) == IS_ARRAY) { array_join(Z_ARRVAL(z_roptions), options, 0, 0); } zval_ptr_dtor(&z_roptions); return options; } static void msg_queue_dtor(php_http_client_enqueue_t *e) { php_http_message_object_t *msg_obj = e->opaque; zend_object_release(&msg_obj->zo); zend_hash_destroy(e->options); FREE_HASHTABLE(e->options); if (e->closure.fci.size) { zval_ptr_dtor(&e->closure.fci.function_name); if (e->closure.fci.object) { zend_object_release(e->closure.fci.object); } } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_enqueue, 0, 0, 1) ZEND_ARG_OBJ_INFO(0, request, http\\Client\\Request, 0) ZEND_ARG_INFO(0, callable) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClient, enqueue) { zval *request; zend_fcall_info fci = empty_fcall_info; zend_fcall_info_cache fcc = empty_fcall_info_cache; php_http_client_object_t *obj; php_http_message_object_t *msg_obj; php_http_client_enqueue_t q = {0}; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O|f", &request, php_http_get_client_request_class_entry(), &fci, &fcc), invalid_arg, return); obj = PHP_HTTP_OBJ(NULL, getThis()); msg_obj = PHP_HTTP_OBJ(NULL, request); if (php_http_client_enqueued(obj->client, msg_obj->message, NULL)) { php_http_throw(bad_method_call, "Failed to enqueue request; request already in queue"); return; } /* set early for progress callback */ q.opaque = msg_obj; if (obj->client->callback.progress.func) { php_http_client_progress_state_t progress = {0}; progress.info = "prepare"; obj->client->callback.progress.func(obj->client->callback.progress.arg, obj->client, &q, &progress); } Z_ADDREF_P(request); q.request = msg_obj->message; q.options = combined_options(NULL, getThis(), request); q.dtor = msg_queue_dtor; q.opaque = msg_obj; q.closure.fci = fci; q.closure.fcc = fcc; if (fci.size) { Z_TRY_ADDREF(fci.function_name); if (fci.object) { GC_ADDREF(fci.object); } } php_http_expect(SUCCESS == php_http_client_enqueue(obj->client, &q), runtime, msg_queue_dtor(&q); return; ); RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_dequeue, 0, 0, 1) ZEND_ARG_OBJ_INFO(0, request, http\\Client\\Request, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClient, dequeue) { zval *request; php_http_client_object_t *obj; php_http_message_object_t *msg_obj; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O", &request, php_http_get_client_request_class_entry()), invalid_arg, return); obj = PHP_HTTP_OBJ(NULL, getThis()); msg_obj = PHP_HTTP_OBJ(NULL, request); if (!php_http_client_enqueued(obj->client, msg_obj->message, NULL)) { php_http_throw(bad_method_call, "Failed to dequeue request; request not in queue"); return; } php_http_expect(SUCCESS == php_http_client_dequeue(obj->client, msg_obj->message), runtime, return); RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_requeue, 0, 0, 1) ZEND_ARG_OBJ_INFO(0, request, http\\Client\\Request, 0) ZEND_ARG_INFO(0, callable) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClient, requeue) { zval *request; zend_fcall_info fci = empty_fcall_info; zend_fcall_info_cache fcc = empty_fcall_info_cache; php_http_client_object_t *obj; php_http_message_object_t *msg_obj; php_http_client_enqueue_t q, *e; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O|f", &request, php_http_get_client_request_class_entry(), &fci, &fcc), invalid_arg, return); obj = PHP_HTTP_OBJ(NULL, getThis()); msg_obj = PHP_HTTP_OBJ(NULL, request); if ((e = php_http_client_enqueued(obj->client, msg_obj->message, NULL))) { combined_options(e->options, getThis(), request); php_http_expect(SUCCESS == php_http_client_requeue(obj->client, msg_obj->message), runtime, return); if (fci.size) { if (e->closure.fci.size) { zval_ptr_dtor(&e->closure.fci.function_name); if (e->closure.fci.object) { zend_object_release(e->closure.fci.object); } } Z_TRY_ADDREF(fci.function_name); if (fci.object) { GC_ADDREF(fci.object); } } RETURN_ZVAL(getThis(), 1, 0); } q.request = msg_obj->message; q.options = combined_options(NULL, getThis(), request); q.dtor = msg_queue_dtor; q.opaque = msg_obj; q.closure.fci = fci; q.closure.fcc = fcc; if (fci.size) { Z_TRY_ADDREF(fci.function_name); if (fci.object) { GC_ADDREF(fci.object); } } Z_ADDREF_P(request); php_http_expect(SUCCESS == php_http_client_enqueue(obj->client, &q), runtime, msg_queue_dtor(&q); return; ); RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(ai_HttpClient_count, 0, 0, IS_LONG, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClient, count) { zend_long count_mode = -1; if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &count_mode)) { php_http_client_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); RETVAL_LONG(zend_llist_count(&obj->client->requests)); } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getResponse, 0, 0, 0) ZEND_ARG_OBJ_INFO(0, request, http\\Client\\Request, 1) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClient, getResponse) { zval *zrequest = NULL; php_http_client_object_t *obj; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|O", &zrequest, php_http_get_client_request_class_entry()), invalid_arg, return); obj = PHP_HTTP_OBJ(NULL, getThis()); if (zrequest) { /* lookup the response with the request */ zend_llist_element *el = NULL; php_http_message_object_t *req_obj = PHP_HTTP_OBJ(NULL, zrequest); for (el = obj->client->responses.head; el; el = el->next) { php_http_message_object_t *response_obj = *(php_http_message_object_t **) el->data; if (response_obj->message->parent == req_obj->message) { RETURN_OBJECT(&response_obj->zo, 1); } } /* not found for the request! */ php_http_throw(unexpected_val, "Could not find response for the request"); return; } /* pop off the last response */ if (obj->client->responses.tail) { php_http_message_object_t *response_obj = *(php_http_message_object_t **) obj->client->responses.tail->data; /* pop off and go */ if (response_obj) { RETVAL_OBJECT(&response_obj->zo, 1); zend_llist_remove_tail(&obj->client->responses); } } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getHistory, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClient, getHistory) { zval zhistory_tmp, *zhistory; php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return); zhistory = zend_read_property(php_http_client_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("history"), 0, &zhistory_tmp); RETVAL_ZVAL(zhistory, 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_send, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClient, send) { php_http_client_object_t *obj; php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return); obj = PHP_HTTP_OBJ(NULL, getThis()); php_http_expect(SUCCESS == php_http_client_exec(obj->client), runtime, return); RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_once, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClient, once) { if (SUCCESS == zend_parse_parameters_none()) { php_http_client_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); RETURN_BOOL(0 < php_http_client_once(obj->client)); } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_wait, 0, 0, 0) ZEND_ARG_INFO(0, timeout) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClient, wait) { double timeout = 0; if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|d", &timeout)) { struct timeval timeout_val; php_http_client_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); timeout_val.tv_sec = (time_t) timeout; timeout_val.tv_usec = PHP_HTTP_USEC(timeout) % PHP_HTTP_MCROSEC; RETURN_BOOL(SUCCESS == php_http_client_wait(obj->client, timeout > 0 ? &timeout_val : NULL)); } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_configure, 0, 0, 1) ZEND_ARG_ARRAY_INFO(0, settings, 1) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClient, configure) { HashTable *settings = NULL; php_http_client_object_t *obj; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|H!", &settings), invalid_arg, return); obj = PHP_HTTP_OBJ(NULL, getThis()); php_http_expect(SUCCESS == php_http_client_setopt(obj->client, PHP_HTTP_CLIENT_OPT_CONFIGURATION, settings), unexpected_val, return); RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_enablePipelining, 0, 0, 0) ZEND_ARG_INFO(0, enable) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClient, enablePipelining) { zend_bool enable = 1; php_http_client_object_t *obj; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &enable), invalid_arg, return); obj = PHP_HTTP_OBJ(NULL, getThis()); php_http_expect(SUCCESS == php_http_client_setopt(obj->client, PHP_HTTP_CLIENT_OPT_ENABLE_PIPELINING, &enable), unexpected_val, return); RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_enableEvents, 0, 0, 0) ZEND_ARG_INFO(0, enable) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClient, enableEvents) { zend_bool enable = 1; php_http_client_object_t *obj; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &enable), invalid_arg, return); obj = PHP_HTTP_OBJ(NULL, getThis()); php_http_expect(SUCCESS == php_http_client_setopt(obj->client, PHP_HTTP_CLIENT_OPT_USE_EVENTS, &enable), unexpected_val, return); RETVAL_ZVAL(getThis(), 1, 0); } struct notify_arg { php_http_object_method_t *cb; zval args[3]; int argc; }; static int notify(zend_object_iterator *iter, void *puser) { zval *observer; struct notify_arg *arg = puser; if ((observer = iter->funcs->get_current_data(iter))) { if (SUCCESS == php_http_object_method_call(arg->cb, observer, NULL, arg->argc, arg->args)) { return ZEND_HASH_APPLY_KEEP; } } return ZEND_HASH_APPLY_STOP; } #if PHP_VERSION_ID >= 80100 ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(ai_HttpClient_notify, 0, 0, IS_VOID, 0) #else ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_notify, 0, 0, 0) #endif ZEND_ARG_OBJ_INFO(0, request, http\\Client\\Request, 1) ZEND_ARG_INFO(0, progress) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClient, notify) { zval *request = NULL, *zprogress = NULL, observers_tmp, *observers; php_http_client_object_t *client_obj; struct notify_arg arg = {NULL}; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|O!o!", &request, php_http_get_client_request_class_entry(), &zprogress), invalid_arg, return); client_obj = PHP_HTTP_OBJ(NULL, getThis()); observers = zend_read_property(php_http_client_class_entry, &client_obj->zo, ZEND_STRL("observers"), 0, &observers_tmp); if (Z_TYPE_P(observers) != IS_OBJECT) { php_http_throw(unexpected_val, "Observer storage is corrupted"); return; } if (client_obj->update) { arg.cb = client_obj->update; ZVAL_COPY(&arg.args[0], getThis()); arg.argc = 1; if (request) { ZVAL_COPY(&arg.args[1], request); arg.argc += 1; } if (zprogress) { ZVAL_COPY(&arg.args[2], zprogress); arg.argc += 1; } spl_iterator_apply(observers, notify, &arg); zval_ptr_dtor(getThis()); if (request) { zval_ptr_dtor(request); } if (zprogress) { zval_ptr_dtor(zprogress); } } #if PHP_VERSION_ID < 80100 RETVAL_ZVAL(getThis(), 1, 0); #endif } #if PHP_VERSION_ID >= 80100 ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(ai_HttpClient_attach, 0, 1, IS_VOID, 0) #else ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_attach, 0, 0, 1) #endif ZEND_ARG_OBJ_INFO(0, observer, SplObserver, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClient, attach) { zval observers_tmp, *observers, *observer, retval; php_http_client_object_t *client_obj; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O", &observer, spl_ce_SplObserver), invalid_arg, return); client_obj = PHP_HTTP_OBJ(NULL, getThis()); observers = zend_read_property(php_http_client_class_entry, &client_obj->zo, ZEND_STRL("observers"), 0, &observers_tmp); if (Z_TYPE_P(observers) != IS_OBJECT) { php_http_throw(unexpected_val, "Observer storage is corrupted"); return; } if (!client_obj->update) { client_obj->update = php_http_object_method_init(NULL, observer, ZEND_STRL("update")); } ZVAL_UNDEF(&retval); zend_call_method_with_1_params(Z_OBJ_P(observers), NULL, NULL, "attach", &retval, observer); zval_ptr_dtor(&retval); #if PHP_VERSION_ID < 80100 RETVAL_ZVAL(getThis(), 1, 0); #endif } #if PHP_VERSION_ID >= 80100 ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(ai_HttpClient_detach, 0, 1, IS_VOID, 0) #else ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_detach, 0, 0, 1) #endif ZEND_ARG_OBJ_INFO(0, observer, SplObserver, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClient, detach) { zval observers_tmp, *observers, *observer, retval; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O", &observer, spl_ce_SplObserver), invalid_arg, return); observers = zend_read_property(php_http_client_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("observers"), 0, &observers_tmp); if (Z_TYPE_P(observers) != IS_OBJECT) { php_http_throw(unexpected_val, "Observer storage is corrupted"); return; } ZVAL_UNDEF(&retval); zend_call_method_with_1_params(Z_OBJ_P(observers), NULL, NULL, "detach", &retval, observer); zval_ptr_dtor(&retval); #if PHP_VERSION_ID < 80100 RETVAL_ZVAL(getThis(), 1, 0); #endif } ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getObservers, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClient, getObservers) { zval observers_tmp, *observers; php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return); observers = zend_read_property(php_http_client_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("observers"), 0, &observers_tmp); if (Z_TYPE_P(observers) != IS_OBJECT) { php_http_throw(unexpected_val, "Observer storage is corrupted"); return; } RETVAL_ZVAL(observers, 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getProgressInfo, 0, 0, 1) ZEND_ARG_OBJ_INFO(0, request, http\\Client\\Request, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClient, getProgressInfo) { zval *request; php_http_client_object_t *obj; php_http_message_object_t *req_obj; php_http_client_progress_state_t *progress; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O", &request, php_http_get_client_request_class_entry()), invalid_arg, return); obj = PHP_HTTP_OBJ(NULL, getThis()); req_obj = PHP_HTTP_OBJ(NULL, request); php_http_expect(SUCCESS == php_http_client_getopt(obj->client, PHP_HTTP_CLIENT_OPT_PROGRESS_INFO, req_obj->message, &progress), unexpected_val, return); object_init(return_value); add_property_bool(return_value, "started", progress->started); add_property_bool(return_value, "finished", progress->finished); add_property_string(return_value, "info", STR_PTR(progress->info)); add_property_double(return_value, "dltotal", progress->dl.total); add_property_double(return_value, "dlnow", progress->dl.now); add_property_double(return_value, "ultotal", progress->ul.total); add_property_double(return_value, "ulnow", progress->ul.now); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getTransferInfo, 0, 0, 1) ZEND_ARG_OBJ_INFO(0, request, http\\Client\\Request, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClient, getTransferInfo) { zval *request; HashTable *info; php_http_client_object_t *obj; php_http_message_object_t *req_obj; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O", &request, php_http_get_client_request_class_entry()), invalid_arg, return); obj = PHP_HTTP_OBJ(NULL, getThis()); req_obj = PHP_HTTP_OBJ(NULL, request); object_init(return_value); info = HASH_OF(return_value); php_http_expect(SUCCESS == php_http_client_getopt(obj->client, PHP_HTTP_CLIENT_OPT_TRANSFER_INFO, req_obj->message, &info), unexpected_val, return); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_setOptions, 0, 0, 0) ZEND_ARG_ARRAY_INFO(0, options, 1) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClient, setOptions) { zval *opts = NULL; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|a!/", &opts), invalid_arg, return); php_http_client_options_set(getThis(), opts); RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getOptions, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClient, getOptions) { if (SUCCESS == zend_parse_parameters_none()) { zval options_tmp, *options = zend_read_property(php_http_client_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("options"), 0, &options_tmp); RETVAL_ZVAL(options, 1, 0); } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_setSslOptions, 0, 0, 0) ZEND_ARG_ARRAY_INFO(0, ssl_option, 1) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClient, setSslOptions) { zval *opts = NULL; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|a!/", &opts), invalid_arg, return); php_http_client_options_set_subr(getThis(), ZEND_STRL("ssl"), opts, 1); RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_addSslOptions, 0, 0, 0) ZEND_ARG_ARRAY_INFO(0, ssl_options, 1) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClient, addSslOptions) { zval *opts = NULL; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|a!/", &opts), invalid_arg, return); php_http_client_options_set_subr(getThis(), ZEND_STRL("ssl"), opts, 0); RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getSslOptions, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClient, getSslOptions) { if (SUCCESS == zend_parse_parameters_none()) { php_http_client_options_get_subr(getThis(), ZEND_STRL("ssl"), return_value); } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_setCookies, 0, 0, 0) ZEND_ARG_ARRAY_INFO(0, cookies, 1) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClient, setCookies) { zval *opts = NULL; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|a!/", &opts), invalid_arg, return); php_http_client_options_set_subr(getThis(), ZEND_STRL("cookies"), opts, 1); RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_addCookies, 0, 0, 0) ZEND_ARG_ARRAY_INFO(0, cookies, 1) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClient, addCookies) { zval *opts = NULL; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|a!/", &opts), invalid_arg, return); php_http_client_options_set_subr(getThis(), ZEND_STRL("cookies"), opts, 0); RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getCookies, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClient, getCookies) { if (SUCCESS == zend_parse_parameters_none()) { php_http_client_options_get_subr(getThis(), ZEND_STRL("cookies"), return_value); } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getAvailableDrivers, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClient, getAvailableDrivers) { if (SUCCESS == zend_parse_parameters_none()) { array_init(return_value); php_http_client_driver_list(Z_ARRVAL_P(return_value)); } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getAvailableOptions, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClient, getAvailableOptions) { if (SUCCESS == zend_parse_parameters_none()) { php_http_client_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); array_init(return_value); php_http_client_getopt(obj->client, PHP_HTTP_CLIENT_OPT_AVAILABLE_OPTIONS, NULL, &Z_ARRVAL_P(return_value)); } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getAvailableConfiguration, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClient, getAvailableConfiguration) { if (SUCCESS == zend_parse_parameters_none()) { php_http_client_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); array_init(return_value); php_http_client_getopt(obj->client, PHP_HTTP_CLIENT_OPT_AVAILABLE_CONFIGURATION, NULL, &Z_ARRVAL_P(return_value)); } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_setDebug, 0, 0, 1) /* using IS_CALLABLE type hint would create a forwards compatibility break */ ZEND_ARG_INFO(0, callback) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClient, setDebug) { zend_fcall_info fci; zend_fcall_info_cache fcc; php_http_client_object_t *client_obj; fci.size = 0; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|f", &fci, &fcc), invalid_arg, return); client_obj = PHP_HTTP_OBJ(NULL, getThis()); if (client_obj->debug.fci.size > 0) { zval_ptr_dtor(&client_obj->debug.fci.function_name); client_obj->debug.fci.size = 0; } if (fci.size > 0) { memcpy(&client_obj->debug.fci, &fci, sizeof(fci)); memcpy(&client_obj->debug.fcc, &fcc, sizeof(fcc)); Z_ADDREF_P(&fci.function_name); client_obj->client->callback.debug.func = handle_debug; client_obj->client->callback.debug.arg = client_obj; } else { client_obj->client->callback.debug.func = NULL; client_obj->client->callback.debug.arg = NULL; } RETVAL_ZVAL(getThis(), 1, 0); } static zend_function_entry php_http_client_methods[] = { PHP_ME(HttpClient, __construct, ai_HttpClient_construct, ZEND_ACC_PUBLIC) PHP_ME(HttpClient, reset, ai_HttpClient_reset, ZEND_ACC_PUBLIC) PHP_ME(HttpClient, enqueue, ai_HttpClient_enqueue, ZEND_ACC_PUBLIC) PHP_ME(HttpClient, dequeue, ai_HttpClient_dequeue, ZEND_ACC_PUBLIC) PHP_ME(HttpClient, requeue, ai_HttpClient_requeue, ZEND_ACC_PUBLIC) PHP_ME(HttpClient, count, ai_HttpClient_count, ZEND_ACC_PUBLIC) PHP_ME(HttpClient, send, ai_HttpClient_send, ZEND_ACC_PUBLIC) PHP_ME(HttpClient, once, ai_HttpClient_once, ZEND_ACC_PUBLIC) PHP_ME(HttpClient, wait, ai_HttpClient_wait, ZEND_ACC_PUBLIC) PHP_ME(HttpClient, getResponse, ai_HttpClient_getResponse, ZEND_ACC_PUBLIC) PHP_ME(HttpClient, getHistory, ai_HttpClient_getHistory, ZEND_ACC_PUBLIC) PHP_ME(HttpClient, configure, ai_HttpClient_configure, ZEND_ACC_PUBLIC) PHP_ME(HttpClient, enablePipelining, ai_HttpClient_enablePipelining, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED) PHP_ME(HttpClient, enableEvents, ai_HttpClient_enableEvents, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED) PHP_ME(HttpClient, notify, ai_HttpClient_notify, ZEND_ACC_PUBLIC) PHP_ME(HttpClient, attach, ai_HttpClient_attach, ZEND_ACC_PUBLIC) PHP_ME(HttpClient, detach, ai_HttpClient_detach, ZEND_ACC_PUBLIC) PHP_ME(HttpClient, getObservers, ai_HttpClient_getObservers, ZEND_ACC_PUBLIC) PHP_ME(HttpClient, getProgressInfo, ai_HttpClient_getProgressInfo, ZEND_ACC_PUBLIC) PHP_ME(HttpClient, getTransferInfo, ai_HttpClient_getTransferInfo, ZEND_ACC_PUBLIC) PHP_ME(HttpClient, setOptions, ai_HttpClient_setOptions, ZEND_ACC_PUBLIC) PHP_ME(HttpClient, getOptions, ai_HttpClient_getOptions, ZEND_ACC_PUBLIC) PHP_ME(HttpClient, setSslOptions, ai_HttpClient_setSslOptions, ZEND_ACC_PUBLIC) PHP_ME(HttpClient, addSslOptions, ai_HttpClient_addSslOptions, ZEND_ACC_PUBLIC) PHP_ME(HttpClient, getSslOptions, ai_HttpClient_getSslOptions, ZEND_ACC_PUBLIC) PHP_ME(HttpClient, setCookies, ai_HttpClient_setCookies, ZEND_ACC_PUBLIC) PHP_ME(HttpClient, addCookies, ai_HttpClient_addCookies, ZEND_ACC_PUBLIC) PHP_ME(HttpClient, getCookies, ai_HttpClient_getCookies, ZEND_ACC_PUBLIC) PHP_ME(HttpClient, getAvailableDrivers, ai_HttpClient_getAvailableDrivers, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) PHP_ME(HttpClient, getAvailableOptions, ai_HttpClient_getAvailableOptions, ZEND_ACC_PUBLIC) PHP_ME(HttpClient, getAvailableConfiguration, ai_HttpClient_getAvailableConfiguration, ZEND_ACC_PUBLIC) PHP_ME(HttpClient, setDebug, ai_HttpClient_setDebug, ZEND_ACC_PUBLIC) EMPTY_FUNCTION_ENTRY }; PHP_MINIT_FUNCTION(http_client) { zend_class_entry ce = {0}; INIT_NS_CLASS_ENTRY(ce, "http", "Client", php_http_client_methods); php_http_client_class_entry = zend_register_internal_class_ex(&ce, NULL); php_http_client_class_entry->create_object = php_http_client_object_new; zend_class_implements(php_http_client_class_entry, 2, spl_ce_SplSubject, zend_ce_countable); memcpy(&php_http_client_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); php_http_client_object_handlers.offset = XtOffsetOf(php_http_client_object_t, zo); php_http_client_object_handlers.free_obj = php_http_client_object_free; php_http_client_object_handlers.clone_obj = NULL; php_http_client_object_handlers.get_gc = php_http_client_object_get_gc; zend_declare_property_null(php_http_client_class_entry, ZEND_STRL("observers"), ZEND_ACC_PRIVATE); zend_declare_property_null(php_http_client_class_entry, ZEND_STRL("options"), ZEND_ACC_PROTECTED); zend_declare_property_null(php_http_client_class_entry, ZEND_STRL("history"), ZEND_ACC_PROTECTED); zend_declare_property_bool(php_http_client_class_entry, ZEND_STRL("recordHistory"), 0, ZEND_ACC_PUBLIC); zend_declare_class_constant_long(php_http_client_class_entry, ZEND_STRL("DEBUG_INFO"), PHP_HTTP_CLIENT_DEBUG_INFO); zend_declare_class_constant_long(php_http_client_class_entry, ZEND_STRL("DEBUG_IN"), PHP_HTTP_CLIENT_DEBUG_IN); zend_declare_class_constant_long(php_http_client_class_entry, ZEND_STRL("DEBUG_OUT"), PHP_HTTP_CLIENT_DEBUG_OUT); zend_declare_class_constant_long(php_http_client_class_entry, ZEND_STRL("DEBUG_HEADER"), PHP_HTTP_CLIENT_DEBUG_HEADER); zend_declare_class_constant_long(php_http_client_class_entry, ZEND_STRL("DEBUG_BODY"), PHP_HTTP_CLIENT_DEBUG_BODY); zend_declare_class_constant_long(php_http_client_class_entry, ZEND_STRL("DEBUG_SSL"), PHP_HTTP_CLIENT_DEBUG_SSL); zend_hash_init(&php_http_client_drivers, 2, NULL, php_http_client_driver_hash_dtor, 1); return SUCCESS; } PHP_MSHUTDOWN_FUNCTION(http_client) { zend_hash_destroy(&php_http_client_drivers); 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 */ pecl_http-4.2.1/src/php_http_client.h0000644000076500000240000001626614117626035016414 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_HTTP_CLIENT_H #define PHP_HTTP_CLIENT_H typedef enum php_http_client_setopt_opt { PHP_HTTP_CLIENT_OPT_ENABLE_PIPELINING, PHP_HTTP_CLIENT_OPT_USE_EVENTS, PHP_HTTP_CLIENT_OPT_CONFIGURATION, } php_http_client_setopt_opt_t; typedef enum php_http_client_getopt_opt { PHP_HTTP_CLIENT_OPT_PROGRESS_INFO, /* php_http_client_enqueue_t*, php_http_client_progress_state_t** */ PHP_HTTP_CLIENT_OPT_TRANSFER_INFO, /* php_http_client_enqueue_t*, HashTable* */ PHP_HTTP_CLIENT_OPT_AVAILABLE_OPTIONS, /* NULL, HashTable* */ PHP_HTTP_CLIENT_OPT_AVAILABLE_CONFIGURATION,/* NULL, HashTable */ } php_http_client_getopt_opt_t; typedef struct php_http_client_enqueue { php_http_message_t *request; /* unique */ HashTable *options; void (*dtor)(struct php_http_client_enqueue *); void *opaque; struct { zend_fcall_info fci; zend_fcall_info_cache fcc; } closure; php_http_message_object_t *request_obj; /* supplemental to request */ } php_http_client_enqueue_t; typedef struct php_http_client *(*php_http_client_init_func_t)(struct php_http_client *p, void *init_arg); typedef struct php_http_client *(*php_http_client_copy_func_t)(struct php_http_client *from, struct php_http_client *to); typedef void (*php_http_client_dtor_func_t)(struct php_http_client *p); typedef void (*php_http_client_reset_func_t)(struct php_http_client *p); typedef ZEND_RESULT_CODE (*php_http_client_exec_func_t)(struct php_http_client *p); typedef int (*php_http_client_once_func_t)(struct php_http_client *p); typedef ZEND_RESULT_CODE (*php_http_client_wait_func_t)(struct php_http_client *p, struct timeval *custom_timeout); typedef ZEND_RESULT_CODE (*php_http_client_enqueue_func_t)(struct php_http_client *p, php_http_client_enqueue_t *enqueue); typedef ZEND_RESULT_CODE (*php_http_client_dequeue_func_t)(struct php_http_client *p, php_http_client_enqueue_t *enqueue); typedef ZEND_RESULT_CODE (*php_http_client_requeue_func_t)(struct php_http_client *p, php_http_client_enqueue_t *enqueue); typedef ZEND_RESULT_CODE (*php_http_client_setopt_func_t)(struct php_http_client *p, php_http_client_setopt_opt_t opt, void *arg); typedef ZEND_RESULT_CODE (*php_http_client_getopt_func_t)(struct php_http_client *h, php_http_client_getopt_opt_t opt, void *arg, void **res); typedef struct php_http_client_ops { php_resource_factory_ops_t *rsrc; php_http_client_init_func_t init; php_http_client_copy_func_t copy; php_http_client_dtor_func_t dtor; php_http_client_reset_func_t reset; php_http_client_exec_func_t exec; php_http_client_wait_func_t wait; php_http_client_once_func_t once; php_http_client_enqueue_func_t enqueue; php_http_client_dequeue_func_t dequeue; php_http_client_requeue_func_t requeue; php_http_client_setopt_func_t setopt; php_http_client_getopt_func_t getopt; } php_http_client_ops_t; typedef struct php_http_client_driver { zend_string *driver_name; zend_string *client_name; zend_string *request_name; php_http_client_ops_t *client_ops; } php_http_client_driver_t; PHP_HTTP_API ZEND_RESULT_CODE php_http_client_driver_add(php_http_client_driver_t *driver); PHP_HTTP_API php_http_client_driver_t *php_http_client_driver_get(zend_string *name); typedef struct php_http_client_progress_state { struct { double now; double total; } ul; struct { double now; double total; } dl; const char *info; unsigned started:1; unsigned finished:1; } php_http_client_progress_state_t; typedef ZEND_RESULT_CODE (*php_http_client_response_callback_t)(void *arg, struct php_http_client *client, php_http_client_enqueue_t *e, php_http_message_t **response); typedef void (*php_http_client_progress_callback_t)(void *arg, struct php_http_client *client, php_http_client_enqueue_t *e, php_http_client_progress_state_t *state); typedef void (*php_http_client_debug_callback_t)(void *arg, struct php_http_client *client, php_http_client_enqueue_t *e, unsigned type, const char *data, size_t size); #define PHP_HTTP_CLIENT_DEBUG_INFO 0x00 #define PHP_HTTP_CLIENT_DEBUG_IN 0x01 #define PHP_HTTP_CLIENT_DEBUG_OUT 0x02 #define PHP_HTTP_CLIENT_DEBUG_HEADER 0x10 #define PHP_HTTP_CLIENT_DEBUG_BODY 0x20 #define PHP_HTTP_CLIENT_DEBUG_SSL 0x40 typedef struct php_http_client { void *ctx; php_resource_factory_t *rf; php_http_client_ops_t *ops; struct { struct { php_http_client_response_callback_t func; void *arg; } response; struct { php_http_client_progress_callback_t func; void *arg; } progress; struct { php_http_client_debug_callback_t func; void *arg; } debug; unsigned depth; } callback; zend_llist requests; zend_llist responses; } php_http_client_t; PHP_HTTP_API zend_class_entry *php_http_client_get_class_entry(); typedef struct php_http_client_object { php_http_client_t *client; php_http_object_method_t *update; php_http_object_method_t notify; struct { zend_fcall_info fci; zend_fcall_info_cache fcc; } debug; long iterator; zval *gc; zend_object zo; } php_http_client_object_t; PHP_HTTP_API php_http_client_t *php_http_client_init(php_http_client_t *h, php_http_client_ops_t *ops, php_resource_factory_t *rf, void *init_arg); PHP_HTTP_API php_http_client_t *php_http_client_copy(php_http_client_t *from, php_http_client_t *to); PHP_HTTP_API void php_http_client_dtor(php_http_client_t *h); PHP_HTTP_API void php_http_client_free(php_http_client_t **h); PHP_HTTP_API ZEND_RESULT_CODE php_http_client_enqueue(php_http_client_t *h, php_http_client_enqueue_t *enqueue); PHP_HTTP_API ZEND_RESULT_CODE php_http_client_dequeue(php_http_client_t *h, php_http_message_t *request); PHP_HTTP_API ZEND_RESULT_CODE php_http_client_wait(php_http_client_t *h, struct timeval *custom_timeout); PHP_HTTP_API int php_http_client_once(php_http_client_t *h); PHP_HTTP_API ZEND_RESULT_CODE php_http_client_exec(php_http_client_t *h); PHP_HTTP_API void php_http_client_reset(php_http_client_t *h); PHP_HTTP_API ZEND_RESULT_CODE php_http_client_setopt(php_http_client_t *h, php_http_client_setopt_opt_t opt, void *arg); PHP_HTTP_API ZEND_RESULT_CODE php_http_client_getopt(php_http_client_t *h, php_http_client_getopt_opt_t opt, void *arg, void *res_ptr); typedef int (*php_http_client_enqueue_cmp_func_t)(php_http_client_enqueue_t *cmp, void *arg); /* compare with request message pointer if compare_func is NULL */ PHP_HTTP_API php_http_client_enqueue_t *php_http_client_enqueued(php_http_client_t *h, void *compare_arg, php_http_client_enqueue_cmp_func_t compare_func); PHP_MINIT_FUNCTION(http_client); PHP_MSHUTDOWN_FUNCTION(http_client); #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 */ pecl_http-4.2.1/src/php_http_client_curl.c0000644000076500000240000032003014117626035017417 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #include "php_http_api.h" #include "php_http_client.h" #include "php_http_client_curl_event.h" #include "php_http_client_curl_user.h" #if PHP_HTTP_HAVE_LIBCURL #define DEBUG_COOKIES 0 #if PHP_HTTP_HAVE_LIBCURL_OPENSSL # include #endif #if PHP_HTTP_HAVE_LIBCURL_GNUTLS # include #endif typedef struct php_http_client_curl_handler { CURL *handle; php_resource_factory_t *rf; php_http_client_t *client; php_http_client_progress_state_t progress; php_http_client_enqueue_t queue; struct { php_http_buffer_t headers; php_http_message_body_t *body; } response; struct { HashTable cache; struct curl_slist *proxyheaders; struct curl_slist *headers; struct curl_slist *resolve; php_http_buffer_t cookies; php_http_buffer_t ranges; struct { uint32_t count; double delay; } retry; long redirects; unsigned range_request:1; unsigned encode_cookies:1; } options; } php_http_client_curl_handler_t; typedef struct php_http_curle_storage { char *url; char *cookiestore; CURLcode errorcode; char errorbuffer[0x100]; } php_http_curle_storage_t; static inline php_http_curle_storage_t *php_http_curle_get_storage(CURL *ch) { php_http_curle_storage_t *st = NULL; curl_easy_getinfo(ch, CURLINFO_PRIVATE, &st); if (!st) { st = pecalloc(1, sizeof(*st), 1); curl_easy_setopt(ch, CURLOPT_PRIVATE, st); curl_easy_setopt(ch, CURLOPT_ERRORBUFFER, st->errorbuffer); } return st; } static void *php_http_curle_ctor(void *opaque, void *init_arg) { void *ch; if ((ch = curl_easy_init())) { php_http_curle_get_storage(ch); return ch; } return NULL; } static void *php_http_curle_copy(void *opaque, void *handle) { void *ch; if ((ch = curl_easy_duphandle(handle))) { curl_easy_reset(ch); php_http_curle_get_storage(ch); return ch; } return NULL; } static void php_http_curle_dtor(void *opaque, void *handle) { php_http_curle_storage_t *st = php_http_curle_get_storage(handle); curl_easy_cleanup(handle); if (st) { if (st->url) { pefree(st->url, 1); } if (st->cookiestore) { pefree(st->cookiestore, 1); } pefree(st, 1); } } static php_resource_factory_ops_t php_http_curle_resource_factory_ops = { php_http_curle_ctor, php_http_curle_copy, php_http_curle_dtor }; static void *php_http_curlm_ctor(void *opaque, void *init_arg) { php_http_client_curl_handle_t *curl = calloc(1, sizeof(*curl)); if (!(curl->multi = curl_multi_init())) { free(curl); return NULL; } if (!(curl->share = curl_share_init())) { curl_multi_cleanup(curl->multi); free(curl); return NULL; } curl_share_setopt(curl->share, CURLSHOPT_SHARE, CURL_LOCK_DATA_COOKIE); curl_share_setopt(curl->share, CURLSHOPT_SHARE, CURL_LOCK_DATA_SSL_SESSION); return curl; } static void php_http_curlm_dtor(void *opaque, void *handle) { php_http_client_curl_handle_t *curl = handle; curl_share_cleanup(curl->share); curl_multi_cleanup(curl->multi); free(handle); } static php_resource_factory_ops_t php_http_curlm_resource_factory_ops = { php_http_curlm_ctor, NULL, php_http_curlm_dtor }; /* curl callbacks */ static size_t php_http_curle_read_callback(void *data, size_t len, size_t n, void *ctx) { php_stream *s = php_http_message_body_stream(ctx); if (s) { return php_stream_read(s, data, len * n); } return 0; } #if PHP_HTTP_CURL_VERSION(7,32,0) static int php_http_curle_xferinfo_callback(void *ctx, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) #else static int php_http_curle_progress_callback(void *ctx, double dltotal, double dlnow, double ultotal, double ulnow) #endif { php_http_client_curl_handler_t *h = ctx; if (h->progress.dl.total != dltotal || h->progress.dl.now != dlnow || h->progress.ul.total != ultotal || h->progress.ul.now != ulnow ) { h->progress.dl.total = dltotal; h->progress.dl.now = dlnow; h->progress.ul.total = ultotal; h->progress.ul.now = ulnow; } if (h->client->callback.progress.func) { h->client->callback.progress.func(h->client->callback.progress.arg, h->client, &h->queue, &h->progress); } return 0; } static int php_http_curle_seek_callback(void *userdata, curl_off_t offset, int origin) { php_http_message_body_t *body = userdata; if (!body) { return 1; } if (0 == php_stream_seek(php_http_message_body_stream(body), offset, origin)) { return 0; } return 2; } static int php_http_curle_raw_callback(CURL *ch, curl_infotype type, char *data, size_t length, void *ctx) { php_http_client_curl_handler_t *h = ctx; unsigned utype = PHP_HTTP_CLIENT_DEBUG_INFO; /* catch progress */ switch (type) { case CURLINFO_TEXT: if (data[0] == '-') { goto text; } else if (php_memnstr(data, ZEND_STRL("Adding handle:"), data + length)) { h->progress.info = "setup"; } else if (php_memnstr(data, ZEND_STRL("addHandle"), data + length)) { h->progress.info = "setup"; } else if (php_memnstr(data, ZEND_STRL("About to connect"), data + length)) { h->progress.info = "resolve"; } else if (php_memnstr(data, ZEND_STRL("Trying"), data + length)) { h->progress.info = "connect"; } else if (php_memnstr(data, ZEND_STRL("Found bundle for host"), data + length)) { h->progress.info = "connect"; } else if (php_memnstr(data, ZEND_STRL("Connected"), data + length)) { h->progress.info = "connected"; } else if (php_memnstr(data, ZEND_STRL("Re-using existing connection!"), data + length)) { h->progress.info = "connected"; } else if (php_memnstr(data, ZEND_STRL("blacklisted"), data + length)) { h->progress.info = "blacklist check"; } else if (php_memnstr(data, ZEND_STRL("TLS"), data + length)) { h->progress.info = "ssl negotiation"; } else if (php_memnstr(data, ZEND_STRL("SSL"), data + length)) { h->progress.info = "ssl negotiation"; } else if (php_memnstr(data, ZEND_STRL("certificate"), data + length)) { h->progress.info = "ssl negotiation"; } else if (php_memnstr(data, ZEND_STRL("ALPN"), data + length)) { h->progress.info = "alpn"; } else if (php_memnstr(data, ZEND_STRL("NPN"), data + length)) { h->progress.info = "npn"; } else if (php_memnstr(data, ZEND_STRL("upload"), data + length)) { h->progress.info = "uploaded"; } else if (php_memnstr(data, ZEND_STRL("left intact"), data + length)) { h->progress.info = "not disconnected"; } else if (php_memnstr(data, ZEND_STRL("closed"), data + length)) { h->progress.info = "disconnected"; } else if (php_memnstr(data, ZEND_STRL("Issue another request"), data + length)) { h->progress.info = "redirect"; } else if (php_memnstr(data, ZEND_STRL("Operation timed out"), data + length)) { h->progress.info = "timeout"; } else { text:; #if 0 h->progress.info = data; data[length - 1] = '\0'; #endif } if (h->client->callback.progress.func) { h->client->callback.progress.func(h->client->callback.progress.arg, h->client, &h->queue, &h->progress); } break; case CURLINFO_HEADER_OUT: utype |= PHP_HTTP_CLIENT_DEBUG_HEADER; goto data_out; case CURLINFO_SSL_DATA_OUT: utype |= PHP_HTTP_CLIENT_DEBUG_SSL; goto data_out; case CURLINFO_DATA_OUT: data_out: utype |= PHP_HTTP_CLIENT_DEBUG_OUT; h->progress.info = "send"; break; case CURLINFO_HEADER_IN: utype |= PHP_HTTP_CLIENT_DEBUG_HEADER; goto data_in; case CURLINFO_SSL_DATA_IN: utype |= PHP_HTTP_CLIENT_DEBUG_SSL; goto data_in; case CURLINFO_DATA_IN: data_in: utype |= PHP_HTTP_CLIENT_DEBUG_IN; h->progress.info = "receive"; break; default: break; } if (h->client->callback.debug.func) { h->client->callback.debug.func(h->client->callback.debug.arg, h->client, &h->queue, utype, data, length); } #if 0 /* debug */ _dpf(type, data, length); #endif return 0; } static int php_http_curle_header_callback(char *data, size_t n, size_t l, void *arg) { php_http_client_curl_handler_t *h = arg; return php_http_buffer_append(&h->response.headers, data, n * l); } static int php_http_curle_body_callback(char *data, size_t n, size_t l, void *arg) { php_http_client_curl_handler_t *h = arg; return php_http_message_body_append(h->response.body, data, n*l); } static ZEND_RESULT_CODE php_http_curle_get_info(CURL *ch, HashTable *info) { char *c = NULL; long l = 0; double d = 0; curl_off_t o = 0; struct curl_slist *s = NULL, *p = NULL; zval tmp; ZVAL_NULL(&tmp); /* BEGIN::CURLINFO */ if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_EFFECTIVE_URL, &c)) { ZVAL_STRING(&tmp, STR_PTR(c)); zend_hash_str_update(info, "effective_url", lenof("effective_url"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_RESPONSE_CODE, &l)) { ZVAL_LONG(&tmp, l); zend_hash_str_update(info, "response_code", lenof("response_code"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_TOTAL_TIME, &d)) { ZVAL_DOUBLE(&tmp, d); zend_hash_str_update(info, "total_time", lenof("total_time"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_NAMELOOKUP_TIME, &d)) { ZVAL_DOUBLE(&tmp, d); zend_hash_str_update(info, "namelookup_time", lenof("namelookup_time"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CONNECT_TIME, &d)) { ZVAL_DOUBLE(&tmp, d); zend_hash_str_update(info, "connect_time", lenof("connect_time"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_PRETRANSFER_TIME, &d)) { ZVAL_DOUBLE(&tmp, d); zend_hash_str_update(info, "pretransfer_time", lenof("pretransfer_time"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SIZE_UPLOAD, &d)) { ZVAL_DOUBLE(&tmp, d); zend_hash_str_update(info, "size_upload", lenof("size_upload"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SIZE_DOWNLOAD, &d)) { ZVAL_DOUBLE(&tmp, d); zend_hash_str_update(info, "size_download", lenof("size_download"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SPEED_DOWNLOAD, &d)) { ZVAL_DOUBLE(&tmp, d); zend_hash_str_update(info, "speed_download", lenof("speed_download"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SPEED_UPLOAD, &d)) { ZVAL_DOUBLE(&tmp, d); zend_hash_str_update(info, "speed_upload", lenof("speed_upload"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_HEADER_SIZE, &l)) { ZVAL_LONG(&tmp, l); zend_hash_str_update(info, "header_size", lenof("header_size"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_REQUEST_SIZE, &l)) { ZVAL_LONG(&tmp, l); zend_hash_str_update(info, "request_size", lenof("request_size"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SSL_VERIFYRESULT, &l)) { ZVAL_LONG(&tmp, l); zend_hash_str_update(info, "ssl_verifyresult", lenof("ssl_verifyresult"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_FILETIME, &l)) { ZVAL_LONG(&tmp, l); zend_hash_str_update(info, "filetime", lenof("filetime"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &d)) { ZVAL_DOUBLE(&tmp, d); zend_hash_str_update(info, "content_length_download", lenof("content_length_download"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CONTENT_LENGTH_UPLOAD, &d)) { ZVAL_DOUBLE(&tmp, d); zend_hash_str_update(info, "content_length_upload", lenof("content_length_upload"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_STARTTRANSFER_TIME, &d)) { ZVAL_DOUBLE(&tmp, d); zend_hash_str_update(info, "starttransfer_time", lenof("starttransfer_time"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CONTENT_TYPE, &c)) { ZVAL_STRING(&tmp, STR_PTR(c)); zend_hash_str_update(info, "content_type", lenof("content_type"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_REDIRECT_TIME, &d)) { ZVAL_DOUBLE(&tmp, d); zend_hash_str_update(info, "redirect_time", lenof("redirect_time"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_REDIRECT_COUNT, &l)) { ZVAL_LONG(&tmp, l); zend_hash_str_update(info, "redirect_count", lenof("redirect_count"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_HTTP_CONNECTCODE, &l)) { ZVAL_LONG(&tmp, l); zend_hash_str_update(info, "connect_code", lenof("connect_code"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_HTTPAUTH_AVAIL, &l)) { ZVAL_LONG(&tmp, l); zend_hash_str_update(info, "httpauth_avail", lenof("httpauth_avail"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_PROXYAUTH_AVAIL, &l)) { ZVAL_LONG(&tmp, l); zend_hash_str_update(info, "proxyauth_avail", lenof("proxyauth_avail"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_OS_ERRNO, &l)) { ZVAL_LONG(&tmp, l); zend_hash_str_update(info, "os_errno", lenof("os_errno"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_NUM_CONNECTS, &l)) { ZVAL_LONG(&tmp, l); zend_hash_str_update(info, "num_connects", lenof("num_connects"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SSL_ENGINES, &s)) { array_init(&tmp); for (p = s; p; p = p->next) { if (p->data) { add_next_index_string(&tmp, p->data); } } zend_hash_str_update(info, "ssl_engines", lenof("ssl_engines"), &tmp); curl_slist_free_all(s); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_REDIRECT_URL, &c)) { ZVAL_STRING(&tmp, STR_PTR(c)); zend_hash_str_update(info, "redirect_url", lenof("redirect_url"), &tmp); } #if PHP_HTTP_CURL_VERSION(7,19,0) if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_PRIMARY_IP, &c)) { ZVAL_STRING(&tmp, STR_PTR(c)); zend_hash_str_update(info, "primary_ip", lenof("primary_ip"), &tmp); } #endif #if PHP_HTTP_CURL_VERSION(7,19,0) if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_APPCONNECT_TIME, &d)) { ZVAL_DOUBLE(&tmp, d); zend_hash_str_update(info, "appconnect_time", lenof("appconnect_time"), &tmp); } #endif #if PHP_HTTP_CURL_VERSION(7,19,4) if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CONDITION_UNMET, &l)) { ZVAL_LONG(&tmp, l); zend_hash_str_update(info, "condition_unmet", lenof("condition_unmet"), &tmp); } #endif #if PHP_HTTP_CURL_VERSION(7,21,0) if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_PRIMARY_PORT, &l)) { ZVAL_LONG(&tmp, l); zend_hash_str_update(info, "primary_port", lenof("primary_port"), &tmp); } #endif #if PHP_HTTP_CURL_VERSION(7,21,0) if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_LOCAL_IP, &c)) { ZVAL_STRING(&tmp, STR_PTR(c)); zend_hash_str_update(info, "local_ip", lenof("local_ip"), &tmp); } #endif #if PHP_HTTP_CURL_VERSION(7,21,0) if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_LOCAL_PORT, &l)) { ZVAL_LONG(&tmp, l); zend_hash_str_update(info, "local_port", lenof("local_port"), &tmp); } #endif #if PHP_HTTP_CURL_VERSION(7,50,0) if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_HTTP_VERSION, &l)) { ZVAL_LONG(&tmp, l); zend_hash_str_update(info, "http_version", lenof("http_version"), &tmp); } #endif #if PHP_HTTP_CURL_VERSION(7,52,0) if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_PROXY_SSL_VERIFYRESULT, &l)) { ZVAL_LONG(&tmp, l); zend_hash_str_update(info, "proxy_ssl_verifyresult", lenof("proxy_ssl_verifyresult"), &tmp); } #endif #if PHP_HTTP_CURL_VERSION(7,52,0) if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_PROTOCOL, &l)) { ZVAL_LONG(&tmp, l); zend_hash_str_update(info, "protocol", lenof("protocol"), &tmp); } #endif #if PHP_HTTP_CURL_VERSION(7,52,0) if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SCHEME, &c)) { ZVAL_STRING(&tmp, STR_PTR(c)); zend_hash_str_update(info, "scheme", lenof("scheme"), &tmp); } #endif #if PHP_HTTP_CURL_VERSION(7,66,0) if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_RETRY_AFTER, &o)) { ZVAL_LONG(&tmp, o); zend_hash_str_update(info, "retry_after", lenof("retry_after"), &tmp); } #endif #if PHP_HTTP_CURL_VERSION(7,72,0) if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_EFFECTIVE_METHOD, &c)) { ZVAL_STRING(&tmp, STR_PTR(c)); zend_hash_str_update(info, "effective_method", lenof("effective_method"), &tmp); } #endif #if PHP_HTTP_CURL_VERSION(7,73,0) if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_PROXY_ERROR, &l)) { ZVAL_LONG(&tmp, l); zend_hash_str_update(info, "proxy_error", lenof("proxy_error"), &tmp); } #endif /* END::CURLINFO */ #if PHP_HTTP_CURL_VERSION(7,34,0) { zval ti_array, subarray; struct curl_tlssessioninfo *ti; #if PHP_HTTP_CURL_VERSION(7,48,0) if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_TLS_SSL_PTR, &ti)) { #else if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_TLS_SESSION, &ti)) { #endif char *backend; ZVAL_NULL(&subarray); array_init(&ti_array); switch (ti->backend) { case CURLSSLBACKEND_NONE: backend = "none"; break; case CURLSSLBACKEND_OPENSSL: backend = "openssl"; #if PHP_HTTP_HAVE_LIBCURL_OPENSSL { #if PHP_HTTP_CURL_VERSION(7,48,0) SSL *ssl = ti->internals; SSL_CTX *ctx = ssl ? SSL_get_SSL_CTX(ssl) : NULL; #else SSL_CTX *ctx = ti->internals; #endif array_init(&subarray); if (ctx) { add_assoc_long_ex(&subarray, ZEND_STRL("number"), SSL_CTX_sess_number(ctx)); add_assoc_long_ex(&subarray, ZEND_STRL("connect"), SSL_CTX_sess_connect(ctx)); add_assoc_long_ex(&subarray, ZEND_STRL("connect_good"), SSL_CTX_sess_connect_good(ctx)); add_assoc_long_ex(&subarray, ZEND_STRL("connect_renegotiate"), SSL_CTX_sess_connect_renegotiate(ctx)); add_assoc_long_ex(&subarray, ZEND_STRL("hits"), SSL_CTX_sess_hits(ctx)); add_assoc_long_ex(&subarray, ZEND_STRL("cache_full"), SSL_CTX_sess_cache_full(ctx)); } } #endif break; case CURLSSLBACKEND_GNUTLS: backend = "gnutls"; #if PHP_HTTP_HAVE_LIBCURL_GNUTLS { gnutls_session_t sess = ti->internals; char *desc; array_init(&subarray); if (sess) { if ((desc = gnutls_session_get_desc(sess))) { add_assoc_string_ex(&subarray, ZEND_STRL("desc"), desc); gnutls_free(desc); } add_assoc_bool_ex(&subarray, ZEND_STRL("resumed"), gnutls_session_is_resumed(sess)); } } #endif break; case CURLSSLBACKEND_NSS: backend = "nss"; break; #if !PHP_HTTP_CURL_VERSION(7,39,0) case CURLSSLBACKEND_QSOSSL: backend = "qsossl"; break; #else case CURLSSLBACKEND_GSKIT: backend = "gskit"; break; #endif case CURLSSLBACKEND_POLARSSL: backend = "polarssl"; break; case CURLSSLBACKEND_CYASSL: backend = "cyassl"; break; case CURLSSLBACKEND_SCHANNEL: backend = "schannel"; break; case CURLSSLBACKEND_DARWINSSL: backend = "darwinssl"; break; default: backend = "unknown"; } add_assoc_string_ex(&ti_array, ZEND_STRL("backend"), backend); add_assoc_zval_ex(&ti_array, ZEND_STRL("internals"), &subarray); zend_hash_str_update(info, "tls_session", lenof("tls_session"), &ti_array); } } #endif #if (PHP_HTTP_CURL_VERSION(7,19,1) && PHP_HTTP_HAVE_LIBCURL_OPENSSL) || \ (PHP_HTTP_CURL_VERSION(7,34,0) && PHP_HTTP_HAVE_LIBCURL_NSS) || \ (PHP_HTTP_CURL_VERSION(7,42,0) && PHP_HTTP_HAVE_LIBCURL_GNUTLS) || \ (PHP_HTTP_CURL_VERSION(7,39,0) && PHP_HTTP_HAVE_LIBCURL_GSKIT) { int i; zval ci_array, subarray; struct curl_certinfo *ci; char *colon, *keyname; if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CERTINFO, &ci)) { array_init(&ci_array); for (i = 0; i < ci->num_of_certs; ++i) { s = ci->certinfo[i]; array_init(&subarray); for (p = s; p; p = p->next) { if (p->data) { if ((colon = strchr(p->data, ':'))) { keyname = estrndup(p->data, colon - p->data); add_assoc_string_ex(&subarray, keyname, colon - p->data, colon + 1); efree(keyname); } else { add_next_index_string(&subarray, p->data); } } } add_next_index_zval(&ci_array, &subarray); } zend_hash_str_update(info, "certinfo", lenof("certinfo"), &ci_array); } } #endif { php_http_curle_storage_t *st = php_http_curle_get_storage(ch); ZVAL_LONG(&tmp, st->errorcode); zend_hash_str_update(info, "curlcode", lenof("curlcode"), &tmp); ZVAL_STRING(&tmp, st->errorbuffer); zend_hash_str_update(info, "error", lenof("error"), &tmp); } return SUCCESS; } static int compare_queue(php_http_client_enqueue_t *e, void *handle) { return handle == ((php_http_client_curl_handler_t *) e->opaque)->handle; } static php_http_message_t *php_http_curlm_responseparser(php_http_client_curl_handler_t *h) { php_http_message_t *response; php_http_header_parser_t parser; zval *zh, tmp; response = php_http_message_init(NULL, 0, h->response.body); php_http_header_parser_init(&parser); while (h->response.headers.used) { php_http_header_parser_state_t st = php_http_header_parser_parse(&parser, &h->response.headers, PHP_HTTP_HEADER_PARSER_CLEANUP, &response->hdrs, (php_http_info_callback_t) php_http_message_info_callback, (void *) &response); if (PHP_HTTP_HEADER_PARSER_STATE_FAILURE == st) { break; } } php_http_header_parser_dtor(&parser); /* move body to right message */ if (response->body != h->response.body) { php_http_message_t *ptr = response; while (ptr->parent) { ptr = ptr->parent; } php_http_message_body_free(&response->body); response->body = ptr->body; ptr->body = NULL; } php_http_message_body_addref(h->response.body); /* let's update the response headers */ if ((zh = php_http_message_header(response, ZEND_STRL("Content-Length")))) { ZVAL_COPY(&tmp, zh); zend_hash_str_update(&response->hdrs, "X-Original-Content-Length", lenof("X-Original-Content-Length"), &tmp); } if ((zh = php_http_message_header(response, ZEND_STRL("Transfer-Encoding")))) { ZVAL_COPY(&tmp, zh); zend_hash_str_del(&response->hdrs, "Transfer-Encoding", lenof("Transfer-Encoding")); zend_hash_str_update(&response->hdrs, "X-Original-Transfer-Encoding", lenof("X-Original-Transfer-Encoding"), &tmp); } if ((zh = php_http_message_header(response, ZEND_STRL("Content-Range")))) { ZVAL_COPY(&tmp, zh); zend_hash_str_del(&response->hdrs, "Content-Range", lenof("Content-Range")); zend_hash_str_update(&response->hdrs, "X-Original-Content-Range", lenof("X-Original-Content-Range"), &tmp); } if ((zh = php_http_message_header(response, ZEND_STRL("Content-Encoding")))) { ZVAL_COPY(&tmp, zh); zend_hash_str_del(&response->hdrs, "Content-Encoding", lenof("Content-Encoding")); zend_hash_str_update(&response->hdrs, "X-Original-Content-Encoding", lenof("X-Original-Content-Encoding"), &tmp); } php_http_message_update_headers(response); return response; } void php_http_client_curl_responsehandler(php_http_client_t *context) { int err_count = 0, remaining = 0; php_http_curle_storage_t *st, *err = NULL; php_http_client_enqueue_t *enqueue; php_http_client_curl_t *curl = context->ctx; do { CURLMsg *msg = curl_multi_info_read(curl->handle->multi, &remaining); if (msg && CURLMSG_DONE == msg->msg) { if (CURLE_OK != msg->data.result) { st = php_http_curle_get_storage(msg->easy_handle); st->errorcode = msg->data.result; /* defer the warnings/exceptions, so the callback is still called for this request */ if (!err) { err = ecalloc(remaining + 1, sizeof(*err)); } memcpy(&err[err_count], st, sizeof(*st)); if (st->url) { err[err_count].url = estrdup(st->url); } err_count++; } if ((enqueue = php_http_client_enqueued(context, msg->easy_handle, compare_queue))) { php_http_client_curl_handler_t *handler = enqueue->opaque; php_http_message_t *response = php_http_curlm_responseparser(handler); if (response) { context->callback.response.func(context->callback.response.arg, context, &handler->queue, &response); php_http_message_free(&response); } } } } while (remaining); if (err_count) { int i = 0; do { php_error_docref(NULL, E_WARNING, "%s; %s (%s)", curl_easy_strerror(err[i].errorcode), err[i].errorbuffer, STR_PTR(err[i].url)); if (err[i].url) { efree(err[i].url); } } while (++i < err_count); efree(err); } } void php_http_client_curl_loop(php_http_client_t *client, curl_socket_t s, int curl_action) { CURLMcode rc; php_http_client_curl_t *curl = client->ctx; #if DBG_EVENTS fprintf(stderr, "H"); #endif do { rc = curl_multi_socket_action(curl->handle->multi, s, curl_action, &curl->unfinished); } while (CURLM_CALL_MULTI_PERFORM == rc); if (CURLM_OK != rc) { php_error_docref(NULL, E_WARNING, "%s", curl_multi_strerror(rc)); } php_http_client_curl_responsehandler(client); } /* curl options */ static php_http_options_t php_http_curle_options, php_http_curlm_options; #define PHP_HTTP_CURLE_OPTION_CHECK_STRLEN 0x0001 #define PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR 0x0002 #define PHP_HTTP_CURLE_OPTION_TRANSFORM_MS 0x0004 #define PHP_HTTP_CURLE_OPTION_IGNORE_RC 0x0008 static ZEND_RESULT_CODE php_http_curle_option_set_ssl_verifyhost(php_http_option_t *opt, zval *val, void *userdata) { php_http_client_curl_handler_t *curl = userdata; CURL *ch = curl->handle; if (CURLE_OK != curl_easy_setopt(ch, opt->option, Z_TYPE_P(val) == IS_TRUE ? 2 : 0)) { return FAILURE; } return SUCCESS; } static ZEND_RESULT_CODE php_http_curle_option_set_cookiesession(php_http_option_t *opt, zval *val, void *userdata) { php_http_client_curl_handler_t *curl = userdata; CURL *ch = curl->handle; if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIESESSION, (long) (Z_TYPE_P(val) == IS_TRUE))) { return FAILURE; } if (Z_TYPE_P(val) == IS_TRUE) { #if DEBUG_COOKIES fprintf(stderr, "CURLOPT_COOKIELIST: SESS\n"); #endif if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIELIST, "SESS")) { return FAILURE; } } return SUCCESS; } static ZEND_RESULT_CODE php_http_curle_option_set_cookiestore(php_http_option_t *opt, zval *val, void *userdata) { php_http_client_curl_handler_t *curl = userdata; CURL *ch = curl->handle; php_http_curle_storage_t *storage = php_http_curle_get_storage(curl->handle); if (storage->cookiestore) { pefree(storage->cookiestore, 1); } if (val && Z_TYPE_P(val) == IS_STRING && Z_STRLEN_P(val)) { storage->cookiestore = pestrndup(Z_STRVAL_P(val), Z_STRLEN_P(val), 1); } else { storage->cookiestore = NULL; } #if DEBUG_COOKIES fprintf(stderr, "CURLOPT_COOKIEFILE: %s\n", storage->cookiestore); #endif // does NOT enable ch->data.cookies until transfer; adds to ch->stsate.cookielist if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIEFILE, storage->cookiestore ? storage->cookiestore : "")) { return FAILURE; } #if DEBUG_COOKIES fprintf(stderr, "CURLOPT_COOKIEJAR: %s\n", storage->cookiestore); #endif // enables ch->data.cookies if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIEJAR, storage->cookiestore)) { return FAILURE; } return SUCCESS; } static ZEND_RESULT_CODE php_http_curle_option_set_cookies(php_http_option_t *opt, zval *val, void *userdata) { php_http_client_curl_handler_t *curl = userdata; CURL *ch = curl->handle; if (val && Z_TYPE_P(val) != IS_NULL) { HashTable *ht = HASH_OF(val); if (curl->options.encode_cookies) { if (SUCCESS == php_http_url_encode_hash_ex(ht, &curl->options.cookies, ZEND_STRL(";"), ZEND_STRL("="), NULL, 0)) { php_http_buffer_fix(&curl->options.cookies); if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIE, curl->options.cookies.data)) { return FAILURE; } } else { return FAILURE; } } else { php_http_arrkey_t cookie_key; zval *cookie_val; ZEND_HASH_FOREACH_KEY_VAL(ht, cookie_key.h, cookie_key.key, cookie_val) { zend_string *zs = zval_get_string(cookie_val); php_http_arrkey_stringify(&cookie_key, NULL); php_http_buffer_appendf(&curl->options.cookies, "%s=%s; ", cookie_key.key->val, zs->val); php_http_arrkey_dtor(&cookie_key); zend_string_release(zs); } ZEND_HASH_FOREACH_END(); php_http_buffer_fix(&curl->options.cookies); if (curl->options.cookies.used) { if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIE, curl->options.cookies.data)) { return FAILURE; } } } } else { php_http_buffer_reset(&curl->options.cookies); if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIE, NULL)) { return FAILURE; } } return SUCCESS; } static ZEND_RESULT_CODE php_http_curle_option_set_encodecookies(php_http_option_t *opt, zval *val, void *userdata) { php_http_client_curl_handler_t *curl = userdata; curl->options.encode_cookies = Z_TYPE_P(val) == IS_TRUE; return SUCCESS; } static ZEND_RESULT_CODE php_http_curle_option_set_lastmodified(php_http_option_t *opt, zval *val, void *userdata) { php_http_client_curl_handler_t *curl = userdata; CURL *ch = curl->handle; if (Z_LVAL_P(val)) { if (Z_LVAL_P(val) > 0) { if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_TIMEVALUE, Z_LVAL_P(val))) { return FAILURE; } } else { if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_TIMEVALUE, (long) sapi_get_request_time() + Z_LVAL_P(val))) { return FAILURE; } } if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_TIMECONDITION, (long) (curl->options.range_request ? CURL_TIMECOND_IFUNMODSINCE : CURL_TIMECOND_IFMODSINCE))) { return FAILURE; } } else { if ( CURLE_OK != curl_easy_setopt(ch, CURLOPT_TIMEVALUE, 0) || CURLE_OK != curl_easy_setopt(ch, CURLOPT_TIMECONDITION, 0) ) { return FAILURE; } } return SUCCESS; } #if PHP_HTTP_CURL_VERSION(7,64,1) static ZEND_RESULT_CODE php_http_curle_option_set_altsvc_ctrl(php_http_option_t *opt, zval *val, void *userdata) { php_http_client_curl_handler_t *curl = userdata; CURL *ch = curl->handle; if (Z_LVAL_P(val)) { if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_ALTSVC_CTRL, Z_LVAL_P(val))) { return FAILURE; } } return SUCCESS; } #endif static ZEND_RESULT_CODE php_http_curle_option_set_compress(php_http_option_t *opt, zval *val, void *userdata) { php_http_client_curl_handler_t *curl = userdata; CURL *ch = curl->handle; #if !PHP_HTTP_CURL_VERSION(7,21,6) # define CURLOPT_ACCEPT_ENCODING CURLOPT_ENCODING #endif if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_ACCEPT_ENCODING, Z_TYPE_P(val) == IS_TRUE ? "" : NULL)) { return FAILURE; } return SUCCESS; } static ZEND_RESULT_CODE php_http_curle_option_set_etag(php_http_option_t *opt, zval *val, void *userdata) { php_http_client_curl_handler_t *curl = userdata; php_http_buffer_t header; if (val && Z_TYPE_P(val) == IS_STRING && Z_STRLEN_P(val)) { zend_bool is_quoted = !((Z_STRVAL_P(val)[0] != '"') || (Z_STRVAL_P(val)[Z_STRLEN_P(val)-1] != '"')); php_http_buffer_init(&header); php_http_buffer_appendf(&header, is_quoted?"%s: %s":"%s: \"%s\"", curl->options.range_request?"If-Match":"If-None-Match", Z_STRVAL_P(val)); php_http_buffer_fix(&header); curl->options.headers = curl_slist_append(curl->options.headers, header.data); php_http_buffer_dtor(&header); } return SUCCESS; } static ZEND_RESULT_CODE php_http_curle_option_set_range(php_http_option_t *opt, zval *val, void *userdata) { php_http_client_curl_handler_t *curl = userdata; CURL *ch = curl->handle; php_http_buffer_reset(&curl->options.ranges); if (val && Z_TYPE_P(val) != IS_NULL) { zval *rr, *rb, *re; HashTable *ht = HASH_OF(val); ZEND_HASH_FOREACH_VAL(ht, rr) { if (Z_TYPE_P(rr) == IS_ARRAY) { if (2 == php_http_array_list(Z_ARRVAL_P(rr), 2, &rb, &re)) { zend_long rbl = zval_get_long(rb), rel = zval_get_long(re); if (rbl >= 0) { if (rel > 0) { php_http_buffer_appendf(&curl->options.ranges, "%ld-%ld,", rbl, rel); } else { php_http_buffer_appendf(&curl->options.ranges, "%ld-", rbl); } } else if (rel > 0) { php_http_buffer_appendf(&curl->options.ranges, "-%ld", rel); } } } } ZEND_HASH_FOREACH_END(); if (curl->options.ranges.used) { curl->options.range_request = 1; /* ditch last comma */ curl->options.ranges.data[curl->options.ranges.used - 1] = '\0'; } } if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_RANGE, curl->options.ranges.data)) { return FAILURE; } return SUCCESS; } static ZEND_RESULT_CODE php_http_curle_option_set_resume(php_http_option_t *opt, zval *val, void *userdata) { php_http_client_curl_handler_t *curl = userdata; CURL *ch = curl->handle; if (Z_LVAL_P(val) > 0) { curl->options.range_request = 1; } if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_RESUME_FROM, Z_LVAL_P(val))) { return FAILURE; } return SUCCESS; } static ZEND_RESULT_CODE php_http_curle_option_set_retrydelay(php_http_option_t *opt, zval *val, void *userdata) { php_http_client_curl_handler_t *curl = userdata; curl->options.retry.delay = Z_DVAL_P(val); return SUCCESS; } static ZEND_RESULT_CODE php_http_curle_option_set_retrycount(php_http_option_t *opt, zval *val, void *userdata) { php_http_client_curl_handler_t *curl = userdata; curl->options.retry.count = Z_LVAL_P(val); return SUCCESS; } static ZEND_RESULT_CODE php_http_curle_option_set_redirect(php_http_option_t *opt, zval *val, void *userdata) { php_http_client_curl_handler_t *curl = userdata; CURL *ch = curl->handle; if ( CURLE_OK != curl_easy_setopt(ch, CURLOPT_FOLLOWLOCATION, Z_LVAL_P(val) ? 1L : 0L) || CURLE_OK != curl_easy_setopt(ch, CURLOPT_MAXREDIRS, curl->options.redirects = Z_LVAL_P(val)) ) { return FAILURE; } return SUCCESS; } static ZEND_RESULT_CODE php_http_curle_option_set_portrange(php_http_option_t *opt, zval *val, void *userdata) { php_http_client_curl_handler_t *curl = userdata; CURL *ch = curl->handle; long localport = 0, localportrange = 0; if (val && Z_TYPE_P(val) != IS_NULL) { zval *zps, *zpe; switch (php_http_array_list(Z_ARRVAL_P(val), 2, &zps, &zpe)) { case 2: localportrange = labs(zval_get_long(zps)-zval_get_long(zpe))+1L; /* no break */ case 1: localport = (zval_get_long(zpe) > 0) ? MIN(zval_get_long(zps), zval_get_long(zpe)) : zval_get_long(zps); break; default: break; } } if ( CURLE_OK != curl_easy_setopt(ch, CURLOPT_LOCALPORT, localport) || CURLE_OK != curl_easy_setopt(ch, CURLOPT_LOCALPORTRANGE, localportrange) ) { return FAILURE; } return SUCCESS; } #if PHP_HTTP_CURL_VERSION(7,37,0) static ZEND_RESULT_CODE php_http_curle_option_set_proxyheader(php_http_option_t *opt, zval *val, void *userdata) { php_http_client_curl_handler_t *curl = userdata; if (val && Z_TYPE_P(val) != IS_NULL) { php_http_arrkey_t header_key; zval *header_val; php_http_buffer_t header; php_http_buffer_init(&header); ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(val), header_key.h, header_key.key, header_val) { if (header_key.key) { zend_string *zs = zval_get_string(header_val); php_http_buffer_appendf(&header, "%s: %s", header_key.key->val, zs->val); zend_string_release(zs); php_http_buffer_fix(&header); curl->options.proxyheaders = curl_slist_append(curl->options.proxyheaders, header.data); php_http_buffer_reset(&header); } } ZEND_HASH_FOREACH_END(); php_http_buffer_dtor(&header); } if (CURLE_OK != curl_easy_setopt(curl->handle, CURLOPT_PROXYHEADER, curl->options.proxyheaders)) { return FAILURE; } if (CURLE_OK != curl_easy_setopt(curl->handle, CURLOPT_HEADEROPT, CURLHEADER_SEPARATE)) { curl_easy_setopt(curl->handle, CURLOPT_PROXYHEADER, NULL); return FAILURE; } return SUCCESS; } #endif #if PHP_HTTP_CURL_VERSION(7,21,3) static ZEND_RESULT_CODE php_http_curle_option_set_resolve(php_http_option_t *opt, zval *val, void *userdata) { php_http_client_curl_handler_t *curl = userdata; CURL *ch = curl->handle; if (val && Z_TYPE_P(val) != IS_NULL) { HashTable *ht = HASH_OF(val); zval *data; ZEND_HASH_FOREACH_VAL(ht, data) { zend_string *zs = zval_get_string(data); curl->options.resolve = curl_slist_append(curl->options.resolve, zs->val); zend_string_release(zs); } ZEND_HASH_FOREACH_END(); if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_RESOLVE, curl->options.resolve)) { return FAILURE; } } else { if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_RESOLVE, NULL)) { return FAILURE; } } return SUCCESS; } #endif #if PHP_HTTP_CURL_VERSION(7,21,4) && PHP_HTTP_HAVE_LIBCURL_TLSAUTH_TYPE static ZEND_RESULT_CODE php_http_curle_option_set_ssl_tlsauthtype(php_http_option_t *opt, zval *val, void *userdata) { php_http_client_curl_handler_t *curl = userdata; CURL *ch = curl->handle; if (val && Z_LVAL_P(val)) { switch (Z_LVAL_P(val)) { case CURL_TLSAUTH_SRP: if (CURLE_OK == curl_easy_setopt(ch, opt->option, PHP_HTTP_LIBCURL_TLSAUTH_SRP)) { return SUCCESS; } /* no break */ default: return FAILURE; } } if (CURLE_OK != curl_easy_setopt(ch, opt->option, PHP_HTTP_LIBCURL_TLSAUTH_DEF)) { return FAILURE; } return SUCCESS; } #endif static void php_http_curle_options_init(php_http_options_t *registry) { php_http_option_t *opt; /* url options */ #if PHP_HTTP_CURL_VERSION(7,42,0) php_http_option_register(registry, ZEND_STRL("path_as_is"), CURLOPT_PATH_AS_IS, _IS_BOOL); #endif /* proxy */ php_http_option_register(registry, ZEND_STRL("proxyhost"), CURLOPT_PROXY, IS_STRING); php_http_option_register(registry, ZEND_STRL("proxytype"), CURLOPT_PROXYTYPE, IS_LONG); php_http_option_register(registry, ZEND_STRL("proxyport"), CURLOPT_PROXYPORT, IS_LONG); if ((opt = php_http_option_register(registry, ZEND_STRL("proxyauth"), CURLOPT_PROXYUSERPWD, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; } if ((opt = php_http_option_register(registry, ZEND_STRL("proxyauthtype"), CURLOPT_PROXYAUTH, IS_LONG))) { Z_LVAL(opt->defval) = CURLAUTH_ANYSAFE; } php_http_option_register(registry, ZEND_STRL("proxytunnel"), CURLOPT_HTTPPROXYTUNNEL, _IS_BOOL); #if PHP_HTTP_CURL_VERSION(7,19,4) php_http_option_register(registry, ZEND_STRL("noproxy"), CURLOPT_NOPROXY, IS_STRING); #endif #if PHP_HTTP_CURL_VERSION(7,55,0) php_http_option_register(registry, ZEND_STRL("socks5_auth"), CURLOPT_SOCKS5_AUTH, IS_LONG); #endif #if PHP_HTTP_CURL_VERSION(7,37,0) if ((opt = php_http_option_register(registry, ZEND_STRL("proxyheader"), CURLOPT_PROXYHEADER, IS_ARRAY))) { opt->setter = php_http_curle_option_set_proxyheader; } #endif #if PHP_HTTP_CURL_VERSION(7,43,0) if (PHP_HTTP_CURL_FEATURE(CURL_VERSION_GSSAPI) && (opt = php_http_option_register(registry, ZEND_STRL("proxy_service_name"), CURLOPT_PROXY_SERVICE_NAME, IS_STRING)) ) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; } #endif #if PHP_HTTP_CURL_VERSION(7,60,0) php_http_option_register(registry, ZEND_STRL("haproxy_protocol"), CURLOPT_HAPROXYPROTOCOL, _IS_BOOL); #endif /* unix sockets */ #if PHP_HTTP_CURL_VERSION(7,40,0) if (PHP_HTTP_CURL_FEATURE(CURL_VERSION_UNIX_SOCKETS)) { if ((opt = php_http_option_register(registry, ZEND_STRL("unix_socket_path"), CURLOPT_UNIX_SOCKET_PATH, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; } #if PHP_HTTP_CURL_VERSION(7,53,0) if ((opt = php_http_option_register(registry, ZEND_STRL("abstract_unix_socket"), CURLOPT_ABSTRACT_UNIX_SOCKET, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; } #endif } #endif /* dns */ if ((opt = php_http_option_register(registry, ZEND_STRL("dns_cache_timeout"), CURLOPT_DNS_CACHE_TIMEOUT, IS_LONG))) { Z_LVAL(opt->defval) = 60; } php_http_option_register(registry, ZEND_STRL("ipresolve"), CURLOPT_IPRESOLVE, IS_LONG); #if PHP_HTTP_CURL_VERSION(7,21,3) if ((opt = php_http_option_register(registry, ZEND_STRL("resolve"), CURLOPT_RESOLVE, IS_ARRAY))) { opt->setter = php_http_curle_option_set_resolve; } #endif #if PHP_HTTP_HAVE_LIBCURL_ARES # if PHP_HTTP_CURL_VERSION(7,24,0) if ((opt = php_http_option_register(registry, ZEND_STRL("dns_servers"), CURLOPT_DNS_SERVERS, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; } # endif # if PHP_HTTP_CURL_VERSION(7,33,0) if ((opt = php_http_option_register(registry, ZEND_STRL("dns_interface"), CURLOPT_DNS_INTERFACE, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; } if ((opt = php_http_option_register(registry, ZEND_STRL("dns_local_ip4"), CURLOPT_DNS_LOCAL_IP4, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; } if ((opt = php_http_option_register(registry, ZEND_STRL("dns_local_ip6"), CURLOPT_DNS_LOCAL_IP6, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; } # endif #endif #if PHP_HTTP_CURL_VERSION(7,60,0) php_http_option_register(registry, ZEND_STRL("dns_shuffle_addresses"), CURLOPT_DNS_SHUFFLE_ADDRESSES, _IS_BOOL); #endif #if PHP_HTTP_CURL_VERSION(7,62,0) php_http_option_register(registry, ZEND_STRL("doh_url"), CURLOPT_DOH_URL, IS_STRING); #endif /* limits */ php_http_option_register(registry, ZEND_STRL("low_speed_limit"), CURLOPT_LOW_SPEED_LIMIT, IS_LONG); php_http_option_register(registry, ZEND_STRL("low_speed_time"), CURLOPT_LOW_SPEED_TIME, IS_LONG); /* LSF weirdance php_http_option_register(registry, ZEND_STRL("max_send_speed"), CURLOPT_MAX_SEND_SPEED_LARGE, IS_LONG); php_http_option_register(registry, ZEND_STRL("max_recv_speed"), CURLOPT_MAX_RECV_SPEED_LARGE, IS_LONG); */ /* connection handling */ /* crashes if ((opt = php_http_option_register(registry, ZEND_STRL("maxconnects"), CURLOPT_MAXCONNECTS, IS_LONG))) { Z_LVAL(opt->defval) = 5; } */ php_http_option_register(registry, ZEND_STRL("fresh_connect"), CURLOPT_FRESH_CONNECT, _IS_BOOL); php_http_option_register(registry, ZEND_STRL("forbid_reuse"), CURLOPT_FORBID_REUSE, _IS_BOOL); #if PHP_HTTP_CURL_VERSION(7,65,0) if ((opt = php_http_option_register(registry, ZEND_STRL("maxage_conn"), CURLOPT_MAXAGE_CONN, IS_LONG))) { ZVAL_LONG(&opt->defval, 118); } #endif /* outgoing interface */ php_http_option_register(registry, ZEND_STRL("interface"), CURLOPT_INTERFACE, IS_STRING); if ((opt = php_http_option_register(registry, ZEND_STRL("portrange"), CURLOPT_LOCALPORT, IS_ARRAY))) { opt->setter = php_http_curle_option_set_portrange; } /* another endpoint port */ php_http_option_register(registry, ZEND_STRL("port"), CURLOPT_PORT, IS_LONG); /* RFC4007 zone_id */ #if PHP_HTTP_CURL_VERSION(7,19,0) php_http_option_register(registry, ZEND_STRL("address_scope"), CURLOPT_ADDRESS_SCOPE, IS_LONG); #endif /* auth */ if ((opt = php_http_option_register(registry, ZEND_STRL("httpauth"), CURLOPT_USERPWD, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; } if ((opt = php_http_option_register(registry, ZEND_STRL("httpauthtype"), CURLOPT_HTTPAUTH, IS_LONG))) { Z_LVAL(opt->defval) = CURLAUTH_ANYSAFE; } #if PHP_HTTP_CURL_VERSION(7,43,0) if (PHP_HTTP_CURL_FEATURE(CURL_VERSION_SSPI) || PHP_HTTP_CURL_FEATURE(CURL_VERSION_GSSAPI)) if ((opt = php_http_option_register(registry, ZEND_STRL("service_name"), CURLOPT_SERVICE_NAME, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; } #endif #if PHP_HTTP_CURL_VERSION(7,61,0) if ((opt = php_http_option_register(registry, ZEND_STRL("xoauth2_bearer"), CURLOPT_XOAUTH2_BEARER, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; } #endif #if PHP_HTTP_CURL_VERSION(7,75,0) php_http_option_register(registry, ZEND_STRL("aws_sigv4"), CURLOPT_AWS_SIGV4, IS_STRING); #endif /* redirects */ if ((opt = php_http_option_register(registry, ZEND_STRL("redirect"), CURLOPT_FOLLOWLOCATION, IS_LONG))) { opt->setter = php_http_curle_option_set_redirect; } php_http_option_register(registry, ZEND_STRL("unrestricted_auth"), CURLOPT_UNRESTRICTED_AUTH, _IS_BOOL); #if PHP_HTTP_CURL_VERSION(7,19,1) php_http_option_register(registry, ZEND_STRL("postredir"), CURLOPT_POSTREDIR, IS_LONG); #endif /* retries */ if ((opt = php_http_option_register(registry, ZEND_STRL("retrycount"), 0, IS_LONG))) { opt->setter = php_http_curle_option_set_retrycount; } if ((opt = php_http_option_register(registry, ZEND_STRL("retrydelay"), 0, IS_DOUBLE))) { opt->setter = php_http_curle_option_set_retrydelay; } /* referer */ if ((opt = php_http_option_register(registry, ZEND_STRL("referer"), CURLOPT_REFERER, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; } if ((opt = php_http_option_register(registry, ZEND_STRL("autoreferer"), CURLOPT_AUTOREFERER, _IS_BOOL))) { ZVAL_BOOL(&opt->defval, 1); } /* useragent */ if ((opt = php_http_option_register(registry, ZEND_STRL("useragent"), CURLOPT_USERAGENT, IS_STRING))) { /* don't check strlen, to allow sending no useragent at all */ ZVAL_PSTRING(&opt->defval, "PECL_HTTP/" PHP_PECL_HTTP_VERSION " " "PHP/" PHP_VERSION " " "libcurl/" LIBCURL_VERSION); } /* resume */ if ((opt = php_http_option_register(registry, ZEND_STRL("resume"), CURLOPT_RESUME_FROM, IS_LONG))) { opt->setter = php_http_curle_option_set_resume; } /* ranges */ if ((opt = php_http_option_register(registry, ZEND_STRL("range"), CURLOPT_RANGE, IS_ARRAY))) { opt->setter = php_http_curle_option_set_range; } /* etag */ if ((opt = php_http_option_register(registry, ZEND_STRL("etag"), 0, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; opt->setter = php_http_curle_option_set_etag; } /* compression */ if ((opt = php_http_option_register(registry, ZEND_STRL("compress"), 0, _IS_BOOL))) { opt->setter = php_http_curle_option_set_compress; } /* lastmodified */ if ((opt = php_http_option_register(registry, ZEND_STRL("lastmodified"), 0, IS_LONG))) { opt->setter = php_http_curle_option_set_lastmodified; } /* cookies */ if ((opt = php_http_option_register(registry, ZEND_STRL("encodecookies"), 0, _IS_BOOL))) { opt->setter = php_http_curle_option_set_encodecookies; ZVAL_BOOL(&opt->defval, 1); } if ((opt = php_http_option_register(registry, ZEND_STRL("cookies"), 0, IS_ARRAY))) { opt->setter = php_http_curle_option_set_cookies; } /* cookiesession, don't load session cookies from cookiestore */ if ((opt = php_http_option_register(registry, ZEND_STRL("cookiesession"), CURLOPT_COOKIESESSION, _IS_BOOL))) { opt->setter = php_http_curle_option_set_cookiesession; } /* cookiestore, read initial cookies from that file and store cookies back into that file */ if ((opt = php_http_option_register(registry, ZEND_STRL("cookiestore"), 0, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; opt->setter = php_http_curle_option_set_cookiestore; } /* maxfilesize */ php_http_option_register(registry, ZEND_STRL("maxfilesize"), CURLOPT_MAXFILESIZE, IS_LONG); /* http protocol version */ php_http_option_register(registry, ZEND_STRL("protocol"), CURLOPT_HTTP_VERSION, IS_LONG); #if PHP_HTTP_CURL_VERSION(7,64,0) php_http_option_register(registry, ZEND_STRL("http09_allowed"), CURLOPT_HTTP09_ALLOWED, _IS_BOOL); #endif /* timeouts */ if ((opt = php_http_option_register(registry, ZEND_STRL("timeout"), CURLOPT_TIMEOUT_MS, IS_DOUBLE))) { opt->flags |= PHP_HTTP_CURLE_OPTION_TRANSFORM_MS; } if ((opt = php_http_option_register(registry, ZEND_STRL("connecttimeout"), CURLOPT_CONNECTTIMEOUT_MS, IS_DOUBLE))) { opt->flags |= PHP_HTTP_CURLE_OPTION_TRANSFORM_MS; Z_DVAL(opt->defval) = 3; } #if PHP_HTTP_CURL_VERSION(7,36,0) if ((opt = php_http_option_register(registry, ZEND_STRL("expect_100_timeout"), CURLOPT_EXPECT_100_TIMEOUT_MS, IS_DOUBLE))) { opt->flags |= PHP_HTTP_CURLE_OPTION_TRANSFORM_MS; Z_DVAL(opt->defval) = 1; } #endif /* tcp */ php_http_option_register(registry, ZEND_STRL("tcp_nodelay"), CURLOPT_TCP_NODELAY, _IS_BOOL); #if PHP_HTTP_CURL_VERSION(7,25,0) php_http_option_register(registry, ZEND_STRL("tcp_keepalive"), CURLOPT_TCP_KEEPALIVE, _IS_BOOL); if ((opt = php_http_option_register(registry, ZEND_STRL("tcp_keepidle"), CURLOPT_TCP_KEEPIDLE, IS_LONG))) { Z_LVAL(opt->defval) = 60; } if ((opt = php_http_option_register(registry, ZEND_STRL("tcp_keepintvl"), CURLOPT_TCP_KEEPINTVL, IS_LONG))) { Z_LVAL(opt->defval) = 60; } #endif #if PHP_HTTP_CURL_VERSION(7,49,0) php_http_option_register(registry, ZEND_STRL("tcp_fastopen"), CURLOPT_TCP_FASTOPEN, _IS_BOOL); #endif /* ssl */ if (PHP_HTTP_CURL_FEATURE(CURL_VERSION_SSL)) { php_http_option_t *ssl_opt, *proxy_opt; if ((ssl_opt = php_http_option_register(registry, ZEND_STRL("ssl"), 0, IS_ARRAY))) { php_http_options_t *ssl_registry = &ssl_opt->suboptions; if ((opt = php_http_option_register(ssl_registry, ZEND_STRL("cert"), CURLOPT_SSLCERT, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; } if ((opt = php_http_option_register(ssl_registry, ZEND_STRL("certtype"), CURLOPT_SSLCERTTYPE, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; ZVAL_PSTRING(&opt->defval, "PEM"); } if ((opt = php_http_option_register(ssl_registry, ZEND_STRL("key"), CURLOPT_SSLKEY, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; } if ((opt = php_http_option_register(ssl_registry, ZEND_STRL("keytype"), CURLOPT_SSLKEYTYPE, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; ZVAL_PSTRING(&opt->defval, "PEM"); } if ((opt = php_http_option_register(ssl_registry, ZEND_STRL("keypasswd"), CURLOPT_SSLKEYPASSWD, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; } php_http_option_register(ssl_registry, ZEND_STRL("engine"), CURLOPT_SSLENGINE, IS_STRING); php_http_option_register(ssl_registry, ZEND_STRL("version"), CURLOPT_SSLVERSION, IS_LONG); if ((opt = php_http_option_register(ssl_registry, ZEND_STRL("verifypeer"), CURLOPT_SSL_VERIFYPEER, _IS_BOOL))) { ZVAL_BOOL(&opt->defval, 1); } if ((opt = php_http_option_register(ssl_registry, ZEND_STRL("verifyhost"), CURLOPT_SSL_VERIFYHOST, _IS_BOOL))) { ZVAL_BOOL(&opt->defval, 1); opt->setter = php_http_curle_option_set_ssl_verifyhost; } #if PHP_HTTP_CURL_VERSION(7,41,0) && (PHP_HTTP_HAVE_LIBCURL_OPENSSL || PHP_HTTP_HAVE_LIBCURL_NSS || PHP_HTTP_HAVE_LIBCURL_GNUTLS) php_http_option_register(ssl_registry, ZEND_STRL("verifystatus"), CURLOPT_SSL_VERIFYSTATUS, _IS_BOOL); #endif php_http_option_register(ssl_registry, ZEND_STRL("cipher_list"), CURLOPT_SSL_CIPHER_LIST, IS_STRING); #if PHP_HTTP_HAVE_LIBCURL_CAINFO if ((opt = php_http_option_register(ssl_registry, ZEND_STRL("cainfo"), CURLOPT_CAINFO, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; # ifdef PHP_HTTP_CAINFO ZVAL_PSTRING(&opt->defval, PHP_HTTP_CAINFO); # endif } #endif #if PHP_HTTP_HAVE_LIBCURL_CAPATH if ((opt = php_http_option_register(ssl_registry, ZEND_STRL("capath"), CURLOPT_CAPATH, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; # ifdef PHP_HTTP_CAPATH ZVAL_PSTRING(&opt->defval, PHP_HTTP_CAPATH); # endif } #endif if ((opt = php_http_option_register(ssl_registry, ZEND_STRL("random_file"), CURLOPT_RANDOM_FILE, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; } if ((opt = php_http_option_register(ssl_registry, ZEND_STRL("egdsocket"), CURLOPT_EGDSOCKET, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; } #if PHP_HTTP_CURL_VERSION(7,19,0) if ((opt = php_http_option_register(ssl_registry, ZEND_STRL("issuercert"), CURLOPT_ISSUERCERT, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; } # if PHP_HTTP_HAVE_LIBCURL_OPENSSL if ((opt = php_http_option_register(ssl_registry, ZEND_STRL("crlfile"), CURLOPT_CRLFILE, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; } # endif #endif #if (PHP_HTTP_CURL_VERSION(7,19,1) && PHP_HTTP_HAVE_LIBCURL_OPENSSL) || (PHP_HTTP_CURL_VERSION(7,34,0) && PHP_HTTP_HAVE_LIBCURL_NSS) || (PHP_HTTP_CURL_VERSION(7,42,0) && defined(PHP_HTTP_HAVE_LIBCURL_GNUTLS)) || (PHP_HTTP_CURL_VERSION(7,39,0) && defined(PHP_HTTP_HAVE_LIBCURL_GSKIT)) if ((opt = php_http_option_register(ssl_registry, ZEND_STRL("certinfo"), CURLOPT_CERTINFO, _IS_BOOL))) { ZVAL_FALSE(&opt->defval); } #endif #if PHP_HTTP_CURL_VERSION(7,36,0) if ((opt = php_http_option_register(ssl_registry, ZEND_STRL("enable_npn"), CURLOPT_SSL_ENABLE_NPN, _IS_BOOL))) { ZVAL_BOOL(&opt->defval, 1); } if ((opt = php_http_option_register(ssl_registry, ZEND_STRL("enable_alpn"), CURLOPT_SSL_ENABLE_ALPN, _IS_BOOL))) { ZVAL_BOOL(&opt->defval, 1); } #endif #if PHP_HTTP_CURL_VERSION(7,39,0) /* FIXME: see http://curl.haxx.se/libcurl/c/CURLOPT_PINNEDPUBLICKEY.html#AVAILABILITY */ if ((opt = php_http_option_register(ssl_registry, ZEND_STRL("pinned_publickey"), CURLOPT_PINNEDPUBLICKEY, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; } #endif #if PHP_HTTP_CURL_VERSION(7,21,4) && PHP_HTTP_HAVE_LIBCURL_TLSAUTH_TYPE if ((opt = php_http_option_register(ssl_registry, ZEND_STRL("tlsauthtype"), CURLOPT_TLSAUTH_TYPE, IS_LONG))) { opt->setter = php_http_curle_option_set_ssl_tlsauthtype; } if ((opt = php_http_option_register(ssl_registry, ZEND_STRL("tlsauthuser"), CURLOPT_TLSAUTH_USERNAME, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; } if ((opt = php_http_option_register(ssl_registry, ZEND_STRL("tlsauthpass"), CURLOPT_TLSAUTH_PASSWORD, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; } #endif #if PHP_HTTP_CURL_VERSION(7,42,0) && (PHP_HTTP_HAVE_LIBCURL_NSS || PHP_HTTP_HAVE_LIBCURL_SECURETRANSPORT) if ((opt = php_http_option_register(ssl_registry, ZEND_STRL("falsestart"), CURLOPT_SSL_FALSESTART, _IS_BOOL))) { opt->flags |= PHP_HTTP_CURLE_OPTION_IGNORE_RC; } #endif #if PHP_HTTP_CURL_VERSION(7,61,0) && PHP_HTTP_HAVE_LIBCURL_TLS13_CIPHERS if ((opt = php_http_option_register(ssl_registry, ZEND_STRL("tls13_ciphers"), CURLOPT_TLS13_CIPHERS, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; } #endif } #if PHP_HTTP_CURL_VERSION(7,52,0) /* proxy_ssl */ if ((proxy_opt = php_http_option_register(registry, ZEND_STRL("proxy_ssl"), 0, IS_ARRAY))) { php_http_options_t *proxy_registry = &proxy_opt->suboptions; if ((opt = php_http_option_register(proxy_registry, ZEND_STRL("cert"), CURLOPT_PROXY_SSLCERT, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; } if ((opt = php_http_option_register(proxy_registry, ZEND_STRL("certtype"), CURLOPT_PROXY_SSLCERTTYPE, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; ZVAL_PSTRING(&opt->defval, "PEM"); } if ((opt = php_http_option_register(proxy_registry, ZEND_STRL("key"), CURLOPT_PROXY_SSLKEY, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; } if ((opt = php_http_option_register(proxy_registry, ZEND_STRL("keytype"), CURLOPT_PROXY_SSLKEYTYPE, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; ZVAL_PSTRING(&opt->defval, "PEM"); } if ((opt = php_http_option_register(proxy_registry, ZEND_STRL("keypasswd"), CURLOPT_PROXY_KEYPASSWD, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; } php_http_option_register(proxy_registry, ZEND_STRL("version"), CURLOPT_PROXY_SSLVERSION, IS_LONG); if ((opt = php_http_option_register(proxy_registry, ZEND_STRL("verifypeer"), CURLOPT_PROXY_SSL_VERIFYPEER, _IS_BOOL))) { ZVAL_BOOL(&opt->defval, 1); } if ((opt = php_http_option_register(proxy_registry, ZEND_STRL("verifyhost"), CURLOPT_PROXY_SSL_VERIFYHOST, _IS_BOOL))) { ZVAL_BOOL(&opt->defval, 1); opt->setter = php_http_curle_option_set_ssl_verifyhost; } php_http_option_register(proxy_registry, ZEND_STRL("cipher_list"), CURLOPT_PROXY_SSL_CIPHER_LIST, IS_STRING); # if PHP_HTTP_CURL_VERSION(7,71,0) if ((opt = php_http_option_register(proxy_registry, ZEND_STRL("issuercert"), CURLOPT_PROXY_ISSUERCERT, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; } # endif # if PHP_HTTP_HAVE_LIBCURL_OPENSSL if ((opt = php_http_option_register(proxy_registry, ZEND_STRL("crlfile"), CURLOPT_PROXY_CRLFILE, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; } # endif # if PHP_HTTP_HAVE_LIBCURL_CAINFO if ((opt = php_http_option_register(proxy_registry, ZEND_STRL("cainfo"), CURLOPT_PROXY_CAINFO, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; # ifdef PHP_HTTP_CAINFO ZVAL_PSTRING(&opt->defval, PHP_HTTP_CAINFO); # endif } # endif # if PHP_HTTP_HAVE_LIBCURL_CAPATH if ((opt = php_http_option_register(proxy_registry, ZEND_STRL("capath"), CURLOPT_PROXY_CAPATH, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; # ifdef PHP_HTTP_CAPATH ZVAL_PSTRING(&opt->defval, PHP_HTTP_CAPATH); # endif } # endif # if PHP_HTTP_HAVE_LIBCURL_TLSAUTH_TYPE if ((opt = php_http_option_register(proxy_registry, ZEND_STRL("tlsauthtype"), CURLOPT_PROXY_TLSAUTH_TYPE, IS_LONG))) { opt->setter = php_http_curle_option_set_ssl_tlsauthtype; } if ((opt = php_http_option_register(proxy_registry, ZEND_STRL("tlsauthuser"), CURLOPT_PROXY_TLSAUTH_USERNAME, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; } if ((opt = php_http_option_register(proxy_registry, ZEND_STRL("tlsauthpass"), CURLOPT_PROXY_TLSAUTH_PASSWORD, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; } # endif # if PHP_HTTP_CURL_VERSION(7,59,0) /* FIXME: see http://curl.haxx.se/libcurl/c/CURLOPT_PINNEDPUBLICKEY.html#AVAILABILITY */ if ((opt = php_http_option_register(proxy_registry, ZEND_STRL("pinned_publickey"), CURLOPT_PROXY_PINNEDPUBLICKEY, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; } # endif # if PHP_HTTP_CURL_VERSION(7,61,0) && PHP_HTTP_HAVE_LIBCURL_TLS13_CIPHERS if ((opt = php_http_option_register(proxy_registry, ZEND_STRL("tls13_ciphers"), CURLOPT_PROXY_TLS13_CIPHERS, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; } # endif } #endif } #if PHP_HTTP_CURL_VERSION(7,64,1) # if !PHP_HTTP_HAVE_LIBCURL_ALT_SVC if (PHP_HTTP_CURL_FEATURE(CURL_VERSION_ALTSVC)) { # endif if ((opt = php_http_option_register(registry, ZEND_STRL("altsvc_ctrl"), CURLOPT_ALTSVC_CTRL, IS_LONG))) { opt->setter = php_http_curle_option_set_altsvc_ctrl; } if ((opt = php_http_option_register(registry, ZEND_STRL("altsvc"), CURLOPT_ALTSVC, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; } # if !PHP_HTTP_HAVE_LIBCURL_ALT_SVC } # endif #endif #if PHP_HTTP_CURL_VERSION(7,74,0) # if !PHP_HTTP_HAVE_LIBCURL_HSTS if (PHP_HTTP_CURL_FEATURE(CURL_VERSION_HSTS)) { # endif php_http_option_register(registry, ZEND_STRL("hsts_ctrl"), CURLOPT_HSTS_CTRL, IS_LONG); if ((opt = php_http_option_register(registry, ZEND_STRL("hsts"), CURLOPT_HSTS, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; } # if !PHP_HTTP_HAVE_LIBCURL_HSTS } # endif #endif } static zval *php_http_curle_get_option(php_http_option_t *opt, HashTable *options, void *userdata) { php_http_client_curl_handler_t *curl = userdata; zval *option; if ((option = php_http_option_get(opt, options, NULL))) { zval zopt; ZVAL_DUP(&zopt, option); convert_to_explicit_type(&zopt, opt->type); zend_hash_update(&curl->options.cache, opt->name, &zopt); return zend_hash_find(&curl->options.cache, opt->name); } return option; } static ZEND_RESULT_CODE php_http_curle_set_option(php_http_option_t *opt, zval *val, void *userdata) { php_http_client_curl_handler_t *curl = userdata; CURL *ch = curl->handle; zval tmp; CURLcode rc = CURLE_UNKNOWN_OPTION; ZEND_RESULT_CODE rv = SUCCESS; if (!val) { val = &opt->defval; } switch (opt->type) { case _IS_BOOL: if (opt->setter) { rv = opt->setter(opt, val, curl); } else if (CURLE_OK != curl_easy_setopt(ch, opt->option, (long) (Z_TYPE_P(val) == IS_TRUE))) { rv = FAILURE; } break; case IS_LONG: if (opt->setter) { rv = opt->setter(opt, val, curl); } else if (CURLE_OK != curl_easy_setopt(ch, opt->option, Z_LVAL_P(val))) { rv = FAILURE; } break; case IS_STRING: if (opt->setter) { rv = opt->setter(opt, val, curl); } else if (!val || Z_TYPE_P(val) == IS_NULL) { if (CURLE_OK != (rc = curl_easy_setopt(ch, opt->option, NULL))) { rv = FAILURE; } } else if ((opt->flags & PHP_HTTP_CURLE_OPTION_CHECK_STRLEN) && !Z_STRLEN_P(val)) { if (CURLE_OK != (rc = curl_easy_setopt(ch, opt->option, NULL))) { rv = FAILURE; } } else if ((opt->flags & PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR) && Z_STRVAL_P(val) && SUCCESS != php_check_open_basedir(Z_STRVAL_P(val))) { if (CURLE_OK != (rc = curl_easy_setopt(ch, opt->option, NULL))) { rv = FAILURE; } } else if (CURLE_OK != (rc = curl_easy_setopt(ch, opt->option, Z_STRVAL_P(val)))) { rv = FAILURE; } break; case IS_DOUBLE: if (opt->flags & PHP_HTTP_CURLE_OPTION_TRANSFORM_MS) { tmp = *val; Z_DVAL(tmp) *= 1000; val = &tmp; } if (opt->setter) { rv = opt->setter(opt, val, curl); } else if (CURLE_OK != curl_easy_setopt(ch, opt->option, (long) Z_DVAL_P(val))) { rv = FAILURE; } break; case IS_ARRAY: if (opt->setter) { rv = opt->setter(opt, val, curl); } else if (Z_TYPE_P(val) != IS_NULL) { rv = php_http_options_apply(&opt->suboptions, Z_ARRVAL_P(val), curl); } break; default: if (opt->setter) { rv = opt->setter(opt, val, curl); } else { rv = FAILURE; } break; } if (rv != SUCCESS) { if (opt->flags & PHP_HTTP_CURLE_OPTION_IGNORE_RC) { rv = SUCCESS; } else { php_error_docref(NULL, E_NOTICE, "Could not set option %s (%s)", opt->name->val, curl_easy_strerror(rc)); } } return rv; } #if PHP_HTTP_CURL_VERSION(7,30,0) && !PHP_HTTP_CURL_VERSION(7,62,0) static ZEND_RESULT_CODE php_http_curlm_option_set_pipelining_bl(php_http_option_t *opt, zval *value, void *userdata) { php_http_client_t *client = userdata; php_http_client_curl_t *curl = client->ctx; CURLM *ch = curl->handle->multi; HashTable tmp_ht; char **bl = NULL; /* array of char *, ending with a NULL */ if (value && Z_TYPE_P(value) != IS_NULL) { zval *entry; HashTable *ht = HASH_OF(value); int c = zend_hash_num_elements(ht); char **ptr = ecalloc(c + 1, sizeof(char *)); bl = ptr; zend_hash_init(&tmp_ht, c, NULL, ZVAL_PTR_DTOR, 0); array_join(ht, &tmp_ht, 0, ARRAY_JOIN_STRINGIFY); ZEND_HASH_FOREACH_VAL(&tmp_ht, entry) { *ptr++ = Z_STRVAL_P(entry); } ZEND_HASH_FOREACH_END(); } if (CURLM_OK != curl_multi_setopt(ch, opt->option, bl)) { if (bl) { efree(bl); zend_hash_destroy(&tmp_ht); } return FAILURE; } if (bl) { efree(bl); zend_hash_destroy(&tmp_ht); } return SUCCESS; } #endif static inline ZEND_RESULT_CODE php_http_curlm_use_eventloop(php_http_client_t *h, php_http_client_curl_ops_t *ev_ops, zval *init_data) { php_http_client_curl_t *curl = h->ctx; void *ev_ctx; if (ev_ops) { if (!(ev_ctx = ev_ops->init(h, init_data))) { return FAILURE; } curl->ev_ctx = ev_ctx; curl->ev_ops = ev_ops; } else { if (curl->ev_ops) { if (curl->ev_ctx) { curl->ev_ops->dtor(&curl->ev_ctx); } curl->ev_ops = NULL; } } return SUCCESS; } static ZEND_RESULT_CODE php_http_curlm_option_set_use_eventloop(php_http_option_t *opt, zval *value, void *userdata) { php_http_client_t *client = userdata; php_http_client_curl_ops_t *ev_ops = NULL; if (value && Z_TYPE_P(value) == IS_OBJECT && instanceof_function(Z_OBJCE_P(value), php_http_client_curl_user_get_class_entry())) { ev_ops = php_http_client_curl_user_ops_get(); #if PHP_HTTP_HAVE_LIBEVENT } else if (value && zend_is_true(value)) { ev_ops = php_http_client_curl_event_ops_get(); #endif } return php_http_curlm_use_eventloop(client, ev_ops, value); } static ZEND_RESULT_CODE php_http_curlm_option_set_share_cookies(php_http_option_t *opt, zval *value, void *userdata) { php_http_client_t *client = userdata; php_http_client_curl_t *curl = client->ctx; CURLSHcode rc; if (Z_TYPE_P(value) == IS_TRUE) { rc = curl_share_setopt(curl->handle->share, CURLSHOPT_SHARE, CURL_LOCK_DATA_COOKIE); } else { rc = curl_share_setopt(curl->handle->share, CURLSHOPT_UNSHARE, CURL_LOCK_DATA_COOKIE); } if (CURLSHE_OK != rc) { php_error_docref(NULL, E_NOTICE, "Could not set option %s (%s)", opt->name->val, curl_share_strerror(rc)); return FAILURE; } return SUCCESS; } #if PHP_HTTP_HAVE_LIBCURL_SHARE_SSL static ZEND_RESULT_CODE php_http_curlm_option_set_share_ssl(php_http_option_t *opt, zval *value, void *userdata) { php_http_client_t *client = userdata; php_http_client_curl_t *curl = client->ctx; CURLSHcode rc; if (Z_TYPE_P(value) == IS_TRUE) { rc = curl_share_setopt(curl->handle->share, CURLSHOPT_SHARE, CURL_LOCK_DATA_SSL_SESSION); } else { rc = curl_share_setopt(curl->handle->share, CURLSHOPT_UNSHARE, CURL_LOCK_DATA_SSL_SESSION); } if (CURLSHE_OK != rc) { php_error_docref(NULL, E_NOTICE, "Could not set option %s (%s)", opt->name->val, curl_share_strerror(rc)); return FAILURE; } return SUCCESS; } #endif static void php_http_curlm_options_init(php_http_options_t *registry) { php_http_option_t *opt; /* set size of connection cache */ if ((opt = php_http_option_register(registry, ZEND_STRL("maxconnects"), CURLMOPT_MAXCONNECTS, IS_LONG))) { /* -1 == default, 0 == unlimited */ ZVAL_LONG(&opt->defval, -1); } /* set max number of connections to a single host */ #if PHP_HTTP_CURL_VERSION(7,30,0) php_http_option_register(registry, ZEND_STRL("max_host_connections"), CURLMOPT_MAX_HOST_CONNECTIONS, IS_LONG); #endif /* max simultaneously open connections */ #if PHP_HTTP_CURL_VERSION(7,30,0) php_http_option_register(registry, ZEND_STRL("max_total_connections"), CURLMOPT_MAX_TOTAL_CONNECTIONS, IS_LONG); #endif #if PHP_HTTP_CURL_VERSION(7,67,0) if ((opt = php_http_option_register(registry, ZEND_STRL("max_concurrent_streams"), CURLMOPT_MAX_CONCURRENT_STREAMS, IS_LONG))) { ZVAL_LONG(&opt->defval, 100); } #endif #if !PHP_HTTP_CURL_VERSION(7,62,0) /* enable/disable HTTP pipelining */ php_http_option_register(registry, ZEND_STRL("pipelining"), CURLMOPT_PIPELINING, _IS_BOOL); # if PHP_HTTP_CURL_VERSION(7,30,0) /* maximum number of requests in a pipeline */ if ((opt = php_http_option_register(registry, ZEND_STRL("max_pipeline_length"), CURLMOPT_MAX_PIPELINE_LENGTH, IS_LONG))) { ZVAL_LONG(&opt->defval, 5); } /* chunk length threshold for pipelining */ php_http_option_register(registry, ZEND_STRL("chunk_length_penalty_size"), CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE, IS_LONG); /* size threshold for pipelining penalty */ php_http_option_register(registry, ZEND_STRL("content_length_penalty_size"), CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE, IS_LONG); /* pipelining server blacklist */ if ((opt = php_http_option_register(registry, ZEND_STRL("pipelining_server_bl"), CURLMOPT_PIPELINING_SERVER_BL, IS_ARRAY))) { opt->setter = php_http_curlm_option_set_pipelining_bl; } /* pipelining host blacklist */ if ((opt = php_http_option_register(registry, ZEND_STRL("pipelining_site_bl"), CURLMOPT_PIPELINING_SITE_BL, IS_ARRAY))) { opt->setter = php_http_curlm_option_set_pipelining_bl; } # endif #endif /* events */ if ((opt = php_http_option_register(registry, ZEND_STRL("use_eventloop"), 0, 0))) { opt->setter = php_http_curlm_option_set_use_eventloop; } /* share */ if ((opt = php_http_option_register(registry, ZEND_STRL("share_cookies"), 0, _IS_BOOL))) { opt->setter = php_http_curlm_option_set_share_cookies; ZVAL_TRUE(&opt->defval); } #if PHP_HTTP_HAVE_LIBCURL_SHARE_SSL if ((opt = php_http_option_register(registry, ZEND_STRL("share_ssl"), 0, _IS_BOOL))) { opt->setter = php_http_curlm_option_set_share_ssl; ZVAL_TRUE(&opt->defval); } #endif } static ZEND_RESULT_CODE php_http_curlm_set_option(php_http_option_t *opt, zval *val, void *userdata) { php_http_client_t *client = userdata; php_http_client_curl_t *curl = client->ctx; CURLM *ch = curl->handle->multi; zval zopt, *orig = val; CURLMcode rc = CURLM_UNKNOWN_OPTION; ZEND_RESULT_CODE rv = SUCCESS; if (!val) { val = &opt->defval; } else if (opt->type && Z_TYPE_P(val) != opt->type && !(Z_TYPE_P(val) == IS_NULL && opt->type == IS_ARRAY)) { ZVAL_DUP(&zopt, val); convert_to_explicit_type(&zopt, opt->type); val = &zopt; } if (opt->setter) { rv = opt->setter(opt, val, client); } else { switch (opt->type) { case _IS_BOOL: if (CURLM_OK != (rc = curl_multi_setopt(ch, opt->option, (long) zend_is_true(val)))) { rv = FAILURE; php_error_docref(NULL, E_NOTICE, "Could not set option %s (%s)", opt->name->val, curl_multi_strerror(rc)); } break; case IS_LONG: if (CURLM_OK != (rc = curl_multi_setopt(ch, opt->option, Z_LVAL_P(val)))) { rv = FAILURE; php_error_docref(NULL, E_NOTICE, "Could not set option %s (%s)", opt->name->val, curl_multi_strerror(rc)); } break; default: rv = FAILURE; php_error_docref(NULL, E_NOTICE, "Could not set option %s", opt->name->val); break; } } if (val && val != orig && val != &opt->defval) { zval_ptr_dtor(val); } return rv; } /* client ops */ static ZEND_RESULT_CODE php_http_client_curl_handler_reset(php_http_client_curl_handler_t *handler) { php_http_client_curl_t *curl = handler->client->ctx; CURL *ch = handler->handle; php_http_curle_storage_t *st; if ((st = php_http_curle_get_storage(ch))) { if (st->url) { pefree(st->url, 1); st->url = NULL; } if (st->cookiestore) { pefree(st->cookiestore, 1); st->cookiestore = NULL; } st->errorbuffer[0] = '\0'; st->errorcode = 0; } curl_easy_setopt(ch, CURLOPT_URL, NULL); curl_easy_setopt(ch, CURLOPT_CUSTOMREQUEST, NULL); curl_easy_setopt(ch, CURLOPT_HTTPGET, 1L); curl_easy_setopt(ch, CURLOPT_NOBODY, 0L); /* libcurl < 7.19.6 does not clear auth info with USERPWD set to NULL */ #if PHP_HTTP_CURL_VERSION(7,19,1) curl_easy_setopt(ch, CURLOPT_PROXYUSERNAME, NULL); curl_easy_setopt(ch, CURLOPT_PROXYPASSWORD, NULL); curl_easy_setopt(ch, CURLOPT_USERNAME, NULL); curl_easy_setopt(ch, CURLOPT_PASSWORD, NULL); #endif #if PHP_HTTP_CURL_VERSION(7,21,3) if (handler->options.resolve) { curl_slist_free_all(handler->options.resolve); handler->options.resolve = NULL; } #endif handler->options.retry.count = 0; handler->options.retry.delay = 0; handler->options.redirects = 0; handler->options.encode_cookies = 1; if (handler->options.headers) { curl_slist_free_all(handler->options.headers); handler->options.headers = NULL; } if (handler->options.proxyheaders) { curl_slist_free_all(handler->options.proxyheaders); handler->options.proxyheaders = NULL; } php_http_buffer_reset(&handler->options.cookies); php_http_buffer_reset(&handler->options.ranges); if (php_http_message_body_size(handler->response.body)) { php_http_message_body_free(&handler->response.body); handler->response.body = php_http_message_body_init(NULL, NULL); } php_http_buffer_reset(&handler->response.headers); #if ZTS curl_easy_setopt(ch, CURLOPT_NOSIGNAL, 1L); #endif curl_easy_setopt(ch, CURLOPT_HEADER, 0L); curl_easy_setopt(ch, CURLOPT_FILETIME, 1L); curl_easy_setopt(ch, CURLOPT_AUTOREFERER, 1L); curl_easy_setopt(ch, CURLOPT_VERBOSE, 1L); curl_easy_setopt(ch, CURLOPT_NOPROGRESS, 0L); curl_easy_setopt(ch, CURLOPT_HEADERFUNCTION, php_http_curle_header_callback); curl_easy_setopt(ch, CURLOPT_WRITEFUNCTION, php_http_curle_body_callback); curl_easy_setopt(ch, CURLOPT_DEBUGFUNCTION, php_http_curle_raw_callback); curl_easy_setopt(ch, CURLOPT_READFUNCTION, php_http_curle_read_callback); curl_easy_setopt(ch, CURLOPT_SEEKFUNCTION, php_http_curle_seek_callback); #if PHP_HTTP_CURL_VERSION(7,32,0) curl_easy_setopt(ch, CURLOPT_XFERINFOFUNCTION, php_http_curle_xferinfo_callback); curl_easy_setopt(ch, CURLOPT_XFERINFODATA, handler); #else curl_easy_setopt(ch, CURLOPT_PROGRESSFUNCTION, php_http_curle_progress_callback); curl_easy_setopt(ch, CURLOPT_PROGRESSDATA, handler); #endif curl_easy_setopt(ch, CURLOPT_DEBUGDATA, handler); curl_easy_setopt(ch, CURLOPT_WRITEDATA, handler); curl_easy_setopt(ch, CURLOPT_HEADERDATA, handler); #if DEBUG_COOKIES fprintf(stderr, "CURLOPT_SHARE: %p\n", curl->handle->share); #endif curl_easy_setopt(ch, CURLOPT_SHARE, curl->handle->share); return SUCCESS; } static php_http_client_curl_handler_t *php_http_client_curl_handler_init(php_http_client_t *h, php_resource_factory_t *rf) { void *handle; php_http_client_curl_handler_t *handler; if (!(handle = php_resource_factory_handle_ctor(rf, NULL))) { php_error_docref(NULL, E_WARNING, "Failed to initialize curl handle"); return NULL; } handler = ecalloc(1, sizeof(*handler)); handler->rf = rf; handler->client = h; handler->handle = handle; handler->response.body = php_http_message_body_init(NULL, NULL); php_http_buffer_init(&handler->response.headers); php_http_buffer_init(&handler->options.cookies); php_http_buffer_init(&handler->options.ranges); zend_hash_init(&handler->options.cache, 0, NULL, ZVAL_PTR_DTOR, 0); php_http_client_curl_handler_reset(handler); return handler; } static ZEND_RESULT_CODE php_http_client_curl_handler_prepare(php_http_client_curl_handler_t *curl, php_http_client_enqueue_t *enqueue) { size_t body_size; php_http_message_t *msg = enqueue->request; php_http_curle_storage_t *storage = php_http_curle_get_storage(curl->handle); /* request url */ if (!PHP_HTTP_INFO(msg).request.url) { php_error_docref(NULL, E_WARNING, "Cannot request empty URL"); return FAILURE; } storage->errorbuffer[0] = '\0'; if (storage->url) { pefree(storage->url, 1); } php_http_url_to_string(PHP_HTTP_INFO(msg).request.url, &storage->url, NULL, 1); curl_easy_setopt(curl->handle, CURLOPT_URL, storage->url); /* apply options */ php_http_options_apply(&php_http_curle_options, enqueue->options, curl); /* request headers */ php_http_message_update_headers(msg); if (zend_hash_num_elements(&msg->hdrs)) { php_http_arrkey_t header_key; zval *header_val; zend_string *header_str; php_http_buffer_t header; #if !PHP_HTTP_CURL_VERSION(7,23,0) zval *ct = zend_hash_str_find(&msg->hdrs, ZEND_STRL("Content-Length")); #endif php_http_buffer_init(&header); ZEND_HASH_FOREACH_KEY_VAL(&msg->hdrs, header_key.h, header_key.key, header_val) { if (header_key.key) { #if !PHP_HTTP_CURL_VERSION(7,23,0) /* avoid duplicate content-length header */ if (ct && ct == header_val) { continue; } #endif header_str = zval_get_string(header_val); php_http_buffer_appendf(&header, "%s: %s", header_key.key->val, header_str->val); php_http_buffer_fix(&header); curl->options.headers = curl_slist_append(curl->options.headers, header.data); php_http_buffer_reset(&header); zend_string_release(header_str); } } ZEND_HASH_FOREACH_END(); php_http_buffer_dtor(&header); } curl_easy_setopt(curl->handle, CURLOPT_HTTPHEADER, curl->options.headers); /* attach request body */ if ((body_size = php_http_message_body_size(msg->body))) { /* RFC2616, section 4.3 (para. 4) states that »a message-body MUST NOT be included in a request if the * specification of the request method (section 5.1.1) does not allow sending an entity-body in request.« * Following the clause in section 5.1.1 (para. 2) that request methods »MUST be implemented with the * same semantics as those specified in section 9« reveal that not any single defined HTTP/1.1 method * does not allow a request body. */ php_stream_rewind(php_http_message_body_stream(msg->body)); curl_easy_setopt(curl->handle, CURLOPT_SEEKDATA, msg->body); curl_easy_setopt(curl->handle, CURLOPT_READDATA, msg->body); curl_easy_setopt(curl->handle, CURLOPT_INFILESIZE, body_size); curl_easy_setopt(curl->handle, CURLOPT_POSTFIELDSIZE, body_size); curl_easy_setopt(curl->handle, CURLOPT_POST, 1L); } else { curl_easy_setopt(curl->handle, CURLOPT_SEEKDATA, NULL); curl_easy_setopt(curl->handle, CURLOPT_READDATA, NULL); curl_easy_setopt(curl->handle, CURLOPT_INFILESIZE, 0L); curl_easy_setopt(curl->handle, CURLOPT_POSTFIELDSIZE, 0L); } /* * Always use CUSTOMREQUEST, else curl won't send any request body for GET etc. * See e.g. bug #69313. * * Here's what curl does: * - CURLOPT_HTTPGET: ignore request body * - CURLOPT_UPLOAD: set "Expect: 100-continue" header * - CURLOPT_POST: set "Content-Type: application/x-www-form-urlencoded" header * Now select the least bad. * * See also https://tools.ietf.org/html/rfc7231#section-5.1.1 */ if (PHP_HTTP_INFO(msg).request.method) { switch(php_http_select_str(PHP_HTTP_INFO(msg).request.method, 2, "HEAD", "PUT")) { case 0: curl_easy_setopt(curl->handle, CURLOPT_NOBODY, 1L); break; case 1: curl_easy_setopt(curl->handle, CURLOPT_UPLOAD, 1L); break; default: curl_easy_setopt(curl->handle, CURLOPT_CUSTOMREQUEST, PHP_HTTP_INFO(msg).request.method); } } else { php_error_docref(NULL, E_WARNING, "Cannot use empty request method"); return FAILURE; } return SUCCESS; } static void php_http_client_curl_handler_clear(php_http_client_curl_handler_t *handler) { curl_easy_setopt(handler->handle, CURLOPT_NOPROGRESS, 1L); #if PHP_HTTP_CURL_VERSION(7,32,0) curl_easy_setopt(handler->handle, CURLOPT_XFERINFOFUNCTION, NULL); #else curl_easy_setopt(handler->handle, CURLOPT_PROGRESSFUNCTION, NULL); #endif curl_easy_setopt(handler->handle, CURLOPT_VERBOSE, 0L); curl_easy_setopt(handler->handle, CURLOPT_DEBUGFUNCTION, NULL); /* see gh issue #84 */ #if DEBUG_COOKIES fprintf(stderr, "CURLOPT_COOKIELIST: FLUSH\n"); fprintf(stderr, "CURLOPT_SHARE: (null)\n"); #endif curl_easy_setopt(handler->handle, CURLOPT_COOKIELIST, "FLUSH"); curl_easy_setopt(handler->handle, CURLOPT_SHARE, NULL); #if PHP_HTTP_CURL_VERSION(7,63,0) && !PHP_HTTP_CURL_VERSION(7,65,0) { php_http_curle_storage_t *st = php_http_curle_get_storage(handler->handle); curl_easy_setopt(handler->handle, CURLOPT_COOKIEJAR, st ? st->cookiestore : NULL); } #endif } static void php_http_client_curl_handler_dtor(php_http_client_curl_handler_t *handler) { php_http_client_curl_handler_clear(handler); php_resource_factory_handle_dtor(handler->rf, handler->handle); php_resource_factory_free(&handler->rf); php_http_message_body_free(&handler->response.body); php_http_buffer_dtor(&handler->response.headers); php_http_buffer_dtor(&handler->options.ranges); php_http_buffer_dtor(&handler->options.cookies); zend_hash_destroy(&handler->options.cache); #if PHP_HTTP_CURL_VERSION(7,21,3) if (handler->options.resolve) { curl_slist_free_all(handler->options.resolve); handler->options.resolve = NULL; } #endif if (handler->options.headers) { curl_slist_free_all(handler->options.headers); handler->options.headers = NULL; } if (handler->options.proxyheaders) { curl_slist_free_all(handler->options.proxyheaders); handler->options.proxyheaders = NULL; } efree(handler); } static php_http_client_t *php_http_client_curl_init(php_http_client_t *h, void *handle) { php_http_client_curl_t *curl; if (!handle && !(handle = php_resource_factory_handle_ctor(h->rf, NULL))) { php_error_docref(NULL, E_WARNING, "Failed to initialize curl handle"); return NULL; } curl = ecalloc(1, sizeof(*curl)); curl->handle = handle; curl->unfinished = 0; h->ctx = curl; return h; } static void php_http_client_curl_dtor(php_http_client_t *h) { php_http_client_curl_t *curl = h->ctx; if (curl->ev_ops) { curl->ev_ops->dtor(&curl->ev_ctx); curl->ev_ops = NULL; } curl->unfinished = 0; php_resource_factory_handle_dtor(h->rf, curl->handle); efree(curl); h->ctx = NULL; } static void queue_dtor(php_http_client_enqueue_t *e) { php_http_client_curl_handler_t *handler = e->opaque; if (handler->queue.dtor) { e->opaque = handler->queue.opaque; handler->queue.dtor(e); } php_http_client_curl_handler_dtor(handler); } static void retire_ch(php_persistent_handle_factory_t *f, void **handle) { CURL *ch = *handle; /* erase all cookies */ if (ch) { curl_easy_reset(ch); curl_easy_setopt(ch, CURLOPT_COOKIELIST, "ALL"); curl_easy_setopt(ch, CURLOPT_COOKIEFILE, NULL); } } static php_resource_factory_t *create_rf(php_http_client_t *h, php_http_client_enqueue_t *enqueue) { php_persistent_handle_factory_t *pf = NULL; php_resource_factory_t *rf = NULL; php_http_url_t *url = enqueue->request->http.info.request.url; if (!url || (!url->host && !url->path)) { php_error_docref(NULL, E_WARNING, "Cannot request empty URL"); return NULL; } /* only if the client itself is setup for persistence */ if (php_resource_factory_is_persistent(h->rf)) { zend_string *id; char *id_str = NULL; size_t id_len; int port = url->port ? url->port : 80; zval *zport; php_persistent_handle_factory_t *phf = h->rf->data; if ((zport = zend_hash_str_find(enqueue->options, ZEND_STRL("port")))) { zend_long lport = zval_get_long(zport); if (lport > 0) { port = lport; } } id_len = spprintf(&id_str, 0, "%.*s:%s:%d", (int) phf->ident->len, phf->ident->val, STR_PTR(url->host), port); id = php_http_cs2zs(id_str, id_len); pf = php_persistent_handle_concede(NULL, PHP_HTTP_G->client.curl.driver.request_name, id, NULL, retire_ch); zend_string_release(id); } if (pf) { rf = php_persistent_handle_resource_factory_init(NULL, pf); } else { rf = php_resource_factory_init(NULL, &php_http_curle_resource_factory_ops, NULL, NULL); } return rf; } static ZEND_RESULT_CODE php_http_client_curl_enqueue(php_http_client_t *h, php_http_client_enqueue_t *enqueue) { CURLMcode rs; php_http_client_curl_t *curl = h->ctx; php_http_client_curl_handler_t *handler; php_http_client_progress_state_t *progress; php_resource_factory_t *rf; rf = create_rf(h, enqueue); if (!rf) { return FAILURE; } handler = php_http_client_curl_handler_init(h, rf); if (!handler) { return FAILURE; } if (SUCCESS != php_http_client_curl_handler_prepare(handler, enqueue)) { php_http_client_curl_handler_dtor(handler); return FAILURE; } handler->queue = *enqueue; enqueue->opaque = handler; enqueue->dtor = queue_dtor; if (CURLM_OK != (rs = curl_multi_add_handle(curl->handle->multi, handler->handle))) { php_http_client_curl_handler_dtor(handler); php_error_docref(NULL, E_WARNING, "Could not enqueue request: %s", curl_multi_strerror(rs)); return FAILURE; } zend_llist_add_element(&h->requests, enqueue); ++curl->unfinished; if (h->callback.progress.func && SUCCESS == php_http_client_getopt(h, PHP_HTTP_CLIENT_OPT_PROGRESS_INFO, enqueue->request, &progress)) { progress->info = "start"; h->callback.progress.func(h->callback.progress.arg, h, &handler->queue, progress); progress->started = 1; } return SUCCESS; } static ZEND_RESULT_CODE php_http_client_curl_requeue(php_http_client_t *h, php_http_client_enqueue_t *enqueue) { CURLMcode rs; php_http_client_curl_t *curl = h->ctx; php_http_client_curl_handler_t *handler = enqueue->opaque; php_http_client_progress_state_t *progress; if (SUCCESS != php_http_client_curl_handler_reset(handler)) { return FAILURE; } if (SUCCESS != php_http_client_curl_handler_prepare(handler, enqueue)) { return FAILURE; } if (CURLM_OK != (rs = curl_multi_remove_handle(curl->handle->multi, handler->handle))) { php_error_docref(NULL, E_WARNING, "Could not dequeue request: %s", curl_multi_strerror(rs)); return FAILURE; } if (CURLM_OK != (rs = curl_multi_add_handle(curl->handle->multi, handler->handle))) { zend_llist_del_element(&h->requests, handler->handle, (int (*)(void *, void *)) compare_queue); php_error_docref(NULL, E_WARNING, "Could not enqueue request: %s", curl_multi_strerror(rs)); return FAILURE; } ++curl->unfinished; if (h->callback.progress.func && SUCCESS == php_http_client_getopt(h, PHP_HTTP_CLIENT_OPT_PROGRESS_INFO, enqueue->request, &progress)) { progress->info = "start"; h->callback.progress.func(h->callback.progress.arg, h, &handler->queue, progress); progress->started = 1; } return SUCCESS; } static ZEND_RESULT_CODE php_http_client_curl_dequeue(php_http_client_t *h, php_http_client_enqueue_t *enqueue) { CURLMcode rs; php_http_client_curl_t *curl = h->ctx; php_http_client_curl_handler_t *handler = enqueue->opaque; if (h->callback.depth && !CG(unclean_shutdown)) { php_error_docref(NULL, E_WARNING, "Could not dequeue request while executing callbacks"); return FAILURE; } php_http_client_curl_handler_clear(handler); if (CURLM_OK == (rs = curl_multi_remove_handle(curl->handle->multi, handler->handle))) { zend_llist_del_element(&h->requests, handler->handle, (int (*)(void *, void *)) compare_queue); return SUCCESS; } else { php_error_docref(NULL, E_WARNING, "Could not dequeue request: %s", curl_multi_strerror(rs)); } return FAILURE; } static void php_http_client_curl_reset(php_http_client_t *h) { zend_llist_element *next_el, *this_el; for (this_el = h->requests.head; this_el; this_el = next_el) { next_el = this_el->next; php_http_client_curl_dequeue(h, (void *) this_el->data); } } #if PHP_WIN32 # define SELECT_ERROR SOCKET_ERROR #else # define SELECT_ERROR -1 #endif static ZEND_RESULT_CODE php_http_client_curl_wait(php_http_client_t *h, struct timeval *custom_timeout) { int MAX; fd_set R, W, E; struct timeval timeout; php_http_client_curl_t *curl = h->ctx; if (curl->ev_ops) { return curl->ev_ops->wait(curl->ev_ctx, custom_timeout); } FD_ZERO(&R); FD_ZERO(&W); FD_ZERO(&E); if (CURLM_OK == curl_multi_fdset(curl->handle->multi, &R, &W, &E, &MAX)) { if (custom_timeout && timerisset(custom_timeout)) { timeout = *custom_timeout; } else { php_http_client_curl_get_timeout(curl, 1000, &timeout); } if (MAX == -1) { php_http_sleep((double) timeout.tv_sec + (double) (timeout.tv_usec / PHP_HTTP_MCROSEC)); return SUCCESS; } else if (SELECT_ERROR != select(MAX + 1, &R, &W, &E, &timeout)) { return SUCCESS; } } return FAILURE; } static int php_http_client_curl_once(php_http_client_t *h) { php_http_client_curl_t *curl = h->ctx; if (!h->callback.depth) { if (curl->ev_ops) { curl->ev_ops->once(curl->ev_ctx); } else { while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(curl->handle->multi, &curl->unfinished)); } php_http_client_curl_responsehandler(h); } return curl->unfinished; } static ZEND_RESULT_CODE php_http_client_curl_exec(php_http_client_t *h) { php_http_client_curl_t *curl = h->ctx; if (!h->callback.depth) { if (curl->ev_ops) { return curl->ev_ops->exec(curl->ev_ctx); } while (php_http_client_curl_once(h) && !EG(exception)) { if (SUCCESS != php_http_client_curl_wait(h, NULL)) { #if PHP_WIN32 /* see http://msdn.microsoft.com/library/en-us/winsock/winsock/windows_sockets_error_codes_2.asp */ php_error_docref(NULL, E_WARNING, "WinSock error: %d", WSAGetLastError()); #else php_error_docref(NULL, E_WARNING, "%s", strerror(errno)); #endif return FAILURE; } } } return SUCCESS; } static ZEND_RESULT_CODE php_http_client_curl_setopt(php_http_client_t *h, php_http_client_setopt_opt_t opt, void *arg) { php_http_client_curl_t *curl = h->ctx; (void) curl; switch (opt) { case PHP_HTTP_CLIENT_OPT_CONFIGURATION: return php_http_options_apply(&php_http_curlm_options, (HashTable *) arg, h); break; #if !PHP_HTTP_CURL_VERSION(7,62,0) case PHP_HTTP_CLIENT_OPT_ENABLE_PIPELINING: if (CURLM_OK != curl_multi_setopt(curl->handle->multi, CURLMOPT_PIPELINING, (long) *((zend_bool *) arg))) { return FAILURE; } break; #endif case PHP_HTTP_CLIENT_OPT_USE_EVENTS: #if PHP_HTTP_HAVE_LIBEVENT return php_http_curlm_use_eventloop(h, (*(zend_bool *) arg) ? php_http_client_curl_event_ops_get() : NULL, NULL); break; #endif default: return FAILURE; } return SUCCESS; } static int apply_available_options(zval *pDest, int num_args, va_list args, zend_hash_key *hash_key) { php_http_option_t *opt = Z_PTR_P(pDest); HashTable *ht; zval entry; int c; ht = va_arg(args, HashTable*); if ((c = zend_hash_num_elements(&opt->suboptions.options))) { array_init_size(&entry, c); zend_hash_apply_with_arguments(&opt->suboptions.options, apply_available_options, 1, Z_ARRVAL(entry)); } else { /* catch deliberate NULL options */ if (Z_TYPE(opt->defval) == IS_STRING && !Z_STRVAL(opt->defval)) { ZVAL_NULL(&entry); } else { ZVAL_ZVAL(&entry, &opt->defval, 1, 0); } } if (hash_key->key) { zend_hash_update(ht, hash_key->key, &entry); } else { zend_hash_index_update(ht, hash_key->h, &entry); } return ZEND_HASH_APPLY_KEEP; } static ZEND_RESULT_CODE php_http_client_curl_getopt(php_http_client_t *h, php_http_client_getopt_opt_t opt, void *arg, void **res) { php_http_client_enqueue_t *enqueue; switch (opt) { case PHP_HTTP_CLIENT_OPT_PROGRESS_INFO: if ((enqueue = php_http_client_enqueued(h, arg, NULL))) { php_http_client_curl_handler_t *handler = enqueue->opaque; *((php_http_client_progress_state_t **) res) = &handler->progress; return SUCCESS; } break; case PHP_HTTP_CLIENT_OPT_TRANSFER_INFO: if ((enqueue = php_http_client_enqueued(h, arg, NULL))) { php_http_client_curl_handler_t *handler = enqueue->opaque; php_http_curle_get_info(handler->handle, *(HashTable **) res); return SUCCESS; } break; case PHP_HTTP_CLIENT_OPT_AVAILABLE_OPTIONS: zend_hash_apply_with_arguments(&php_http_curle_options.options, apply_available_options, 1, *(HashTable **) res); break; case PHP_HTTP_CLIENT_OPT_AVAILABLE_CONFIGURATION: zend_hash_apply_with_arguments(&php_http_curlm_options.options, apply_available_options, 1, *(HashTable **) res); break; default: break; } return FAILURE; } static php_http_client_ops_t php_http_client_curl_ops = { &php_http_curlm_resource_factory_ops, php_http_client_curl_init, NULL /* copy */, php_http_client_curl_dtor, php_http_client_curl_reset, php_http_client_curl_exec, php_http_client_curl_wait, php_http_client_curl_once, php_http_client_curl_enqueue, php_http_client_curl_dequeue, php_http_client_curl_requeue, php_http_client_curl_setopt, php_http_client_curl_getopt }; php_http_client_ops_t *php_http_client_curl_get_ops(void) { return &php_http_client_curl_ops; } #define REGISTER_NS_STRING_OR_NULL_CONSTANT(ns, name, str, flags) \ do { \ if ((str) != NULL) { \ REGISTER_NS_STRING_CONSTANT(ns, name, str, flags); \ } else { \ REGISTER_NS_NULL_CONSTANT(ns, name, flags); \ } \ } while (0) PHP_MINIT_FUNCTION(http_client_curl) { curl_version_info_data *info; php_http_options_t *options; PHP_HTTP_G->client.curl.driver.driver_name = zend_string_init(ZEND_STRL("curl"), 1); PHP_HTTP_G->client.curl.driver.client_name = zend_string_init(ZEND_STRL("http\\Client\\Curl"), 1); PHP_HTTP_G->client.curl.driver.request_name = zend_string_init(ZEND_STRL("http\\Client\\Curl\\Request"), 1); PHP_HTTP_G->client.curl.driver.client_ops = &php_http_client_curl_ops; if (SUCCESS != php_http_client_driver_add(&PHP_HTTP_G->client.curl.driver)) { return FAILURE; } if (SUCCESS != php_persistent_handle_provide(PHP_HTTP_G->client.curl.driver.client_name, &php_http_curlm_resource_factory_ops, NULL, NULL)) { return FAILURE; } if (SUCCESS != php_persistent_handle_provide(PHP_HTTP_G->client.curl.driver.request_name, &php_http_curle_resource_factory_ops, NULL, NULL)) { return FAILURE; } if ((options = php_http_options_init(&php_http_curle_options, 1))) { options->getter = php_http_curle_get_option; options->setter = php_http_curle_set_option; php_http_curle_options_init(options); } if ((options = php_http_options_init(&php_http_curlm_options, 1))) { options->getter = php_http_option_get; options->setter = php_http_curlm_set_option; php_http_curlm_options_init(options); } if ((info = curl_version_info(CURLVERSION_NOW))) { char tmp_ver[0x20], *tmp_ptr, *tmp_end; #define tmp_ver_init() do {\ tmp_ver[0] = 0; \ tmp_ptr = &tmp_ver[0]; \ tmp_end = &tmp_ver[sizeof(tmp_ver) - 1]; \ } while (0) /* * Feature constants */ REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "FEATURES", info->features, CONST_CS|CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "IPV6", CURL_VERSION_IPV6, CONST_CS|CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "KERBEROS4", CURL_VERSION_KERBEROS4, CONST_CS|CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "SSL", CURL_VERSION_SSL, CONST_CS|CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "LIBZ", CURL_VERSION_LIBZ, CONST_CS|CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "NTLM", CURL_VERSION_NTLM, CONST_CS|CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "GSSNEGOTIATE", CURL_VERSION_GSSNEGOTIATE, CONST_CS|CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "ASYNCHDNS", CURL_VERSION_ASYNCHDNS, CONST_CS|CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "SPNEGO", CURL_VERSION_SPNEGO, CONST_CS|CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "LARGEFILE", CURL_VERSION_LARGEFILE, CONST_CS|CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "IDN", CURL_VERSION_IDN, CONST_CS|CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "SSPI", CURL_VERSION_SSPI, CONST_CS|CONST_PERSISTENT); #if PHP_HTTP_CURL_VERSION(7,21,4) REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "TLSAUTH_SRP", CURL_VERSION_TLSAUTH_SRP, CONST_CS|CONST_PERSISTENT); #endif #if PHP_HTTP_CURL_VERSION(7,22,0) REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "NTLM_WB", CURL_VERSION_NTLM_WB, CONST_CS|CONST_PERSISTENT); #endif #if PHP_HTTP_CURL_VERSION(7,33,0) REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "HTTP2", CURL_VERSION_HTTP2, CONST_CS|CONST_PERSISTENT); #endif #if PHP_HTTP_CURL_VERSION(7,38,0) REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "GSSAPI", CURL_VERSION_GSSAPI, CONST_CS|CONST_PERSISTENT); #endif #if PHP_HTTP_CURL_VERSION(7,40,0) REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "KERBEROS5", CURL_VERSION_KERBEROS5, CONST_CS|CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "UNIX_SOCKETS", CURL_VERSION_UNIX_SOCKETS, CONST_CS|CONST_PERSISTENT); #endif #if PHP_HTTP_CURL_VERSION(7,47,0) REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "PSL", CURL_VERSION_PSL, CONST_CS|CONST_PERSISTENT); #endif #if PHP_HTTP_CURL_VERSION(7,52,0) REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "HTTPS_PROXY", CURL_VERSION_HTTPS_PROXY, CONST_CS|CONST_PERSISTENT); #endif #if PHP_HTTP_CURL_VERSION(7,56,0) REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "MULTI_SSL", CURL_VERSION_MULTI_SSL, CONST_CS|CONST_PERSISTENT); #endif #if PHP_HTTP_CURL_VERSION(7,57,0) REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "BROTLI", CURL_VERSION_BROTLI, CONST_CS|CONST_PERSISTENT); #endif #if PHP_HTTP_CURL_VERSION(7,64,1) REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "ALTSVC", CURL_VERSION_ALTSVC, CONST_CS|CONST_PERSISTENT); #endif #if PHP_HTTP_CURL_VERSION(7,66,0) REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "HTTP3", CURL_VERSION_HTTP3, CONST_CS|CONST_PERSISTENT); #endif #if PHP_HTTP_CURL_VERSION(7,72,0) REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "ZSTD", CURL_VERSION_ZSTD, CONST_CS|CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "UNICODE", CURL_VERSION_UNICODE, CONST_CS|CONST_PERSISTENT); #endif #if PHP_HTTP_CURL_VERSION(7,74,0) REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "HSTS", CURL_VERSION_HSTS, CONST_CS|CONST_PERSISTENT); #endif /* * Version constants */ REGISTER_NS_STRING_CONSTANT("http\\Client\\Curl", "VERSIONS", curl_version(), CONST_CS|CONST_PERSISTENT); REGISTER_NS_STRING_CONSTANT("http\\Client\\Curl\\Versions", "CURL", info->version, CONST_CS|CONST_PERSISTENT); REGISTER_NS_STRING_OR_NULL_CONSTANT("http\\Client\\Curl\\Versions", "SSL", info->ssl_version, CONST_CS|CONST_PERSISTENT); REGISTER_NS_STRING_OR_NULL_CONSTANT("http\\Client\\Curl\\Versions", "LIBZ", info->libz_version, CONST_CS|CONST_PERSISTENT); REGISTER_NS_STRING_OR_NULL_CONSTANT("http\\Client\\Curl\\Versions", "ARES", info->ares, CONST_CS|CONST_PERSISTENT); REGISTER_NS_STRING_OR_NULL_CONSTANT("http\\Client\\Curl\\Versions", "IDN", info->libidn, CONST_CS|CONST_PERSISTENT); tmp_ver_init(); if (info->iconv_ver_num) { tmp_ptr = zend_print_ulong_to_buf(tmp_end, info->iconv_ver_num & 0xf); tmp_end = tmp_ptr - 1; tmp_ptr = zend_print_ulong_to_buf(tmp_end, info->iconv_ver_num >> 8); *tmp_end = '.'; } REGISTER_NS_STRING_OR_NULL_CONSTANT("http\\Client\\Curl\\Versions", "ICONV", *tmp_ptr ? tmp_ptr : NULL, CONST_CS|CONST_PERSISTENT); #if PHP_HTTP_CURL_VERSION(7,57,0) REGISTER_NS_STRING_OR_NULL_CONSTANT("http\\Client\\Curl\\Versions", "BROTLI", info->brotli_version, CONST_CS|CONST_PERSISTENT); #endif #if PHP_HTTP_CURL_VERSION(7,66,0) REGISTER_NS_STRING_OR_NULL_CONSTANT("http\\Client\\Curl\\Versions", "NGHTTP2", info->nghttp2_version, CONST_CS|CONST_PERSISTENT); REGISTER_NS_STRING_OR_NULL_CONSTANT("http\\Client\\Curl\\Versions", "QUIC", info->quic_version, CONST_CS|CONST_PERSISTENT); #endif #if PHP_HTTP_CURL_VERSION(7,70,0) REGISTER_NS_STRING_OR_NULL_CONSTANT("http\\Client\\Curl\\Versions", "CAINFO", info->cainfo, CONST_CS|CONST_PERSISTENT); REGISTER_NS_STRING_OR_NULL_CONSTANT("http\\Client\\Curl\\Versions", "CAPATH", info->capath, CONST_CS|CONST_PERSISTENT); #endif #if PHP_HTTP_CURL_VERSION(7,72,0) REGISTER_NS_STRING_OR_NULL_CONSTANT("http\\Client\\Curl\\Versions", "ZSTD", info->zstd_version, CONST_CS|CONST_PERSISTENT); #endif #if PHP_HTTP_CURL_VERSION(7,75,0) REGISTER_NS_STRING_OR_NULL_CONSTANT("http\\Client\\Curl\\Versions", "HYPER", info->hyper_version, CONST_CS|CONST_PERSISTENT); #endif } /* * HTTP Protocol Version Constants */ REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "HTTP_VERSION_1_0", CURL_HTTP_VERSION_1_0, CONST_CS|CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "HTTP_VERSION_1_1", CURL_HTTP_VERSION_1_1, CONST_CS|CONST_PERSISTENT); #if PHP_HTTP_CURL_VERSION(7,33,0) REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "HTTP_VERSION_2_0", CURL_HTTP_VERSION_2_0, CONST_CS|CONST_PERSISTENT); #endif #if PHP_HTTP_CURL_VERSION(7,47,0) REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "HTTP_VERSION_2TLS", CURL_HTTP_VERSION_2TLS, CONST_CS|CONST_PERSISTENT); #endif #if PHP_HTTP_CURL_VERSION(7,49,0) REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "HTTP_VERSION_2_PRIOR_KNOWLEDGE", CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE, CONST_CS|CONST_PERSISTENT); #endif #if PHP_HTTP_CURL_VERSION(7,66,0) REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "HTTP_VERSION_3", CURL_HTTP_VERSION_3, CONST_CS|CONST_PERSISTENT); #endif REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "HTTP_VERSION_ANY", CURL_HTTP_VERSION_NONE, CONST_CS|CONST_PERSISTENT); /* * SSL Version Constants */ REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "SSL_VERSION_TLSv1", CURL_SSLVERSION_TLSv1, CONST_CS|CONST_PERSISTENT); #if PHP_HTTP_CURL_VERSION(7,34,0) REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "SSL_VERSION_TLSv1_0", CURL_SSLVERSION_TLSv1_0, CONST_CS|CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "SSL_VERSION_TLSv1_1", CURL_SSLVERSION_TLSv1_1, CONST_CS|CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "SSL_VERSION_TLSv1_2", CURL_SSLVERSION_TLSv1_2, CONST_CS|CONST_PERSISTENT); #endif #if PHP_HTTP_CURL_VERSION(7,52,0) REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "SSL_VERSION_TLSv1_3", CURL_SSLVERSION_TLSv1_3, CONST_CS|CONST_PERSISTENT); #endif REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "SSL_VERSION_SSLv2", CURL_SSLVERSION_SSLv2, CONST_CS|CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "SSL_VERSION_SSLv3", CURL_SSLVERSION_SSLv3, CONST_CS|CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "SSL_VERSION_ANY", CURL_SSLVERSION_DEFAULT, CONST_CS|CONST_PERSISTENT); #if PHP_HTTP_CURL_VERSION(7,21,4) && PHP_HTTP_HAVE_LIBCURL_TLSAUTH_TYPE REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "TLSAUTH_SRP", CURL_TLSAUTH_SRP, CONST_CS|CONST_PERSISTENT); #endif #if PHP_HTTP_CURL_VERSION(7,54,0) REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "SSL_VERSION_MAX_DEFAULT", CURL_SSLVERSION_MAX_DEFAULT, CONST_CS|CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "SSL_VERSION_MAX_TLSv1_0", CURL_SSLVERSION_MAX_TLSv1_0, CONST_CS|CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "SSL_VERSION_MAX_TLSv1_1", CURL_SSLVERSION_MAX_TLSv1_1, CONST_CS|CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "SSL_VERSION_MAX_TLSv1_2", CURL_SSLVERSION_MAX_TLSv1_2, CONST_CS|CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "SSL_VERSION_MAX_TLSv1_3", CURL_SSLVERSION_MAX_TLSv1_3, CONST_CS|CONST_PERSISTENT); #endif /* * DNS IPvX resolving */ REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "IPRESOLVE_V4", CURL_IPRESOLVE_V4, CONST_CS|CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "IPRESOLVE_V6", CURL_IPRESOLVE_V6, CONST_CS|CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "IPRESOLVE_ANY", CURL_IPRESOLVE_WHATEVER, CONST_CS|CONST_PERSISTENT); /* * Auth Constants */ REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "AUTH_NONE", CURLAUTH_NONE, CONST_CS|CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "AUTH_BASIC", CURLAUTH_BASIC, CONST_CS|CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "AUTH_DIGEST", CURLAUTH_DIGEST, CONST_CS|CONST_PERSISTENT); #if PHP_HTTP_CURL_VERSION(7,19,3) REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "AUTH_DIGEST_IE", CURLAUTH_DIGEST_IE, CONST_CS|CONST_PERSISTENT); #endif REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "AUTH_NTLM", CURLAUTH_NTLM, CONST_CS|CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "AUTH_GSSNEG", CURLAUTH_GSSNEGOTIATE, CONST_CS|CONST_PERSISTENT); #if PHP_HTTP_CURL_VERSION(7,38,0) REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "AUTH_SPNEGO", CURLAUTH_NEGOTIATE, CONST_CS|CONST_PERSISTENT); #endif #if PHP_HTTP_CURL_VERSION(7,61,0) REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "AUTH_BEARER", CURLAUTH_BEARER, CONST_CS|CONST_PERSISTENT); #endif #if PHP_HTTP_CURL_VERSION(7,75,0) REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "AWS_SIGV4", CURLAUTH_AWS_SIGV4, CONST_CS|CONST_PERSISTENT); #endif REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "AUTH_ANY", CURLAUTH_ANY, CONST_CS|CONST_PERSISTENT); /* * Proxy Type Constants */ REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "PROXY_SOCKS4", CURLPROXY_SOCKS4, CONST_CS|CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "PROXY_SOCKS4A", CURLPROXY_SOCKS4A, CONST_CS|CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "PROXY_SOCKS5_HOSTNAME", CURLPROXY_SOCKS5_HOSTNAME, CONST_CS|CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "PROXY_SOCKS5", CURLPROXY_SOCKS5, CONST_CS|CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "PROXY_HTTP", CURLPROXY_HTTP, CONST_CS|CONST_PERSISTENT); #if PHP_HTTP_CURL_VERSION(7,19,4) REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "PROXY_HTTP_1_0", CURLPROXY_HTTP_1_0, CONST_CS|CONST_PERSISTENT); #endif /* * Post Redirection Constants */ #if PHP_HTTP_CURL_VERSION(7,19,1) REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "POSTREDIR_301", CURL_REDIR_POST_301, CONST_CS|CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "POSTREDIR_302", CURL_REDIR_POST_302, CONST_CS|CONST_PERSISTENT); #if PHP_HTTP_CURL_VERSION(7,26,0) REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "POSTREDIR_303", CURL_REDIR_POST_303, CONST_CS|CONST_PERSISTENT); #endif REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "POSTREDIR_ALL", CURL_REDIR_POST_ALL, CONST_CS|CONST_PERSISTENT); #endif #if PHP_HTTP_CURL_VERSION(7,64,1) REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "ALTSVC_READONLYFILE", CURLALTSVC_READONLYFILE, CONST_CS|CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "ALTSVC_H1", CURLALTSVC_H1, CONST_CS|CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "ALTSVC_H2", CURLALTSVC_H2, CONST_CS|CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "ALTSVC_H3", CURLALTSVC_H3, CONST_CS|CONST_PERSISTENT); #endif #if PHP_HTTP_CURL_VERSION(7,74,0) REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "HSTS_ENABLE", CURLHSTS_ENABLE, CONST_CS|CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "HSTS_READONLYFILE", CURLHSTS_READONLYFILE, CONST_CS|CONST_PERSISTENT); #endif return SUCCESS; } PHP_MSHUTDOWN_FUNCTION(http_client_curl) { php_persistent_handle_cleanup(PHP_HTTP_G->client.curl.driver.client_name, NULL); php_persistent_handle_cleanup(PHP_HTTP_G->client.curl.driver.request_name, NULL); zend_string_release(PHP_HTTP_G->client.curl.driver.client_name); zend_string_release(PHP_HTTP_G->client.curl.driver.request_name); zend_string_release(PHP_HTTP_G->client.curl.driver.driver_name); php_http_options_dtor(&php_http_curle_options); php_http_options_dtor(&php_http_curlm_options); return SUCCESS; } #endif /* PHP_HTTP_HAVE_LIBCURL */ /* * 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 */ pecl_http-4.2.1/src/php_http_client_curl.h0000644000076500000240000000473714117626035017441 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_HTTP_CLIENT_CURL_H #define PHP_HTTP_CLIENT_CURL_H #if PHP_HTTP_HAVE_LIBCURL struct php_http_client_curl_globals { php_http_client_driver_t driver; }; typedef struct php_http_client_curl_handle { CURLM *multi; CURLSH *share; } php_http_client_curl_handle_t; typedef struct php_http_client_curl_ops { void *(*init)(); void (*dtor)(void **ctx_ptr); ZEND_RESULT_CODE (*once)(void *ctx); ZEND_RESULT_CODE (*wait)(void *ctx, struct timeval *custom_timeout); ZEND_RESULT_CODE (*exec)(void *ctx); } php_http_client_curl_ops_t; typedef struct php_http_client_curl { php_http_client_curl_handle_t *handle; int unfinished; /* int because of curl_multi_perform() */ void *ev_ctx; php_http_client_curl_ops_t *ev_ops; } php_http_client_curl_t; static inline void php_http_client_curl_get_timeout(php_http_client_curl_t *curl, long max_tout, struct timeval *timeout) { timeout->tv_sec = 0; timeout->tv_usec = 0; /* always returns CURLM_OK, check max_tout instead */ curl_multi_timeout(curl->handle->multi, &max_tout); if (!max_tout) { /* immediately */ return; } if (max_tout < 0) { /* 5ms */ max_tout = 5; } else if (max_tout > 1000) { /* 1s */ max_tout = 1000; } timeout->tv_sec = max_tout / 1000; timeout->tv_usec = (max_tout % 1000) * 1000; } PHP_HTTP_API void php_http_client_curl_responsehandler(php_http_client_t *client); PHP_HTTP_API void php_http_client_curl_loop(php_http_client_t *client, curl_socket_t s, int curl_action); PHP_HTTP_API php_http_client_ops_t *php_http_client_curl_get_ops(void); PHP_MINIT_FUNCTION(http_client_curl); PHP_MSHUTDOWN_FUNCTION(http_client_curl); #endif /* PHP_HTTP_HAVE_LIBCURL */ #endif /* PHP_HTTP_CLIENT_CURL_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 */ pecl_http-4.2.1/src/php_http_client_curl_event.c0000644000076500000240000002031714117626035020625 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #include "php_http_api.h" #if PHP_HTTP_HAVE_LIBCURL #if PHP_HTTP_HAVE_LIBEVENT #include #ifndef DBG_EVENTS # define DBG_EVENTS 0 #endif typedef struct php_http_client_curl_event_context { php_http_client_t *client; struct event_base *evbase; struct event *timeout; } php_http_client_curl_event_context_t; typedef struct php_http_client_curl_event_ev { struct event evnt; php_http_client_curl_event_context_t *context; } php_http_client_curl_event_ev_t; static inline int etoca(short action) { switch (action & (EV_READ|EV_WRITE)) { case EV_READ: return CURL_CSELECT_IN; break; case EV_WRITE: return CURL_CSELECT_OUT; break; case EV_READ|EV_WRITE: return CURL_CSELECT_IN|CURL_CSELECT_OUT; break; default: return 0; } } static void php_http_client_curl_event_handler(void *context, curl_socket_t s, int curl_action) { CURLMcode rc; php_http_client_curl_event_context_t *ctx = context; php_http_client_curl_t *curl = ctx->client->ctx; #if DBG_EVENTS fprintf(stderr, "H"); #endif do { rc = curl_multi_socket_action(curl->handle->multi, s, curl_action, &curl->unfinished); } while (CURLM_CALL_MULTI_PERFORM == rc); if (CURLM_OK != rc) { php_error_docref(NULL, E_WARNING, "%s", curl_multi_strerror(rc)); } php_http_client_curl_responsehandler(ctx->client); } static void php_http_client_curl_event_timeout_callback(int socket, short action, void *event_data) { #if DBG_EVENTS fprintf(stderr, "T"); #endif /* ignore and use -1,0 on timeout */ (void) socket; (void) action; php_http_client_curl_event_handler(event_data, CURL_SOCKET_TIMEOUT, 0); } static void php_http_client_curl_event_timer(CURLM *multi, long timeout_ms, void *timer_data) { php_http_client_curl_event_context_t *context = timer_data; struct timeval timeout; #if DBG_EVENTS fprintf(stderr, "(%ld)", timeout_ms); #endif switch (timeout_ms) { case -1: if (event_initialized(context->timeout) && event_pending(context->timeout, EV_TIMEOUT, NULL)) { event_del(context->timeout); } break; case 0: php_http_client_curl_event_handler(context, CURL_SOCKET_TIMEOUT, 0); break; default: if (!event_initialized(context->timeout)) { event_assign(context->timeout, context->evbase, CURL_SOCKET_TIMEOUT, 0, php_http_client_curl_event_timeout_callback, context); } timeout.tv_sec = timeout_ms / 1000; timeout.tv_usec = (timeout_ms % 1000) * 1000; if (!event_pending(context->timeout, EV_TIMEOUT, &timeout)) { event_add(context->timeout, &timeout); } break; } } static void php_http_client_curl_event_callback(int socket, short action, void *event_data) { php_http_client_curl_event_context_t *ctx = event_data; php_http_client_curl_t *curl = ctx->client->ctx; #if DBG_EVENTS fprintf(stderr, "E"); #endif php_http_client_curl_event_handler(event_data, socket, etoca(action)); /* remove timeout if there are no transfers left */ if (!curl->unfinished && event_initialized(ctx->timeout) && event_pending(ctx->timeout, EV_TIMEOUT, NULL)) { event_del(ctx->timeout); } } static int php_http_client_curl_event_socket(CURL *easy, curl_socket_t sock, int action, void *socket_data, void *assign_data) { php_http_client_curl_event_context_t *ctx = socket_data; php_http_client_curl_t *curl = ctx->client->ctx; int events = EV_PERSIST; php_http_client_curl_event_ev_t *ev = assign_data; #if DBG_EVENTS fprintf(stderr, "S"); #endif if (!ev) { ev = ecalloc(1, sizeof(*ev)); ev->context = ctx; curl_multi_assign(curl->handle->multi, sock, ev); } else { event_del(&ev->evnt); } switch (action) { case CURL_POLL_IN: events |= EV_READ; break; case CURL_POLL_OUT: events |= EV_WRITE; break; case CURL_POLL_INOUT: events |= EV_READ|EV_WRITE; break; case CURL_POLL_REMOVE: efree(ev); /* no break */ case CURL_POLL_NONE: return 0; default: php_error_docref(NULL, E_WARNING, "Unknown socket action %d", action); return -1; } event_assign(&ev->evnt, ctx->evbase, sock, events, php_http_client_curl_event_callback, ctx); event_add(&ev->evnt, NULL); return 0; } static ZEND_RESULT_CODE php_http_client_curl_event_once(void *context) { php_http_client_curl_event_context_t *ctx = context; #if DBG_EVENTS fprintf(stderr, "O"); #endif if (0 > event_base_loop(ctx->evbase, EVLOOP_NONBLOCK)) { return FAILURE; } return SUCCESS; } static ZEND_RESULT_CODE php_http_client_curl_event_wait(void *context, struct timeval *custom_timeout) { php_http_client_curl_event_context_t *ctx = context; struct timeval timeout; #if DBG_EVENTS fprintf(stderr, "W"); #endif if (!event_initialized(ctx->timeout)) { if (0 > event_assign(ctx->timeout, ctx->evbase, CURL_SOCKET_TIMEOUT, 0, php_http_client_curl_event_timeout_callback, ctx)) { return FAILURE; } } else if (custom_timeout && timerisset(custom_timeout)) { if (0 > event_add(ctx->timeout, custom_timeout)) { return FAILURE; } } else if (!event_pending(ctx->timeout, EV_TIMEOUT, NULL)) { php_http_client_curl_get_timeout(ctx->client->ctx, 1000, &timeout); if (0 > event_add(ctx->timeout, &timeout)) { return FAILURE; } } if (0 > event_base_loop(ctx->evbase, EVLOOP_ONCE)) { return FAILURE; } return SUCCESS; } static ZEND_RESULT_CODE php_http_client_curl_event_exec(void *context) { php_http_client_curl_event_context_t *ctx = context; php_http_client_curl_t *curl = ctx->client->ctx; #if DBG_EVENTS fprintf(stderr, "E"); #endif /* kickstart */ php_http_client_curl_event_handler(ctx, CURL_SOCKET_TIMEOUT, 0); do { if (0 > event_base_dispatch(ctx->evbase)) { return FAILURE; } } while (curl->unfinished && !EG(exception)); return SUCCESS; } static void *php_http_client_curl_event_init(php_http_client_t *client) { php_http_client_curl_t *curl = client->ctx; php_http_client_curl_event_context_t *ctx; struct event_base *evb = event_base_new(); #if DBG_EVENTS fprintf(stderr, "I"); #endif if (!evb) { return NULL; } ctx = ecalloc(1, sizeof(*ctx)); ctx->client = client; ctx->evbase = evb; ctx->timeout = ecalloc(1, sizeof(struct event)); curl_multi_setopt(curl->handle->multi, CURLMOPT_SOCKETDATA, ctx); curl_multi_setopt(curl->handle->multi, CURLMOPT_SOCKETFUNCTION, php_http_client_curl_event_socket); curl_multi_setopt(curl->handle->multi, CURLMOPT_TIMERDATA, ctx); curl_multi_setopt(curl->handle->multi, CURLMOPT_TIMERFUNCTION, php_http_client_curl_event_timer); return ctx; } static void php_http_client_curl_event_dtor(void **context) { php_http_client_curl_event_context_t *ctx = *context; php_http_client_curl_t *curl; #if DBG_EVENTS fprintf(stderr, "D"); #endif curl = ctx->client->ctx; curl_multi_setopt(curl->handle->multi, CURLMOPT_SOCKETDATA, NULL); curl_multi_setopt(curl->handle->multi, CURLMOPT_SOCKETFUNCTION, NULL); curl_multi_setopt(curl->handle->multi, CURLMOPT_TIMERDATA, NULL); curl_multi_setopt(curl->handle->multi, CURLMOPT_TIMERFUNCTION, NULL); if (event_initialized(ctx->timeout) && event_pending(ctx->timeout, EV_TIMEOUT, NULL)) { event_del(ctx->timeout); } efree(ctx->timeout); event_base_free(ctx->evbase); efree(ctx); *context = NULL; } static php_http_client_curl_ops_t php_http_client_curl_event_ops = { &php_http_client_curl_event_init, &php_http_client_curl_event_dtor, &php_http_client_curl_event_once, &php_http_client_curl_event_wait, &php_http_client_curl_event_exec, }; php_http_client_curl_ops_t *php_http_client_curl_event_ops_get() { return &php_http_client_curl_event_ops; } #endif /* PHP_HTTP_HAVE_LIBEVENT */ #endif /* PHP_HTTP_HAVE_LIBCURL */ /* * 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 */ pecl_http-4.2.1/src/php_http_client_curl_event.h0000644000076500000240000000201514117626035020625 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_HTTP_CLIENT_CURL_EVENT_H #define PHP_HTTP_CLIENT_CURL_EVENT_H #if PHP_HTTP_HAVE_LIBCURL #if PHP_HTTP_HAVE_LIBEVENT php_http_client_curl_ops_t *php_http_client_curl_event_ops_get(); #endif #endif #endif /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ pecl_http-4.2.1/src/php_http_client_curl_user.c0000644000076500000240000002350714117626035020466 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #include "php_http_api.h" #include "php_network.h" #include "zend_closures.h" #if PHP_HTTP_HAVE_LIBCURL typedef struct php_http_client_curl_user_ev { php_stream *socket; php_http_client_curl_user_context_t *context; } php_http_client_curl_user_ev_t; static ZEND_NAMED_FUNCTION(php_http_client_curl_user_handler) { zval *zstream = NULL, *zclient = NULL; php_stream *stream = NULL; long action = 0; php_socket_t fd = CURL_SOCKET_TIMEOUT; php_http_client_object_t *client = NULL; php_http_client_curl_t *curl; if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "O|rl", &zclient, php_http_client_get_class_entry(), &zstream, &action)) { return; } client = PHP_HTTP_OBJ(NULL, zclient); if (zstream) { php_stream_from_zval(stream, zstream); if (SUCCESS != php_stream_cast(stream, PHP_STREAM_AS_SOCKETD, (void *) &fd, 1)) { return; } } php_http_client_curl_loop(client->client, fd, action); curl = client->client->ctx; RETVAL_LONG(curl->unfinished); } static void php_http_client_curl_user_timer(CURLM *multi, long timeout_ms, void *timer_data) { php_http_client_curl_user_context_t *context = timer_data; #if DBG_EVENTS fprintf(stderr, "\ntimer <- timeout_ms: %ld\n", timeout_ms); #endif if (timeout_ms <= 0) { php_http_client_curl_loop(context->client, CURL_SOCKET_TIMEOUT, 0); } else { zval args[1], *ztimeout = &args[0]; ZVAL_LONG(ztimeout, timeout_ms); php_http_object_method_call(&context->timer, &context->user, NULL, 1, args); zval_ptr_dtor(ztimeout); } } static int php_http_client_curl_user_socket(CURL *easy, curl_socket_t sock, int action, void *socket_data, void *assign_data) { php_http_client_curl_user_context_t *ctx = socket_data; php_http_client_curl_t *curl = ctx->client->ctx; php_http_client_curl_user_ev_t *ev = assign_data; zval args[2], *zaction = &args[1], *zsocket = &args[0]; #if DBG_EVENTS fprintf(stderr, "S"); #endif if (!ev) { ev = ecalloc(1, sizeof(*ev)); ev->context = ctx; ev->socket = php_stream_sock_open_from_socket(sock, NULL); curl_multi_assign(curl->handle->multi, sock, ev); } switch (action) { case CURL_POLL_IN: case CURL_POLL_OUT: case CURL_POLL_INOUT: case CURL_POLL_REMOVE: case CURL_POLL_NONE: php_stream_to_zval(ev->socket, zsocket); Z_TRY_ADDREF_P(zsocket); ZVAL_LONG(zaction, action); php_http_object_method_call(&ctx->socket, &ctx->user, NULL, 2, args); zval_ptr_dtor(zsocket); zval_ptr_dtor(zaction); break; default: php_error_docref(NULL, E_WARNING, "Unknown socket action %d", action); return -1; } if (action == CURL_POLL_REMOVE) { php_stream_close(ev->socket); efree(ev); curl_multi_assign(curl->handle->multi, sock, NULL); } return 0; } static ZEND_RESULT_CODE php_http_client_curl_user_once(void *context) { php_http_client_curl_user_context_t *ctx = context; #if DBG_EVENTS fprintf(stderr, "O"); #endif return php_http_object_method_call(&ctx->once, &ctx->user, NULL, 0, NULL); } static ZEND_RESULT_CODE php_http_client_curl_user_wait(void *context, struct timeval *custom_timeout) { php_http_client_curl_user_context_t *ctx = context; struct timeval timeout; zval args[1], *ztimeout = &args[0]; ZEND_RESULT_CODE rv; #if DBG_EVENTS fprintf(stderr, "W"); #endif if (!custom_timeout || !timerisset(custom_timeout)) { php_http_client_curl_get_timeout(ctx->client->ctx, 1000, &timeout); custom_timeout = &timeout; } ZVAL_LONG(ztimeout, custom_timeout->tv_sec * 1000 + custom_timeout->tv_usec / 1000); rv = php_http_object_method_call(&ctx->wait, &ctx->user, NULL, 1, args); zval_ptr_dtor(ztimeout); return rv; } static ZEND_RESULT_CODE php_http_client_curl_user_exec(void *context) { php_http_client_curl_user_context_t *ctx = context; php_http_client_curl_t *curl = ctx->client->ctx; #if DBG_EVENTS fprintf(stderr, "E"); #endif /* kickstart */ php_http_client_curl_loop(ctx->client, CURL_SOCKET_TIMEOUT, 0); do { if (SUCCESS != php_http_object_method_call(&ctx->send, &ctx->user, NULL, 0, NULL)) { return FAILURE; } } while (curl->unfinished && !EG(exception)); return SUCCESS; } static void *php_http_client_curl_user_init(php_http_client_t *client, void *user_data) { php_http_client_curl_t *curl = client->ctx; php_http_client_curl_user_context_t *ctx; php_http_object_method_t init; zval args[1], *zclosure = &args[0]; #if DBG_EVENTS fprintf(stderr, "I"); #endif ctx = ecalloc(1, sizeof(*ctx)); ctx->client = client; ZVAL_COPY(&ctx->user, user_data); memset(&ctx->closure, 0, sizeof(ctx->closure)); ctx->closure.common.type = ZEND_INTERNAL_FUNCTION; ctx->closure.common.function_name = zend_string_init(ZEND_STRL("php_http_client_curl_user_handler"), 0); ctx->closure.internal_function.handler = php_http_client_curl_user_handler; zend_create_closure(zclosure, &ctx->closure, NULL, NULL, NULL); php_http_object_method_init(&init, &ctx->user, ZEND_STRL("init")); php_http_object_method_call(&init, &ctx->user, NULL, 1, args); php_http_object_method_dtor(&init); zval_ptr_dtor(zclosure); php_http_object_method_init(&ctx->timer, &ctx->user, ZEND_STRL("timer")); php_http_object_method_init(&ctx->socket, &ctx->user, ZEND_STRL("socket")); php_http_object_method_init(&ctx->once, &ctx->user, ZEND_STRL("once")); php_http_object_method_init(&ctx->wait, &ctx->user, ZEND_STRL("wait")); php_http_object_method_init(&ctx->send, &ctx->user, ZEND_STRL("send")); curl_multi_setopt(curl->handle->multi, CURLMOPT_SOCKETDATA, ctx); curl_multi_setopt(curl->handle->multi, CURLMOPT_SOCKETFUNCTION, php_http_client_curl_user_socket); curl_multi_setopt(curl->handle->multi, CURLMOPT_TIMERDATA, ctx); curl_multi_setopt(curl->handle->multi, CURLMOPT_TIMERFUNCTION, php_http_client_curl_user_timer); return ctx; } static void php_http_client_curl_user_dtor(void **context) { php_http_client_curl_user_context_t *ctx = *context; php_http_client_curl_t *curl; #if DBG_EVENTS fprintf(stderr, "D"); #endif curl = ctx->client->ctx; curl_multi_setopt(curl->handle->multi, CURLMOPT_SOCKETDATA, NULL); curl_multi_setopt(curl->handle->multi, CURLMOPT_SOCKETFUNCTION, NULL); curl_multi_setopt(curl->handle->multi, CURLMOPT_TIMERDATA, NULL); curl_multi_setopt(curl->handle->multi, CURLMOPT_TIMERFUNCTION, NULL); php_http_object_method_dtor(&ctx->timer); php_http_object_method_dtor(&ctx->socket); php_http_object_method_dtor(&ctx->once); php_http_object_method_dtor(&ctx->wait); php_http_object_method_dtor(&ctx->send); zend_string_release(ctx->closure.common.function_name); zval_ptr_dtor(&ctx->user); efree(ctx); *context = NULL; } static php_http_client_curl_ops_t php_http_client_curl_user_ops = { &php_http_client_curl_user_init, &php_http_client_curl_user_dtor, &php_http_client_curl_user_once, &php_http_client_curl_user_wait, &php_http_client_curl_user_exec, }; php_http_client_curl_ops_t *php_http_client_curl_user_ops_get() { return &php_http_client_curl_user_ops; } static zend_class_entry *php_http_client_curl_user_class_entry; zend_class_entry *php_http_client_curl_user_get_class_entry() { return php_http_client_curl_user_class_entry; } ZEND_BEGIN_ARG_INFO_EX(ai_init, 0, 0, 1) /* using IS_CALLABLE type hint would create a forwards compatibility break */ ZEND_ARG_INFO(0, run) ZEND_END_ARG_INFO(); ZEND_BEGIN_ARG_INFO_EX(ai_timer, 0, 0, 1) #if PHP_VERSION_ID >= 70000 ZEND_ARG_TYPE_INFO(0, timeout_ms, IS_LONG, 0) #else ZEND_ARG_INFO(0, timeout_ms) #endif ZEND_END_ARG_INFO(); ZEND_BEGIN_ARG_INFO_EX(ai_socket, 0, 0, 2) ZEND_ARG_INFO(0, socket) #if PHP_VERSION_ID >= 70000 ZEND_ARG_TYPE_INFO(0, action, IS_LONG, 0) #else ZEND_ARG_INFO(0, action) #endif ZEND_END_ARG_INFO(); ZEND_BEGIN_ARG_INFO_EX(ai_once, 0, 0, 0) ZEND_END_ARG_INFO(); ZEND_BEGIN_ARG_INFO_EX(ai_wait, 0, 0, 0) #if PHP_VERSION_ID >= 70000 ZEND_ARG_TYPE_INFO(0, timeout_ms, IS_LONG, 0) #else ZEND_ARG_INFO(0, timeout_ms) #endif ZEND_END_ARG_INFO(); ZEND_BEGIN_ARG_INFO_EX(ai_send, 0, 0, 0) ZEND_END_ARG_INFO(); static zend_function_entry php_http_client_curl_user_methods[] = { PHP_ABSTRACT_ME(HttpClientCurlUser, init, ai_init) PHP_ABSTRACT_ME(HttpClientCurlUser, timer, ai_timer) PHP_ABSTRACT_ME(HttpClientCurlUser, socket, ai_socket) PHP_ABSTRACT_ME(HttpClientCurlUser, once, ai_once) PHP_ABSTRACT_ME(HttpClientCurlUser, wait, ai_wait) PHP_ABSTRACT_ME(HttpClientCulrUser, send, ai_send) {0} }; PHP_MINIT_FUNCTION(http_client_curl_user) { zend_class_entry ce = {0}; INIT_NS_CLASS_ENTRY(ce, "http\\Client\\Curl", "User", php_http_client_curl_user_methods); php_http_client_curl_user_class_entry = zend_register_internal_interface(&ce); zend_declare_class_constant_long(php_http_client_curl_user_class_entry, ZEND_STRL("POLL_NONE"), CURL_POLL_NONE); zend_declare_class_constant_long(php_http_client_curl_user_class_entry, ZEND_STRL("POLL_IN"), CURL_POLL_IN); zend_declare_class_constant_long(php_http_client_curl_user_class_entry, ZEND_STRL("POLL_OUT"), CURL_POLL_OUT); zend_declare_class_constant_long(php_http_client_curl_user_class_entry, ZEND_STRL("POLL_INOUT"), CURL_POLL_INOUT); zend_declare_class_constant_long(php_http_client_curl_user_class_entry, ZEND_STRL("POLL_REMOVE"), CURL_POLL_REMOVE); return SUCCESS; } #endif /* PHP_HTTP_HAVE_LIBCURL */ /* * 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 */ pecl_http-4.2.1/src/php_http_client_curl_user.h0000644000076500000240000000534714117626035020475 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_HTTP_CLIENT_CURL_USER_H #define PHP_HTTP_CLIENT_CURL_USER_H #if PHP_HTTP_HAVE_LIBCURL typedef struct php_http_client_curl_user_context { php_http_client_t *client; zval user; zend_function closure; php_http_object_method_t timer; php_http_object_method_t socket; php_http_object_method_t once; php_http_object_method_t wait; php_http_object_method_t send; } php_http_client_curl_user_context_t; PHP_HTTP_API zend_class_entry *php_http_client_curl_user_get_class_entry(); PHP_HTTP_API php_http_client_curl_ops_t *php_http_client_curl_user_ops_get(); PHP_MINIT_FUNCTION(http_client_curl_user); #endif #if 0 | +--------------------------------------------------------------------+ */ #include "php_http_api.h" static zend_class_entry *php_http_client_request_class_entry; zend_class_entry *php_http_get_client_request_class_entry(void) { return php_http_client_request_class_entry; } void php_http_client_options_set_subr(zval *this_ptr, char *key, size_t len, zval *opts, int overwrite); void php_http_client_options_set(zval *this_ptr, zval *opts); void php_http_client_options_get_subr(zval *this_ptr, char *key, size_t len, zval *return_value); #define PHP_HTTP_CLIENT_REQUEST_OBJECT_INIT(obj) \ do { \ if (!obj->message) { \ obj->message = php_http_message_init(NULL, PHP_HTTP_REQUEST, NULL); \ } \ } while(0) ZEND_BEGIN_ARG_INFO_EX(ai_HttpClientRequest___construct, 0, 0, 0) ZEND_ARG_INFO(0, method) ZEND_ARG_INFO(0, url) ZEND_ARG_ARRAY_INFO(0, headers, 1) ZEND_ARG_OBJ_INFO(0, body, http\\Message\\Body, 1) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClientRequest, __construct) { char *meth_str = NULL; size_t meth_len = 0; zval *zheaders = NULL, *zbody = NULL, *zurl = NULL; php_http_message_object_t *obj; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|s!z!a!O!", &meth_str, &meth_len, &zurl, &zheaders, &zbody, php_http_get_message_body_class_entry()), invalid_arg, return); obj = PHP_HTTP_OBJ(NULL, getThis()); if (obj->message) { php_http_message_set_type(obj->message, PHP_HTTP_REQUEST); } else { obj->message = php_http_message_init(NULL, PHP_HTTP_REQUEST, NULL); } if (zbody) { php_http_expect(SUCCESS == php_http_message_object_set_body(obj, zbody), unexpected_val, return); } if (meth_str && meth_len) { PHP_HTTP_INFO(obj->message).request.method = estrndup(meth_str, meth_len); } if (zurl) { php_http_url_t *url = php_http_url_from_zval(zurl, PHP_HTTP_URL_STDFLAGS); if (url) { PHP_HTTP_INFO(obj->message).request.url = php_http_url_mod(url, NULL, PHP_HTTP_URL_STDFLAGS); php_http_url_free(&url); } } if (zheaders) { array_copy(Z_ARRVAL_P(zheaders), &obj->message->hdrs); } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpClientRequest_setContentType, 0, 0, 1) ZEND_ARG_INFO(0, content_type) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClientRequest, setContentType) { zend_string *ct_str; php_http_message_object_t *obj; zval zct; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "S", &ct_str), invalid_arg, return); if (ct_str->len && !strchr(ct_str->val, '/')) { php_http_throw(unexpected_val, "Content type \"%s\" does not seem to contain a primary and a secondary part", ct_str->val); return; } obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_CLIENT_REQUEST_OBJECT_INIT(obj); ZVAL_STR_COPY(&zct, ct_str); zend_hash_str_update(&obj->message->hdrs, "Content-Type", lenof("Content-Type"), &zct); RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpClientRequest_getContentType, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClientRequest, getContentType) { if (SUCCESS == zend_parse_parameters_none()) { php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); zval *zct; PHP_HTTP_CLIENT_REQUEST_OBJECT_INIT(obj); php_http_message_update_headers(obj->message); zct = php_http_message_header(obj->message, ZEND_STRL("Content-Type")); if (zct) { RETURN_ZVAL(zct, 1, 0); } } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpClientRequest_setQuery, 0, 0, 0) ZEND_ARG_INFO(0, query_data) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClientRequest, setQuery) { zval *qdata = NULL, arr, str; php_http_message_object_t *obj; php_http_url_t *old_url = NULL, new_url = {NULL}; unsigned flags = PHP_HTTP_URL_REPLACE; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "z!", &qdata), invalid_arg, return); obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_CLIENT_REQUEST_OBJECT_INIT(obj); ZVAL_NULL(&str); if (qdata) { array_init(&arr); php_http_expect(SUCCESS == php_http_querystring_update(&arr, qdata, &str), bad_querystring, zval_dtor(&arr); return; ); new_url.query = Z_STRVAL(str); zval_dtor(&arr); } else { flags = PHP_HTTP_URL_STRIP_QUERY; } if (obj->message->http.info.request.url) { old_url = obj->message->http.info.request.url; } obj->message->http.info.request.url = php_http_url_mod(old_url, &new_url, flags); if (old_url) { php_http_url_free(&old_url); } zval_ptr_dtor(&str); RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpClientRequest_getQuery, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClientRequest, getQuery) { if (SUCCESS == zend_parse_parameters_none()) { php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_CLIENT_REQUEST_OBJECT_INIT(obj); if (obj->message->http.info.request.url && obj->message->http.info.request.url->query) { RETVAL_STRING(obj->message->http.info.request.url->query); } } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpClientRequest_addQuery, 0, 0, 1) ZEND_ARG_INFO(0, query_data) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClientRequest, addQuery) { zval *qdata, arr, str; php_http_message_object_t *obj; php_http_url_t *old_url = NULL, new_url = {NULL}; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "z", &qdata), invalid_arg, return); obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_CLIENT_REQUEST_OBJECT_INIT(obj); array_init(&arr); ZVAL_NULL(&str); php_http_expect(SUCCESS == php_http_querystring_update(&arr, qdata, &str), bad_querystring, zval_dtor(&arr); return; ); new_url.query = Z_STRVAL(str); zval_dtor(&arr); if (obj->message->http.info.request.url) { old_url = obj->message->http.info.request.url; } obj->message->http.info.request.url = php_http_url_mod(old_url, &new_url, PHP_HTTP_URL_JOIN_QUERY); if (old_url) { php_http_url_free(&old_url); } zval_ptr_dtor(&str); RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpClientRequest_setOptions, 0, 0, 0) ZEND_ARG_ARRAY_INFO(0, options, 1) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClientRequest, setOptions) { zval *opts = NULL; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|a!/", &opts), invalid_arg, return); php_http_client_options_set(getThis(), opts); RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpClientRequest_getOptions, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClientRequest, getOptions) { if (SUCCESS == zend_parse_parameters_none()) { zval tmp, *zoptions = zend_read_property(php_http_client_request_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("options"), 0, &tmp); RETURN_ZVAL(zoptions, 1, 0); } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpClientRequest_setSslOptions, 0, 0, 0) ZEND_ARG_ARRAY_INFO(0, ssl_options, 1) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClientRequest, setSslOptions) { zval *opts = NULL; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|a!/", &opts), invalid_arg, return); php_http_client_options_set_subr(getThis(), ZEND_STRL("ssl"), opts, 1); RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpClientRequest_addSslOptions, 0, 0, 0) ZEND_ARG_ARRAY_INFO(0, ssl_options, 1) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClientRequest, addSslOptions) { zval *opts = NULL; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|a!/", &opts), invalid_arg, return); php_http_client_options_set_subr(getThis(), ZEND_STRL("ssl"), opts, 0); RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpClientRequest_getSslOptions, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClientRequest, getSslOptions) { if (SUCCESS == zend_parse_parameters_none()) { php_http_client_options_get_subr(getThis(), ZEND_STRL("ssl"), return_value); } } static zend_function_entry php_http_client_request_methods[] = { PHP_ME(HttpClientRequest, __construct, ai_HttpClientRequest___construct, ZEND_ACC_PUBLIC) PHP_ME(HttpClientRequest, setContentType, ai_HttpClientRequest_setContentType, ZEND_ACC_PUBLIC) PHP_ME(HttpClientRequest, getContentType, ai_HttpClientRequest_getContentType, ZEND_ACC_PUBLIC) PHP_ME(HttpClientRequest, setQuery, ai_HttpClientRequest_setQuery, ZEND_ACC_PUBLIC) PHP_ME(HttpClientRequest, getQuery, ai_HttpClientRequest_getQuery, ZEND_ACC_PUBLIC) PHP_ME(HttpClientRequest, addQuery, ai_HttpClientRequest_addQuery, ZEND_ACC_PUBLIC) PHP_ME(HttpClientRequest, setOptions, ai_HttpClientRequest_setOptions, ZEND_ACC_PUBLIC) PHP_ME(HttpClientRequest, getOptions, ai_HttpClientRequest_getOptions, ZEND_ACC_PUBLIC) PHP_ME(HttpClientRequest, setSslOptions, ai_HttpClientRequest_setSslOptions, ZEND_ACC_PUBLIC) PHP_ME(HttpClientRequest, getSslOptions, ai_HttpClientRequest_getSslOptions, ZEND_ACC_PUBLIC) PHP_ME(HttpClientRequest, addSslOptions, ai_HttpClientRequest_addSslOptions, ZEND_ACC_PUBLIC) EMPTY_FUNCTION_ENTRY }; PHP_MINIT_FUNCTION(http_client_request) { zend_class_entry ce = {0}; INIT_NS_CLASS_ENTRY(ce, "http\\Client", "Request", php_http_client_request_methods); php_http_client_request_class_entry = zend_register_internal_class_ex(&ce, php_http_message_get_class_entry()); zend_declare_property_null(php_http_client_request_class_entry, ZEND_STRL("options"), ZEND_ACC_PROTECTED); 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 */ pecl_http-4.2.1/src/php_http_client_request.h0000644000076500000240000000202714117626035020152 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_HTTP_CLIENT_REQUEST_H #define PHP_HTTP_CLIENT_REQUEST_H PHP_HTTP_API zend_class_entry *php_http_get_client_request_class_entry(void); PHP_MINIT_FUNCTION(http_client_request); #endif /* PHP_HTTP_CLIENT_REQUEST_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 */ pecl_http-4.2.1/src/php_http_client_response.c0000644000076500000240000001123214117626035020311 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #include "php_http_api.h" static zend_class_entry *php_http_client_response_class_entry; zend_class_entry *php_http_get_client_response_class_entry(void) { return php_http_client_response_class_entry; } ZEND_BEGIN_ARG_INFO_EX(ai_HttpClientResponse_getCookies, 0, 0, 0) ZEND_ARG_INFO(0, flags) ZEND_ARG_INFO(0, allowed_extras) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClientResponse, getCookies) { zend_long flags = 0; zval *allowed_extras_array = NULL; int i = 0; char **allowed_extras = NULL; zval *header = NULL, *entry = NULL; php_http_message_object_t *msg; if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "|la!/", &flags, &allowed_extras_array)) { return; } msg = PHP_HTTP_OBJ(NULL, getThis()); array_init(return_value); if (allowed_extras_array) { /* FIXME: use zend_string** instead of char** */ allowed_extras = ecalloc(zend_hash_num_elements(Z_ARRVAL_P(allowed_extras_array)) + 1, sizeof(char *)); ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(allowed_extras_array), entry) { zend_string *zs = zval_get_string(entry); allowed_extras[i++] = estrndup(zs->val, zs->len); zend_string_release(zs); } ZEND_HASH_FOREACH_END(); } if ((header = php_http_message_header(msg->message, ZEND_STRL("Set-Cookie")))) { php_http_cookie_list_t *list; if (Z_TYPE_P(header) == IS_ARRAY) { zval *single_header; ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(header), single_header) { zend_string *zs = zval_get_string(single_header); if ((list = php_http_cookie_list_parse(NULL, zs->val, zs->len, flags, allowed_extras))) { zval cookie; ZVAL_OBJ(&cookie, &php_http_cookie_object_new_ex(php_http_cookie_get_class_entry(), list)->zo); add_next_index_zval(return_value, &cookie); } zend_string_release(zs); } ZEND_HASH_FOREACH_END(); } else { zend_string *zs = zval_get_string(header); if ((list = php_http_cookie_list_parse(NULL, zs->val, zs->len, flags, allowed_extras))) { zval cookie; ZVAL_OBJ(&cookie, &php_http_cookie_object_new_ex(php_http_cookie_get_class_entry(), list)->zo); add_next_index_zval(return_value, &cookie); } zend_string_release(zs); } } if (allowed_extras) { for (i = 0; allowed_extras[i]; ++i) { efree(allowed_extras[i]); } efree(allowed_extras); } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpClientResponse_getTransferInfo, 0, 0, 0) ZEND_ARG_INFO(0, element) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClientResponse, getTransferInfo) { char *info_name = NULL; size_t info_len = 0; zval info_tmp, info_name_tmp, *info; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|s", &info_name, &info_len), invalid_arg, return); info = zend_read_property(php_http_client_response_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("transferInfo"), 0, &info_tmp); /* request completed? */ if (Z_TYPE_P(info) != IS_OBJECT) { php_http_throw(bad_method_call, "Incomplete state"); return; } if (info_len && info_name) { info = zend_read_property(NULL, Z_OBJ_P(info), php_http_pretty_key(info_name, info_len, 0, 0), info_len, 0, &info_name_tmp); if (!info) { php_http_throw(unexpected_val, "Could not find transfer info with name '%s'", info_name); return; } } RETURN_ZVAL(info, 1, 0); } static zend_function_entry php_http_client_response_methods[] = { PHP_ME(HttpClientResponse, getCookies, ai_HttpClientResponse_getCookies, ZEND_ACC_PUBLIC) PHP_ME(HttpClientResponse, getTransferInfo, ai_HttpClientResponse_getTransferInfo, ZEND_ACC_PUBLIC) EMPTY_FUNCTION_ENTRY }; PHP_MINIT_FUNCTION(http_client_response) { zend_class_entry ce = {0}; INIT_NS_CLASS_ENTRY(ce, "http\\Client", "Response", php_http_client_response_methods); php_http_client_response_class_entry = zend_register_internal_class_ex(&ce, php_http_message_get_class_entry()); zend_declare_property_null(php_http_client_response_class_entry, ZEND_STRL("transferInfo"), ZEND_ACC_PROTECTED); 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 */ pecl_http-4.2.1/src/php_http_client_response.h0000644000076500000240000000203514117626035020317 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_HTTP_CLIENT_RESPONSE_H #define PHP_HTTP_CLIENT_RESPONSE_H PHP_HTTP_API zend_class_entry *php_http_get_client_response_class_entry(void); PHP_MINIT_FUNCTION(http_client_response); #endif /* PHP_HTTP_CLIENT_RESPONSE_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 */ pecl_http-4.2.1/src/php_http_cookie.c0000644000076500000240000007034114117626035016374 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #include "php_http_api.h" php_http_cookie_list_t *php_http_cookie_list_init(php_http_cookie_list_t *list) { 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 = -1; list->max_age = -1; list->flags = 0; return list; } php_http_cookie_list_t *php_http_cookie_list_copy(php_http_cookie_list_t *from, php_http_cookie_list_t *to) { to = php_http_cookie_list_init(to); array_copy(&from->cookies, &to->cookies); array_copy(&from->extras, &to->extras); PTR_SET(to->path, from->path ? estrdup(from->path) : NULL); PTR_SET(to->domain, from->domain ? estrdup(from->domain) : NULL); to->expires = from->expires; to->max_age = from->max_age; to->flags = from->flags; return to; } void php_http_cookie_list_dtor(php_http_cookie_list_t *list) { if (list) { zend_hash_destroy(&list->cookies); zend_hash_destroy(&list->extras); PTR_SET(list->path, NULL); PTR_SET(list->domain, NULL); } } void php_http_cookie_list_free(php_http_cookie_list_t **list) { if (*list) { php_http_cookie_list_dtor(*list); efree(*list); *list = NULL; } } const char *php_http_cookie_list_get_cookie(php_http_cookie_list_t *list, const char *name, size_t name_len, zval *zcookie) { zval *cookie = zend_symtable_str_find(&list->cookies, name, name_len); if (!cookie || (Z_TYPE_P(cookie) != IS_STRING)) { return NULL; } if (zcookie) { *zcookie = *cookie; } return Z_STRVAL_P(cookie); } const char *php_http_cookie_list_get_extra(php_http_cookie_list_t *list, const char *name, size_t name_len, zval *zextra) { zval *extra = zend_symtable_str_find(&list->extras, name, name_len); if (!extra || (Z_TYPE_P(extra) != IS_STRING)) { return NULL; } if (zextra) { *zextra = *extra; } return Z_STRVAL_P(extra); } 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) { zval cookie_value; ZVAL_STRINGL(&cookie_value, value, value_len); zend_symtable_str_update(&list->cookies, name, name_len, &cookie_value); } 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) { zval extra_value; ZVAL_STRINGL(&extra_value, value, value_len); zend_symtable_str_update(&list->extras, name, name_len, &extra_value); } #define _KEY_IS(s) (key->key && key->key->len == sizeof(s)-1 && !strncasecmp(key->key->val, (s), key->key->len)) static void add_entry(php_http_cookie_list_t *list, char **allowed_extras, long flags, zend_hash_key *key, zval *val) { zval arg; ZVAL_DUP(&arg, val); convert_to_string(&arg); if (!(flags & PHP_HTTP_COOKIE_PARSE_RAW)) { Z_STRLEN(arg) = php_raw_url_decode(Z_STRVAL(arg), Z_STRLEN(arg)); zend_string_forget_hash_val(Z_STR(arg)); } if _KEY_IS("path") { PTR_SET(list->path, estrndup(Z_STRVAL(arg), Z_STRLEN(arg))); } else if _KEY_IS("domain") { PTR_SET(list->domain, estrndup(Z_STRVAL(arg), Z_STRLEN(arg))); } else if _KEY_IS("expires") { char *date = estrndup(Z_STRVAL(arg), Z_STRLEN(arg)); list->expires = php_parse_date(date, NULL); efree(date); } else if _KEY_IS("max-age") { list->max_age = zval_get_long(val); } else if _KEY_IS("secure") { list->flags |= PHP_HTTP_COOKIE_SECURE; } else if _KEY_IS("httpOnly") { list->flags |= PHP_HTTP_COOKIE_HTTPONLY; } else { php_http_arrkey_t tmp = {0}; php_http_arrkey_stringify(&tmp, key); /* check for extra */ if (allowed_extras) { char **ae = allowed_extras; for (; *ae; ++ae) { if (!strncasecmp(*ae, tmp.key->val, tmp.key->len)) { zend_symtable_update(&list->extras, tmp.key, &arg); php_http_arrkey_dtor(&tmp); return; } } } /* cookie */ zend_symtable_update(&list->cookies, tmp.key, &arg); php_http_arrkey_dtor(&tmp); return; } zval_ptr_dtor(&arg); } php_http_cookie_list_t *php_http_cookie_list_parse(php_http_cookie_list_t *list, const char *str, size_t len, long flags, char **allowed_extras) { php_http_params_opts_t opts; HashTable params; zend_hash_key k, arg_k; zval *param, *val, *args, *arg; php_http_params_opts_default_get(&opts); opts.input.str = estrndup(str, len); opts.input.len = len; opts.param = NULL; zend_hash_init(¶ms, 10, NULL, ZVAL_PTR_DTOR, 0); php_http_params_parse(¶ms, &opts); efree(opts.input.str); list = php_http_cookie_list_init(list); ZEND_HASH_FOREACH_KEY_VAL(¶ms, k.h, k.key, param) { if (Z_TYPE_P(param) == IS_ARRAY) { if ((val = zend_hash_str_find(Z_ARRVAL_P(param), ZEND_STRL("value")))) { add_entry(list, NULL, flags, &k, val); } if ((args = zend_hash_str_find(Z_ARRVAL_P(param), ZEND_STRL("arguments"))) && Z_TYPE_P(args) == IS_ARRAY) { ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(args), arg_k.h, arg_k.key, arg) { add_entry(list, allowed_extras, flags, &arg_k, arg); } ZEND_HASH_FOREACH_END(); } } } ZEND_HASH_FOREACH_END(); zend_hash_destroy(¶ms); return list; } void php_http_cookie_list_to_struct(php_http_cookie_list_t *list, zval *strct) { zval cookies, extras, tmp; HashTable *ht = HASH_OF(strct); array_init_size(&cookies, zend_hash_num_elements(&list->cookies)); array_copy(&list->cookies, Z_ARRVAL(cookies)); zend_symtable_str_update(ht, ZEND_STRL("cookies"), &cookies); array_init_size(&extras, zend_hash_num_elements(&list->extras)); array_copy(&list->extras, Z_ARRVAL(extras)); zend_symtable_str_update(ht, ZEND_STRL("extras"), &extras); ZVAL_LONG(&tmp, list->flags); zend_symtable_str_update(ht, ZEND_STRL("flags"), &tmp); ZVAL_LONG(&tmp, list->expires); zend_symtable_str_update(ht, ZEND_STRL("expires"), &tmp); ZVAL_LONG(&tmp, list->max_age); zend_symtable_str_update(ht, ZEND_STRL("max-age"), &tmp); ZVAL_STRING(&tmp, STR_PTR(list->path)); zend_symtable_str_update(ht, ZEND_STRL("path"), &tmp); ZVAL_STRING(&tmp, STR_PTR(list->domain)); zend_symtable_str_update(ht, ZEND_STRL("domain"), &tmp); } php_http_cookie_list_t *php_http_cookie_list_from_struct(php_http_cookie_list_t *list, zval *strct) { zval *tmp; HashTable *ht; ht = HASH_OF(strct); list = php_http_cookie_list_init(list); if ((tmp = zend_hash_str_find_ind(ht, ZEND_STRL("cookies"))) && Z_TYPE_P(tmp) == IS_ARRAY){ array_copy(Z_ARRVAL_P(tmp), &list->cookies); } if ((tmp = zend_hash_str_find_ind(ht, ZEND_STRL("extras"))) && Z_TYPE_P(tmp) == IS_ARRAY){ array_copy(Z_ARRVAL_P(tmp), &list->extras); } if ((tmp = zend_hash_str_find_ind(ht, ZEND_STRL("flags")))) { list->flags = zval_get_long(tmp); } if ((tmp = zend_hash_str_find_ind(ht, ZEND_STRL("expires")))) { if (Z_TYPE_P(tmp) == IS_LONG) { list->expires = Z_LVAL_P(tmp); } else { zend_long lval; zend_string *lstr = zval_get_string(tmp); if (IS_LONG == is_numeric_string(lstr->val, lstr->len, &lval, NULL, 0)) { list->expires = lval; } else { list->expires = php_parse_date(lstr->val, NULL); } zend_string_release(lstr); } } if ((tmp = zend_hash_str_find_ind(ht, ZEND_STRL("max-age")))) { if (Z_TYPE_P(tmp) == IS_LONG) { list->max_age = Z_LVAL_P(tmp); } else { zend_long lval; zend_string *lstr = zval_get_string(tmp); if (IS_LONG == is_numeric_string(lstr->val, lstr->len, &lval, NULL, 0)) { list->max_age = lval; } zend_string_release(lstr); } } if ((tmp = zend_hash_str_find_ind(ht, ZEND_STRL("path")))) { zend_string *str = zval_get_string(tmp); list->path = estrndup(str->val, str->len); zend_string_release(str); } if ((tmp = zend_hash_str_find_ind(ht, ZEND_STRL("domain")))) { zend_string *str = zval_get_string(tmp); list->domain = estrndup(str->val, str->len); zend_string_release(str); } return list; } static inline void append_encoded(php_http_buffer_t *buf, const char *key, size_t key_len, const char *val, size_t val_len) { zend_string *enc_str[2]; enc_str[0] = php_raw_url_encode(key, key_len); enc_str[1] = php_raw_url_encode(val, val_len); php_http_buffer_append(buf, enc_str[0]->val, enc_str[0]->len); php_http_buffer_appends(buf, "="); php_http_buffer_append(buf, enc_str[1]->val, enc_str[1]->len); php_http_buffer_appends(buf, "; "); zend_string_release(enc_str[0]); zend_string_release(enc_str[1]); } void php_http_cookie_list_to_string(php_http_cookie_list_t *list, char **str, size_t *len) { php_http_buffer_t buf; zend_hash_key key; zval *val; php_http_buffer_init(&buf); ZEND_HASH_FOREACH_KEY_VAL(&list->cookies, key.h, key.key, val) { zend_string *str = zval_get_string(val); php_http_arrkey_t arrkey = {0}; php_http_arrkey_stringify(&arrkey, &key); append_encoded(&buf, arrkey.key->val, arrkey.key->len, str->val, str->len); php_http_arrkey_dtor(&arrkey); zend_string_release(str); } ZEND_HASH_FOREACH_END(); 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 >= 0) { zend_string *date = php_format_date(ZEND_STRL(PHP_HTTP_DATE_FORMAT), list->expires, 0); php_http_buffer_appendf(&buf, "expires=%s; ", date->val); zend_string_release(date); } if (list->max_age >= 0) { php_http_buffer_appendf(&buf, "max-age=%ld; ", list->max_age); } ZEND_HASH_FOREACH_KEY_VAL(&list->extras, key.h, key.key, val) { zend_string *str = zval_get_string(val); php_http_arrkey_t arrkey; php_http_arrkey_stringify(&arrkey, &key); append_encoded(&buf, arrkey.key->val, arrkey.key->len, str->val, str->len); php_http_arrkey_dtor(&arrkey); zend_string_release(str); } ZEND_HASH_FOREACH_END(); 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 = buf.data; *len = buf.used; } static zend_class_entry *php_http_cookie_class_entry; zend_class_entry *php_http_cookie_get_class_entry(void) { return php_http_cookie_class_entry; } static zend_object_handlers php_http_cookie_object_handlers; zend_object *php_http_cookie_object_new(zend_class_entry *ce) { return &php_http_cookie_object_new_ex(ce, NULL)->zo; } php_http_cookie_object_t *php_http_cookie_object_new_ex(zend_class_entry *ce, php_http_cookie_list_t *list) { php_http_cookie_object_t *o; if (!ce) { ce = php_http_cookie_class_entry; } o = ecalloc(1, sizeof(*o) + zend_object_properties_size(ce)); zend_object_std_init(&o->zo, ce); object_properties_init(&o->zo, ce); o->zo.handlers = &php_http_cookie_object_handlers; if (list) { o->list = list; } return o; } #define PHP_HTTP_COOKIE_OBJECT_INIT(obj) \ do { \ if (!obj->list) { \ obj->list = php_http_cookie_list_init(NULL); \ } \ } while(0) zend_object *php_http_cookie_object_clone(zend_object *obj) { php_http_cookie_object_t *new_obj, *old_obj = PHP_HTTP_OBJ(obj, NULL); PHP_HTTP_COOKIE_OBJECT_INIT(old_obj); new_obj = php_http_cookie_object_new_ex(old_obj->zo.ce, php_http_cookie_list_copy(old_obj->list, NULL)); zend_objects_clone_members(&new_obj->zo, &old_obj->zo); return &new_obj->zo; } void php_http_cookie_object_free(zend_object *object) { php_http_cookie_object_t *obj = PHP_HTTP_OBJ(object, NULL); php_http_cookie_list_free(&obj->list); zend_object_std_dtor(object); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie___construct, 0, 0, 0) ZEND_ARG_INFO(0, cookie_string) ZEND_ARG_INFO(0, parser_flags) ZEND_ARG_INFO(0, allowed_extras) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpCookie, __construct) { php_http_cookie_object_t *obj; zval *zcookie = NULL; zend_long flags = 0; char **ae = NULL; HashTable *allowed_extras = NULL; zend_error_handling zeh; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|z!lH/", &zcookie, &flags, &allowed_extras), invalid_arg, return); obj = PHP_HTTP_OBJ(NULL, getThis()); zend_replace_error_handling(EH_THROW, php_http_get_exception_runtime_class_entry(), &zeh); if (zcookie) { if (allowed_extras && zend_hash_num_elements(allowed_extras)) { char **ae_ptr = safe_emalloc(zend_hash_num_elements(allowed_extras) + 1, sizeof(char *), 0); zval *val; ae = ae_ptr; ZEND_HASH_FOREACH_VAL(allowed_extras, val) { zend_string *str = zval_get_string(val); *ae_ptr++ = estrndup(str->val, str->len); zend_string_release(str); } ZEND_HASH_FOREACH_END(); *ae_ptr = NULL; } switch (Z_TYPE_P(zcookie)) { case IS_OBJECT: if (instanceof_function(Z_OBJCE_P(zcookie), php_http_cookie_class_entry)) { php_http_cookie_object_t *zco = PHP_HTTP_OBJ(NULL, zcookie); if (zco->list) { obj->list = php_http_cookie_list_copy(zco->list, NULL); } break; } /* no break */ case IS_ARRAY: obj->list = php_http_cookie_list_from_struct(obj->list, zcookie); break; default: { zend_string *str = zval_get_string(zcookie); obj->list = php_http_cookie_list_parse(obj->list, str->val, str->len, flags, ae); zend_string_release(str); break; } } if (ae) { char **ae_ptr; for (ae_ptr = ae; *ae_ptr; ++ae_ptr) { efree(*ae_ptr); } efree(ae); } } zend_restore_error_handling(&zeh); PHP_HTTP_COOKIE_OBJECT_INIT(obj); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_getCookies, 0, 0, 0) ZEND_END_ARG_INFO();; static PHP_METHOD(HttpCookie, getCookies) { php_http_cookie_object_t *obj; if (SUCCESS != zend_parse_parameters_none()) { return; } obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_COOKIE_OBJECT_INIT(obj); array_init_size(return_value, zend_hash_num_elements(&obj->list->cookies)); array_copy(&obj->list->cookies, Z_ARRVAL_P(return_value)); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_setCookies, 0, 0, 0) ZEND_ARG_INFO(0, cookies) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpCookie, setCookies) { HashTable *cookies = NULL; php_http_cookie_object_t *obj; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|H/", &cookies), invalid_arg, return); obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_COOKIE_OBJECT_INIT(obj); zend_hash_clean(&obj->list->cookies); if (cookies) { array_copy_strings(cookies, &obj->list->cookies); } RETURN_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_addCookies, 0, 0, 1) ZEND_ARG_INFO(0, cookies) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpCookie, addCookies) { HashTable *cookies = NULL; php_http_cookie_object_t *obj; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "H/", &cookies), invalid_arg, return); obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_COOKIE_OBJECT_INIT(obj); array_join(cookies, &obj->list->cookies, 1, ARRAY_JOIN_STRONLY|ARRAY_JOIN_STRINGIFY); RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_getExtras, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpCookie, getExtras) { php_http_cookie_object_t *obj; if (SUCCESS != zend_parse_parameters_none()) { return; } obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_COOKIE_OBJECT_INIT(obj); array_init_size(return_value, zend_hash_num_elements(&obj->list->extras)); array_copy(&obj->list->extras, Z_ARRVAL_P(return_value)); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_setExtras, 0, 0, 0) ZEND_ARG_INFO(0, extras) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpCookie, setExtras) { HashTable *extras = NULL; php_http_cookie_object_t *obj; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|H/", &extras), invalid_arg, return); obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_COOKIE_OBJECT_INIT(obj); zend_hash_clean(&obj->list->extras); if (extras) { array_copy_strings(extras, &obj->list->extras); } RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_addExtras, 0, 0, 1) ZEND_ARG_INFO(0, extras) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpCookie, addExtras) { HashTable *extras = NULL; php_http_cookie_object_t *obj; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "H/", &extras), invalid_arg, return); obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_COOKIE_OBJECT_INIT(obj); array_join(extras, &obj->list->extras, 1, ARRAY_JOIN_STRONLY|ARRAY_JOIN_STRINGIFY); RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_getCookie, 0, 0, 1) ZEND_ARG_INFO(0, name) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpCookie, getCookie) { char *name_str; size_t name_len; zval zvalue; php_http_cookie_object_t *obj; if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name_str, &name_len)) { return; } obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_COOKIE_OBJECT_INIT(obj); if (php_http_cookie_list_get_cookie(obj->list, name_str, name_len, &zvalue)) { RETURN_ZVAL(&zvalue, 1, 0); } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_setCookie, 0, 0, 1) ZEND_ARG_INFO(0, cookie_name) ZEND_ARG_INFO(0, cookie_value) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpCookie, setCookie) { char *name_str, *value_str = NULL; size_t name_len, value_len = 0; php_http_cookie_object_t *obj; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s|s!", &name_str, &name_len, &value_str, &value_len), invalid_arg, return); obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_COOKIE_OBJECT_INIT(obj); if (!value_str) { php_http_cookie_list_del_cookie(obj->list, name_str, name_len); } else { php_http_cookie_list_add_cookie(obj->list, name_str, name_len, value_str, value_len); } RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_addCookie, 0, 0, 2) ZEND_ARG_INFO(0, cookie_name) ZEND_ARG_INFO(0, cookie_value) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpCookie, addCookie) { char *name_str, *value_str; size_t name_len, value_len; php_http_cookie_object_t *obj; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "ss", &name_str, &name_len, &value_str, &value_len), invalid_arg, return); obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_COOKIE_OBJECT_INIT(obj); php_http_cookie_list_add_cookie(obj->list, name_str, name_len, value_str, value_len); RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_getExtra, 0, 0, 1) ZEND_ARG_INFO(0, name) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpCookie, getExtra) { char *name_str; size_t name_len; zval zvalue; php_http_cookie_object_t *obj; if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name_str, &name_len)) { return; } obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_COOKIE_OBJECT_INIT(obj); if (php_http_cookie_list_get_extra(obj->list, name_str, name_len, &zvalue)) { RETURN_ZVAL(&zvalue, 1, 0); } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_setExtra, 0, 0, 1) ZEND_ARG_INFO(0, extra_name) ZEND_ARG_INFO(0, extra_value) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpCookie, setExtra) { char *name_str, *value_str = NULL; size_t name_len, value_len = 0; php_http_cookie_object_t *obj; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s|s!", &name_str, &name_len, &value_str, &value_len), invalid_arg, return); obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_COOKIE_OBJECT_INIT(obj); if (!value_str) { php_http_cookie_list_del_extra(obj->list, name_str, name_len); } else { php_http_cookie_list_add_extra(obj->list, name_str, name_len, value_str, value_len); } RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_addExtra, 0, 0, 2) ZEND_ARG_INFO(0, extra_name) ZEND_ARG_INFO(0, extra_value) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpCookie, addExtra) { char *name_str, *value_str; size_t name_len, value_len; php_http_cookie_object_t *obj; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "ss", &name_str, &name_len, &value_str, &value_len), invalid_arg, return); obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_COOKIE_OBJECT_INIT(obj); php_http_cookie_list_add_extra(obj->list, name_str, name_len, value_str, value_len); RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_getDomain, 0, 0, 0) ZEND_END_ARG_INFO();; static PHP_METHOD(HttpCookie, getDomain) { php_http_cookie_object_t *obj; if (SUCCESS != zend_parse_parameters_none()) { return; } obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_COOKIE_OBJECT_INIT(obj); if (obj->list->domain) { RETURN_STRING(obj->list->domain); } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_setDomain, 0, 0, 0) ZEND_ARG_INFO(0, value) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpCookie, setDomain) { char *domain_str = NULL; size_t domain_len = 0; php_http_cookie_object_t *obj; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|s!", &domain_str, &domain_len), invalid_arg, return); obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_COOKIE_OBJECT_INIT(obj); PTR_SET(obj->list->domain, domain_str ? estrndup(domain_str, domain_len) : NULL); RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_getPath, 0, 0, 0) ZEND_END_ARG_INFO();; static PHP_METHOD(HttpCookie, getPath) { php_http_cookie_object_t *obj; if (SUCCESS != zend_parse_parameters_none()) { return; } obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_COOKIE_OBJECT_INIT(obj); if (obj->list->path) { RETURN_STRING(obj->list->path); } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_setPath, 0, 0, 0) ZEND_ARG_INFO(0, value) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpCookie, setPath) { char *path_str = NULL; size_t path_len = 0; php_http_cookie_object_t *obj; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|s!", &path_str, &path_len), invalid_arg, return); obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_COOKIE_OBJECT_INIT(obj); PTR_SET(obj->list->path, path_str ? estrndup(path_str, path_len) : NULL); RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_getExpires, 0, 0, 0) ZEND_END_ARG_INFO();; static PHP_METHOD(HttpCookie, getExpires) { php_http_cookie_object_t *obj; if (SUCCESS != zend_parse_parameters_none()) { return; } obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_COOKIE_OBJECT_INIT(obj); RETURN_LONG(obj->list->expires); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_setExpires, 0, 0, 0) ZEND_ARG_INFO(0, value) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpCookie, setExpires) { zend_long ts = -1; php_http_cookie_object_t *obj; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &ts), invalid_arg, return); obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_COOKIE_OBJECT_INIT(obj); obj->list->expires = ts; RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_getMaxAge, 0, 0, 0) ZEND_END_ARG_INFO();; static PHP_METHOD(HttpCookie, getMaxAge) { php_http_cookie_object_t *obj; if (SUCCESS != zend_parse_parameters_none()) { return; } obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_COOKIE_OBJECT_INIT(obj); RETURN_LONG(obj->list->max_age); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_setMaxAge, 0, 0, 0) ZEND_ARG_INFO(0, value) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpCookie, setMaxAge) { zend_long ma = -1; php_http_cookie_object_t *obj; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &ma), invalid_arg, return); obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_COOKIE_OBJECT_INIT(obj); obj->list->max_age = ma; RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_getFlags, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpCookie, getFlags) { php_http_cookie_object_t *obj; if (SUCCESS != zend_parse_parameters_none()) { return; } obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_COOKIE_OBJECT_INIT(obj); RETURN_LONG(obj->list->flags); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_setFlags, 0, 0, 0) ZEND_ARG_INFO(0, value) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpCookie, setFlags) { zend_long flags = 0; php_http_cookie_object_t *obj; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &flags), invalid_arg, return); obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_COOKIE_OBJECT_INIT(obj); obj->list->flags = flags; RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_toString, 0, 0, 0) ZEND_END_ARG_INFO();; static PHP_METHOD(HttpCookie, toString) { php_http_cookie_object_t *obj; char *str; size_t len; if (SUCCESS != zend_parse_parameters_none()) { RETURN_EMPTY_STRING(); } obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_COOKIE_OBJECT_INIT(obj); php_http_cookie_list_to_string(obj->list, &str, &len); RETURN_NEW_STR(php_http_cs2zs(str, len)); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_toArray, 0, 0, 0) ZEND_END_ARG_INFO();; static PHP_METHOD(HttpCookie, toArray) { php_http_cookie_object_t *obj; if (SUCCESS != zend_parse_parameters_none()) { return; } obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_COOKIE_OBJECT_INIT(obj); array_init_size(return_value, 8); php_http_cookie_list_to_struct(obj->list, return_value); } static zend_function_entry php_http_cookie_methods[] = { PHP_ME(HttpCookie, __construct, ai_HttpCookie___construct, ZEND_ACC_PUBLIC) PHP_ME(HttpCookie, getCookies, ai_HttpCookie_getCookies, ZEND_ACC_PUBLIC) PHP_ME(HttpCookie, setCookies, ai_HttpCookie_setCookies, ZEND_ACC_PUBLIC) PHP_ME(HttpCookie, addCookies, ai_HttpCookie_addCookies, ZEND_ACC_PUBLIC) PHP_ME(HttpCookie, getCookie, ai_HttpCookie_getCookie, ZEND_ACC_PUBLIC) PHP_ME(HttpCookie, setCookie, ai_HttpCookie_setCookie, ZEND_ACC_PUBLIC) PHP_ME(HttpCookie, addCookie, ai_HttpCookie_addCookie, ZEND_ACC_PUBLIC) PHP_ME(HttpCookie, getExtras, ai_HttpCookie_getExtras, ZEND_ACC_PUBLIC) PHP_ME(HttpCookie, setExtras, ai_HttpCookie_setExtras, ZEND_ACC_PUBLIC) PHP_ME(HttpCookie, addExtras, ai_HttpCookie_addExtras, ZEND_ACC_PUBLIC) PHP_ME(HttpCookie, getExtra, ai_HttpCookie_getExtra, ZEND_ACC_PUBLIC) PHP_ME(HttpCookie, setExtra, ai_HttpCookie_setExtra, ZEND_ACC_PUBLIC) PHP_ME(HttpCookie, addExtra, ai_HttpCookie_addExtra, ZEND_ACC_PUBLIC) PHP_ME(HttpCookie, getDomain, ai_HttpCookie_getDomain, ZEND_ACC_PUBLIC) PHP_ME(HttpCookie, setDomain, ai_HttpCookie_setDomain, ZEND_ACC_PUBLIC) PHP_ME(HttpCookie, getPath, ai_HttpCookie_getPath, ZEND_ACC_PUBLIC) PHP_ME(HttpCookie, setPath, ai_HttpCookie_setPath, ZEND_ACC_PUBLIC) PHP_ME(HttpCookie, getExpires, ai_HttpCookie_getExpires, ZEND_ACC_PUBLIC) PHP_ME(HttpCookie, setExpires, ai_HttpCookie_setExpires, ZEND_ACC_PUBLIC) PHP_ME(HttpCookie, getMaxAge, ai_HttpCookie_getMaxAge, ZEND_ACC_PUBLIC) PHP_ME(HttpCookie, setMaxAge, ai_HttpCookie_setMaxAge, ZEND_ACC_PUBLIC) PHP_ME(HttpCookie, getFlags, ai_HttpCookie_getFlags, ZEND_ACC_PUBLIC) PHP_ME(HttpCookie, setFlags, ai_HttpCookie_setFlags, ZEND_ACC_PUBLIC) PHP_ME(HttpCookie, toArray, ai_HttpCookie_toArray, ZEND_ACC_PUBLIC) PHP_ME(HttpCookie, toString, ai_HttpCookie_toString, ZEND_ACC_PUBLIC) ZEND_MALIAS(HttpCookie, __toString, toString, ai_HttpCookie_toString, ZEND_ACC_PUBLIC) EMPTY_FUNCTION_ENTRY }; PHP_MINIT_FUNCTION(http_cookie) { zend_class_entry ce = {0}; INIT_NS_CLASS_ENTRY(ce, "http", "Cookie", php_http_cookie_methods); php_http_cookie_class_entry = zend_register_internal_class(&ce); 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.offset = XtOffsetOf(php_http_cookie_object_t, zo); php_http_cookie_object_handlers.clone_obj = php_http_cookie_object_clone; php_http_cookie_object_handlers.free_obj = php_http_cookie_object_free; zend_declare_class_constant_long(php_http_cookie_class_entry, ZEND_STRL("PARSE_RAW"), PHP_HTTP_COOKIE_PARSE_RAW); zend_declare_class_constant_long(php_http_cookie_class_entry, ZEND_STRL("SECURE"), PHP_HTTP_COOKIE_SECURE); zend_declare_class_constant_long(php_http_cookie_class_entry, ZEND_STRL("HTTPONLY"), PHP_HTTP_COOKIE_HTTPONLY); 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 */ pecl_http-4.2.1/src/php_http_cookie.h0000644000076500000240000000741614117626035016404 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #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; time_t max_age; } php_http_cookie_list_t; PHP_HTTP_API php_http_cookie_list_t *php_http_cookie_list_init(php_http_cookie_list_t *list); PHP_HTTP_API php_http_cookie_list_t *php_http_cookie_list_parse(php_http_cookie_list_t *list, const char *str, size_t len, long flags, char **allowed_extras); 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); PHP_HTTP_API void php_http_cookie_list_dtor(php_http_cookie_list_t *list); PHP_HTTP_API void php_http_cookie_list_free(php_http_cookie_list_t **list); #define php_http_cookie_list_has_cookie(list, name, name_len) zend_symtable_str_exists(&(list)->cookies, (name), (name_len)) #define php_http_cookie_list_del_cookie(list, name, name_len) zend_symtable_str_del(&(list)->cookies, (name), (name_len)) 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); PHP_HTTP_API const char *php_http_cookie_list_get_cookie(php_http_cookie_list_t *list, const char *name, size_t name_len, zval *cookie); #define php_http_cookie_list_has_extra(list, name, name_len) zend_symtable_str_exists(&(list)->extras, (name), (name_len)) #define php_http_cookie_list_del_extra(list, name, name_len) zend_symtable_str_del(&(list)->extras, (name), (name_len)) 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); PHP_HTTP_API const char *php_http_cookie_list_get_extra(php_http_cookie_list_t *list, const char *name, size_t name_len, zval *extra); PHP_HTTP_API void php_http_cookie_list_to_string(php_http_cookie_list_t *list, char **str, size_t *len); PHP_HTTP_API php_http_cookie_list_t *php_http_cookie_list_from_struct(php_http_cookie_list_t *list, zval *strct); PHP_HTTP_API void php_http_cookie_list_to_struct(php_http_cookie_list_t *list, zval *strct); PHP_HTTP_API zend_class_entry *php_http_cookie_get_class_entry(void); typedef struct php_http_cookie_object { php_http_cookie_list_t *list; zend_object zo; } php_http_cookie_object_t; zend_object *php_http_cookie_object_new(zend_class_entry *ce); php_http_cookie_object_t *php_http_cookie_object_new_ex(zend_class_entry *ce, php_http_cookie_list_t *list); zend_object *php_http_cookie_object_clone(zend_object *this_ptr); void php_http_cookie_object_free(zend_object *object); 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 */ pecl_http-4.2.1/src/php_http_curl.c0000644000076500000240000000701014117626035016061 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #include "php_http_api.h" #if PHP_HTTP_HAVE_LIBCURL #if ZTS && PHP_HTTP_HAVE_LIBCURL_SSL # include "TSRM.h" # if PHP_WIN32 # define PHP_HTTP_NEED_OPENSSL_TSL 1 # include # else /* !PHP_WIN32 */ # if PHP_HTTP_HAVE_LIBCURL_OPENSSL # define PHP_HTTP_NEED_OPENSSL_TSL 1 # include # elif PHP_HTTP_HAVE_LIBCURL_GNUTLS # define PHP_HTTP_NEED_GNUTLS_TSL 1 # include # endif /* PHP_HTTP_HAVE_LIBCURL_OPENSSL || PHP_HTTP_HAVE_LIBCURL_GNUTLS */ # endif /* PHP_WIN32 */ #endif /* ZTS && PHP_HTTP_HAVE_LIBCURL_SSL */ #if PHP_HTTP_NEED_OPENSSL_TSL static MUTEX_T *php_http_openssl_tsl = NULL; static void php_http_openssl_thread_lock(int mode, int n, const char * file, int line) { if (mode & CRYPTO_LOCK) { tsrm_mutex_lock(php_http_openssl_tsl[n]); } else { tsrm_mutex_unlock(php_http_openssl_tsl[n]); } } static unsigned long php_http_openssl_thread_id(void) { return (unsigned long) tsrm_thread_id(); } #endif #if PHP_HTTP_NEED_GNUTLS_TSL static int php_http_gnutls_mutex_create(void **m) { if (*((MUTEX_T *) m) = tsrm_mutex_alloc()) { return SUCCESS; } else { return FAILURE; } } static int php_http_gnutls_mutex_destroy(void **m) { tsrm_mutex_free(*((MUTEX_T *) m)); return SUCCESS; } static int php_http_gnutls_mutex_lock(void **m) { return tsrm_mutex_lock(*((MUTEX_T *) m)); } static int php_http_gnutls_mutex_unlock(void **m) { return tsrm_mutex_unlock(*((MUTEX_T *) m)); } static struct gcry_thread_cbs php_http_gnutls_tsl = { GCRY_THREAD_OPTION_USER, NULL, php_http_gnutls_mutex_create, php_http_gnutls_mutex_destroy, php_http_gnutls_mutex_lock, php_http_gnutls_mutex_unlock }; #endif PHP_MINIT_FUNCTION(http_curl) { #if PHP_HTTP_NEED_OPENSSL_TSL /* mod_ssl, libpq or ext/curl might already have set thread lock callbacks */ if (!CRYPTO_get_id_callback()) { int i, c = CRYPTO_num_locks(); php_http_openssl_tsl = malloc(c * sizeof(MUTEX_T)); for (i = 0; i < c; ++i) { php_http_openssl_tsl[i] = tsrm_mutex_alloc(); } CRYPTO_set_id_callback(php_http_openssl_thread_id); CRYPTO_set_locking_callback(php_http_openssl_thread_lock); } #endif #if PHP_HTTP_NEED_GNUTLS_TSL gcry_control(GCRYCTL_SET_THREAD_CBS, &php_http_gnutls_tsl); #endif if (CURLE_OK != curl_global_init(CURL_GLOBAL_ALL)) { return FAILURE; } return SUCCESS; } PHP_MSHUTDOWN_FUNCTION(http_curl) { curl_global_cleanup(); #if PHP_HTTP_NEED_OPENSSL_TSL if (php_http_openssl_tsl) { int i, c = CRYPTO_num_locks(); CRYPTO_set_id_callback(NULL); CRYPTO_set_locking_callback(NULL); for (i = 0; i < c; ++i) { tsrm_mutex_free(php_http_openssl_tsl[i]); } free(php_http_openssl_tsl); php_http_openssl_tsl = NULL; } #endif return SUCCESS; } #endif /* PHP_HTTP_HAVE_LIBCURL */ /* * 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 */ pecl_http-4.2.1/src/php_http_curl.h0000644000076500000240000000245214117626035016073 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_HTTP_CURL_H #define PHP_HTTP_CURL_H #if PHP_HTTP_HAVE_LIBCURL #include #define PHP_HTTP_CURL_VERSION(x, y, z) (LIBCURL_VERSION_NUM >= (((x)<<16) + ((y)<<8) + (z))) #define PHP_HTTP_CURL_FEATURE(f) (curl_version_info(CURLVERSION_NOW)->features & (f)) #if !PHP_HTTP_CURL_VERSION(7,21,5) # define CURLE_UNKNOWN_OPTION CURLE_FAILED_INIT #endif PHP_MINIT_FUNCTION(http_curl); PHP_MSHUTDOWN_FUNCTION(http_curl); #endif /* PHP_HTTP_HAVE_LIBCURL */ #endif /* PHP_HTTP_CURL_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 */ pecl_http-4.2.1/src/php_http_encoding.c0000644000076500000240000005033014117626035016705 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #include "php_http_api.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; } } const char *php_http_encoding_dechunk(const char *encoded, size_t encoded_len, char **decoded, size_t *decoded_len) { int eol_len = 0; char *n_ptr = NULL; const char *e_ptr = encoded; *decoded_len = 0; *decoded = ecalloc(1, encoded_len + 1); while ((encoded + encoded_len - e_ptr) > 0) { unsigned long 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_error_docref(NULL, E_NOTICE, "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_error_docref(NULL, E_WARNING, "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 */ while(1) { switch (*e_ptr) { case '0': case '\r': case '\n': ++e_ptr; continue; } break; } 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_error_docref(NULL, E_WARNING, "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_error_docref(NULL, E_WARNING, "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_error_docref(NULL, E_WARNING, "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; } php_http_encoding_stream_t *php_http_encoding_stream_init(php_http_encoding_stream_t *s, php_http_encoding_stream_ops_t *ops, unsigned flags) { int freeme; if ((freeme = !s)) { s = pemalloc(sizeof(*s), (flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT)); } memset(s, 0, sizeof(*s)); s->flags = flags; if (EXPECTED(s->ops = ops)) { php_http_encoding_stream_t *ss = s->ops->init(s); if (EXPECTED(ss)) { return ss; } } else { return s; } if (freeme) { pefree(s, (flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT)); } return NULL; } php_http_encoding_stream_t *php_http_encoding_stream_copy(php_http_encoding_stream_t *from, php_http_encoding_stream_t *to) { if (from->ops->copy) { php_http_encoding_stream_t *ns; if (!to) { to = pemalloc(sizeof(*to), (from->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT)); } memset(to, 0, sizeof(*to)); to->flags = from->flags; to->ops = from->ops; if ((ns = to->ops->copy(from, to))) { return ns; } else { return to; } } return NULL; } ZEND_RESULT_CODE php_http_encoding_stream_reset(php_http_encoding_stream_t **s) { php_http_encoding_stream_t *ss; if (EXPECTED((*s)->ops->dtor)) { (*s)->ops->dtor(*s); } if (EXPECTED(ss = (*s)->ops->init(*s))) { ss->flags &= ~PHP_HTTP_ENCODING_STREAM_DIRTY; *s = ss; return SUCCESS; } return FAILURE; } ZEND_RESULT_CODE php_http_encoding_stream_update(php_http_encoding_stream_t *s, const char *in_str, size_t in_len, char **out_str, size_t *out_len) { ZEND_RESULT_CODE rc = FAILURE; if (EXPECTED(s->ops->update)) { rc = s->ops->update(s, in_str, in_len, out_str, out_len); } s->flags |= PHP_HTTP_ENCODING_STREAM_DIRTY; return rc; } ZEND_RESULT_CODE php_http_encoding_stream_flush(php_http_encoding_stream_t *s, char **out_str, size_t *out_len) { if (!s->ops->flush) { *out_str = NULL; *out_len = 0; return SUCCESS; } return s->ops->flush(s, out_str, out_len); } zend_bool php_http_encoding_stream_done(php_http_encoding_stream_t *s) { if (!s->ops->done) { return !(s->flags & PHP_HTTP_ENCODING_STREAM_DIRTY); } return s->ops->done(s); } ZEND_RESULT_CODE php_http_encoding_stream_finish(php_http_encoding_stream_t *s, char **out_str, size_t *out_len) { if (!s->ops->finish) { *out_str = NULL; *out_len = 0; s->flags &= ~PHP_HTTP_ENCODING_STREAM_DIRTY; return SUCCESS; } return s->ops->finish(s, out_str, out_len); } void php_http_encoding_stream_dtor(php_http_encoding_stream_t *s) { if (EXPECTED(s->ops->dtor)) { s->ops->dtor(s); } } void php_http_encoding_stream_free(php_http_encoding_stream_t **s) { if (EXPECTED(*s)) { if (EXPECTED((*s)->ops->dtor)) { (*s)->ops->dtor(*s); } pefree(*s, ((*s)->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT)); *s = NULL; } } struct dechunk_ctx { php_http_buffer_t buffer; unsigned long hexlen; unsigned zeroed:1; }; 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)); 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 *dechunk_copy(php_http_encoding_stream_t *from, php_http_encoding_stream_t *to) { int p = from->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT; struct dechunk_ctx *from_ctx = from->ctx, *to_ctx = pemalloc(sizeof(*to_ctx), p); if (php_http_buffer_init_ex(&to_ctx->buffer, PHP_HTTP_BUFFER_DEFAULT_SIZE, p ? PHP_HTTP_BUFFER_INIT_PERSISTENT : 0)) { to_ctx->hexlen = from_ctx->hexlen; to_ctx->zeroed = from_ctx->zeroed; php_http_buffer_append(&to_ctx->buffer, from_ctx->buffer.data, from_ctx->buffer.used); to->ctx = to_ctx; return to; } pefree(to_ctx, p); php_error_docref(NULL, E_WARNING, "Failed to copy inflate encoding stream: out of memory"); return NULL; } static ZEND_RESULT_CODE dechunk_update(php_http_encoding_stream_t *s, const char *data, size_t data_len, char **decoded, size_t *decoded_len) { php_http_buffer_t tmp; struct dechunk_ctx *ctx = s->ctx; if (ctx->zeroed) { php_error_docref(NULL, E_WARNING, "Dechunk encoding stream has already reached the end of chunked input"); return FAILURE; } if ((PHP_HTTP_BUFFER_NOMEM == php_http_buffer_append(&ctx->buffer, data, data_len)) || !php_http_buffer_fix(&ctx->buffer)) { /* OOM */ return FAILURE; } *decoded = NULL; *decoded_len = 0; php_http_buffer_init(&tmp); /* we have data in our buffer */ while (ctx->buffer.used) { /* we already know the size of the chunk and are waiting for data */ if (ctx->hexlen) { /* not enough data buffered */ if (ctx->buffer.used < 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, ctx->buffer.data, ctx->buffer.used); /* waiting for less data now */ ctx->hexlen -= ctx->buffer.used; /* 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, ctx->buffer.data, ctx->hexlen); /* remove outgoing data from the buffer */ php_http_buffer_cut(&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 < ctx->buffer.used && ( ctx->buffer.data[off] == '\n' || ctx->buffer.data[off] == '\r')) { ++off; } if (off) { php_http_buffer_cut(&ctx->buffer, 0, off); } /* still data there? */ if (ctx->buffer.used) { 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(ctx->buffer.data, ctx->buffer.used, &eollen))) { char *stop = NULL; /* read in chunk size */ ctx->hexlen = strtoul(ctx->buffer.data, &stop, 16); /* if strtoul() stops at the beginning of the buffered data there's something oddly wrong, i.e. bad input */ if (stop == ctx->buffer.data) { php_error_docref(NULL, E_WARNING, "Failed to parse chunk len from '%.*s'", (int) MIN(16, ctx->buffer.used), ctx->buffer.data); php_http_buffer_dtor(&tmp); return FAILURE; } /* cut out */ php_http_buffer_cut(&ctx->buffer, 0, eolstr + eollen - ctx->buffer.data); /* 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 < ctx->buffer.used && ( ctx->buffer.data[off] == '\n' || ctx->buffer.data[off] == '\r')) { ++off; } if (off) { php_http_buffer_cut(&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 = tmp.data; *decoded_len = tmp.used; return SUCCESS; } static ZEND_RESULT_CODE 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 -= ctx->buffer.used; /* no more buffered data */ php_http_buffer_reset(&ctx->buffer); } else { *decoded = NULL; *decoded_len = 0; } return SUCCESS; } static zend_bool dechunk_done(php_http_encoding_stream_t *s) { return ((struct dechunk_ctx *) s->ctx)->zeroed; } 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_dechunk_ops = { dechunk_init, dechunk_copy, dechunk_update, dechunk_flush, dechunk_done, NULL, dechunk_dtor }; php_http_encoding_stream_ops_t *php_http_encoding_stream_get_dechunk_ops(void) { return &php_http_encoding_dechunk_ops; } static zend_object_handlers php_http_encoding_stream_object_handlers; zend_object *php_http_encoding_stream_object_new(zend_class_entry *ce) { return &php_http_encoding_stream_object_new_ex(ce, NULL)->zo; } php_http_encoding_stream_object_t *php_http_encoding_stream_object_new_ex(zend_class_entry *ce, php_http_encoding_stream_t *s) { php_http_encoding_stream_object_t *o; o = ecalloc(1, sizeof(*o) + zend_object_properties_size(ce)); zend_object_std_init(&o->zo, ce); object_properties_init(&o->zo, ce); if (s) { o->stream = s; } o->zo.handlers = &php_http_encoding_stream_object_handlers; return o; } zend_object *php_http_encoding_stream_object_clone(zend_object *object) { php_http_encoding_stream_object_t *new_obj, *old_obj = PHP_HTTP_OBJ(object, NULL); php_http_encoding_stream_t *cpy = php_http_encoding_stream_copy(old_obj->stream, NULL); if (!cpy) { return NULL; } new_obj = php_http_encoding_stream_object_new_ex(old_obj->zo.ce, cpy); zend_objects_clone_members(&new_obj->zo, &old_obj->zo); return &new_obj->zo; } void php_http_encoding_stream_object_free(zend_object *object) { php_http_encoding_stream_object_t *o = PHP_HTTP_OBJ(object, NULL); if (o->stream) { php_http_encoding_stream_free(&o->stream); } zend_object_std_dtor(object); } static zend_class_entry *php_http_encoding_stream_class_entry; zend_class_entry *php_http_get_encoding_stream_class_entry(void) { return php_http_encoding_stream_class_entry; } static zend_class_entry *php_http_dechunk_stream_class_entry; zend_class_entry *php_http_get_dechunk_stream_class_entry(void) { return php_http_dechunk_stream_class_entry; } ZEND_BEGIN_ARG_INFO_EX(ai_HttpEncodingStream___construct, 0, 0, 0) ZEND_ARG_INFO(0, flags) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpEncodingStream, __construct) { zend_long flags = 0; php_http_encoding_stream_object_t *obj; php_http_encoding_stream_ops_t *ops; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &flags), invalid_arg, return); obj = PHP_HTTP_OBJ(NULL, getThis()); if (UNEXPECTED(obj->stream)) { php_http_throw(bad_method_call, "http\\Encoding\\Stream cannot be initialized twice"); return; } if (instanceof_function(obj->zo.ce, php_http_get_deflate_stream_class_entry())) { ops = php_http_encoding_stream_get_deflate_ops(); } else if (instanceof_function(obj->zo.ce, php_http_get_inflate_stream_class_entry())) { ops = php_http_encoding_stream_get_inflate_ops(); } else if (instanceof_function(obj->zo.ce, php_http_dechunk_stream_class_entry)) { ops = &php_http_encoding_dechunk_ops; #if PHP_HTTP_HAVE_LIBBROTLI } else if (instanceof_function(obj->zo.ce, php_http_get_enbrotli_stream_class_entry())) { ops = php_http_encoding_stream_get_enbrotli_ops(); } else if (instanceof_function(obj->zo.ce, php_http_get_debrotli_stream_class_entry())) { ops = php_http_encoding_stream_get_debrotli_ops(); #endif } else { php_http_throw(runtime, "Unknown http\\Encoding\\Stream class '%s'", obj->zo.ce->name->val); return; } php_http_expect(obj->stream = php_http_encoding_stream_init(obj->stream, ops, flags), runtime, return); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpEncodingStream_update, 0, 0, 1) ZEND_ARG_INFO(0, data) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpEncodingStream, update) { size_t data_len; char *data_str; if (EXPECTED(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &data_str, &data_len))) { php_http_encoding_stream_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); if (EXPECTED(obj->stream)) { char *encoded_str = NULL; size_t encoded_len; if (EXPECTED(SUCCESS == php_http_encoding_stream_update(obj->stream, data_str, data_len, &encoded_str, &encoded_len))) { if (EXPECTED(encoded_str)) { RETURN_STR(php_http_cs2zs(encoded_str, encoded_len)); } else { RETURN_EMPTY_STRING(); } } } } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpEncodingStream_flush, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpEncodingStream, flush) { if (EXPECTED(SUCCESS == zend_parse_parameters_none())) { php_http_encoding_stream_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); if (EXPECTED(obj->stream)) { char *encoded_str = NULL; size_t encoded_len; if (EXPECTED(SUCCESS == php_http_encoding_stream_flush(obj->stream, &encoded_str, &encoded_len))) { if (encoded_str) { RETURN_STR(php_http_cs2zs(encoded_str, encoded_len)); } else { RETURN_EMPTY_STRING(); } } } } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpEncodingStream_done, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpEncodingStream, done) { if (EXPECTED(SUCCESS == zend_parse_parameters_none())) { php_http_encoding_stream_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); if (EXPECTED(obj->stream)) { RETURN_BOOL(php_http_encoding_stream_done(obj->stream)); } } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpEncodingStream_finish, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpEncodingStream, finish) { if (EXPECTED(SUCCESS == zend_parse_parameters_none())) { php_http_encoding_stream_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); if (EXPECTED(obj->stream)) { char *encoded_str = NULL; size_t encoded_len; if (EXPECTED(SUCCESS == php_http_encoding_stream_finish(obj->stream, &encoded_str, &encoded_len))) { if (EXPECTED(SUCCESS == php_http_encoding_stream_reset(&obj->stream))) { if (encoded_str) { RETURN_STR(php_http_cs2zs(encoded_str, encoded_len)); } else { RETURN_EMPTY_STRING(); } } else { PTR_FREE(encoded_str); } } } } } static zend_function_entry php_http_encoding_stream_methods[] = { PHP_ME(HttpEncodingStream, __construct, ai_HttpEncodingStream___construct, ZEND_ACC_PUBLIC) PHP_ME(HttpEncodingStream, update, ai_HttpEncodingStream_update, ZEND_ACC_PUBLIC) PHP_ME(HttpEncodingStream, flush, ai_HttpEncodingStream_flush, ZEND_ACC_PUBLIC) PHP_ME(HttpEncodingStream, done, ai_HttpEncodingStream_done, ZEND_ACC_PUBLIC) PHP_ME(HttpEncodingStream, finish, ai_HttpEncodingStream_finish, ZEND_ACC_PUBLIC) EMPTY_FUNCTION_ENTRY }; ZEND_BEGIN_ARG_INFO_EX(ai_HttpDechunkStream_decode, 0, 0, 1) ZEND_ARG_INFO(0, data) ZEND_ARG_INFO(1, decoded_len) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpDechunkStream, decode) { char *str; size_t len; zval *zlen = NULL; if (EXPECTED(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s|z!", &str, &len, &zlen))) { const char *end_ptr; char *enc_str = NULL; size_t enc_len; if (EXPECTED(end_ptr = php_http_encoding_dechunk(str, len, &enc_str, &enc_len))) { if (zlen) { ZVAL_DEREF(zlen); zval_dtor(zlen); ZVAL_LONG(zlen, str + len - end_ptr); } if (enc_str) { RETURN_STR(php_http_cs2zs(enc_str, enc_len)); } else { RETURN_EMPTY_STRING(); } } } RETURN_FALSE; } static zend_function_entry php_http_dechunk_stream_methods[] = { PHP_ME(HttpDechunkStream, decode, ai_HttpDechunkStream_decode, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) EMPTY_FUNCTION_ENTRY }; PHP_MINIT_FUNCTION(http_encoding) { zend_class_entry ce = {0}; INIT_NS_CLASS_ENTRY(ce, "http\\Encoding", "Stream", php_http_encoding_stream_methods); php_http_encoding_stream_class_entry = zend_register_internal_class(&ce); php_http_encoding_stream_class_entry->ce_flags |= 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.offset = XtOffsetOf(php_http_encoding_stream_object_t, zo); php_http_encoding_stream_object_handlers.clone_obj = php_http_encoding_stream_object_clone; php_http_encoding_stream_object_handlers.free_obj = php_http_encoding_stream_object_free; zend_declare_class_constant_long(php_http_encoding_stream_class_entry, ZEND_STRL("FLUSH_NONE"), PHP_HTTP_ENCODING_STREAM_FLUSH_NONE); zend_declare_class_constant_long(php_http_encoding_stream_class_entry, ZEND_STRL("FLUSH_SYNC"), PHP_HTTP_ENCODING_STREAM_FLUSH_SYNC); zend_declare_class_constant_long(php_http_encoding_stream_class_entry, ZEND_STRL("FLUSH_FULL"), PHP_HTTP_ENCODING_STREAM_FLUSH_FULL); memset(&ce, 0, sizeof(ce)); INIT_NS_CLASS_ENTRY(ce, "http\\Encoding\\Stream", "Dechunk", php_http_dechunk_stream_methods); php_http_dechunk_stream_class_entry = zend_register_internal_class_ex(&ce, php_http_encoding_stream_class_entry); php_http_dechunk_stream_class_entry->create_object = php_http_encoding_stream_object_new; return SUCCESS; } /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ pecl_http-4.2.1/src/php_http_encoding.h0000644000076500000240000001120214117626035016705 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_HTTP_ENCODING_H #define PHP_HTTP_ENCODING_H extern PHP_MINIT_FUNCTION(http_encoding); #define PHP_HTTP_ENCODING_STREAM_PERSISTENT 0x01000000 #define PHP_HTTP_ENCODING_STREAM_DIRTY 0x02000000 #define PHP_HTTP_ENCODING_STREAM_FLUSH_NONE 0x00000000 #define PHP_HTTP_ENCODING_STREAM_FLUSH_SYNC 0x00100000 #define PHP_HTTP_ENCODING_STREAM_FLUSH_FULL 0x00200000 #define PHP_HTTP_ENCODING_STREAM_FLUSH_FLAG(flags, full, sync, none) \ (((flags) & PHP_HTTP_ENCODING_STREAM_FLUSH_FULL) ? (full) : \ (((flags) & PHP_HTTP_ENCODING_STREAM_FLUSH_SYNC) ? (sync) : (none))) typedef struct php_http_encoding_stream php_http_encoding_stream_t; 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 ZEND_RESULT_CODE (*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 ZEND_RESULT_CODE (*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 ZEND_RESULT_CODE (*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; }; PHP_HTTP_API php_http_encoding_stream_t *php_http_encoding_stream_init(php_http_encoding_stream_t *s, php_http_encoding_stream_ops_t *ops, unsigned flags); PHP_HTTP_API php_http_encoding_stream_t *php_http_encoding_stream_copy(php_http_encoding_stream_t *from, php_http_encoding_stream_t *to); PHP_HTTP_API ZEND_RESULT_CODE php_http_encoding_stream_reset(php_http_encoding_stream_t **s); PHP_HTTP_API ZEND_RESULT_CODE php_http_encoding_stream_update(php_http_encoding_stream_t *s, const char *in_str, size_t in_len, char **out_str, size_t *out_len); PHP_HTTP_API ZEND_RESULT_CODE 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 ZEND_RESULT_CODE 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 php_http_encoding_stream_ops_t *php_http_encoding_stream_get_dechunk_ops(void); PHP_HTTP_API const char *php_http_encoding_dechunk(const char *encoded, size_t encoded_len, char **decoded, size_t *decoded_len); PHP_HTTP_API zend_class_entry *php_http_get_dechunk_stream_class_entry(void); typedef struct php_http_encoding_stream_object { php_http_encoding_stream_t *stream; zend_object zo; } php_http_encoding_stream_object_t; PHP_HTTP_API zend_class_entry *php_http_get_encoding_stream_class_entry(void); zend_object *php_http_encoding_stream_object_new(zend_class_entry *ce); php_http_encoding_stream_object_t *php_http_encoding_stream_object_new_ex(zend_class_entry *ce, php_http_encoding_stream_t *s); zend_object *php_http_encoding_stream_object_clone(zend_object *object); void php_http_encoding_stream_object_free(zend_object *object); #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 */ pecl_http-4.2.1/src/php_http_encoding_zlib.c0000644000076500000240000004760514117626035017740 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #include "php_http_api.h" #define PHP_HTTP_INFLATE_ROUNDS 100 #define PHP_HTTP_INFLATE_BUFFER_SIZE 0x1000 #define PHP_HTTP_DEFLATE_BUFFER_SIZE 0x8000 #define PHP_HTTP_DEFLATE_BUFFER_SIZE_GUESS(S) \ (((size_t) ((double) S * (double) 1.015)) + 10 + 8 + 4 + 1) #define PHP_HTTP_INFLATE_BUFFER_SIZE_GUESS(S) \ (((S) + 1) << 3) #define PHP_HTTP_INFLATE_BUFFER_SIZE_ALIGN(S) \ ((S) += (S) >> (3)) #define PHP_HTTP_INFLATE_FLUSH_FLAG(flags) \ PHP_HTTP_ENCODING_STREAM_FLUSH_FLAG((flags), Z_FULL_FLUSH, Z_SYNC_FLUSH, Z_NO_FLUSH) #define PHP_HTTP_DEFLATE_FLUSH_FLAG(flags) \ PHP_HTTP_ENCODING_STREAM_FLUSH_FLAG((flags), Z_FULL_FLUSH, Z_SYNC_FLUSH, Z_NO_FLUSH) #define PHP_HTTP_WINDOW_BITS_ZLIB 0x0000000f #define PHP_HTTP_WINDOW_BITS_GZIP 0x0000001f #define PHP_HTTP_WINDOW_BITS_ANY 0x0000002f #define PHP_HTTP_WINDOW_BITS_RAW -0x000000f #define PHP_HTTP_DEFLATE_LEVEL_SET(flags, level) \ switch (flags & 0xf) \ { \ default: \ if ((flags & 0xf) < 10) { \ level = flags & 0xf; \ break; \ } \ case PHP_HTTP_DEFLATE_LEVEL_DEF: \ level = Z_DEFAULT_COMPRESSION; \ break; \ } #define PHP_HTTP_DEFLATE_WBITS_SET(flags, wbits) \ switch (flags & 0xf0) \ { \ case PHP_HTTP_DEFLATE_TYPE_GZIP: \ wbits = PHP_HTTP_WINDOW_BITS_GZIP; \ break; \ case PHP_HTTP_DEFLATE_TYPE_RAW: \ wbits = PHP_HTTP_WINDOW_BITS_RAW; \ break; \ default: \ wbits = PHP_HTTP_WINDOW_BITS_ZLIB; \ break; \ } #define PHP_HTTP_INFLATE_WBITS_SET(flags, wbits) \ if (flags & PHP_HTTP_INFLATE_TYPE_RAW) { \ wbits = PHP_HTTP_WINDOW_BITS_RAW; \ } else { \ wbits = PHP_HTTP_WINDOW_BITS_ANY; \ } #define PHP_HTTP_DEFLATE_STRATEGY_SET(flags, strategy) \ switch (flags & 0xf00) \ { \ case PHP_HTTP_DEFLATE_STRATEGY_FILT: \ strategy = Z_FILTERED; \ break; \ case PHP_HTTP_DEFLATE_STRATEGY_HUFF: \ strategy = Z_HUFFMAN_ONLY; \ break; \ case PHP_HTTP_DEFLATE_STRATEGY_RLE: \ strategy = Z_RLE; \ break; \ case PHP_HTTP_DEFLATE_STRATEGY_FIXED: \ strategy = Z_FIXED; \ break; \ default: \ strategy = Z_DEFAULT_STRATEGY; \ break; \ } ZEND_RESULT_CODE php_http_encoding_deflate(int flags, const char *data, size_t data_len, char **encoded, size_t *encoded_len) { int status, level, wbits, strategy; z_stream Z; PHP_HTTP_DEFLATE_LEVEL_SET(flags, level); PHP_HTTP_DEFLATE_WBITS_SET(flags, wbits); PHP_HTTP_DEFLATE_STRATEGY_SET(flags, strategy); memset(&Z, 0, sizeof(z_stream)); *encoded = NULL; *encoded_len = 0; status = deflateInit2(&Z, level, Z_DEFLATED, wbits, MAX_MEM_LEVEL, strategy); if (EXPECTED(Z_OK == status)) { *encoded_len = PHP_HTTP_DEFLATE_BUFFER_SIZE_GUESS(data_len); *encoded = emalloc(*encoded_len); Z.next_in = (Bytef *) data; Z.next_out = (Bytef *) *encoded; Z.avail_in = data_len; Z.avail_out = *encoded_len; status = deflate(&Z, Z_FINISH); deflateEnd(&Z); if (EXPECTED(Z_STREAM_END == status)) { /* size buffer down to actual length */ *encoded = erealloc(*encoded, Z.total_out + 1); (*encoded)[*encoded_len = Z.total_out] = '\0'; return SUCCESS; } else { PTR_SET(*encoded, NULL); *encoded_len = 0; } } php_error_docref(NULL, E_WARNING, "Could not deflate data: %s", zError(status)); return FAILURE; } static php_http_encoding_stream_t *deflate_init(php_http_encoding_stream_t *s) { int status, level, wbits, strategy, p = (s->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT); z_streamp ctx = pecalloc(1, sizeof(z_stream), p); PHP_HTTP_DEFLATE_LEVEL_SET(s->flags, level); PHP_HTTP_DEFLATE_WBITS_SET(s->flags, wbits); PHP_HTTP_DEFLATE_STRATEGY_SET(s->flags, strategy); if (EXPECTED(Z_OK == (status = deflateInit2(ctx, level, Z_DEFLATED, wbits, MAX_MEM_LEVEL, strategy)))) { if (EXPECTED(ctx->opaque = php_http_buffer_init_ex(NULL, PHP_HTTP_DEFLATE_BUFFER_SIZE, p ? PHP_HTTP_BUFFER_INIT_PERSISTENT : 0))) { s->ctx = ctx; return s; } deflateEnd(ctx); status = Z_MEM_ERROR; } pefree(ctx, p); php_error_docref(NULL, E_WARNING, "Failed to initialize deflate encoding stream: %s", zError(status)); return NULL; } static php_http_encoding_stream_t *deflate_copy(php_http_encoding_stream_t *from, php_http_encoding_stream_t *to) { int status, p = to->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT; z_streamp from_ctx = from->ctx, to_ctx = pecalloc(1, sizeof(*to_ctx), p); if (Z_OK == (status = deflateCopy(to_ctx, from_ctx))) { if ((to_ctx->opaque = php_http_buffer_init_ex(NULL, PHP_HTTP_DEFLATE_BUFFER_SIZE, p ? PHP_HTTP_BUFFER_INIT_PERSISTENT : 0))) { php_http_buffer_append(to_ctx->opaque, PHP_HTTP_BUFFER(from_ctx->opaque)->data, PHP_HTTP_BUFFER(from_ctx->opaque)->used); to->ctx = to_ctx; return to; } deflateEnd(to_ctx); status = Z_MEM_ERROR; } php_error_docref(NULL, E_WARNING, "Failed to copy deflate encoding stream: %s", zError(status)); return NULL; } static ZEND_RESULT_CODE deflate_update(php_http_encoding_stream_t *s, const char *data, size_t data_len, char **encoded, size_t *encoded_len) { int status; z_streamp ctx = s->ctx; /* append input to our buffer */ php_http_buffer_append(PHP_HTTP_BUFFER(ctx->opaque), data, data_len); ctx->next_in = (Bytef *) PHP_HTTP_BUFFER(ctx->opaque)->data; ctx->avail_in = PHP_HTTP_BUFFER(ctx->opaque)->used; /* deflate */ *encoded_len = PHP_HTTP_DEFLATE_BUFFER_SIZE_GUESS(data_len); *encoded = emalloc(*encoded_len); ctx->avail_out = *encoded_len; ctx->next_out = (Bytef *) *encoded; switch (status = deflate(ctx, PHP_HTTP_DEFLATE_FLUSH_FLAG(s->flags))) { case Z_OK: case Z_STREAM_END: /* cut processed chunk off the buffer */ if (ctx->avail_in) { php_http_buffer_cut(PHP_HTTP_BUFFER(ctx->opaque), 0, PHP_HTTP_BUFFER(ctx->opaque)->used - ctx->avail_in); } else { php_http_buffer_reset(PHP_HTTP_BUFFER(ctx->opaque)); } /* size buffer down to actual size */ *encoded_len -= ctx->avail_out; *encoded = erealloc(*encoded, *encoded_len + 1); (*encoded)[*encoded_len] = '\0'; return SUCCESS; } PTR_SET(*encoded, NULL); *encoded_len = 0; php_error_docref(NULL, E_WARNING, "Failed to update deflate stream: %s", zError(status)); return FAILURE; } static ZEND_RESULT_CODE deflate_flush(php_http_encoding_stream_t *s, char **encoded, size_t *encoded_len) { int status; z_streamp ctx = s->ctx; *encoded_len = PHP_HTTP_DEFLATE_BUFFER_SIZE; *encoded = emalloc(*encoded_len); ctx->avail_in = 0; ctx->next_in = NULL; ctx->avail_out = *encoded_len; ctx->next_out = (Bytef *) *encoded; status = deflate(ctx, Z_FULL_FLUSH); if (EXPECTED(Z_OK == status || Z_STREAM_END == status)) { *encoded_len = PHP_HTTP_DEFLATE_BUFFER_SIZE - ctx->avail_out; *encoded = erealloc(*encoded, *encoded_len + 1); (*encoded)[*encoded_len] = '\0'; return SUCCESS; } PTR_SET(*encoded, NULL); *encoded_len = 0; php_error_docref(NULL, E_WARNING, "Failed to flush deflate stream: %s", zError(status)); return FAILURE; } static ZEND_RESULT_CODE deflate_finish(php_http_encoding_stream_t *s, char **encoded, size_t *encoded_len) { int status; z_streamp ctx = s->ctx; *encoded_len = PHP_HTTP_DEFLATE_BUFFER_SIZE; *encoded = emalloc(*encoded_len); /* deflate remaining input */ ctx->next_in = (Bytef *) PHP_HTTP_BUFFER(ctx->opaque)->data; ctx->avail_in = PHP_HTTP_BUFFER(ctx->opaque)->used; ctx->avail_out = *encoded_len; ctx->next_out = (Bytef *) *encoded; do { status = deflate(ctx, Z_FINISH); } while (Z_OK == status); if (EXPECTED(Z_STREAM_END == status)) { /* cut processed input off */ php_http_buffer_cut(PHP_HTTP_BUFFER(ctx->opaque), 0, PHP_HTTP_BUFFER(ctx->opaque)->used - ctx->avail_in); /* size down */ *encoded_len -= ctx->avail_out; *encoded = erealloc(*encoded, *encoded_len + 1); (*encoded)[*encoded_len] = '\0'; return SUCCESS; } PTR_SET(*encoded, NULL); *encoded_len = 0; php_error_docref(NULL, E_WARNING, "Failed to finish deflate stream: %s", zError(status)); return FAILURE; } static zend_bool deflate_done(php_http_encoding_stream_t *s) { z_streamp ctx = s->ctx; return !ctx->avail_in && !PHP_HTTP_BUFFER(ctx->opaque)->used; } static void deflate_dtor(php_http_encoding_stream_t *s) { if (EXPECTED(s->ctx)) { z_streamp ctx = s->ctx; if (EXPECTED(ctx->opaque)) { php_http_buffer_free((php_http_buffer_t **) &ctx->opaque); } deflateEnd(ctx); pefree(ctx, (s->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT)); s->ctx = NULL; } } static inline int php_http_inflate_rounds(z_stream *Z, int flush, char **buf, size_t *len) { int status = 0, round = 0; php_http_buffer_t buffer; *buf = NULL; *len = 0; php_http_buffer_init_ex(&buffer, Z->avail_in, PHP_HTTP_BUFFER_INIT_PREALLOC); do { if (UNEXPECTED(PHP_HTTP_BUFFER_NOMEM == php_http_buffer_resize_ex(&buffer, buffer.size, 0, 1))) { status = Z_MEM_ERROR; } else { Z->avail_out = buffer.free; Z->next_out = (Bytef *) buffer.data + buffer.used; #if 0 fprintf(stderr, "\n%3d: %3d PRIOR: size=%7lu,\tfree=%7lu,\tused=%7lu,\tavail_in=%7lu,\tavail_out=%7lu\n", round, status, buffer.size, buffer.free, buffer.used, Z->avail_in, Z->avail_out); #endif status = inflate(Z, flush); php_http_buffer_account(&buffer, buffer.free - Z->avail_out); #if 0 fprintf(stderr, "%3d: %3d AFTER: size=%7lu,\tfree=%7lu,\tused=%7lu,\tavail_in=%7lu,\tavail_out=%7lu\n", round, status, buffer.size, buffer.free, buffer.used, Z->avail_in, Z->avail_out); #endif PHP_HTTP_INFLATE_BUFFER_SIZE_ALIGN(buffer.size); } } while ((Z_BUF_ERROR == status || (Z_OK == status && Z->avail_in)) && ++round < PHP_HTTP_INFLATE_ROUNDS); if (EXPECTED(status == Z_OK || status == Z_STREAM_END)) { php_http_buffer_shrink(&buffer); php_http_buffer_fix(&buffer); *buf = buffer.data; *len = buffer.used; } else { php_http_buffer_dtor(&buffer); } return status; } ZEND_RESULT_CODE php_http_encoding_inflate(const char *data, size_t data_len, char **decoded, size_t *decoded_len) { z_stream Z; int status, wbits = PHP_HTTP_WINDOW_BITS_ANY; memset(&Z, 0, sizeof(z_stream)); retry_raw_inflate: status = inflateInit2(&Z, wbits); if (EXPECTED(Z_OK == status)) { Z.next_in = (Bytef *) data; Z.avail_in = data_len + 1; /* include the terminating NULL, see #61287 */ switch (status = php_http_inflate_rounds(&Z, Z_NO_FLUSH, decoded, decoded_len)) { case Z_STREAM_END: inflateEnd(&Z); return SUCCESS; case Z_OK: status = Z_DATA_ERROR; break; case Z_DATA_ERROR: /* raw deflated data? */ if (PHP_HTTP_WINDOW_BITS_ANY == wbits) { inflateEnd(&Z); wbits = PHP_HTTP_WINDOW_BITS_RAW; goto retry_raw_inflate; } break; } inflateEnd(&Z); if (*decoded_len && *decoded) { efree(*decoded); } } php_error_docref(NULL, E_WARNING, "Could not inflate data: %s", zError(status)); return FAILURE; } static php_http_encoding_stream_t *inflate_init(php_http_encoding_stream_t *s) { int status, wbits, p = (s->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT); z_streamp ctx = pecalloc(1, sizeof(z_stream), p); PHP_HTTP_INFLATE_WBITS_SET(s->flags, wbits); if (EXPECTED(Z_OK == (status = inflateInit2(ctx, wbits)))) { if ((ctx->opaque = php_http_buffer_init_ex(NULL, PHP_HTTP_DEFLATE_BUFFER_SIZE, p ? PHP_HTTP_BUFFER_INIT_PERSISTENT : 0))) { s->ctx = ctx; return s; } inflateEnd(ctx); status = Z_MEM_ERROR; } pefree(ctx, p); php_error_docref(NULL, E_WARNING, "Failed to initialize inflate stream: %s", zError(status)); return NULL; } static php_http_encoding_stream_t *inflate_copy(php_http_encoding_stream_t *from, php_http_encoding_stream_t *to) { int status, p = from->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT; z_streamp from_ctx = from->ctx, to_ctx = pecalloc(1, sizeof(*to_ctx), p); if (Z_OK == (status = inflateCopy(to_ctx, from_ctx))) { if ((to_ctx->opaque = php_http_buffer_init_ex(NULL, PHP_HTTP_DEFLATE_BUFFER_SIZE, p ? PHP_HTTP_BUFFER_INIT_PERSISTENT : 0))) { php_http_buffer_append(to_ctx->opaque, PHP_HTTP_BUFFER(from_ctx->opaque)->data, PHP_HTTP_BUFFER(from_ctx->opaque)->used); to->ctx = to_ctx; return to; } inflateEnd(to_ctx); status = Z_MEM_ERROR; } php_error_docref(NULL, E_WARNING, "Failed to copy inflate encoding stream: %s", zError(status)); return NULL; } static ZEND_RESULT_CODE inflate_update(php_http_encoding_stream_t *s, const char *data, size_t data_len, char **decoded, size_t *decoded_len) { int status; z_streamp ctx = s->ctx; /* append input to buffer */ php_http_buffer_append(PHP_HTTP_BUFFER(ctx->opaque), data, data_len); retry_raw_inflate: ctx->next_in = (Bytef *) PHP_HTTP_BUFFER(ctx->opaque)->data; ctx->avail_in = PHP_HTTP_BUFFER(ctx->opaque)->used; switch (status = php_http_inflate_rounds(ctx, PHP_HTTP_INFLATE_FLUSH_FLAG(s->flags), decoded, decoded_len)) { case Z_OK: case Z_STREAM_END: /* cut off */ if (ctx->avail_in) { php_http_buffer_cut(PHP_HTTP_BUFFER(ctx->opaque), 0, PHP_HTTP_BUFFER(ctx->opaque)->used - ctx->avail_in); } else { php_http_buffer_reset(PHP_HTTP_BUFFER(ctx->opaque)); } return SUCCESS; case Z_DATA_ERROR: /* raw deflated data ? */ if (!(s->flags & PHP_HTTP_INFLATE_TYPE_RAW) && !ctx->total_out) { inflateEnd(ctx); s->flags |= PHP_HTTP_INFLATE_TYPE_RAW; inflateInit2(ctx, PHP_HTTP_WINDOW_BITS_RAW); goto retry_raw_inflate; } break; } php_error_docref(NULL, E_WARNING, "Failed to update inflate stream: %s", zError(status)); return FAILURE; } static ZEND_RESULT_CODE inflate_finish(php_http_encoding_stream_t *s, char **decoded, size_t *decoded_len) { int status; z_streamp ctx = s->ctx; if (!PHP_HTTP_BUFFER(ctx->opaque)->used) { *decoded = NULL; *decoded_len = 0; return SUCCESS; } *decoded_len = (PHP_HTTP_BUFFER(ctx->opaque)->used + 1) * PHP_HTTP_INFLATE_ROUNDS; *decoded = emalloc(*decoded_len); /* inflate remaining input */ ctx->next_in = (Bytef *) PHP_HTTP_BUFFER(ctx->opaque)->data; ctx->avail_in = PHP_HTTP_BUFFER(ctx->opaque)->used; ctx->avail_out = *decoded_len; ctx->next_out = (Bytef *) *decoded; if (Z_STREAM_END == (status = inflate(ctx, Z_FINISH))) { /* cut processed input off */ php_http_buffer_cut(PHP_HTTP_BUFFER(ctx->opaque), 0, PHP_HTTP_BUFFER(ctx->opaque)->used - ctx->avail_in); /* size down */ *decoded_len -= ctx->avail_out; *decoded = erealloc(*decoded, *decoded_len + 1); (*decoded)[*decoded_len] = '\0'; return SUCCESS; } PTR_SET(*decoded, NULL); *decoded_len = 0; php_error_docref(NULL, E_WARNING, "Failed to finish inflate stream: %s", zError(status)); return FAILURE; } static zend_bool inflate_done(php_http_encoding_stream_t *s) { z_streamp ctx = s->ctx; return !ctx->avail_in && !PHP_HTTP_BUFFER(ctx->opaque)->used; } static void inflate_dtor(php_http_encoding_stream_t *s) { if (EXPECTED(s->ctx)) { z_streamp ctx = s->ctx; if (EXPECTED(ctx->opaque)) { php_http_buffer_free((php_http_buffer_t **) &ctx->opaque); } inflateEnd(ctx); pefree(ctx, (s->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT)); s->ctx = NULL; } } static php_http_encoding_stream_ops_t php_http_encoding_deflate_ops = { deflate_init, deflate_copy, deflate_update, deflate_flush, deflate_done, deflate_finish, deflate_dtor }; php_http_encoding_stream_ops_t *php_http_encoding_stream_get_deflate_ops(void) { return &php_http_encoding_deflate_ops; } static php_http_encoding_stream_ops_t php_http_encoding_inflate_ops = { inflate_init, inflate_copy, inflate_update, NULL, inflate_done, inflate_finish, inflate_dtor }; php_http_encoding_stream_ops_t *php_http_encoding_stream_get_inflate_ops(void) { return &php_http_encoding_inflate_ops; } static zend_class_entry *php_http_deflate_stream_class_entry; zend_class_entry *php_http_get_deflate_stream_class_entry(void) { return php_http_deflate_stream_class_entry; } static zend_class_entry *php_http_inflate_stream_class_entry; zend_class_entry *php_http_get_inflate_stream_class_entry(void) { return php_http_inflate_stream_class_entry; } ZEND_BEGIN_ARG_INFO_EX(ai_HttpDeflateStream_encode, 0, 0, 1) ZEND_ARG_INFO(0, data) ZEND_ARG_INFO(0, flags) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpDeflateStream, encode) { char *str; size_t len; zend_long flags = 0; if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &str, &len, &flags)) { char *enc_str = NULL; size_t enc_len; if (SUCCESS == php_http_encoding_deflate(flags, str, len, &enc_str, &enc_len)) { if (enc_str) { RETURN_STR(php_http_cs2zs(enc_str, enc_len)); } else { RETURN_EMPTY_STRING(); } } } RETURN_FALSE; } static zend_function_entry php_http_deflate_stream_methods[] = { PHP_ME(HttpDeflateStream, encode, ai_HttpDeflateStream_encode, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) EMPTY_FUNCTION_ENTRY }; ZEND_BEGIN_ARG_INFO_EX(ai_HttpInflateStream_decode, 0, 0, 1) ZEND_ARG_INFO(0, data) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpInflateStream, decode) { char *str; size_t len; if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &str, &len)) { char *enc_str = NULL; size_t enc_len; if (SUCCESS == php_http_encoding_inflate(str, len, &enc_str, &enc_len)) { if (enc_str) { RETURN_STR(php_http_cs2zs(enc_str, enc_len)); } else { RETURN_EMPTY_STRING(); } } } RETURN_FALSE; } static zend_function_entry php_http_inflate_stream_methods[] = { PHP_ME(HttpInflateStream, decode, ai_HttpInflateStream_decode, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) EMPTY_FUNCTION_ENTRY }; PHP_MINIT_FUNCTION(http_encoding_zlib) { zend_class_entry ce; memset(&ce, 0, sizeof(ce)); INIT_NS_CLASS_ENTRY(ce, "http\\Encoding\\Stream", "Deflate", php_http_deflate_stream_methods); php_http_deflate_stream_class_entry = zend_register_internal_class_ex(&ce, php_http_get_encoding_stream_class_entry()); php_http_deflate_stream_class_entry->create_object = php_http_encoding_stream_object_new; zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("TYPE_GZIP"), PHP_HTTP_DEFLATE_TYPE_GZIP); zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("TYPE_ZLIB"), PHP_HTTP_DEFLATE_TYPE_ZLIB); zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("TYPE_RAW"), PHP_HTTP_DEFLATE_TYPE_RAW); zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("LEVEL_DEF"), PHP_HTTP_DEFLATE_LEVEL_DEF); zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("LEVEL_MIN"), PHP_HTTP_DEFLATE_LEVEL_MIN); zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("LEVEL_MAX"), PHP_HTTP_DEFLATE_LEVEL_MAX); zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("STRATEGY_DEF"), PHP_HTTP_DEFLATE_STRATEGY_DEF); zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("STRATEGY_FILT"), PHP_HTTP_DEFLATE_STRATEGY_FILT); zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("STRATEGY_HUFF"), PHP_HTTP_DEFLATE_STRATEGY_HUFF); zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("STRATEGY_RLE"), PHP_HTTP_DEFLATE_STRATEGY_RLE); zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("STRATEGY_FIXED"), PHP_HTTP_DEFLATE_STRATEGY_FIXED); memset(&ce, 0, sizeof(ce)); INIT_NS_CLASS_ENTRY(ce, "http\\Encoding\\Stream", "Inflate", php_http_inflate_stream_methods); php_http_inflate_stream_class_entry = zend_register_internal_class_ex(&ce, php_http_get_encoding_stream_class_entry()); php_http_inflate_stream_class_entry->create_object = php_http_encoding_stream_object_new; return SUCCESS; } /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ pecl_http-4.2.1/src/php_http_encoding_zlib.h0000644000076500000240000000446114117626035017736 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_HTTP_ENCODING_ZLIB_H #define PHP_HTTP_ENCODING_ZLIB_H #include "php_http_encoding.h" #include #ifndef Z_FIXED /* Z_FIXED does not exist prior 1.2.2.2 */ # define Z_FIXED 0 #endif extern PHP_MINIT_FUNCTION(http_encoding_zlib); zend_class_entry *php_http_get_deflate_stream_class_entry(void); zend_class_entry *php_http_get_inflate_stream_class_entry(void); PHP_HTTP_API php_http_encoding_stream_ops_t *php_http_encoding_stream_get_deflate_ops(void); PHP_HTTP_API php_http_encoding_stream_ops_t *php_http_encoding_stream_get_inflate_ops(void); PHP_HTTP_API ZEND_RESULT_CODE php_http_encoding_deflate(int flags, const char *data, size_t data_len, char **encoded, size_t *encoded_len); PHP_HTTP_API ZEND_RESULT_CODE php_http_encoding_inflate(const char *data, size_t data_len, char **decoded, size_t *decoded_len); #define PHP_HTTP_DEFLATE_LEVEL_DEF 0x00000000 #define PHP_HTTP_DEFLATE_LEVEL_MIN 0x00000001 #define PHP_HTTP_DEFLATE_LEVEL_MAX 0x00000009 #define PHP_HTTP_DEFLATE_TYPE_ZLIB 0x00000000 #define PHP_HTTP_DEFLATE_TYPE_GZIP 0x00000010 #define PHP_HTTP_DEFLATE_TYPE_RAW 0x00000020 #define PHP_HTTP_DEFLATE_STRATEGY_DEF 0x00000000 #define PHP_HTTP_DEFLATE_STRATEGY_FILT 0x00000100 #define PHP_HTTP_DEFLATE_STRATEGY_HUFF 0x00000200 #define PHP_HTTP_DEFLATE_STRATEGY_RLE 0x00000300 #define PHP_HTTP_DEFLATE_STRATEGY_FIXED 0x00000400 #define PHP_HTTP_INFLATE_TYPE_ZLIB 0x00000000 #define PHP_HTTP_INFLATE_TYPE_GZIP 0x00000000 #define PHP_HTTP_INFLATE_TYPE_RAW 0x00000001 #endif /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ pecl_http-4.2.1/src/php_http_encoding_brotli.c0000644000076500000240000003106614117626035020265 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #include "php_http_api.h" #if PHP_HTTP_HAVE_LIBBROTLI #define PHP_HTTP_DEBROTLI_ROUNDS 100 #define PHP_HTTP_ENBROTLI_ROUNDS 100 #define PHP_HTTP_ENBROTLI_BUFFER_SIZE_GUESS(S) \ BrotliEncoderMaxCompressedSize(S) #define PHP_HTTP_DEBROTLI_BUFFER_SIZE_ALIGN(S) \ ((S) += (S) >> 3) #define PHP_HTTP_ENBROTLI_FLUSH_FLAG(flags) \ PHP_HTTP_ENCODING_STREAM_FLUSH_FLAG((flags), BROTLI_OPERATION_FLUSH, BROTLI_OPERATION_FLUSH, BROTLI_OPERATION_PROCESS) #define PHP_HTTP_ENBROTLI_BUFFER_SIZE 0x2000 #define PHP_HTTP_DEBROTLI_BUFFER_SIZE 0x1000 #define PHP_HTTP_ENBROTLI_LEVEL_SET(flags, level) \ level = (((flags) & 0xf) ?: PHP_HTTP_ENBROTLI_LEVEL_DEF) #define PHP_HTTP_ENBROTLI_WBITS_SET(flags, wbits) \ wbits = ((((flags) >> 4) & 0xff) ?: (PHP_HTTP_ENBROTLI_WBITS_DEF >> 4)) #define PHP_HTTP_ENBROTLI_MODE_SET(flags, mode) \ mode = (((flags) >> 12) & 0xf) static php_http_encoding_stream_t *enbrotli_init(php_http_encoding_stream_t *s) { BrotliEncoderState *br; int q, win, mode; PHP_HTTP_ENBROTLI_LEVEL_SET(s->flags, q); PHP_HTTP_ENBROTLI_WBITS_SET(s->flags, win); PHP_HTTP_ENBROTLI_MODE_SET(s->flags, mode); br = BrotliEncoderCreateInstance(NULL, NULL, NULL); if (EXPECTED(br)) { BrotliEncoderSetParameter(br, BROTLI_PARAM_QUALITY, q); BrotliEncoderSetParameter(br, BROTLI_PARAM_LGWIN, win); BrotliEncoderSetParameter(br, BROTLI_PARAM_MODE, mode); s->ctx = br; return s; } php_error_docref(NULL, E_WARNING, "Failed to initialize brotli encoding stream"); return NULL; } static ZEND_RESULT_CODE enbrotli_update(php_http_encoding_stream_t *s, const char *data, size_t data_len, char **encoded, size_t *encoded_len) { php_http_buffer_t out; const unsigned char *in_ptr; size_t in_len; BROTLI_BOOL rc; php_http_buffer_init_ex(&out, PHP_HTTP_ENBROTLI_BUFFER_SIZE_GUESS(data_len), 0); in_len = data_len; in_ptr = (const unsigned char *) data; while (in_len) { size_t out_len = 0; rc = BrotliEncoderCompressStream(s->ctx, PHP_HTTP_ENBROTLI_FLUSH_FLAG(s->flags), &in_len, &in_ptr, &out_len, NULL, NULL); if (!rc) { break; } if (BrotliEncoderHasMoreOutput(s->ctx)) { const char *out_str = (const char *) BrotliEncoderTakeOutput(s->ctx, &out_len); php_http_buffer_append(&out, out_str, out_len); } } if (rc) { if (out.used) { php_http_buffer_shrink(&out); php_http_buffer_fix(&out); *encoded = out.data; *encoded_len = out.used; } else { *encoded = NULL; *encoded_len = 0; php_http_buffer_dtor(&out); } return SUCCESS; } php_http_buffer_dtor(&out); *encoded = NULL; *encoded_len = 0; php_error_docref(NULL, E_WARNING, "Failed to update brotli encoding stream"); return FAILURE; } static inline ZEND_RESULT_CODE enbrotli_flush_ex(php_http_encoding_stream_t *s, BrotliEncoderOperation op, char **encoded, size_t *encoded_len) { php_http_buffer_t out; BROTLI_BOOL rc; int round = 0; php_http_buffer_init_ex(&out, PHP_HTTP_ENBROTLI_BUFFER_SIZE, 0); do { const unsigned char *empty = NULL; size_t unused = 0, out_len = 0; rc = BrotliEncoderCompressStream(s->ctx, op, &unused, &empty, &out_len, NULL, NULL); if (!rc) { break; } if (BrotliEncoderHasMoreOutput(s->ctx)) { const char *out_str = (const char *) BrotliEncoderTakeOutput(s->ctx, &out_len); php_http_buffer_append(&out, out_str, out_len); } else { if (out.used) { php_http_buffer_shrink(&out); php_http_buffer_fix(&out); *encoded = out.data; *encoded_len = out.used; } else { *encoded = NULL; *encoded_len = 0; } return SUCCESS; } } while (++round < PHP_HTTP_ENBROTLI_ROUNDS); php_http_buffer_dtor(&out); *encoded = NULL; *encoded_len = 0; php_error_docref(NULL, E_WARNING, "Failed to flush brotli encoding stream"); return FAILURE; } static ZEND_RESULT_CODE enbrotli_flush(php_http_encoding_stream_t *s, char **encoded, size_t *encoded_len) { return enbrotli_flush_ex(s, BROTLI_OPERATION_FLUSH, encoded, encoded_len); } static ZEND_RESULT_CODE enbrotli_finish(php_http_encoding_stream_t *s, char **encoded, size_t *encoded_len) { ZEND_RESULT_CODE rc; do { rc = enbrotli_flush_ex(s, BROTLI_OPERATION_FINISH, encoded, encoded_len); } while (SUCCESS == rc && !BrotliEncoderIsFinished(s->ctx)); return rc; } static zend_bool enbrotli_done(php_http_encoding_stream_t *s) { return !(s->flags & PHP_HTTP_ENCODING_STREAM_DIRTY) || BrotliEncoderIsFinished(s->ctx); } static void enbrotli_dtor(php_http_encoding_stream_t *s) { if (s->ctx) { BrotliEncoderDestroyInstance(s->ctx); s->ctx = NULL; } } static php_http_encoding_stream_t *debrotli_init(php_http_encoding_stream_t *s) { BrotliDecoderState *br; br = BrotliDecoderCreateInstance(NULL, NULL, NULL); if (br) { s->ctx = br; return s; } php_error_docref(NULL, E_WARNING, "Failed to initialize brotli decoding stream"); return NULL; } static ZEND_RESULT_CODE debrotli_update(php_http_encoding_stream_t *s, const char *encoded, size_t encoded_len, char **decoded, size_t *decoded_len) { php_http_buffer_t out; BrotliDecoderResult rc; const unsigned char *in_ptr; size_t in_len; in_ptr = (const unsigned char *) encoded; in_len = encoded_len; php_http_buffer_init_ex(&out, encoded_len, PHP_HTTP_BUFFER_INIT_PREALLOC); while (in_len) { size_t out_len = 0; rc = BrotliDecoderDecompressStream(s->ctx, &in_len, &in_ptr, &out_len, NULL, NULL); if (BROTLI_DECODER_RESULT_ERROR == rc) { break; } if (BrotliDecoderHasMoreOutput(s->ctx)) { const char *out_str = (const char *) BrotliDecoderTakeOutput(s->ctx, &out_len); php_http_buffer_append(&out, out_str, out_len); } } if (BROTLI_DECODER_RESULT_ERROR != rc) { if (out.used) { php_http_buffer_shrink(&out); php_http_buffer_fix(&out); *decoded = out.data; *decoded_len = out.used; } else { php_http_buffer_dtor(&out); *decoded = NULL; *decoded_len = 0; } return SUCCESS; } php_http_buffer_dtor(&out); php_error_docref(NULL, E_WARNING, "Could not brotli decode data: %s", BrotliDecoderErrorString(BrotliDecoderGetErrorCode(s->ctx))); return FAILURE; } static zend_bool debrotli_done(php_http_encoding_stream_t *s) { return !BrotliDecoderIsUsed(s->ctx) || BrotliDecoderIsFinished(s->ctx); } static void debrotli_dtor(php_http_encoding_stream_t *s) { if (s->ctx) { BrotliDecoderDestroyInstance(s->ctx); s->ctx = NULL; } } static php_http_encoding_stream_ops_t php_http_encoding_enbrotli_ops = { enbrotli_init, NULL, enbrotli_update, enbrotli_flush, enbrotli_done, enbrotli_finish, enbrotli_dtor }; php_http_encoding_stream_ops_t *php_http_encoding_stream_get_enbrotli_ops(void) { return &php_http_encoding_enbrotli_ops; } static php_http_encoding_stream_ops_t php_http_encoding_debrotli_ops = { debrotli_init, NULL, debrotli_update, NULL, debrotli_done, NULL, debrotli_dtor }; php_http_encoding_stream_ops_t *php_http_encoding_stream_get_debrotli_ops(void) { return &php_http_encoding_debrotli_ops; } ZEND_RESULT_CODE php_http_encoding_enbrotli(int flags, const char *data, size_t data_len, char **encoded, size_t *encoded_len) { BROTLI_BOOL rc; int q, win, mode; *encoded_len = PHP_HTTP_ENBROTLI_BUFFER_SIZE_GUESS(data_len); *encoded = emalloc(*encoded_len + 1); PHP_HTTP_ENBROTLI_LEVEL_SET(flags, q); PHP_HTTP_ENBROTLI_WBITS_SET(flags, win); PHP_HTTP_ENBROTLI_MODE_SET(flags, mode); rc = BrotliEncoderCompress(q, win, mode, data_len, (const unsigned char *) data, encoded_len, (unsigned char *) *encoded); if (rc) { return SUCCESS; } PTR_SET(*encoded, NULL); *encoded_len = 0; php_error_docref(NULL, E_WARNING, "Could not brotli encode data"); return FAILURE; } ZEND_RESULT_CODE php_http_encoding_debrotli(const char *encoded, size_t encoded_len, char **decoded, size_t *decoded_len) { php_http_encoding_stream_t s = {0}; ZEND_RESULT_CODE rc = FAILURE; if (debrotli_init(&s)) { rc = debrotli_update(&s, encoded, encoded_len, decoded, decoded_len); debrotli_dtor(&s); } return rc; } static zend_class_entry *php_http_enbrotli_stream_class_entry; zend_class_entry *php_http_get_enbrotli_stream_class_entry(void) { return php_http_enbrotli_stream_class_entry; } static zend_class_entry *php_http_debrotli_stream_class_entry; zend_class_entry *php_http_get_debrotli_stream_class_entry(void) { return php_http_debrotli_stream_class_entry; } ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnbrotliStream_encode, 0, 0, 1) ZEND_ARG_INFO(0, data) ZEND_ARG_INFO(0, flags) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpEnbrotliStream, encode) { char *str; size_t len; zend_long flags = PHP_HTTP_ENBROTLI_MODE_GENERIC | PHP_HTTP_ENBROTLI_WBITS_DEF | PHP_HTTP_ENBROTLI_LEVEL_DEF; if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &str, &len, &flags)) { char *enc_str = NULL; size_t enc_len; if (SUCCESS == php_http_encoding_enbrotli(flags, str, len, &enc_str, &enc_len)) { if (enc_str) { RETURN_STR(php_http_cs2zs(enc_str, enc_len)); } else { RETURN_EMPTY_STRING(); } } } RETURN_FALSE; } static zend_function_entry php_http_enbrotli_stream_methods[] = { PHP_ME(HttpEnbrotliStream, encode, ai_HttpEnbrotliStream_encode, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) EMPTY_FUNCTION_ENTRY }; ZEND_BEGIN_ARG_INFO_EX(ai_HttpDebrotliStream_decode, 0, 0, 1) ZEND_ARG_INFO(0, data) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpDebrotliStream, decode) { char *str; size_t len; if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &str, &len)) { char *enc_str = NULL; size_t enc_len; if (SUCCESS == php_http_encoding_debrotli(str, len, &enc_str, &enc_len)) { if (enc_str) { RETURN_STR(php_http_cs2zs(enc_str, enc_len)); } else { RETURN_EMPTY_STRING(); } } } RETURN_FALSE; } static zend_function_entry php_http_debrotli_stream_methods[] = { PHP_ME(HttpDebrotliStream, decode, ai_HttpDebrotliStream_decode, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) EMPTY_FUNCTION_ENTRY }; /* POS */ const void *BrotliGetDictionary(); const void *(*php_http_brotli_get_dictionary)(); PHP_MINIT_FUNCTION(http_encoding_brotli) { zend_class_entry ce; /* force link to libbrotlicommon, because their libraries don't */ php_http_brotli_get_dictionary = BrotliGetDictionary(); memset(&ce, 0, sizeof(ce)); INIT_NS_CLASS_ENTRY(ce, "http\\Encoding\\Stream", "Enbrotli", php_http_enbrotli_stream_methods); php_http_enbrotli_stream_class_entry = zend_register_internal_class_ex(&ce, php_http_get_encoding_stream_class_entry()); php_http_enbrotli_stream_class_entry->create_object = php_http_encoding_stream_object_new; zend_declare_class_constant_long(php_http_enbrotli_stream_class_entry, ZEND_STRL("LEVEL_MIN"), PHP_HTTP_ENBROTLI_LEVEL_MIN); zend_declare_class_constant_long(php_http_enbrotli_stream_class_entry, ZEND_STRL("LEVEL_DEF"), PHP_HTTP_ENBROTLI_LEVEL_DEF); zend_declare_class_constant_long(php_http_enbrotli_stream_class_entry, ZEND_STRL("LEVEL_MAX"), PHP_HTTP_ENBROTLI_LEVEL_MAX); zend_declare_class_constant_long(php_http_enbrotli_stream_class_entry, ZEND_STRL("WBITS_MIN"), PHP_HTTP_ENBROTLI_WBITS_MIN); zend_declare_class_constant_long(php_http_enbrotli_stream_class_entry, ZEND_STRL("WBITS_DEF"), PHP_HTTP_ENBROTLI_WBITS_DEF); zend_declare_class_constant_long(php_http_enbrotli_stream_class_entry, ZEND_STRL("WBITS_MAX"), PHP_HTTP_ENBROTLI_WBITS_MAX); zend_declare_class_constant_long(php_http_enbrotli_stream_class_entry, ZEND_STRL("MODE_GENERIC"), PHP_HTTP_ENBROTLI_MODE_GENERIC); zend_declare_class_constant_long(php_http_enbrotli_stream_class_entry, ZEND_STRL("MODE_TEXT"), PHP_HTTP_ENBROTLI_MODE_TEXT); zend_declare_class_constant_long(php_http_enbrotli_stream_class_entry, ZEND_STRL("MODE_FONT"), PHP_HTTP_ENBROTLI_MODE_FONT); memset(&ce, 0, sizeof(ce)); INIT_NS_CLASS_ENTRY(ce, "http\\Encoding\\Stream", "Debrotli", php_http_debrotli_stream_methods); php_http_debrotli_stream_class_entry = zend_register_internal_class_ex(&ce, php_http_get_encoding_stream_class_entry()); php_http_debrotli_stream_class_entry->create_object = php_http_encoding_stream_object_new; return SUCCESS; } #endif /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ pecl_http-4.2.1/src/php_http_encoding_brotli.h0000644000076500000240000000407614117626035020273 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_HTTP_ENCODING_BROTLI_H #define PHP_HTTP_ENCODING_BROTLI_H #if PHP_HTTP_HAVE_LIBBROTLI #include #include extern PHP_MINIT_FUNCTION(http_encoding_brotli); PHP_HTTP_API zend_class_entry *php_http_get_enbrotli_stream_class_entry(void); PHP_HTTP_API zend_class_entry *php_http_get_debrotli_stream_class_entry(void); PHP_HTTP_API php_http_encoding_stream_ops_t *php_http_encoding_stream_get_enbrotli_ops(void); PHP_HTTP_API php_http_encoding_stream_ops_t *php_http_encoding_stream_get_debrotli_ops(void); PHP_HTTP_API ZEND_RESULT_CODE php_http_encoding_enbrotli(int flags, const char *data, size_t data_len, char **encoded, size_t *encoded_len); PHP_HTTP_API ZEND_RESULT_CODE php_http_encoding_debrotli(const char *encoded, size_t encoded_len, char **decoded, size_t *decoded_len); #define PHP_HTTP_ENBROTLI_LEVEL_MIN 0x00000001 #define PHP_HTTP_ENBROTLI_LEVEL_DEF 0x00000004 #define PHP_HTTP_ENBROTLI_LEVEL_MAX 0x0000000b #define PHP_HTTP_ENBROTLI_WBITS_MIN 0x000000a0 #define PHP_HTTP_ENBROTLI_WBITS_DEF 0x00000160 #define PHP_HTTP_ENBROTLI_WBITS_MAX 0x00000180 #define PHP_HTTP_ENBROTLI_MODE_GENERIC 0x00000000 #define PHP_HTTP_ENBROTLI_MODE_TEXT 0x00001000 #define PHP_HTTP_ENBROTLI_MODE_FONT 0x00002000 #endif #endif /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ pecl_http-4.2.1/src/php_http_env.c0000644000076500000240000005470014117626035015714 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #include "php_http_api.h" #include "php_variables.h" PHP_RSHUTDOWN_FUNCTION(http_env) { php_http_env_reset(); return SUCCESS; } void php_http_env_reset() { 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.server_var) { zval_ptr_dtor(PHP_HTTP_G->env.server_var); PHP_HTTP_G->env.server_var = NULL; } } void php_http_env_get_request_headers(HashTable *headers) { php_http_arrkey_t key; zval *hsv, *header; if (!PHP_HTTP_G->env.request.headers) { ALLOC_HASHTABLE(PHP_HTTP_G->env.request.headers); ZEND_INIT_SYMTABLE(PHP_HTTP_G->env.request.headers); if ((hsv = php_http_env_get_superglobal(ZEND_STRL("_SERVER")))) { ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(hsv), key.h, key.key, header) { if (key.key && key.key->len > 5 && *key.key->val == 'H' && !strncmp(key.key->val, "HTTP_", 5)) { size_t key_len = key.key->len - 5; char *key_str = php_http_pretty_key(estrndup(&key.key->val[5], key_len), key_len, 1, 1); Z_TRY_ADDREF_P(header); zend_symtable_str_update(PHP_HTTP_G->env.request.headers, key_str, key_len, header); efree(key_str); } else if (key.key && key.key->len > 8 && *key.key->val == 'C' && !strncmp(key.key->val, "CONTENT_", 8)) { char *key_str = php_http_pretty_key(estrndup(key.key->val, key.key->len), key.key->len, 1, 1); Z_TRY_ADDREF_P(header); zend_symtable_str_update(PHP_HTTP_G->env.request.headers, key_str, key.key->len, header); efree(key_str); } } ZEND_HASH_FOREACH_END(); } } if (headers) { array_copy(PHP_HTTP_G->env.request.headers, headers); } } char *php_http_env_get_request_header(const char *name_str, size_t name_len, size_t *len, php_http_message_t *request) { HashTable *request_headers; zval *zvalue = NULL; char *val = NULL, *key = php_http_pretty_key(estrndup(name_str, name_len), name_len, 1, 1); if (request) { request_headers = &request->hdrs; } else { php_http_env_get_request_headers(NULL); request_headers = PHP_HTTP_G->env.request.headers; } if ((zvalue = zend_symtable_str_find(request_headers, key, name_len))) { zend_string *zs = zval_get_string(zvalue); val = estrndup(zs->val, zs->len); if (len) { *len = zs->len; } zend_string_release(zs); } efree(key); return val; } zend_bool php_http_env_got_request_header(const char *name_str, size_t name_len, php_http_message_t *request) { HashTable *request_headers; char *key = php_http_pretty_key(estrndup(name_str, name_len), name_len, 1, 1); zend_bool got; if (request) { request_headers = &request->hdrs; } else { php_http_env_get_request_headers(NULL); request_headers = PHP_HTTP_G->env.request.headers; } got = zend_symtable_str_exists(request_headers, key, name_len); efree(key); return got; } zval *php_http_env_get_superglobal(const char *key, size_t key_len) { zval *hsv; zend_string *key_str = zend_string_init(key, key_len, 0); zend_is_auto_global(key_str); hsv = zend_hash_find(&EG(symbol_table), key_str); zend_string_release(key_str); if (Z_TYPE_P(hsv) != IS_ARRAY) { return NULL; } return hsv; } zval *php_http_env_get_server_var(const char *key, size_t key_len, zend_bool check) { zval *hsv, *var; /* if available, this is a lot faster than accessing $_SERVER * / if (sapi_module.getenv) { char *env; if ((!(env = sapi_module.getenv((char *) key, key_len))) || (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; } / * */ if (!(hsv = php_http_env_get_superglobal(ZEND_STRL("_SERVER")))) { return NULL; } if (!(var = zend_symtable_str_find(Z_ARRVAL_P(hsv), key, key_len))) { return NULL; } if (check && !((Z_TYPE_P(var) == IS_STRING) && Z_STRVAL_P(var) && Z_STRLEN_P(var))) { return NULL; } return var; } php_http_message_body_t *php_http_env_get_request_body(void) { if (!PHP_HTTP_G->env.request.body) { php_stream *s = php_stream_temp_new(); php_stream *input = php_stream_open_wrapper("php://input", "r", 0, NULL); /* php://input does not support stat */ php_stream_copy_to_stream_ex(input, s, -1, NULL); php_stream_close(input); php_stream_rewind(s); PHP_HTTP_G->env.request.body = php_http_message_body_init(NULL, s); } return PHP_HTTP_G->env.request.body; } const char *php_http_env_get_request_method(php_http_message_t *request) { const char *m; if (PHP_HTTP_MESSAGE_TYPE(REQUEST, request)) { m = request->http.info.request.method; } else { m = SG(request_info).request_method; } return m ? m : "GET"; } php_http_range_status_t php_http_env_get_request_ranges(HashTable *ranges, size_t length, php_http_message_t *request) { zval zentry; char *range, *rp, c; long begin = -1, end = -1, *ptr; if (!(range = php_http_env_get_request_header(ZEND_STRL("Range"), NULL, request))) { return PHP_HTTP_RANGE_NO; } if (strncmp(range, "bytes=", lenof("bytes="))) { PTR_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: PTR_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) { PTR_FREE(range); return PHP_HTTP_RANGE_ERR; } begin = length - end; end = length - 1; break; /* "12345-(NNN)" */ default: if (length <= (size_t) begin) { PTR_FREE(range); return PHP_HTTP_RANGE_ERR; } switch (end) { /* "12345-0" */ case -10: PTR_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) { PTR_FREE(range); return PHP_HTTP_RANGE_ERR; } break; } break; } } array_init(&zentry); add_index_long(&zentry, 0, begin); add_index_long(&zentry, 1, end); zend_hash_next_index_insert(ranges, &zentry); begin = -1; end = -1; ptr = &begin; break; default: PTR_FREE(range); return PHP_HTTP_RANGE_NO; } } while (c != 0); PTR_FREE(range); return PHP_HTTP_RANGE_OK; } static void grab_headers(void *data, void *arg) { php_http_buffer_appendl(PHP_HTTP_BUFFER(arg), ((sapi_header_struct *)data)->header); php_http_buffer_appends(PHP_HTTP_BUFFER(arg), PHP_HTTP_CRLF); } static void grab_header(void *data, void *arg) { struct { char *name_str; size_t name_len; char *value_ptr; } *args = arg; sapi_header_struct *header = data; if ( header->header_len > args->name_len && header->header[args->name_len] == ':' && !strncmp(header->header, args->name_str, args->name_len) ) { args->value_ptr = &header->header[args->name_len + 1]; while (PHP_HTTP_IS_CTYPE(space, *args->value_ptr)) { ++args->value_ptr; } } } ZEND_RESULT_CODE php_http_env_get_response_headers(HashTable *headers_ht) { ZEND_RESULT_CODE status; php_http_buffer_t headers; php_http_buffer_init(&headers); zend_llist_apply_with_argument(&SG(sapi_headers).headers, grab_headers, &headers); php_http_buffer_fix(&headers); status = php_http_header_parse(headers.data, headers.used, headers_ht, NULL, NULL); php_http_buffer_dtor(&headers); return status; } char *php_http_env_get_response_header(const char *name_str, size_t name_len) { struct { char *name_str; size_t name_len; char *value_ptr; } args; args.name_str = php_http_pretty_key(estrndup(name_str, name_len), name_len, 1, 1); args.name_len = name_len; args.value_ptr = NULL; zend_llist_apply_with_argument(&SG(sapi_headers).headers, grab_header, &args); efree(args.name_str); return args.value_ptr ? estrdup(args.value_ptr) : NULL; } long php_http_env_get_response_code(void) { long code = SG(sapi_headers).http_response_code; return code ? code : 200; } ZEND_RESULT_CODE php_http_env_set_response_code(long http_code) { return sapi_header_op(SAPI_HEADER_SET_STATUS, (void *) (zend_intptr_t) http_code); } ZEND_RESULT_CODE php_http_env_set_response_status_line(long code, php_http_version_t *v) { sapi_header_line h = {NULL, 0, 0}; ZEND_RESULT_CODE ret; char *line; h.line_len = spprintf(&line, 0, "HTTP/%u.%u %ld %s", v->major, v->minor, code, php_http_env_get_response_status_for_code(code)); h.line = line; ret = sapi_header_op(SAPI_HEADER_REPLACE, (void *) &h); efree(line); return ret; } ZEND_RESULT_CODE php_http_env_set_response_protocol_version(php_http_version_t *v) { return php_http_env_set_response_status_line(php_http_env_get_response_code(), v); } ZEND_RESULT_CODE php_http_env_set_response_header(long http_code, const char *header_str, size_t header_len, zend_bool replace) { sapi_header_line h = {header_str, header_len, http_code}; ZEND_RESULT_CODE ret = sapi_header_op(replace ? SAPI_HEADER_REPLACE : SAPI_HEADER_ADD, (void *) &h); return ret; } ZEND_RESULT_CODE php_http_env_set_response_header_va(long http_code, zend_bool replace, const char *fmt, va_list argv) { ZEND_RESULT_CODE ret = FAILURE; sapi_header_line h = {NULL, 0, http_code}; char *line; h.line_len = vspprintf(&line, 0, fmt, argv); h.line = line; if (h.line) { if (h.line_len) { ret = sapi_header_op(replace ? SAPI_HEADER_REPLACE : SAPI_HEADER_ADD, (void *) &h); } efree(line); } return ret; } ZEND_RESULT_CODE php_http_env_set_response_header_format(long http_code, zend_bool replace, const char *fmt, ...) { ZEND_RESULT_CODE ret; va_list args; va_start(args, fmt); ret = php_http_env_set_response_header_va(http_code, replace, fmt, args); va_end(args); return ret; } ZEND_RESULT_CODE php_http_env_set_response_header_value(long http_code, const char *name_str, size_t name_len, zval *value, zend_bool replace) { if (!value) { sapi_header_line h = {(char *) name_str, name_len, http_code}; return sapi_header_op(SAPI_HEADER_DELETE, (void *) &h); } if (Z_TYPE_P(value) == IS_ARRAY || Z_TYPE_P(value) == IS_OBJECT) { int first = replace; zval *data_ptr; HashTable *ht = HASH_OF(value); ZEND_HASH_FOREACH_VAL_IND(ht, data_ptr) { if (SUCCESS != php_http_env_set_response_header_value(http_code, name_str, name_len, data_ptr, first)) { return FAILURE; } first = 0; } ZEND_HASH_FOREACH_END(); return SUCCESS; } else { zend_string *data = zval_get_string(value); if (!data->len) { zend_string_release(data); return php_http_env_set_response_header_value(http_code, name_str, name_len, NULL, replace); } else { sapi_header_line h; ZEND_RESULT_CODE ret; char *line; if (name_len > INT_MAX) { return FAILURE; } h.response_code = http_code; h.line_len = spprintf(&line, 0, "%s: %s", name_str, data->val); h.line = line; ret = sapi_header_op(replace ? SAPI_HEADER_REPLACE : SAPI_HEADER_ADD, (void *) &h); zend_string_release(data); PTR_FREE(line); return ret; } } } const char *php_http_env_get_response_status_for_code(unsigned code) { switch (code) { #define PHP_HTTP_RESPONSE_CODE(c, s) case c: return s; #include "php_http_response_codes.h" #undef PHP_HTTP_RESPONSE_CODE default: return NULL; } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_getRequestHeader, 0, 0, 0) ZEND_ARG_INFO(0, header_name) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpEnv, getRequestHeader) { char *header_name_str = NULL; size_t header_name_len = 0; if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "|s!", &header_name_str, &header_name_len)) { return; } if (header_name_str && header_name_len) { size_t header_length; char *header_value = php_http_env_get_request_header(header_name_str, header_name_len, &header_length, NULL); if (header_value) { RETURN_STR(php_http_cs2zs(header_value, header_length)); } } else { array_init(return_value); php_http_env_get_request_headers(Z_ARRVAL_P(return_value)); } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_getRequestBody, 0, 0, 0) ZEND_ARG_INFO(0, body_class_name) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpEnv, getRequestBody) { php_http_message_body_t *body; php_http_message_body_object_t *body_obj; zend_class_entry *class_entry = php_http_get_message_body_class_entry(); php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|C", &class_entry), invalid_arg, return); body = php_http_env_get_request_body(); if (SUCCESS == php_http_new((void *) &body_obj, class_entry, (php_http_new_t) php_http_message_body_object_new_ex, php_http_get_message_body_class_entry(), body)) { php_http_message_body_addref(body); RETVAL_OBJ(&body_obj->zo); } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_getResponseStatusForCode, 0, 0, 1) ZEND_ARG_INFO(0, code) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpEnv, getResponseStatusForCode) { zend_long code; const char *status; if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "l", &code)) { return; } if ((status = php_http_env_get_response_status_for_code(code))) { RETURN_STRING(status); } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_getResponseStatusForAllCodes, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpEnv, getResponseStatusForAllCodes) { if (SUCCESS != zend_parse_parameters_none()) { return; } array_init(return_value); #define PHP_HTTP_RESPONSE_CODE(code, status) add_index_string(return_value, code, status); #include "php_http_response_codes.h" #undef PHP_HTTP_RESPONSE_CODE } ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_getResponseHeader, 0, 0, 0) ZEND_ARG_INFO(0, header_name) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpEnv, getResponseHeader) { char *header_name_str = NULL; size_t header_name_len = 0; if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "|s!", &header_name_str, &header_name_len)) { return; } if (header_name_str && header_name_len) { char *header_value = php_http_env_get_response_header(header_name_str, header_name_len); if (header_value) { RETURN_STR(php_http_cs2zs(header_value, strlen(header_value))); } } else { array_init(return_value); php_http_env_get_response_headers(Z_ARRVAL_P(return_value)); } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_getResponseCode, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpEnv, getResponseCode) { if (SUCCESS != zend_parse_parameters_none()) { return; } RETURN_LONG(php_http_env_get_response_code()); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_setResponseHeader, 0, 0, 1) ZEND_ARG_INFO(0, header_name) ZEND_ARG_INFO(0, header_value) ZEND_ARG_INFO(0, response_code) ZEND_ARG_INFO(0, replace_header) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpEnv, setResponseHeader) { char *header_name_str; size_t header_name_len; zval *header_value = NULL; zend_long code = 0; zend_bool replace_header = 1; if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "s|z!lb", &header_name_str, &header_name_len, &header_value, &code, &replace_header)) { return; } RETURN_BOOL(SUCCESS == php_http_env_set_response_header_value(code, header_name_str, header_name_len, header_value, replace_header)); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_setResponseCode, 0, 0, 1) ZEND_ARG_INFO(0, code) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpEnv, setResponseCode) { zend_long code; if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "l", &code)) { return; } RETURN_BOOL(SUCCESS == php_http_env_set_response_code(code)); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_negotiateLanguage, 0, 0, 1) ZEND_ARG_INFO(0, supported) ZEND_ARG_INFO(1, result_array) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpEnv, negotiateLanguage) { HashTable *supported; zval *rs_array = NULL; if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "H|z", &supported, &rs_array)) { return; } if (rs_array) { ZVAL_DEREF(rs_array); zval_dtor(rs_array); array_init(rs_array); } PHP_HTTP_DO_NEGOTIATE(language, supported, rs_array); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_negotiateCharset, 0, 0, 1) ZEND_ARG_INFO(0, supported) ZEND_ARG_INFO(1, result_array) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpEnv, negotiateCharset) { HashTable *supported; zval *rs_array = NULL; if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "H|z", &supported, &rs_array)) { return; } if (rs_array) { ZVAL_DEREF(rs_array); zval_dtor(rs_array); array_init(rs_array); } PHP_HTTP_DO_NEGOTIATE(charset, supported, rs_array); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_negotiateEncoding, 0, 0, 1) ZEND_ARG_INFO(0, supported) ZEND_ARG_INFO(1, result_array) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpEnv, negotiateEncoding) { HashTable *supported; zval *rs_array = NULL; if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "H|z", &supported, &rs_array)) { return; } if (rs_array) { ZVAL_DEREF(rs_array); zval_dtor(rs_array); array_init(rs_array); } PHP_HTTP_DO_NEGOTIATE(encoding, supported, rs_array); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_negotiateContentType, 0, 0, 1) ZEND_ARG_INFO(0, supported) ZEND_ARG_INFO(1, result_array) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpEnv, negotiateContentType) { HashTable *supported; zval *rs_array = NULL; if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "H|z", &supported, &rs_array)) { return; } if (rs_array) { ZVAL_DEREF(rs_array); zval_dtor(rs_array); array_init(rs_array); } PHP_HTTP_DO_NEGOTIATE(content_type, supported, rs_array); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_negotiate, 0, 0, 2) ZEND_ARG_INFO(0, params) ZEND_ARG_INFO(0, supported) ZEND_ARG_INFO(0, primary_type_separator) ZEND_ARG_INFO(1, result_array) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpEnv, negotiate) { HashTable *supported, *rs; zval *rs_array = NULL; char *value_str, *sep_str = NULL; size_t value_len, sep_len = 0; if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "sH|s!z", &value_str, &value_len, &supported, &sep_str, &sep_len, &rs_array)) { return; } if (rs_array) { ZVAL_DEREF(rs_array); zval_dtor(rs_array); array_init(rs_array); } if ((rs = php_http_negotiate(value_str, value_len, supported, sep_str, sep_len))) { PHP_HTTP_DO_NEGOTIATE_HANDLE_RESULT(rs, supported, rs_array); } else { PHP_HTTP_DO_NEGOTIATE_HANDLE_DEFAULT(supported, rs_array); } } ZEND_BEGIN_ARG_INFO(ai_HttpEnv_reset, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpEnv, reset) { zend_parse_parameters_none(); php_http_env_reset(); } static zend_function_entry php_http_env_methods[] = { PHP_ME(HttpEnv, getRequestHeader, ai_HttpEnv_getRequestHeader, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) PHP_ME(HttpEnv, getRequestBody, ai_HttpEnv_getRequestBody, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) PHP_ME(HttpEnv, getResponseStatusForCode, ai_HttpEnv_getResponseStatusForCode, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) PHP_ME(HttpEnv, getResponseStatusForAllCodes, ai_HttpEnv_getResponseStatusForAllCodes, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) PHP_ME(HttpEnv, getResponseHeader, ai_HttpEnv_getResponseHeader, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) PHP_ME(HttpEnv, getResponseCode, ai_HttpEnv_getResponseCode, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) PHP_ME(HttpEnv, setResponseHeader, ai_HttpEnv_setResponseHeader, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) PHP_ME(HttpEnv, setResponseCode, ai_HttpEnv_setResponseCode, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) PHP_ME(HttpEnv, negotiateLanguage, ai_HttpEnv_negotiateLanguage, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) PHP_ME(HttpEnv, negotiateContentType, ai_HttpEnv_negotiateContentType, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) PHP_ME(HttpEnv, negotiateEncoding, ai_HttpEnv_negotiateEncoding, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) PHP_ME(HttpEnv, negotiateCharset, ai_HttpEnv_negotiateCharset, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) PHP_ME(HttpEnv, negotiate, ai_HttpEnv_negotiate, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) PHP_ME(HttpEnv, reset, ai_HttpEnv_reset, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) EMPTY_FUNCTION_ENTRY }; static zend_class_entry *php_http_env_class_entry; zend_class_entry *php_http_env_get_class_entry(void) { return php_http_env_class_entry; } PHP_MINIT_FUNCTION(http_env) { zend_class_entry ce = {0}; INIT_NS_CLASS_ENTRY(ce, "http", "Env", php_http_env_methods); php_http_env_class_entry = zend_register_internal_class(&ce); 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 */ pecl_http-4.2.1/src/php_http_env.h0000644000076500000240000000741414117626035015721 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_HTTP_ENV_H #define PHP_HTTP_ENV_H #include "php_http_message_body.h" #include "php_http_version.h" struct php_http_env_globals { zval *server_var; char *etag_mode; struct { HashTable *headers; php_http_message_body_t *body; } request; }; typedef enum php_http_content_encoding { PHP_HTTP_CONTENT_ENCODING_NONE, PHP_HTTP_CONTENT_ENCODING_GZIP } php_http_content_encoding_t; 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, php_http_message_t *request); PHP_HTTP_API void php_http_env_get_request_headers(HashTable *headers); PHP_HTTP_API char *php_http_env_get_request_header(const char *name_str, size_t name_len, size_t *len, php_http_message_t *request); PHP_HTTP_API zend_bool php_http_env_got_request_header(const char *name_str, size_t name_len, php_http_message_t *request); PHP_HTTP_API php_http_message_body_t *php_http_env_get_request_body(void); PHP_HTTP_API const char *php_http_env_get_request_method(php_http_message_t *request); 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(void); PHP_HTTP_API const char *php_http_env_get_response_status_for_code(unsigned code); PHP_HTTP_API ZEND_RESULT_CODE php_http_env_get_response_headers(HashTable *headers_ht); PHP_HTTP_API char *php_http_env_get_response_header(const char *name_str, size_t name_len); PHP_HTTP_API ZEND_RESULT_CODE php_http_env_set_response_code(long http_code); PHP_HTTP_API ZEND_RESULT_CODE php_http_env_set_response_protocol_version(php_http_version_t *v); PHP_HTTP_API ZEND_RESULT_CODE php_http_env_set_response_header(long http_code, const char *header_str, size_t header_len, zend_bool replace); PHP_HTTP_API ZEND_RESULT_CODE php_http_env_set_response_header_value(long http_code, const char *name_str, size_t name_len, zval *value, zend_bool replace); PHP_HTTP_API ZEND_RESULT_CODE php_http_env_set_response_header_format(long http_code, zend_bool replace, const char *fmt, ...); PHP_HTTP_API ZEND_RESULT_CODE php_http_env_set_response_header_va(long http_code, zend_bool replace, const char *fmt, va_list argv); PHP_HTTP_API zval *php_http_env_get_server_var(const char *key_str, size_t key_len, zend_bool check); PHP_HTTP_API zval *php_http_env_get_superglobal(const char *key, size_t key_len); static inline zend_bool php_http_env_got_server_var(const char *v) { return NULL != php_http_env_get_server_var(v, strlen(v), 1); } PHP_HTTP_API void php_http_env_reset(); PHP_HTTP_API zend_class_entry *php_http_env_get_class_entry(void); PHP_MINIT_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 */ pecl_http-4.2.1/src/php_http_env_request.c0000644000076500000240000002332314117626035017461 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #include "php_http_api.h" static int grab_file(zval *tmp_name, int argc, va_list argv, zend_hash_key *key) { zval *zfiles, *name, *zname, *error, *zerror, *type, *ztype, *size, *zsize; zend_hash_key *file_key; zfiles = (zval *) va_arg(argv, zval *); file_key = (zend_hash_key *) va_arg(argv, zend_hash_key *); name = (zval *) va_arg(argv, zval *); size = (zval *) va_arg(argv, zval *); type = (zval *) va_arg(argv, zval *); error = (zval *) va_arg(argv, zval *); if ((zname = zend_hash_index_find(Z_ARRVAL_P(name), key->h)) && (zsize = zend_hash_index_find(Z_ARRVAL_P(size), key->h)) && (ztype = zend_hash_index_find(Z_ARRVAL_P(type), key->h)) && (zerror = zend_hash_index_find(Z_ARRVAL_P(error), key->h)) ) { zval entry, *array; array_init(&entry); Z_TRY_ADDREF_P(tmp_name); add_assoc_zval_ex(&entry, ZEND_STRL("file"), tmp_name); Z_TRY_ADDREF_P(zname); add_assoc_zval_ex(&entry, ZEND_STRL("name"), zname); Z_TRY_ADDREF_P(zsize); add_assoc_zval_ex(&entry, ZEND_STRL("size"), zsize); Z_TRY_ADDREF_P(ztype); add_assoc_zval_ex(&entry, ZEND_STRL("type"), ztype); Z_TRY_ADDREF_P(zerror); add_assoc_zval_ex(&entry, ZEND_STRL("error"), zerror); if (file_key->key && (array = zend_hash_find(Z_ARRVAL_P(zfiles), file_key->key))) { add_next_index_zval(array, &entry); } else if (!file_key->key && (array = zend_hash_index_find(Z_ARRVAL_P(zfiles), file_key->h))) { add_next_index_zval(array, &entry); } else { zval tmp; array_init(&tmp); add_next_index_zval(&tmp, &entry); if (file_key->key) { zend_hash_update(Z_ARRVAL_P(zfiles), file_key->key, &tmp); } else { zend_hash_index_update(Z_ARRVAL_P(zfiles), file_key->h, &tmp); } } } return ZEND_HASH_APPLY_KEEP; } static int grab_files(zval *val, int argc, va_list argv, zend_hash_key *key) { zval *zfiles, *name, *tmp_name, *error, *type, *size; zfiles = (zval *) va_arg(argv, zval *); if ((Z_TYPE_P(val) == IS_ARRAY) && (tmp_name = zend_hash_str_find(Z_ARRVAL_P(val), ZEND_STRL("tmp_name"))) && (name = zend_hash_str_find(Z_ARRVAL_P(val), ZEND_STRL("name"))) && (size = zend_hash_str_find(Z_ARRVAL_P(val), ZEND_STRL("size"))) && (type = zend_hash_str_find(Z_ARRVAL_P(val), ZEND_STRL("type"))) && (error = zend_hash_str_find(Z_ARRVAL_P(val), ZEND_STRL("error"))) ) { int count; if (Z_TYPE_P(tmp_name) == IS_ARRAY && (count = zend_hash_num_elements(Z_ARRVAL_P(tmp_name))) > 1) { if (count == zend_hash_num_elements(Z_ARRVAL_P(name)) && count == zend_hash_num_elements(Z_ARRVAL_P(size)) && count == zend_hash_num_elements(Z_ARRVAL_P(type)) && count == zend_hash_num_elements(Z_ARRVAL_P(error)) ) { zend_hash_apply_with_arguments(Z_ARRVAL_P(tmp_name), grab_file, 6, zfiles, key, name, size, type, error); } else { /* wat?! */ return ZEND_HASH_APPLY_STOP; } } else { zval *tmp, entry; ZVAL_DUP(&entry, val); if ((tmp = zend_hash_str_find(Z_ARRVAL_P(val), ZEND_STRL("tmp_name")))) { Z_ADDREF_P(tmp); add_assoc_zval_ex(&entry, ZEND_STRL("file"), tmp); zend_hash_str_del(Z_ARRVAL(entry), ZEND_STRL("tmp_name")); } if (key->key) { zend_hash_update(Z_ARRVAL_P(zfiles), key->key, &entry); } else { zend_hash_index_update(Z_ARRVAL_P(zfiles), key->h, &entry); } } } return ZEND_HASH_APPLY_KEEP; } #define PHP_HTTP_ENV_REQUEST_OBJECT_INIT(obj) \ do { \ if (!obj->message) { \ obj->message = php_http_message_init_env(NULL, PHP_HTTP_REQUEST); \ } \ } while(0) static zend_class_entry *php_http_env_request_class_entry; zend_class_entry *php_http_get_env_request_class_entry(void) { return php_http_env_request_class_entry; } ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvRequest___construct, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpEnvRequest, __construct) { php_http_message_object_t *obj; zval *zsg, zqs; php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return); obj = PHP_HTTP_OBJ(NULL, getThis()); obj->body = NULL; php_http_expect(obj->message = php_http_message_init_env(obj->message, PHP_HTTP_REQUEST), unexpected_val, return); zsg = php_http_env_get_superglobal(ZEND_STRL("_GET")); object_init_ex(&zqs, php_http_querystring_get_class_entry()); php_http_expect(SUCCESS == php_http_querystring_ctor(&zqs, zsg), unexpected_val, return); zend_update_property(php_http_env_request_class_entry, &obj->zo, ZEND_STRL("query"), &zqs); zval_ptr_dtor(&zqs); zsg = php_http_env_get_superglobal(ZEND_STRL("_POST")); object_init_ex(&zqs, php_http_querystring_get_class_entry()); php_http_expect(SUCCESS == php_http_querystring_ctor(&zqs, zsg), unexpected_val, return); zend_update_property(php_http_env_request_class_entry, &obj->zo, ZEND_STRL("form"), &zqs); zval_ptr_dtor(&zqs); zsg = php_http_env_get_superglobal(ZEND_STRL("_COOKIE")); object_init_ex(&zqs, php_http_querystring_get_class_entry()); php_http_expect(SUCCESS == php_http_querystring_ctor(&zqs, zsg), unexpected_val, return); zend_update_property(php_http_env_request_class_entry, &obj->zo, ZEND_STRL("cookie"), &zqs); zval_ptr_dtor(&zqs); array_init(&zqs); if ((zsg = php_http_env_get_superglobal(ZEND_STRL("_FILES")))) { zend_hash_apply_with_arguments(Z_ARRVAL_P(zsg), grab_files, 1, &zqs); } zend_update_property(php_http_env_request_class_entry, &obj->zo, ZEND_STRL("files"), &zqs); zval_ptr_dtor(&zqs); } #define call_querystring_get(prop) \ do {\ zend_fcall_info fci; \ zend_fcall_info_cache fcc; \ zval rv, mn, *args = ecalloc(sizeof(zval), ZEND_NUM_ARGS()); \ zval *this_ptr = getThis(); \ zval qs_tmp, *qs = zend_read_property(Z_OBJCE_P(this_ptr), Z_OBJ_P(this_ptr), ZEND_STRL(prop), 0, &qs_tmp); \ \ ZVAL_NULL(&rv); \ array_init(&mn); \ Z_TRY_ADDREF_P(qs); \ add_next_index_zval(&mn, qs); \ add_next_index_stringl(&mn, ZEND_STRL("get")); \ zend_fcall_info_init(&mn, 0, &fci, &fcc, NULL, NULL); \ zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args); \ zend_fcall_info_argp(&fci, ZEND_NUM_ARGS(), args); \ zend_fcall_info_call(&fci, &fcc, &rv, NULL); \ zend_fcall_info_args_clear(&fci, 1); \ efree(args); \ zval_dtor(&mn); \ RETVAL_ZVAL(&rv, 0, 1); \ } while(0); ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvRequest_getForm, 0, 0, 0) ZEND_ARG_INFO(0, name) ZEND_ARG_INFO(0, type) ZEND_ARG_INFO(0, defval) ZEND_ARG_INFO(0, delete) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpEnvRequest, getForm) { if (ZEND_NUM_ARGS()) { call_querystring_get("form"); } else { zval zform_tmp, *zform = zend_read_property(php_http_env_request_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("form"), 0, &zform_tmp); RETURN_ZVAL(zform, 1, 0); } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvRequest_getQuery, 0, 0, 0) ZEND_ARG_INFO(0, name) ZEND_ARG_INFO(0, type) ZEND_ARG_INFO(0, defval) ZEND_ARG_INFO(0, delete) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpEnvRequest, getQuery) { if (ZEND_NUM_ARGS()) { call_querystring_get("query"); } else { zval zquery_tmp, *zquery = zend_read_property(php_http_env_request_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("query"), 0, &zquery_tmp); RETURN_ZVAL(zquery, 1, 0); } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvRequest_getCookie, 0, 0, 0) ZEND_ARG_INFO(0, name) ZEND_ARG_INFO(0, type) ZEND_ARG_INFO(0, defval) ZEND_ARG_INFO(0, delete) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpEnvRequest, getCookie) { if (ZEND_NUM_ARGS()) { call_querystring_get("cookie"); } else { zval zcookie_tmp, *zcookie = zend_read_property(php_http_env_request_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("cookie"), 0, &zcookie_tmp); RETURN_ZVAL(zcookie, 1, 0); } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvRequest_getFiles, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpEnvRequest, getFiles) { if (SUCCESS == zend_parse_parameters_none()) { zval zfiles_tmp, *zfiles = zend_read_property(php_http_env_request_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("files"), 0, &zfiles_tmp); RETURN_ZVAL(zfiles, 1, 0); } } static zend_function_entry php_http_env_request_methods[] = { PHP_ME(HttpEnvRequest, __construct, ai_HttpEnvRequest___construct, ZEND_ACC_PUBLIC) PHP_ME(HttpEnvRequest, getForm, ai_HttpEnvRequest_getForm, ZEND_ACC_PUBLIC) PHP_ME(HttpEnvRequest, getQuery, ai_HttpEnvRequest_getQuery, ZEND_ACC_PUBLIC) PHP_ME(HttpEnvRequest, getCookie, ai_HttpEnvRequest_getCookie, ZEND_ACC_PUBLIC) PHP_ME(HttpEnvRequest, getFiles, ai_HttpEnvRequest_getFiles, ZEND_ACC_PUBLIC) EMPTY_FUNCTION_ENTRY }; PHP_MINIT_FUNCTION(http_env_request) { zend_class_entry ce = {0}; INIT_NS_CLASS_ENTRY(ce, "http\\Env", "Request", php_http_env_request_methods); php_http_env_request_class_entry = zend_register_internal_class_ex(&ce, php_http_message_get_class_entry()); zend_declare_property_null(php_http_env_request_class_entry, ZEND_STRL("query"), ZEND_ACC_PROTECTED); zend_declare_property_null(php_http_env_request_class_entry, ZEND_STRL("form"), ZEND_ACC_PROTECTED); zend_declare_property_null(php_http_env_request_class_entry, ZEND_STRL("cookie"), ZEND_ACC_PROTECTED); zend_declare_property_null(php_http_env_request_class_entry, ZEND_STRL("files"), ZEND_ACC_PROTECTED); 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 */ pecl_http-4.2.1/src/php_http_env_request.h0000644000076500000240000000175314117626035017471 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_HTTP_ENV_REQUEST_H #define PHP_HTTP_ENV_REQUEST_H PHP_HTTP_API zend_class_entry *php_http_get_env_request_class_entry(void); PHP_MINIT_FUNCTION(http_env_request); #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 */ pecl_http-4.2.1/src/php_http_env_response.c0000644000076500000240000013113214117626035017625 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #include "php_http_api.h" static void set_option(zval *options, const char *name_str, size_t name_len, int type, void *value_ptr, size_t value_len) { if (Z_TYPE_P(options) == IS_OBJECT) { if (EXPECTED(value_ptr)) { switch (type) { case IS_DOUBLE: zend_update_property_double(Z_OBJCE_P(options), Z_OBJ_P(options), name_str, name_len, *(double *)value_ptr); break; case IS_LONG: zend_update_property_long(Z_OBJCE_P(options), Z_OBJ_P(options), name_str, name_len, *(zend_long *)value_ptr); break; case IS_STRING: zend_update_property_stringl(Z_OBJCE_P(options), Z_OBJ_P(options), name_str, name_len, value_ptr, value_len); break; case IS_ARRAY: case IS_OBJECT: zend_update_property(Z_OBJCE_P(options), Z_OBJ_P(options), name_str, name_len, value_ptr); break; } } else { zend_update_property_null(Z_OBJCE_P(options), Z_OBJ_P(options), name_str, name_len); } } else { convert_to_array(options); if (EXPECTED(value_ptr)) { switch (type) { case IS_DOUBLE: add_assoc_double_ex(options, name_str, name_len, *(double *)value_ptr); break; case IS_LONG: add_assoc_long_ex(options, name_str, name_len, *(zend_long *)value_ptr); break; case IS_STRING: { zend_string *value = zend_string_init(value_ptr, value_len, 0); add_assoc_str_ex(options, name_str, name_len, value); break; case IS_ARRAY: case IS_OBJECT: Z_ADDREF_P(value_ptr); add_assoc_zval_ex(options, name_str, name_len, value_ptr); break; } } } else { add_assoc_null_ex(options, name_str, name_len); } } } static zval *get_option(zval *options, const char *name_str, size_t name_len, zval *tmp) { zval *val = NULL; if (EXPECTED(Z_TYPE_P(options) == IS_OBJECT)) { val = zend_read_property(Z_OBJCE_P(options), Z_OBJ_P(options), name_str, name_len, 0, tmp); } else if (EXPECTED(Z_TYPE_P(options) == IS_ARRAY)) { val = zend_symtable_str_find(Z_ARRVAL_P(options), name_str, name_len); } else { abort(); } if (val) { Z_TRY_ADDREF_P(val); } return val; } static php_http_message_body_t *get_body(zval *options) { zval zbody_tmp, *zbody; php_http_message_body_t *body = NULL; if (EXPECTED(zbody = get_option(options, ZEND_STRL("body"), &zbody_tmp))) { if ((Z_TYPE_P(zbody) == IS_OBJECT) && instanceof_function(Z_OBJCE_P(zbody), php_http_get_message_body_class_entry())) { php_http_message_body_object_t *body_obj = PHP_HTTP_OBJ(NULL, zbody); body = body_obj->body; } Z_TRY_DELREF_P(zbody); } return body; } static php_http_message_t *get_request(zval *options) { zval zrequest_tmp, *zrequest; php_http_message_t *request = NULL; if (EXPECTED(zrequest = get_option(options, ZEND_STRL("request"), &zrequest_tmp))) { if (UNEXPECTED(Z_TYPE_P(zrequest) == IS_OBJECT && instanceof_function(Z_OBJCE_P(zrequest), php_http_message_get_class_entry()))) { php_http_message_object_t *request_obj = PHP_HTTP_OBJ(NULL, zrequest); request = request_obj->message; } Z_TRY_DELREF_P(zrequest); } return request; } static void set_cookie(zval *options, zval *zcookie_new) { zval tmp, zcookies_set_tmp, *zcookies_set; php_http_arrkey_t key; php_http_cookie_object_t *obj = PHP_HTTP_OBJ(NULL, zcookie_new); array_init(&tmp); zcookies_set = get_option(options, ZEND_STRL("cookies"), &zcookies_set_tmp); if (zcookies_set && Z_TYPE_P(zcookies_set) == IS_ARRAY) { array_copy(Z_ARRVAL_P(zcookies_set), Z_ARRVAL(tmp)); zval_ptr_dtor(zcookies_set); } ZEND_HASH_FOREACH_KEY(&obj->list->cookies, key.h, key.key) { Z_ADDREF_P(zcookie_new); if (key.key) { add_assoc_zval_ex(&tmp, key.key->val, key.key->len, zcookie_new); } else { add_index_zval(&tmp, key.h, zcookie_new); } } ZEND_HASH_FOREACH_END(); set_option(options, ZEND_STRL("cookies"), IS_ARRAY, &tmp, 0); zval_ptr_dtor(&tmp); } php_http_cache_status_t php_http_env_is_response_cached_by_etag(zval *options, const char *header_str, size_t header_len, php_http_message_t *request) { php_http_cache_status_t ret = PHP_HTTP_CACHE_NO; char *header = NULL, *etag = NULL; php_http_message_body_t *body; zval zetag_tmp, *zetag; if (UNEXPECTED(!(body = get_body(options)))) { return ret; } if (EXPECTED(zetag = get_option(options, ZEND_STRL("etag"), &zetag_tmp)) && Z_TYPE_P(zetag) != IS_NULL) { zend_string *zs = zval_get_string(zetag); etag = estrndup(zs->val, zs->len); zend_string_release(zs); zval_ptr_dtor(zetag); } if (!etag && (etag = php_http_message_body_etag(body))) { set_option(options, ZEND_STRL("etag"), IS_STRING, etag, strlen(etag)); } if (etag && (header = php_http_env_get_request_header(header_str, header_len, NULL, request))) { ret = php_http_match(header, etag, PHP_HTTP_MATCH_WORD) ? PHP_HTTP_CACHE_HIT : PHP_HTTP_CACHE_MISS; } PTR_FREE(etag); PTR_FREE(header); return ret; } php_http_cache_status_t php_http_env_is_response_cached_by_last_modified(zval *options, const char *header_str, size_t header_len, php_http_message_t *request) { php_http_cache_status_t ret = PHP_HTTP_CACHE_NO; char *header; time_t ums, lm = 0; php_http_message_body_t *body; zval zlm_tmp, *zlm; if (UNEXPECTED(!(body = get_body(options)))) { return ret; } if (EXPECTED(zlm = get_option(options, ZEND_STRL("lastModified"), &zlm_tmp))) { lm = zval_get_long(zlm); zval_ptr_dtor(zlm); } if (EXPECTED(lm <= 0)) { lm = php_http_message_body_mtime(body); set_option(options, ZEND_STRL("lastModified"), IS_LONG, &lm, 0); } if ((header = php_http_env_get_request_header(header_str, header_len, NULL, request))) { ums = php_parse_date(header, NULL); if (ums > 0 && ums >= lm) { ret = PHP_HTTP_CACHE_HIT; } else { ret = PHP_HTTP_CACHE_MISS; } } PTR_FREE(header); return ret; } static zend_bool php_http_env_response_is_cacheable(php_http_env_response_t *r, php_http_message_t *request) { long status = r->ops->get_status(r); if (status && status / 100 != 2) { return 0; } if (php_http_env_got_request_header(ZEND_STRL("Authorization"), request)) { return 0; } if (-1 == php_http_select_str(php_http_env_get_request_method(request), 2, "HEAD", "GET")) { return 0; } return 1; } static size_t output(void *context, char *buf, size_t len) { php_http_env_response_t *r = context; if (UNEXPECTED(SUCCESS != r->ops->write(r, buf, len))) { return (size_t) -1; } /* we really only need to flush when throttling is enabled, because we push the data as fast as possible anyway if not */ if (UNEXPECTED(r->throttle.delay >= PHP_HTTP_DIFFSEC)) { r->ops->flush(r); php_http_sleep(r->throttle.delay); } return len; } static ZEND_RESULT_CODE php_http_env_response_send_data(php_http_env_response_t *r, const char *buf, size_t len) { size_t chunks_sent, chunk = r->throttle.chunk ? r->throttle.chunk : PHP_HTTP_SENDBUF_SIZE; if (r->content.encoder) { char *enc_str = NULL; size_t enc_len = 0; if (buf) { if (SUCCESS != php_http_encoding_stream_update(r->content.encoder, buf, len, &enc_str, &enc_len)) { return FAILURE; } } else { if (SUCCESS != php_http_encoding_stream_finish(r->content.encoder, &enc_str, &enc_len)) { return FAILURE; } } if (!enc_str) { return SUCCESS; } chunks_sent = php_http_buffer_chunked_output(&r->buffer, enc_str, enc_len, buf ? chunk : 0, output, r); PTR_FREE(enc_str); } else { chunks_sent = php_http_buffer_chunked_output(&r->buffer, buf, len, buf ? chunk : 0, output, r); } return chunks_sent != (size_t) -1 ? SUCCESS : FAILURE; } static inline ZEND_RESULT_CODE php_http_env_response_send_done(php_http_env_response_t *r) { return php_http_env_response_send_data(r, NULL, 0); } php_http_env_response_t *php_http_env_response_init(php_http_env_response_t *r, zval *options, php_http_env_response_ops_t *ops, void *init_arg) { zend_bool free_r; if ((free_r = !r)) { r = emalloc(sizeof(*r)); } memset(r, 0, sizeof(*r)); if (ops) { r->ops = ops; } else { r->ops = php_http_env_response_get_sapi_ops(); } r->buffer = php_http_buffer_init(NULL); ZVAL_COPY(&r->options, options); if (r->ops->init && (SUCCESS != r->ops->init(r, init_arg))) { if (free_r) { php_http_env_response_free(&r); } else { php_http_env_response_dtor(r); r = NULL; } } return r; } void php_http_env_response_dtor(php_http_env_response_t *r) { if (r->ops->dtor) { r->ops->dtor(r); } php_http_buffer_free(&r->buffer); zval_ptr_dtor(&r->options); PTR_FREE(r->content.type); PTR_FREE(r->content.encoding); if (r->content.encoder) { php_http_encoding_stream_free(&r->content.encoder); } } void php_http_env_response_free(php_http_env_response_t **r) { if (*r) { php_http_env_response_dtor(*r); efree(*r); *r = NULL; } } static ZEND_RESULT_CODE php_http_env_response_send_head(php_http_env_response_t *r, php_http_message_t *request) { ZEND_RESULT_CODE ret = SUCCESS; zval zoption_tmp, *zoption, *options = &r->options; if (r->done) { return ret; } if (EXPECTED(zoption = get_option(options, ZEND_STRL("headers"), &zoption_tmp))) { if (EXPECTED(Z_TYPE_P(zoption) == IS_ARRAY)) { php_http_header_to_callback(Z_ARRVAL_P(zoption), 0, (php_http_pass_format_callback_t) r->ops->set_header, r); } zval_ptr_dtor(zoption); } if (EXPECTED(zoption = get_option(options, ZEND_STRL("responseCode"), &zoption_tmp))) { zend_long rc = zval_get_long(zoption); zval_ptr_dtor(zoption); if (rc > 0) { ret = r->ops->set_status(r, rc); } } if (ret != SUCCESS) { return ret; } if (EXPECTED(zoption = get_option(options, ZEND_STRL("httpVersion"), &zoption_tmp))) { php_http_version_t v; zend_string *zs = zval_get_string(zoption); if (EXPECTED(zs->len && php_http_version_parse(&v, zs->val))) { ret = r->ops->set_protocol_version(r, &v); php_http_version_dtor(&v); } zend_string_release(zs); zval_ptr_dtor(zoption); } if (ret != SUCCESS) { return ret; } if (EXPECTED(zoption = get_option(options, ZEND_STRL("cookies"), &zoption_tmp))) { if (Z_TYPE_P(zoption) == IS_ARRAY) { zval *zcookie; ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(zoption), zcookie) { if (Z_TYPE_P(zcookie) == IS_OBJECT && instanceof_function(Z_OBJCE_P(zcookie), php_http_cookie_get_class_entry())) { php_http_cookie_object_t *obj = PHP_HTTP_OBJ(NULL, zcookie); char *str; size_t len; php_http_cookie_list_to_string(obj->list, &str, &len); if (SUCCESS != (ret = r->ops->add_header(r, "Set-Cookie: %s", str))) { efree(str); break; } efree(str); } } ZEND_HASH_FOREACH_END(); } zval_ptr_dtor(zoption); } if (ret != SUCCESS) { return ret; } if (EXPECTED(zoption = get_option(options, ZEND_STRL("contentType"), &zoption_tmp))) { zend_string *zs = zval_get_string(zoption); zval_ptr_dtor(zoption); if (zs->len && strchr(zs->val, '/')) { if (SUCCESS == (ret = r->ops->set_header(r, "Content-Type: %.*s", zs->len, zs->val))) { r->content.type = estrndup(zs->val, zs->len); } } zend_string_release(zs); } if (ret != SUCCESS) { return ret; } if (UNEXPECTED(r->range.status == PHP_HTTP_RANGE_OK)) { if (zend_hash_num_elements(&r->range.values) == 1) { zval *range, *begin, *end; if (EXPECTED( 1 == php_http_array_list(&r->range.values, 1, &range) && 2 == php_http_array_list(Z_ARRVAL_P(range), 2, &begin, &end)) ) { if (SUCCESS == (ret = r->ops->set_status(r, 206))) { ret = r->ops->set_header(r, "Content-Range: bytes %ld-%ld/%zu", Z_LVAL_P(begin), Z_LVAL_P(end), r->content.length); } } else { /* this should never happen */ zend_hash_destroy(&r->range.values); ret = FAILURE; } } else { php_http_boundary(r->range.boundary, sizeof(r->range.boundary)); if (SUCCESS == (ret = r->ops->set_status(r, 206))) { ret = r->ops->set_header(r, "Content-Type: multipart/byteranges; boundary=%s", r->range.boundary); } } } else { if (EXPECTED(zoption = get_option(options, ZEND_STRL("cacheControl"), &zoption_tmp))) { zend_string *zs = zval_get_string(zoption); zval_ptr_dtor(zoption); if (zs->len) { ret = r->ops->set_header(r, "Cache-Control: %.*s", zs->len, zs->val); } zend_string_release(zs); } if (ret != SUCCESS) { return ret; } if (EXPECTED(zoption = get_option(options, ZEND_STRL("contentDisposition"), &zoption_tmp))) { if (Z_TYPE_P(zoption) == IS_ARRAY) { php_http_buffer_t buf; php_http_buffer_init(&buf); if (php_http_params_to_string(&buf, Z_ARRVAL_P(zoption), ZEND_STRL(","), ZEND_STRL(";"), ZEND_STRL("="), PHP_HTTP_PARAMS_DEFAULT)) { if (buf.used) { ret = r->ops->set_header(r, "Content-Disposition: %.*s", buf.used, buf.data); } } php_http_buffer_dtor(&buf); } zval_ptr_dtor(zoption); } if (ret != SUCCESS) { return ret; } if (EXPECTED(zoption = get_option(options, ZEND_STRL("contentEncoding"), &zoption_tmp))) { zend_long ce = zval_get_long(zoption); zval zsupported; HashTable *result = NULL; zval_ptr_dtor(zoption); switch (ce) { case PHP_HTTP_CONTENT_ENCODING_GZIP: array_init(&zsupported); add_next_index_stringl(&zsupported, ZEND_STRL("none")); add_next_index_stringl(&zsupported, ZEND_STRL("gzip")); add_next_index_stringl(&zsupported, ZEND_STRL("deflate")); if ((result = php_http_negotiate_encoding(Z_ARRVAL(zsupported), request))) { zend_string *key_str = NULL; zend_ulong index = 0; zend_hash_internal_pointer_reset(result); if (HASH_KEY_IS_STRING == zend_hash_get_current_key(result, &key_str, &index)) { if (zend_string_equals_literal(key_str, "gzip")) { if (!(r->content.encoder = php_http_encoding_stream_init(NULL, php_http_encoding_stream_get_deflate_ops(), PHP_HTTP_DEFLATE_TYPE_GZIP))) { ret = FAILURE; } else if (SUCCESS == (ret = r->ops->set_header(r, "Content-Encoding: gzip"))) { r->content.encoding = estrndup(key_str->val, key_str->len); } } else if (zend_string_equals_literal(key_str, "deflate")) { if (!(r->content.encoder = php_http_encoding_stream_init(NULL, php_http_encoding_stream_get_deflate_ops(), PHP_HTTP_DEFLATE_TYPE_ZLIB))) { ret = FAILURE; } else if (SUCCESS == (ret = r->ops->set_header(r, "Content-Encoding: deflate"))) { r->content.encoding = estrndup(key_str->val, key_str->len); } } else { ret = r->ops->del_header(r, ZEND_STRL("Content-Encoding")); } if (SUCCESS == ret) { ret = r->ops->add_header(r, "Vary: Accept-Encoding"); } } zend_hash_destroy(result); FREE_HASHTABLE(result); } zval_dtor(&zsupported); break; case PHP_HTTP_CONTENT_ENCODING_NONE: default: ret = r->ops->del_header(r, ZEND_STRL("Content-Encoding")); break; } } if (SUCCESS != ret) { return ret; } if (php_http_env_response_is_cacheable(r, request)) { switch (php_http_env_is_response_cached_by_etag(options, ZEND_STRL("If-None-Match"), request)) { 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(options, ZEND_STRL("If-Modified-Since"), request)) { break; } /* no break */ case PHP_HTTP_CACHE_HIT: ret = r->ops->set_status(r, 304); r->done = 1; break; } if (EXPECTED(zoption = get_option(options, ZEND_STRL("etag"), &zoption_tmp))) { zend_string *zs = zval_get_string(zoption); zval_ptr_dtor(zoption); if (EXPECTED(*zs->val != '"' && strncmp(zs->val, "W/\"", 3))) { ret = r->ops->set_header(r, "ETag: \"%s\"", zs->val); } else { ret = r->ops->set_header(r, "ETag: %s", zs->val); } zend_string_release(zs); } if (EXPECTED(zoption = get_option(options, ZEND_STRL("lastModified"), &zoption_tmp))) { zend_long lm = zval_get_long(zoption); zval_ptr_dtor(zoption); if (EXPECTED(lm)) { zend_string *date = php_format_date(ZEND_STRL(PHP_HTTP_DATE_FORMAT), lm, 0); if (date) { ret = r->ops->set_header(r, "Last-Modified: %s", date->val); zend_string_release(date); } } } } } return ret; } static ZEND_RESULT_CODE php_http_env_response_send_body(php_http_env_response_t *r) { ZEND_RESULT_CODE ret = SUCCESS; zval zoption_tmp, *zoption; php_http_message_body_t *body; if (r->done) { return ret; } if (EXPECTED(body = get_body(&r->options))) { if (EXPECTED(zoption = get_option(&r->options, ZEND_STRL("throttleDelay"), &zoption_tmp))) { r->throttle.delay = zval_get_double(zoption); zval_ptr_dtor(zoption); } if (EXPECTED(zoption = get_option(&r->options, ZEND_STRL("throttleChunk"), &zoption_tmp))) { r->throttle.chunk = zval_get_long(zoption); zval_ptr_dtor(zoption); } if (UNEXPECTED(r->range.status == PHP_HTTP_RANGE_OK)) { if (zend_hash_num_elements(&r->range.values) == 1) { /* single range */ zval *range, *begin, *end; if ( 1 == php_http_array_list(&r->range.values, 1, &range) && 2 == php_http_array_list(Z_ARRVAL_P(range), 2, &begin, &end) ) { /* send chunk */ ret = php_http_message_body_to_callback(body, (php_http_pass_callback_t) php_http_env_response_send_data, r, Z_LVAL_P(begin), Z_LVAL_P(end) - Z_LVAL_P(begin) + 1); if (ret == SUCCESS) { ret = php_http_env_response_send_done(r); } zend_hash_destroy(&r->range.values); } else { /* this should never happen */ zend_hash_destroy(&r->range.values); r->ops->set_status(r, 500); ret = FAILURE; } } else { /* send multipart/byte-ranges message */ zval *chunk; ZEND_HASH_FOREACH_VAL(&r->range.values, chunk) { zval *begin, *end; if (2 == php_http_array_list(Z_ARRVAL_P(chunk), 2, &begin, &end)) { php_http_buffer_appendf(r->buffer, PHP_HTTP_CRLF "--%s" PHP_HTTP_CRLF "Content-Type: %s" PHP_HTTP_CRLF "Content-Range: bytes %ld-%ld/%zu" PHP_HTTP_CRLF PHP_HTTP_CRLF, /* - */ r->range.boundary, r->content.type ? r->content.type : "application/octet-stream", Z_LVAL_P(begin), Z_LVAL_P(end), r->content.length ); ret = php_http_message_body_to_callback(body, (php_http_pass_callback_t) php_http_env_response_send_data, r, Z_LVAL_P(begin), Z_LVAL_P(end) - Z_LVAL_P(begin) + 1); } } ZEND_HASH_FOREACH_END(); if (ret == SUCCESS) { php_http_buffer_appendf(r->buffer, PHP_HTTP_CRLF "--%s--", r->range.boundary); ret = php_http_env_response_send_done(r); } zend_hash_destroy(&r->range.values); } } else { ret = php_http_message_body_to_callback(body, (php_http_pass_callback_t) php_http_env_response_send_data, r, 0, 0); if (ret == SUCCESS) { ret = php_http_env_response_send_done(r); } } } return ret; } ZEND_RESULT_CODE php_http_env_response_send(php_http_env_response_t *r) { php_http_message_t *request; php_http_message_body_t *body; request = get_request(&r->options); /* check for ranges */ if (EXPECTED(body = get_body(&r->options))) { r->content.length = php_http_message_body_size(body); if (UNEXPECTED(SUCCESS != r->ops->set_header(r, "Accept-Ranges: bytes"))) { return FAILURE; } else { ZEND_INIT_SYMTABLE_EX(&r->range.values, 0, 0); r->range.status = php_http_env_get_request_ranges(&r->range.values, r->content.length, request); switch (r->range.status) { case PHP_HTTP_RANGE_NO: zend_hash_destroy(&r->range.values); break; case PHP_HTTP_RANGE_ERR: if (php_http_env_got_request_header(ZEND_STRL("If-Range"), request)) { r->range.status = PHP_HTTP_RANGE_NO; zend_hash_destroy(&r->range.values); } else { r->done = 1; zend_hash_destroy(&r->range.values); if (SUCCESS != r->ops->set_status(r, 416)) { return FAILURE; } if (SUCCESS != r->ops->set_header(r, "Content-Range: bytes */%zu", r->content.length)) { return FAILURE; } } break; case PHP_HTTP_RANGE_OK: if (PHP_HTTP_CACHE_MISS == php_http_env_is_response_cached_by_etag(&r->options, ZEND_STRL("If-Range"), request) || PHP_HTTP_CACHE_MISS == php_http_env_is_response_cached_by_last_modified(&r->options, ZEND_STRL("If-Range"), request) ) { r->range.status = PHP_HTTP_RANGE_NO; zend_hash_destroy(&r->range.values); break; } if (PHP_HTTP_CACHE_MISS == php_http_env_is_response_cached_by_etag(&r->options, ZEND_STRL("If-Match"), request) || PHP_HTTP_CACHE_MISS == php_http_env_is_response_cached_by_last_modified(&r->options, ZEND_STRL("If-Unmodified-Since"), request) || PHP_HTTP_CACHE_MISS == php_http_env_is_response_cached_by_last_modified(&r->options, ZEND_STRL("Unless-Modified-Since"), request) ) { r->done = 1; zend_hash_destroy(&r->range.values); if (SUCCESS != r->ops->set_status(r, 412)) { return FAILURE; } break; } break; } } } if (UNEXPECTED(SUCCESS != php_http_env_response_send_head(r, request))) { php_error_docref(NULL, E_WARNING, "Failed to send response headers"); return FAILURE; } if (UNEXPECTED(SUCCESS != php_http_env_response_send_body(r))) { php_error_docref(NULL, E_WARNING, "Failed to send response body"); return FAILURE; } if (UNEXPECTED(SUCCESS != r->ops->finish(r))) { php_error_docref(NULL, E_WARNING, "Failed to finish response"); return FAILURE; } return SUCCESS; } static long php_http_env_response_sapi_get_status(php_http_env_response_t *r) { return php_http_env_get_response_code(); } static ZEND_RESULT_CODE php_http_env_response_sapi_set_status(php_http_env_response_t *r, long http_code) { return php_http_env_set_response_code(http_code); } static ZEND_RESULT_CODE php_http_env_response_sapi_set_protocol_version(php_http_env_response_t *r, php_http_version_t *v) { return php_http_env_set_response_protocol_version(v); } static ZEND_RESULT_CODE php_http_env_response_sapi_set_header(php_http_env_response_t *r, const char *fmt, ...) { ZEND_RESULT_CODE ret; va_list args; va_start(args, fmt); ret = php_http_env_set_response_header_va(0, 1, fmt, args); va_end(args); return ret; } static ZEND_RESULT_CODE php_http_env_response_sapi_add_header(php_http_env_response_t *r, const char *fmt, ...) { ZEND_RESULT_CODE ret; va_list args; va_start(args, fmt); ret = php_http_env_set_response_header_va(0, 0, fmt, args); va_end(args); return ret; } static ZEND_RESULT_CODE php_http_env_response_sapi_del_header(php_http_env_response_t *r, const char *header_str, size_t header_len) { return php_http_env_set_response_header_value(0, header_str, header_len, NULL, 1); } static ZEND_RESULT_CODE php_http_env_response_sapi_write(php_http_env_response_t *r, const char *data_str, size_t data_len) { if (0 < PHPWRITE(data_str, data_len)) { return SUCCESS; } return FAILURE; } static ZEND_RESULT_CODE php_http_env_response_sapi_flush(php_http_env_response_t *r) { if (php_output_get_level()) { php_output_flush_all(); } if (!(php_output_get_status() & PHP_OUTPUT_IMPLICITFLUSH)) { sapi_flush(); } return SUCCESS; } static ZEND_RESULT_CODE php_http_env_response_sapi_finish(php_http_env_response_t *r) { return SUCCESS; } static php_http_env_response_ops_t php_http_env_response_sapi_ops = { NULL, NULL, php_http_env_response_sapi_get_status, php_http_env_response_sapi_set_status, php_http_env_response_sapi_set_protocol_version, php_http_env_response_sapi_set_header, php_http_env_response_sapi_add_header, php_http_env_response_sapi_del_header, php_http_env_response_sapi_write, php_http_env_response_sapi_flush, php_http_env_response_sapi_finish }; php_http_env_response_ops_t *php_http_env_response_get_sapi_ops(void) { return &php_http_env_response_sapi_ops; } typedef struct php_http_env_response_stream_ctx { HashTable header; php_http_version_t version; long status_code; php_stream *stream; php_stream_filter *chunked_filter; php_http_message_t *request; unsigned started:1; unsigned finished:1; unsigned chunked:1; } php_http_env_response_stream_ctx_t; static ZEND_RESULT_CODE php_http_env_response_stream_init(php_http_env_response_t *r, void *init_arg) { php_http_env_response_stream_ctx_t *ctx; size_t buffer_size = 0x1000; ctx = ecalloc(1, sizeof(*ctx)); ctx->stream = init_arg; GC_ADDREF(ctx->stream->res); ZEND_INIT_SYMTABLE(&ctx->header); php_http_version_init(&ctx->version, 1, 1); php_stream_set_option(ctx->stream, PHP_STREAM_OPTION_WRITE_BUFFER, PHP_STREAM_BUFFER_FULL, &buffer_size); ctx->status_code = 200; ctx->chunked = 1; ctx->request = get_request(&r->options); /* there are some limitations regarding TE:chunked, see https://tools.ietf.org/html/rfc7230#section-3.3.1 */ if (UNEXPECTED(ctx->request && ctx->request->http.version.major == 1 && ctx->request->http.version.minor == 0)) { ctx->version.minor = 0; } r->ctx = ctx; return SUCCESS; } static void php_http_env_response_stream_dtor(php_http_env_response_t *r) { php_http_env_response_stream_ctx_t *ctx = r->ctx; if (UNEXPECTED(ctx->chunked_filter)) { ctx->chunked_filter = php_stream_filter_remove(ctx->chunked_filter, 1); } zend_hash_destroy(&ctx->header); zend_list_delete(ctx->stream->res); efree(ctx); r->ctx = NULL; } static void php_http_env_response_stream_header(php_http_env_response_stream_ctx_t *ctx, HashTable *header, php_http_buffer_t *buf) { zval *val; ZEND_HASH_FOREACH_VAL(header, val) { if (UNEXPECTED(Z_TYPE_P(val) == IS_ARRAY)) { php_http_env_response_stream_header(ctx, Z_ARRVAL_P(val), buf); } else { zend_string *zs = zval_get_string(val); if (ctx->chunked) { /* disable chunked transfer encoding if we've got an explicit content-length */ if (!strncasecmp(zs->val, "Content-Length:", lenof("Content-Length:"))) { ctx->chunked = 0; } } php_http_buffer_append(buf, zs->val, zs->len); php_http_buffer_appends(buf, PHP_HTTP_CRLF); zend_string_release(zs); } } ZEND_HASH_FOREACH_END(); } static ZEND_RESULT_CODE php_http_env_response_stream_start(php_http_env_response_stream_ctx_t *ctx) { php_http_buffer_t header_buf; if (ctx->started || ctx->finished) { return FAILURE; } php_http_buffer_init(&header_buf); php_http_buffer_appendf(&header_buf, "HTTP/%u.%u %ld %s" PHP_HTTP_CRLF, ctx->version.major, ctx->version.minor, ctx->status_code, php_http_env_get_response_status_for_code(ctx->status_code)); /* there are some limitations regarding TE:chunked, see https://tools.ietf.org/html/rfc7230#section-3.3.1 */ if (UNEXPECTED(ctx->version.major == 1 && ctx->version.minor == 0)) { ctx->chunked = 0; } else if (UNEXPECTED(ctx->status_code == 204 || ctx->status_code/100 == 1)) { ctx->chunked = 0; } else if (UNEXPECTED(ctx->request && ctx->status_code/100 == 2 && !strcasecmp(ctx->request->http.info.request.method, "CONNECT"))) { ctx->chunked = 0; } php_http_env_response_stream_header(ctx, &ctx->header, &header_buf); /* enable chunked transfer encoding */ if (ctx->chunked) { php_http_buffer_appends(&header_buf, "Transfer-Encoding: chunked" PHP_HTTP_CRLF); } php_http_buffer_appends(&header_buf, PHP_HTTP_CRLF); if (header_buf.used == php_stream_write(ctx->stream, header_buf.data, header_buf.used)) { ctx->started = 1; } php_http_buffer_dtor(&header_buf); php_stream_flush(ctx->stream); if (ctx->chunked) { ctx->chunked_filter = php_stream_filter_create("http.chunked_encode", NULL, 0); if (ctx->chunked_filter) { php_stream_filter_append(&ctx->stream->writefilters, ctx->chunked_filter); } } return ctx->started ? SUCCESS : FAILURE; } static long php_http_env_response_stream_get_status(php_http_env_response_t *r) { php_http_env_response_stream_ctx_t *ctx = r->ctx; return ctx->status_code; } static ZEND_RESULT_CODE php_http_env_response_stream_set_status(php_http_env_response_t *r, long http_code) { php_http_env_response_stream_ctx_t *stream_ctx = r->ctx; if (stream_ctx->started || stream_ctx->finished) { return FAILURE; } stream_ctx->status_code = http_code; return SUCCESS; } static ZEND_RESULT_CODE php_http_env_response_stream_set_protocol_version(php_http_env_response_t *r, php_http_version_t *v) { php_http_env_response_stream_ctx_t *stream_ctx = r->ctx; if (stream_ctx->started || stream_ctx->finished) { return FAILURE; } memcpy(&stream_ctx->version, v, sizeof(stream_ctx->version)); return SUCCESS; } static ZEND_RESULT_CODE php_http_env_response_stream_set_header_ex(php_http_env_response_t *r, zend_bool replace, const char *fmt, va_list argv) { php_http_env_response_stream_ctx_t *stream_ctx = r->ctx; char *header_end, *header_str = NULL; size_t header_len = 0; zval zheader, *zheader_ptr; zend_string *header_key; ZEND_RESULT_CODE rv; if (UNEXPECTED(stream_ctx->started || stream_ctx->finished)) { return FAILURE; } header_len = vspprintf(&header_str, 0, fmt, argv); if (UNEXPECTED(!(header_end = strchr(header_str, ':')))) { efree(header_str); return FAILURE; } header_key = zend_string_init(header_str, header_end - header_str, 0); if (!replace && (zheader_ptr = zend_hash_find(&stream_ctx->header, header_key))) { convert_to_array(zheader_ptr); rv = add_next_index_str(zheader_ptr, php_http_cs2zs(header_str, header_len)); } else { ZVAL_STR(&zheader, php_http_cs2zs(header_str, header_len)); rv = zend_hash_update(&stream_ctx->header, header_key, &zheader) ? SUCCESS : FAILURE; } zend_string_release(header_key); return rv; } static ZEND_RESULT_CODE php_http_env_response_stream_set_header(php_http_env_response_t *r, const char *fmt, ...) { ZEND_RESULT_CODE ret; va_list argv; va_start(argv, fmt); ret = php_http_env_response_stream_set_header_ex(r, 1, fmt, argv); va_end(argv); return ret; } static ZEND_RESULT_CODE php_http_env_response_stream_add_header(php_http_env_response_t *r, const char *fmt, ...) { ZEND_RESULT_CODE ret; va_list argv; va_start(argv, fmt); ret = php_http_env_response_stream_set_header_ex(r, 0, fmt, argv); va_end(argv); return ret; } static ZEND_RESULT_CODE php_http_env_response_stream_del_header(php_http_env_response_t *r, const char *header_str, size_t header_len) { php_http_env_response_stream_ctx_t *stream_ctx = r->ctx; if (stream_ctx->started || stream_ctx->finished) { return FAILURE; } zend_hash_str_del(&stream_ctx->header, header_str, header_len); return SUCCESS; } static ZEND_RESULT_CODE php_http_env_response_stream_write(php_http_env_response_t *r, const char *data_str, size_t data_len) { php_http_env_response_stream_ctx_t *stream_ctx = r->ctx; if (stream_ctx->finished) { return FAILURE; } if (!stream_ctx->started) { if (SUCCESS != php_http_env_response_stream_start(stream_ctx)) { return FAILURE; } } if (data_len != php_stream_write(stream_ctx->stream, data_str, data_len)) { return FAILURE; } return SUCCESS; } static ZEND_RESULT_CODE php_http_env_response_stream_flush(php_http_env_response_t *r) { php_http_env_response_stream_ctx_t *stream_ctx = r->ctx; if (stream_ctx->finished) { return FAILURE; } if (!stream_ctx->started) { if (SUCCESS != php_http_env_response_stream_start(stream_ctx)) { return FAILURE; } } return php_stream_flush(stream_ctx->stream); } static ZEND_RESULT_CODE php_http_env_response_stream_finish(php_http_env_response_t *r) { php_http_env_response_stream_ctx_t *ctx = r->ctx; if (UNEXPECTED(ctx->finished)) { return FAILURE; } if (UNEXPECTED(!ctx->started)) { if (SUCCESS != php_http_env_response_stream_start(ctx)) { return FAILURE; } } php_stream_flush(ctx->stream); if (ctx->chunked && ctx->chunked_filter) { php_stream_filter_flush(ctx->chunked_filter, 1); ctx->chunked_filter = php_stream_filter_remove(ctx->chunked_filter, 1); } ctx->finished = 1; return SUCCESS; } static php_http_env_response_ops_t php_http_env_response_stream_ops = { php_http_env_response_stream_init, php_http_env_response_stream_dtor, php_http_env_response_stream_get_status, php_http_env_response_stream_set_status, php_http_env_response_stream_set_protocol_version, php_http_env_response_stream_set_header, php_http_env_response_stream_add_header, php_http_env_response_stream_del_header, php_http_env_response_stream_write, php_http_env_response_stream_flush, php_http_env_response_stream_finish }; php_http_env_response_ops_t *php_http_env_response_get_stream_ops(void) { return &php_http_env_response_stream_ops; } #define PHP_HTTP_ENV_RESPONSE_OBJECT_INIT(obj) \ do { \ if (!obj->message) { \ obj->message = php_http_message_init_env(NULL, PHP_HTTP_RESPONSE); \ } \ } while (0) ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse___construct, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpEnvResponse, __construct) { php_http_message_object_t *obj; php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return); obj = PHP_HTTP_OBJ(NULL, getThis()); php_http_expect(obj->message = php_http_message_init_env(obj->message, PHP_HTTP_RESPONSE), unexpected_val, return); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse___invoke, 0, 0, 1) ZEND_ARG_INFO(0, ob_string) ZEND_ARG_INFO(0, ob_flags) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpEnvResponse, __invoke) { char *ob_str; size_t ob_len; zend_long ob_flags = 0; if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &ob_str, &ob_len, &ob_flags)) { php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_ENV_RESPONSE_OBJECT_INIT(obj); if (!obj->body) { php_http_message_object_init_body_object(obj); } if (ob_flags & PHP_OUTPUT_HANDLER_CLEAN) { php_stream_truncate_set_size(php_http_message_body_stream(obj->message->body), 0); } else { php_http_message_body_append(obj->message->body, ob_str, ob_len); } RETURN_TRUE; } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_setEnvRequest, 0, 0, 1) ZEND_ARG_OBJ_INFO(0, env_request, http\\Message, 1) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpEnvResponse, setEnvRequest) { zval *env_req = NULL; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|O", &env_req, php_http_message_get_class_entry()), invalid_arg, return); set_option(getThis(), ZEND_STRL("request"), IS_OBJECT, env_req, 0); RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_setContentType, 0, 0, 1) ZEND_ARG_INFO(0, content_type) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpEnvResponse, setContentType) { char *ct_str = NULL; size_t ct_len = 0; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s!", &ct_str, &ct_len), invalid_arg, return); set_option(getThis(), ZEND_STRL("contentType"), IS_STRING, ct_str, ct_len); RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_setContentDisposition, 0, 0, 1) ZEND_ARG_ARRAY_INFO(0, disposition_params, 1) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpEnvResponse, setContentDisposition) { zval *zdisposition; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "a", &zdisposition), invalid_arg, return); zend_update_property(Z_OBJCE_P(ZEND_THIS), Z_OBJ_P(ZEND_THIS), ZEND_STRL("contentDisposition"), zdisposition); RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_setContentEncoding, 0, 0, 1) ZEND_ARG_INFO(0, content_encoding) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpEnvResponse, setContentEncoding) { zend_long ce; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "l", &ce), invalid_arg, return); set_option(getThis(), ZEND_STRL("contentEncoding"), IS_LONG, &ce, 0); RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_setCacheControl, 0, 0, 1) ZEND_ARG_INFO(0, cache_control) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpEnvResponse, setCacheControl) { char *cc_str = NULL; size_t cc_len = 0; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s!", &cc_str, &cc_len), invalid_arg, return); set_option(getThis(), ZEND_STRL("cacheControl"), IS_STRING, cc_str, cc_len); RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_setLastModified, 0, 0, 1) ZEND_ARG_INFO(0, last_modified) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpEnvResponse, setLastModified) { zend_long last_modified; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "l", &last_modified), invalid_arg, return); set_option(getThis(), ZEND_STRL("lastModified"), IS_LONG, &last_modified, 0); RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_isCachedByLastModified, 0, 0, 0) ZEND_ARG_INFO(0, header_name) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpEnvResponse, isCachedByLastModified) { char *header_name_str = NULL; size_t header_name_len = 0; if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|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, get_request(getThis()))); } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_setEtag, 0, 0, 1) ZEND_ARG_INFO(0, etag) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpEnvResponse, setEtag) { char *etag_str = NULL; size_t etag_len = 0; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s!", &etag_str, &etag_len), invalid_arg, return); set_option(getThis(), ZEND_STRL("etag"), IS_STRING, etag_str, etag_len); RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_isCachedByEtag, 0, 0, 0) ZEND_ARG_INFO(0, header_name) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpEnvResponse, isCachedByEtag) { char *header_name_str = NULL; size_t header_name_len = 0; if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|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, get_request(getThis()))); } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_setThrottleRate, 0, 0, 1) ZEND_ARG_INFO(0, chunk_size) ZEND_ARG_INFO(0, delay) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpEnvResponse, setThrottleRate) { zend_long chunk_size; double delay = 1; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "l|d", &chunk_size, &delay), invalid_arg, return); set_option(getThis(), ZEND_STRL("throttleDelay"), IS_DOUBLE, &delay, 0); set_option(getThis(), ZEND_STRL("throttleChunk"), IS_LONG, &chunk_size, 0); RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_setCookie, 0, 0, 1) ZEND_ARG_INFO(0, cookie) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpEnvResponse, setCookie) { zval *zcookie_new, tmp; zend_string *zs; zend_error_handling zeh; php_http_cookie_list_t *list = NULL; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "z", &zcookie_new), invalid_arg, return); zend_replace_error_handling(EH_THROW, php_http_get_exception_unexpected_val_class_entry(), &zeh); switch (Z_TYPE_P(zcookie_new)) { case IS_OBJECT: if (instanceof_function(Z_OBJCE_P(zcookie_new), php_http_cookie_get_class_entry())) { Z_ADDREF_P(zcookie_new); break; } /* no break */ case IS_ARRAY: list = php_http_cookie_list_from_struct(NULL, zcookie_new); zcookie_new = &tmp; ZVAL_OBJECT(zcookie_new, &php_http_cookie_object_new_ex(php_http_cookie_get_class_entry(), list)->zo, 0); break; default: zs = zval_get_string(zcookie_new); list = php_http_cookie_list_parse(NULL, zs->val, zs->len, 0, NULL); zend_string_release(zs); zcookie_new = &tmp; ZVAL_OBJECT(zcookie_new, &php_http_cookie_object_new_ex(php_http_cookie_get_class_entry(), list)->zo, 0); } zend_restore_error_handling(&zeh); set_cookie(getThis(), zcookie_new); zval_ptr_dtor(zcookie_new); RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_send, 0, 0, 0) ZEND_ARG_INFO(0, stream) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpEnvResponse, send) { zval *zstream = NULL; php_stream *s = NULL; if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|r", &zstream)) { /* first flush the output layer to avoid conflicting headers and output; * also, ob_start($thisEnvResponse) might have been called */ php_output_end_all(); if (zstream) { php_http_env_response_t *r; php_stream_from_zval(s, zstream); r = php_http_env_response_init(NULL, getThis(), php_http_env_response_get_stream_ops(), s); if (!r) { RETURN_FALSE; } RETVAL_BOOL(SUCCESS == php_http_env_response_send(r)); php_http_env_response_free(&r); } else { php_http_env_response_t r; if (!php_http_env_response_init(&r, getThis(), NULL, NULL)) { RETURN_FALSE; } RETVAL_BOOL(SUCCESS == php_http_env_response_send(&r)); php_http_env_response_dtor(&r); } } } static zend_function_entry php_http_env_response_methods[] = { PHP_ME(HttpEnvResponse, __construct, ai_HttpEnvResponse___construct, ZEND_ACC_PUBLIC) PHP_ME(HttpEnvResponse, __invoke, ai_HttpEnvResponse___invoke, ZEND_ACC_PUBLIC) PHP_ME(HttpEnvResponse, setEnvRequest, ai_HttpEnvResponse_setEnvRequest, ZEND_ACC_PUBLIC) PHP_ME(HttpEnvResponse, setCookie, ai_HttpEnvResponse_setCookie, ZEND_ACC_PUBLIC) PHP_ME(HttpEnvResponse, setContentType, ai_HttpEnvResponse_setContentType, ZEND_ACC_PUBLIC) PHP_ME(HttpEnvResponse, setContentDisposition, ai_HttpEnvResponse_setContentDisposition, ZEND_ACC_PUBLIC) PHP_ME(HttpEnvResponse, setContentEncoding, ai_HttpEnvResponse_setContentEncoding, ZEND_ACC_PUBLIC) PHP_ME(HttpEnvResponse, setCacheControl, ai_HttpEnvResponse_setCacheControl, ZEND_ACC_PUBLIC) PHP_ME(HttpEnvResponse, setLastModified, ai_HttpEnvResponse_setLastModified, ZEND_ACC_PUBLIC) PHP_ME(HttpEnvResponse, isCachedByLastModified, ai_HttpEnvResponse_isCachedByLastModified, ZEND_ACC_PUBLIC) PHP_ME(HttpEnvResponse, setEtag, ai_HttpEnvResponse_setEtag, ZEND_ACC_PUBLIC) PHP_ME(HttpEnvResponse, isCachedByEtag, ai_HttpEnvResponse_isCachedByEtag, ZEND_ACC_PUBLIC) PHP_ME(HttpEnvResponse, setThrottleRate, ai_HttpEnvResponse_setThrottleRate, ZEND_ACC_PUBLIC) PHP_ME(HttpEnvResponse, send, ai_HttpEnvResponse_send, ZEND_ACC_PUBLIC) EMPTY_FUNCTION_ENTRY }; static zend_class_entry *php_http_env_response_class_entry; zend_class_entry *php_http_get_env_response_class_entry(void) { return php_http_env_response_class_entry; } PHP_MINIT_FUNCTION(http_env_response) { zend_class_entry ce = {0}; INIT_NS_CLASS_ENTRY(ce, "http\\Env", "Response", php_http_env_response_methods); php_http_env_response_class_entry = zend_register_internal_class_ex(&ce, php_http_message_get_class_entry()); zend_declare_class_constant_long(php_http_env_response_class_entry, ZEND_STRL("CONTENT_ENCODING_NONE"), PHP_HTTP_CONTENT_ENCODING_NONE); zend_declare_class_constant_long(php_http_env_response_class_entry, ZEND_STRL("CONTENT_ENCODING_GZIP"), PHP_HTTP_CONTENT_ENCODING_GZIP); zend_declare_class_constant_long(php_http_env_response_class_entry, ZEND_STRL("CACHE_NO"), PHP_HTTP_CACHE_NO); zend_declare_class_constant_long(php_http_env_response_class_entry, ZEND_STRL("CACHE_HIT"), PHP_HTTP_CACHE_HIT); zend_declare_class_constant_long(php_http_env_response_class_entry, ZEND_STRL("CACHE_MISS"), PHP_HTTP_CACHE_MISS); zend_declare_property_null(php_http_env_response_class_entry, ZEND_STRL("request"), ZEND_ACC_PROTECTED); zend_declare_property_null(php_http_env_response_class_entry, ZEND_STRL("cookies"), ZEND_ACC_PROTECTED); zend_declare_property_null(php_http_env_response_class_entry, ZEND_STRL("contentType"), ZEND_ACC_PROTECTED); zend_declare_property_null(php_http_env_response_class_entry, ZEND_STRL("contentDisposition"), ZEND_ACC_PROTECTED); zend_declare_property_null(php_http_env_response_class_entry, ZEND_STRL("contentEncoding"), ZEND_ACC_PROTECTED); zend_declare_property_null(php_http_env_response_class_entry, ZEND_STRL("cacheControl"), ZEND_ACC_PROTECTED); zend_declare_property_null(php_http_env_response_class_entry, ZEND_STRL("etag"), ZEND_ACC_PROTECTED); zend_declare_property_null(php_http_env_response_class_entry, ZEND_STRL("lastModified"), ZEND_ACC_PROTECTED); zend_declare_property_null(php_http_env_response_class_entry, ZEND_STRL("throttleDelay"), ZEND_ACC_PROTECTED); zend_declare_property_null(php_http_env_response_class_entry, ZEND_STRL("throttleChunk"), ZEND_ACC_PROTECTED); 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 */ pecl_http-4.2.1/src/php_http_env_response.h0000644000076500000240000000634014117626035017634 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_HTTP_ENV_RESPONSE_H #define PHP_HTTP_ENV_RESPONSE_H typedef struct php_http_env_response php_http_env_response_t; typedef struct php_http_env_response_ops { ZEND_RESULT_CODE (*init)(php_http_env_response_t *r, void *arg); void (*dtor)(php_http_env_response_t *r); long (*get_status)(php_http_env_response_t *r); ZEND_RESULT_CODE (*set_status)(php_http_env_response_t *r, long http_code); ZEND_RESULT_CODE (*set_protocol_version)(php_http_env_response_t *r, php_http_version_t *v); ZEND_RESULT_CODE (*set_header)(php_http_env_response_t *r, const char *fmt, ...); ZEND_RESULT_CODE (*add_header)(php_http_env_response_t *r, const char *fmt, ...); ZEND_RESULT_CODE (*del_header)(php_http_env_response_t *r, const char *header_str, size_t header_len); ZEND_RESULT_CODE (*write)(php_http_env_response_t *r, const char *data_str, size_t data_len); ZEND_RESULT_CODE (*flush)(php_http_env_response_t *r); ZEND_RESULT_CODE (*finish)(php_http_env_response_t *r); } php_http_env_response_ops_t; PHP_HTTP_API php_http_env_response_ops_t *php_http_env_response_get_sapi_ops(void); PHP_HTTP_API php_http_env_response_ops_t *php_http_env_response_get_stream_ops(void); struct php_http_env_response { void *ctx; php_http_env_response_ops_t *ops; php_http_cookie_list_t *cookies; php_http_buffer_t *buffer; zval options; struct { size_t chunk; double delay; } throttle; struct { php_http_range_status_t status; HashTable values; char boundary[32]; } range; struct { size_t length; char *type; char *encoding; php_http_encoding_stream_t *encoder; } content; zend_bool done; }; PHP_HTTP_API php_http_env_response_t *php_http_env_response_init(php_http_env_response_t *r, zval *options, php_http_env_response_ops_t *ops, void *ops_ctx); PHP_HTTP_API ZEND_RESULT_CODE php_http_env_response_send(php_http_env_response_t *r); PHP_HTTP_API void php_http_env_response_dtor(php_http_env_response_t *r); PHP_HTTP_API void php_http_env_response_free(php_http_env_response_t **r); PHP_HTTP_API php_http_cache_status_t php_http_env_is_response_cached_by_etag(zval *options, const char *header_str, size_t header_len, php_http_message_t *request); PHP_HTTP_API php_http_cache_status_t php_http_env_is_response_cached_by_last_modified(zval *options, const char *header_str, size_t header_len, php_http_message_t *request); PHP_HTTP_API zend_class_entry *php_http_get_env_response_class_entry(); PHP_MINIT_FUNCTION(http_env_response); #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 */ pecl_http-4.2.1/src/php_http_etag.c0000644000076500000240000000354414117626035016044 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #include "php_http_api.h" #include "ext/hash/php_hash.h" #include "ext/standard/crc32.h" #include "ext/standard/sha1.h" #include "ext/standard/md5.h" #if PHP_VERSION_ID >= 80100 # define HASH_INIT_ARGS ,NULL #else # define HASH_INIT_ARGS #endif php_http_etag_t *php_http_etag_init(const char *mode) { php_http_etag_t *e; zend_string *mode_str = zend_string_init(mode, strlen(mode), 0); const php_hash_ops *eho = php_hash_fetch_ops(mode_str); if (!eho) { zend_string_release(mode_str); return NULL; } zend_string_release(mode_str); e = emalloc(sizeof(*e) + eho->context_size - 1); e->ops = eho; eho->hash_init(e->ctx HASH_INIT_ARGS); return e; } char *php_http_etag_finish(php_http_etag_t *e) { unsigned char digest[128] = {0}; char *etag; e->ops->hash_final(digest, e->ctx); etag = php_http_etag_digest(digest, e->ops->digest_size); efree(e); return etag; } size_t php_http_etag_update(php_http_etag_t *e, const char *data_ptr, size_t data_len) { e->ops->hash_update(e->ctx, (const unsigned char *) data_ptr, data_len); return data_len; } /* * 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 */ pecl_http-4.2.1/src/php_http_etag.h0000644000076500000240000000306614117626035016050 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_HTTP_ETAG_H #define PHP_HTTP_ETAG_H #include "ext/hash/php_hash.h" typedef struct php_http_etag { const php_hash_ops *ops; char ctx[1]; } php_http_etag_t; PHP_HTTP_API php_http_etag_t *php_http_etag_init(const char *mode); PHP_HTTP_API size_t php_http_etag_update(php_http_etag_t *e, const char *data_ptr, size_t data_len); PHP_HTTP_API char *php_http_etag_finish(php_http_etag_t *e); 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 */ /* * 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 */ pecl_http-4.2.1/src/php_http_exception.c0000644000076500000240000001445514117626035017125 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #include "php_http_api.h" #include "ext/spl/spl_exceptions.h" #ifndef PHP_HTTP_DBG_EXCEPTIONS # define PHP_HTTP_DBG_EXCEPTIONS 0 #endif #if PHP_HTTP_DBG_EXCEPTIONS static void php_http_exception_hook(zval *ex) { if (ex) { zval *m = zend_read_property(Z_OBJCE_P(ex), ex, "message", lenof("message"), 0); fprintf(stderr, "*** Threw exception '%s'\n", Z_STRVAL_P(m)); } else { fprintf(stderr, "*** Threw NULL exception\n"); } } #endif static zend_class_entry *php_http_exception_interface_class_entry; zend_class_entry *php_http_get_exception_interface_class_entry(void) { return php_http_exception_interface_class_entry; } static zend_class_entry *php_http_exception_runtime_class_entry; zend_class_entry *php_http_get_exception_runtime_class_entry(void) { return php_http_exception_runtime_class_entry; } static zend_class_entry *php_http_exception_unexpected_val_class_entry; zend_class_entry *php_http_get_exception_unexpected_val_class_entry(void) { return php_http_exception_unexpected_val_class_entry; } static zend_class_entry *php_http_exception_bad_method_call_class_entry; zend_class_entry *php_http_get_exception_bad_method_call_class_entry(void) { return php_http_exception_bad_method_call_class_entry; } static zend_class_entry *php_http_exception_invalid_arg_class_entry; zend_class_entry *php_http_get_exception_invalid_arg_class_entry(void) { return php_http_exception_invalid_arg_class_entry; } static zend_class_entry *php_http_exception_bad_header_class_entry; zend_class_entry *php_http_get_exception_bad_header_class_entry(void) { return php_http_exception_bad_header_class_entry; } static zend_class_entry *php_http_exception_bad_url_class_entry; zend_class_entry *php_http_get_exception_bad_url_class_entry(void) { return php_http_exception_bad_url_class_entry; } static zend_class_entry *php_http_exception_bad_message_class_entry; zend_class_entry *php_http_get_exception_bad_message_class_entry(void) { return php_http_exception_bad_message_class_entry; } static zend_class_entry *php_http_exception_bad_conversion_class_entry; zend_class_entry *php_http_get_exception_bad_conversion_class_entry(void) { return php_http_exception_bad_conversion_class_entry; } static zend_class_entry *php_http_exception_bad_querystring_class_entry; zend_class_entry *php_http_get_exception_bad_querystring_class_entry(void) { return php_http_exception_bad_querystring_class_entry; } PHP_MINIT_FUNCTION(http_exception) { zend_class_entry *cep, ce = {0}; INIT_NS_CLASS_ENTRY(ce, "http", "Exception", NULL); php_http_exception_interface_class_entry = zend_register_internal_interface(&ce); /* * Would be great to only have a few exceptions and rather more identifying * error codes, but zend_replace_error_handling() does not accept any codes. */ memset(&ce, 0, sizeof(ce)); INIT_NS_CLASS_ENTRY(ce, "http\\Exception", "RuntimeException", NULL); cep = zend_register_internal_class_ex(&ce, spl_ce_RuntimeException); zend_class_implements(cep, 1, php_http_exception_interface_class_entry); php_http_exception_runtime_class_entry = cep; memset(&ce, 0, sizeof(ce)); INIT_NS_CLASS_ENTRY(ce, "http\\Exception", "UnexpectedValueException", NULL); cep = zend_register_internal_class_ex(&ce, spl_ce_UnexpectedValueException); zend_class_implements(cep, 1, php_http_exception_interface_class_entry); php_http_exception_unexpected_val_class_entry = cep; memset(&ce, 0, sizeof(ce)); INIT_NS_CLASS_ENTRY(ce, "http\\Exception", "BadMethodCallException", NULL); cep = zend_register_internal_class_ex(&ce, spl_ce_BadMethodCallException); zend_class_implements(cep, 1, php_http_exception_interface_class_entry); php_http_exception_bad_method_call_class_entry = cep; memset(&ce, 0, sizeof(ce)); INIT_NS_CLASS_ENTRY(ce, "http\\Exception", "InvalidArgumentException", NULL); cep = zend_register_internal_class_ex(&ce, spl_ce_InvalidArgumentException); zend_class_implements(cep, 1, php_http_exception_interface_class_entry); php_http_exception_invalid_arg_class_entry = cep; memset(&ce, 0, sizeof(ce)); INIT_NS_CLASS_ENTRY(ce, "http\\Exception", "BadHeaderException", NULL); cep = zend_register_internal_class_ex(&ce, spl_ce_DomainException); zend_class_implements(cep, 1, php_http_exception_interface_class_entry); php_http_exception_bad_header_class_entry = cep; memset(&ce, 0, sizeof(ce)); INIT_NS_CLASS_ENTRY(ce, "http\\Exception", "BadUrlException", NULL); cep = zend_register_internal_class_ex(&ce, spl_ce_DomainException); zend_class_implements(cep, 1, php_http_exception_interface_class_entry); php_http_exception_bad_url_class_entry = cep; memset(&ce, 0, sizeof(ce)); INIT_NS_CLASS_ENTRY(ce, "http\\Exception", "BadMessageException", NULL); cep = zend_register_internal_class_ex(&ce, spl_ce_DomainException); zend_class_implements(cep, 1, php_http_exception_interface_class_entry); php_http_exception_bad_message_class_entry = cep; memset(&ce, 0, sizeof(ce)); INIT_NS_CLASS_ENTRY(ce, "http\\Exception", "BadConversionException", NULL); cep = zend_register_internal_class_ex(&ce, spl_ce_DomainException); zend_class_implements(cep, 1, php_http_exception_interface_class_entry); php_http_exception_bad_conversion_class_entry = cep; memset(&ce, 0, sizeof(ce)); INIT_NS_CLASS_ENTRY(ce, "http\\Exception", "BadQueryStringException", NULL); cep = zend_register_internal_class_ex(&ce, spl_ce_DomainException); zend_class_implements(cep, 1, php_http_exception_interface_class_entry); php_http_exception_bad_querystring_class_entry = cep; #if PHP_HTTP_DBG_EXCEPTIONS zend_throw_exception_hook = php_http_exception_hook; #endif return SUCCESS; } /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ pecl_http-4.2.1/src/php_http_exception.h0000644000076500000240000000441414117626035017124 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_HTTP_EXCEPTION_H #define PHP_HTTP_EXCEPTION_H /* short hand for zend_throw_exception_ex */ #define php_http_throw(e, ...) \ zend_throw_exception_ex(php_http_get_exception_ ##e## _class_entry(), 0, __VA_ARGS__) /* wrap a call with replaced zend_error_handling */ #define php_http_expect(test, e, fail) \ do { \ zend_error_handling __zeh; \ zend_replace_error_handling(EH_THROW, php_http_get_exception_ ##e## _class_entry(), &__zeh); \ if (UNEXPECTED(!(test))) { \ zend_restore_error_handling(&__zeh); \ fail; \ } \ zend_restore_error_handling(&__zeh); \ } while(0) PHP_HTTP_API zend_class_entry *php_http_get_exception_interface_class_entry(void); PHP_HTTP_API zend_class_entry *php_http_get_exception_runtime_class_entry(void); PHP_HTTP_API zend_class_entry *php_http_get_exception_unexpected_val_class_entry(void); PHP_HTTP_API zend_class_entry *php_http_get_exception_bad_method_call_class_entry(void); PHP_HTTP_API zend_class_entry *php_http_get_exception_invalid_arg_class_entry(void); PHP_HTTP_API zend_class_entry *php_http_get_exception_bad_header_class_entry(void); PHP_HTTP_API zend_class_entry *php_http_get_exception_bad_url_class_entry(void); PHP_HTTP_API zend_class_entry *php_http_get_exception_bad_message_class_entry(void); PHP_HTTP_API zend_class_entry *php_http_get_exception_bad_conversion_class_entry(void); PHP_HTTP_API zend_class_entry *php_http_get_exception_bad_querystring_class_entry(void); 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 */ pecl_http-4.2.1/src/php_http_filter.c0000644000076500000240000003200714117626035016405 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #include "php_http_api.h" #ifndef DBG_FILTER # define DBG_FILTER 0 #endif PHP_MINIT_FUNCTION(http_filter) { php_stream_filter_register_factory("http.*", &php_http_filter_factory); 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 #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) #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 PHP_HTTP_FILTER_IS_CLOSING(stream, flags) \ ( (flags & PSFS_FLAG_FLUSH_CLOSE) \ || php_stream_eof(stream) \ || ((stream->ops == &php_stream_temp_ops || stream->ops == &php_stream_memory_ops) && stream->eof) \ ) #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); \ if (!__buck) { \ pefree(__data, this->is_persistent); \ return PSFS_ERR_FATAL; \ } \ \ php_stream_bucket_append(buckets_out, __buck); \ } typedef struct _http_chunked_decode_filter_buffer_t { php_http_buffer_t buffer; unsigned long hexlen; } PHP_HTTP_FILTER_BUFFER(chunked_decode); typedef php_http_encoding_stream_t PHP_HTTP_FILTER_BUFFER(stream); static PHP_HTTP_FILTER_FUNCTION(chunked_decode) { int out_avail = 0; php_stream_bucket *ptr, *nxt; PHP_HTTP_FILTER_BUFFER(chunked_decode) *buffer = Z_PTR(this->abstract); if (bytes_consumed) { *bytes_consumed = 0; } /* fetch available bucket data */ for (ptr = buckets_in->head; ptr; ptr = nxt) { 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; } nxt = ptr->next; php_stream_bucket_unlink(ptr); php_stream_bucket_delref(ptr); } if (!php_http_buffer_fix(PHP_HTTP_BUFFER(buffer))) { return PSFS_ERR_FATAL; } /* we have data in our buffer */ while (PHP_HTTP_BUFFER(buffer)->used) { /* we already know the size of the chunk and are waiting for data */ if (buffer->hexlen) { /* not enough data buffered */ if (PHP_HTTP_BUFFER(buffer)->used < 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(buffer)->data, PHP_HTTP_BUFFER(buffer)->used); /* waiting for less data now */ buffer->hexlen -= PHP_HTTP_BUFFER(buffer)->used; /* 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(buffer)->data, 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(buffer)->used && ( PHP_HTTP_BUFFER(buffer)->data[off] == '\n' || PHP_HTTP_BUFFER(buffer)->data[off] == '\r')) { ++off; } if (off) { php_http_buffer_cut(PHP_HTTP_BUFFER(buffer), 0, off); } /* still data there? */ if (PHP_HTTP_BUFFER(buffer)->used) { 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(buffer)->data, PHP_HTTP_BUFFER(buffer)->used, &eollen))) { char *stop = NULL; /* read in chunk size */ buffer->hexlen = strtoul(PHP_HTTP_BUFFER(buffer)->data, &stop, 16); /* if strtoul() stops at the beginning of the buffered data there's something oddly wrong, i.e. bad input */ if (stop == PHP_HTTP_BUFFER(buffer)->data) { return PSFS_ERR_FATAL; } /* cut out */ php_http_buffer_cut(PHP_HTTP_BUFFER(buffer), 0, eolstr + eollen - PHP_HTTP_BUFFER(buffer)->data); /* buffer->hexlen is 0 now or contains the size of the next chunk */ if (!buffer->hexlen) { php_stream_notify_info(PHP_STREAM_CONTEXT(stream), 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 (PHP_HTTP_FILTER_IS_CLOSING(stream, flags) && buffer->hexlen && PHP_HTTP_BUFFER(buffer)->used) { out_avail = 1; NEW_BUCKET(PHP_HTTP_BUFFER(buffer)->data, PHP_HTTP_BUFFER(buffer)->used); 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 = Z_PTR(this->abstract); php_http_buffer_dtor(PHP_HTTP_BUFFER(b)); pefree(b, this->is_persistent); } static PHP_HTTP_FILTER_FUNCTION(chunked_encode) { php_http_buffer_t buf; php_stream_bucket *ptr, *nxt; if (bytes_consumed) { *bytes_consumed = 0; } /* new data available? */ php_http_buffer_init(&buf); /* fetch available bucket data */ for (ptr = buckets_in->head; ptr; ptr = nxt) { if (bytes_consumed) { *bytes_consumed += ptr->buflen; } #if DBG_FILTER fprintf(stderr, "update: chunked (-> %zu) (w: %zu, r: %zu)\n", ptr->buflen, stream->writepos, stream->readpos); #endif nxt = ptr->next; php_stream_bucket_unlink(ptr); php_http_buffer_appendf(&buf, "%lx" PHP_HTTP_CRLF, (long unsigned int) ptr->buflen); php_http_buffer_append(&buf, ptr->buf, ptr->buflen); php_http_buffer_appends(&buf, PHP_HTTP_CRLF); /* pass through */ NEW_BUCKET(buf.data, buf.used); /* reset */ php_http_buffer_reset(&buf); php_stream_bucket_delref(ptr); } /* free buffer */ php_http_buffer_dtor(&buf); /* terminate with "0" */ if (PHP_HTTP_FILTER_IS_CLOSING(stream, flags)) { #if DBG_FILTER fprintf(stderr, "finish: chunked\n"); #endif NEW_BUCKET("0" PHP_HTTP_CRLF PHP_HTTP_CRLF, lenof("0" PHP_HTTP_CRLF PHP_HTTP_CRLF)); } return PSFS_PASS_ON; } static PHP_HTTP_FILTER_FUNCTION(stream) { php_stream_bucket *ptr, *nxt; PHP_HTTP_FILTER_BUFFER(stream) *buffer = Z_PTR(this->abstract); if (bytes_consumed) { *bytes_consumed = 0; } /* fetch available bucket data */ for (ptr = buckets_in->head; ptr; ptr = nxt) { char *encoded = NULL; size_t encoded_len = 0; if (bytes_consumed) { *bytes_consumed += ptr->buflen; } #if DBG_FILTER fprintf(stderr, "bucket: b=%p p=%p p=%p\n", ptr->brigade, ptr->prev, ptr->next); #endif nxt = ptr->next; php_stream_bucket_unlink(ptr); if (SUCCESS != php_http_encoding_stream_update(buffer, ptr->buf, ptr->buflen, &encoded, &encoded_len)) { return PSFS_ERR_FATAL; } #if DBG_FILTER fprintf(stderr, "update: compress (-> %zu) (w: %zu, r: %zu)\n", encoded_len, stream->writepos, stream->readpos); #endif if (encoded) { if (encoded_len) { NEW_BUCKET(encoded, encoded_len); } efree(encoded); } php_stream_bucket_delref(ptr); } /* flush & close */ if (flags & PSFS_FLAG_FLUSH_INC) { char *encoded = NULL; size_t encoded_len = 0; if (SUCCESS != php_http_encoding_stream_flush(buffer, &encoded, &encoded_len)) { return PSFS_ERR_FATAL; } #if DBG_FILTER fprintf(stderr, "flush: compress (-> %zu)\n", encoded_len); #endif if (encoded) { if (encoded_len) { NEW_BUCKET(encoded, encoded_len); } efree(encoded); } } if (PHP_HTTP_FILTER_IS_CLOSING(stream, flags)) { char *encoded = NULL; size_t encoded_len = 0; if (SUCCESS != php_http_encoding_stream_finish(buffer, &encoded, &encoded_len)) { return PSFS_ERR_FATAL; } #if DBG_FILTER fprintf(stderr, "finish: compress (-> %zu)\n", encoded_len); #endif if (encoded) { if (encoded_len) { NEW_BUCKET(encoded, encoded_len); } efree(encoded); } } return PSFS_PASS_ON; } static PHP_HTTP_FILTER_DESTRUCTOR(stream) { PHP_HTTP_FILTER_BUFFER(stream) *buffer = Z_PTR(this->abstract); php_http_encoding_stream_free(&buffer); } static PHP_HTTP_FILTER_OPS(chunked_decode) = { PHP_HTTP_FILTER_FUNC(chunked_decode), PHP_HTTP_FILTER_DTOR(chunked_decode), "http.chunked_decode" }; static PHP_HTTP_FILTER_OPS(chunked_encode) = { PHP_HTTP_FILTER_FUNC(chunked_encode), NULL, "http.chunked_encode" }; static PHP_HTTP_FILTER_OPS(deflate) = { PHP_HTTP_FILTER_FUNC(stream), PHP_HTTP_FILTER_DTOR(stream), "http.deflate" }; static PHP_HTTP_FILTER_OPS(inflate) = { PHP_HTTP_FILTER_FUNC(stream), PHP_HTTP_FILTER_DTOR(stream), "http.inflate" }; #if PHP_HTTP_HAVE_LIBBROTLI static PHP_HTTP_FILTER_OPS(brotli_encode) = { PHP_HTTP_FILTER_FUNC(stream), PHP_HTTP_FILTER_DTOR(stream), "http.brotli_encode" }; static PHP_HTTP_FILTER_OPS(brotli_decode) = { PHP_HTTP_FILTER_FUNC(stream), PHP_HTTP_FILTER_DTOR(stream), "http.brotli_decode" }; #endif #if PHP_VERSION_ID >= 70200 static php_stream_filter *http_filter_create(const char *name, zval *params, uint8_t p) #else static php_stream_filter *http_filter_create(const char *name, zval *params, int p) #endif { zval *tmp = params; php_stream_filter *f = NULL; int flags = p ? PHP_HTTP_ENCODING_STREAM_PERSISTENT : 0; if (params) { switch (Z_TYPE_P(params)) { case IS_ARRAY: case IS_OBJECT: if (!(tmp = zend_hash_str_find_ind(HASH_OF(params), ZEND_STRL("flags")))) { break; } /* no break */ default: flags |= zval_get_long(tmp) & 0x0fffffff; break; } } 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")) { PHP_HTTP_FILTER_BUFFER(stream) *b = NULL; if ((b = php_http_encoding_stream_init(NULL, php_http_encoding_stream_get_inflate_ops(), flags))) { if (!(f = php_stream_filter_alloc(&PHP_HTTP_FILTER_OP(inflate), b, p))) { php_http_encoding_stream_free(&b); } } } else if (!strcasecmp(name, "http.deflate")) { PHP_HTTP_FILTER_BUFFER(stream) *b = NULL; if ((b = php_http_encoding_stream_init(NULL, php_http_encoding_stream_get_deflate_ops(), flags))) { if (!(f = php_stream_filter_alloc(&PHP_HTTP_FILTER_OP(deflate), b, p))) { php_http_encoding_stream_free(&b); } } #if PHP_HTTP_HAVE_LIBBROTLI } else if (!strcasecmp(name, "http.brotli_encode")) { PHP_HTTP_FILTER_BUFFER(stream) *b = NULL; if ((b = php_http_encoding_stream_init(NULL, php_http_encoding_stream_get_enbrotli_ops(), flags))) { if (!(f = php_stream_filter_alloc(&PHP_HTTP_FILTER_OP(brotli_encode), b, p))) { php_http_encoding_stream_free(&b); } } } else if (!strcasecmp(name, "http.brotli_decode")) { PHP_HTTP_FILTER_BUFFER(stream) *b = NULL; if ((b = php_http_encoding_stream_init(NULL, php_http_encoding_stream_get_debrotli_ops(), flags))) { if (!(f = php_stream_filter_alloc(&PHP_HTTP_FILTER_OP(brotli_decode), b, p))) { php_http_encoding_stream_free(&b); } } #endif } return f; } 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 */ pecl_http-4.2.1/src/php_http_filter.h0000644000076500000240000000172214117626035016412 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_HTTP_FILTER_H #define PHP_HTTP_FILTER_H PHP_HTTP_API 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 */ pecl_http-4.2.1/src/php_http_header_parser.c0000644000076500000240000004225014117626035017725 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #include "php_http_api.h" #ifndef DBG_PARSER # define DBG_PARSER 0 #endif 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_VALUE_EX, 0}, {PHP_HTTP_HEADER_PARSER_STATE_HEADER_DONE, 0}, {PHP_HTTP_HEADER_PARSER_STATE_DONE, 0} }; php_http_header_parser_t *php_http_header_parser_init(php_http_header_parser_t *parser) { if (!parser) { parser = emalloc(sizeof(*parser)); } memset(parser, 0, sizeof(*parser)); return parser; } static inline php_http_header_parser_state_t php_http_header_parser_state_push(php_http_header_parser_t *parser, php_http_header_parser_state_t state) { zend_ptr_stack_push(&(parser)->stack, (void *) (state)); return state; } #define php_http_header_parser_state_ex(parser) ((parser)->stack.top \ ? (php_http_header_parser_state_t) (parser)->stack.elements[(parser)->stack.top - 1] \ : PHP_HTTP_HEADER_PARSER_STATE_START) php_http_header_parser_state_t php_http_header_parser_state_is(php_http_header_parser_t *parser) { return php_http_header_parser_state_ex(parser); } #define php_http_header_parser_state_pop(parser) ((parser)->stack.top \ ? (php_http_header_parser_state_t) zend_ptr_stack_pop(&(parser)->stack) \ : PHP_HTTP_HEADER_PARSER_STATE_START) void php_http_header_parser_dtor(php_http_header_parser_t *parser) { zend_ptr_stack_destroy(&parser->stack); php_http_info_dtor(&parser->info); PTR_FREE(parser->_key.str); PTR_FREE(parser->_val.str); } void php_http_header_parser_free(php_http_header_parser_t **parser) { if (*parser) { php_http_header_parser_dtor(*parser); efree(*parser); *parser = NULL; } } /* NOTE: 'str' has to be null terminated */ static void php_http_header_parser_error(size_t valid_len, char *str, size_t len, const char *eol_str ) { zend_string *escaped_str, *zstr_str = zend_string_init(str, len, 0); #if PHP_VERSION_ID < 70300 escaped_str = php_addcslashes(zstr_str, 1, ZEND_STRL("\x0..\x1F\x7F..\xFF")); #else escaped_str = php_addcslashes(zstr_str, ZEND_STRL("\x0..\x1F\x7F..\xFF")); zend_string_release_ex(zstr_str, 0); #endif if (valid_len != len && (!eol_str || (str+valid_len) != eol_str)) { php_error_docref(NULL, E_WARNING, "Failed to parse headers: unexpected character '\\%03o' at pos %zu of '%s'", str[valid_len], valid_len, escaped_str->val); } else if (eol_str) { php_error_docref(NULL, E_WARNING, "Failed to parse headers: unexpected end of line at pos %zu of '%s'", eol_str - str, escaped_str->val); } else { php_error_docref(NULL, E_WARNING, "Failed to parse headers: unexpected end of input at pos %zu of '%s'", len, escaped_str->val); } efree(escaped_str); } php_http_header_parser_state_t php_http_header_parser_parse(php_http_header_parser_t *parser, php_http_buffer_t *buffer, unsigned flags, HashTable *headers, php_http_info_callback_t callback_func, void *callback_arg) { while (buffer->used || !php_http_header_parser_states[php_http_header_parser_state_ex(parser)].need_data) { #if DBG_PARSER const char *state[] = {"START", "KEY", "VALUE", "VALUE_EX", "HEADER_DONE", "DONE"}; fprintf(stderr, "#HP: %s (avail:%zu, num:%d cleanup:%u)\n", php_http_header_parser_state_is(parser) < 0 ? "FAILURE" : state[php_http_header_parser_state_is(parser)], buffer->used, headers?zend_hash_num_elements(headers):0, flags); _dpf(0, buffer->data, buffer->used); #endif switch (php_http_header_parser_state_pop(parser)) { case PHP_HTTP_HEADER_PARSER_STATE_FAILURE: php_error_docref(NULL, E_WARNING, "Failed to parse headers"); return php_http_header_parser_state_push(parser, 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, PHP_HTTP_HEADER_PARSER_STATE_KEY); break; } case PHP_HTTP_HEADER_PARSER_STATE_KEY: { const char *colon, *eol_str = NULL; int eol_len = 0; /* fix buffer here, so eol_str pointer doesn't become obsolete afterwards */ php_http_buffer_fix(buffer); 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, PHP_HTTP_HEADER_PARSER_STATE_DONE); } else if (php_http_info_parse(&parser->info, buffer->data)) { /* new message starting with request/response line */ if (callback_func) { callback_func(callback_arg, &headers, &parser->info); } 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, PHP_HTTP_HEADER_PARSER_STATE_HEADER_DONE); } else if ((colon = memchr(buffer->data, ':', buffer->used)) && (!eol_str || eol_str > colon)) { /* header: string */ size_t valid_len; parser->_key.len = colon - buffer->data; parser->_key.str = estrndup(buffer->data, parser->_key.len); valid_len = strspn(parser->_key.str, PHP_HTTP_HEADER_NAME_CHARS); if (valid_len != parser->_key.len) { php_http_header_parser_error(valid_len, parser->_key.str, parser->_key.len, eol_str); PTR_SET(parser->_key.str, NULL); return php_http_header_parser_state_push(parser, PHP_HTTP_HEADER_PARSER_STATE_FAILURE); } while (PHP_HTTP_IS_CTYPE(space, *++colon) && *colon != '\n' && *colon != '\r'); php_http_buffer_cut(buffer, 0, colon - buffer->data); php_http_header_parser_state_push(parser, PHP_HTTP_HEADER_PARSER_STATE_VALUE); } else if (eol_str || (flags & PHP_HTTP_HEADER_PARSER_CLEANUP)) { /* neither reqeust/response line nor 'header:' string, or injected new line or NUL etc. */ php_http_header_parser_error(strspn(buffer->data, PHP_HTTP_HEADER_NAME_CHARS), buffer->data, buffer->used, eol_str); return php_http_header_parser_state_push(parser, PHP_HTTP_HEADER_PARSER_STATE_FAILURE); } else { /* keep feeding */ return php_http_header_parser_state_push(parser, PHP_HTTP_HEADER_PARSER_STATE_KEY); } break; } case PHP_HTTP_HEADER_PARSER_STATE_VALUE: { const char *eol_str; int eol_len; #define SET_ADD_VAL(slen, eol_len) \ do { \ const char *ptr = buffer->data; \ size_t len = slen; \ \ while (len > 0 && PHP_HTTP_IS_CTYPE(space, *ptr)) { \ ++ptr; \ --len; \ } \ while (len > 0 && PHP_HTTP_IS_CTYPE(space, ptr[len - 1])) { \ --len; \ } \ \ if (len > 0) { \ if (parser->_val.str) { \ parser->_val.str = erealloc(parser->_val.str, parser->_val.len + len + 2); \ parser->_val.str[parser->_val.len++] = ' '; \ memcpy(&parser->_val.str[parser->_val.len], ptr, len); \ parser->_val.len += len; \ parser->_val.str[parser->_val.len] = '\0'; \ } else { \ parser->_val.len = len; \ parser->_val.str = estrndup(ptr, len); \ } \ } \ php_http_buffer_cut(buffer, 0, slen + eol_len); \ } while (0) if ((eol_str = php_http_locate_bin_eol(buffer->data, buffer->used, &eol_len))) { SET_ADD_VAL(eol_str - buffer->data, eol_len); php_http_header_parser_state_push(parser, PHP_HTTP_HEADER_PARSER_STATE_VALUE_EX); } else if (flags & PHP_HTTP_HEADER_PARSER_CLEANUP) { if (buffer->used) { SET_ADD_VAL(buffer->used, 0); } php_http_header_parser_state_push(parser, PHP_HTTP_HEADER_PARSER_STATE_HEADER_DONE); } else { return php_http_header_parser_state_push(parser, PHP_HTTP_HEADER_PARSER_STATE_VALUE); } break; } case PHP_HTTP_HEADER_PARSER_STATE_VALUE_EX: if (buffer->used && (*buffer->data == ' ' || *buffer->data == '\t')) { php_http_header_parser_state_push(parser, PHP_HTTP_HEADER_PARSER_STATE_VALUE); } else if (buffer->used || (flags & PHP_HTTP_HEADER_PARSER_CLEANUP)) { php_http_header_parser_state_push(parser, PHP_HTTP_HEADER_PARSER_STATE_HEADER_DONE); } else { /* keep feeding */ return php_http_header_parser_state_push(parser, PHP_HTTP_HEADER_PARSER_STATE_VALUE_EX); } break; case PHP_HTTP_HEADER_PARSER_STATE_HEADER_DONE: if (parser->_key.str && parser->_val.str) { zval tmp, *exist; size_t valid_len = strlen(parser->_val.str); /* check for truncation */ if (valid_len != parser->_val.len) { php_http_header_parser_error(valid_len, parser->_val.str, parser->_val.len, NULL); PTR_SET(parser->_key.str, NULL); PTR_SET(parser->_val.str, NULL); return php_http_header_parser_state_push(parser, PHP_HTTP_HEADER_PARSER_STATE_FAILURE); } if (!headers && callback_func) { callback_func(callback_arg, &headers, NULL); } php_http_pretty_key(parser->_key.str, parser->_key.len, 1, 1); if ((exist = zend_symtable_str_find(headers, parser->_key.str, parser->_key.len))) { convert_to_array(exist); add_next_index_str(exist, php_http_cs2zs(parser->_val.str, parser->_val.len)); } else { ZVAL_STR(&tmp, php_http_cs2zs(parser->_val.str, parser->_val.len)); zend_symtable_str_update(headers, parser->_key.str, parser->_key.len, &tmp); } parser->_val.str = NULL; } PTR_SET(parser->_key.str, NULL); PTR_SET(parser->_val.str, NULL); php_http_header_parser_state_push(parser, 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); } php_http_header_parser_state_t php_http_header_parser_parse_stream(php_http_header_parser_t *parser, php_http_buffer_t *buf, php_stream *s, unsigned flags, HashTable *headers, php_http_info_callback_t callback_func, void *callback_arg) { php_http_header_parser_state_t state = PHP_HTTP_HEADER_PARSER_STATE_START; if (!buf->data) { php_http_buffer_resize_ex(buf, 0x1000, 1, 0); } while (1) { size_t justread = 0; #if DBG_PARSER const char *states[] = {"START", "KEY", "VALUE", "VALUE_EX", "HEADER_DONE", "DONE"}; fprintf(stderr, "#SHP: %s (f:%u)\n", states[state], flags); #endif /* resize if needed */ if (buf->free < 0x1000) { php_http_buffer_resize_ex(buf, 0x1000, 1, 0); } switch (state) { case PHP_HTTP_HEADER_PARSER_STATE_FAILURE: case PHP_HTTP_HEADER_PARSER_STATE_DONE: return state; default: /* read line */ php_stream_get_line(s, buf->data + buf->used, buf->free, &justread); /* if we fail reading a whole line, try a single char */ if (!justread) { int c = php_stream_getc(s); if (c != EOF) { char s[1] = {c}; justread = php_http_buffer_append(buf, s, 1); } } php_http_buffer_account(buf, justread); } if (justread) { state = php_http_header_parser_parse(parser, buf, flags, headers, callback_func, callback_arg); } else if (php_stream_eof(s)) { return php_http_header_parser_parse(parser, buf, flags | PHP_HTTP_HEADER_PARSER_CLEANUP, headers, callback_func, callback_arg); } else { return state; } } return PHP_HTTP_HEADER_PARSER_STATE_DONE; } static zend_class_entry *php_http_header_parser_class_entry; zend_class_entry *php_http_get_header_parser_class_entry(void) { return php_http_header_parser_class_entry; } static zend_object_handlers php_http_header_parser_object_handlers; zend_object *php_http_header_parser_object_new(zend_class_entry *ce) { return &php_http_header_parser_object_new_ex(ce, NULL)->zo; } php_http_header_parser_object_t *php_http_header_parser_object_new_ex(zend_class_entry *ce, php_http_header_parser_t *parser) { php_http_header_parser_object_t *o; o = ecalloc(1, sizeof(php_http_header_parser_object_t) + zend_object_properties_size(ce)); zend_object_std_init(&o->zo, ce); object_properties_init(&o->zo, ce); if (parser) { o->parser = parser; } else { o->parser = php_http_header_parser_init(NULL); } o->buffer = php_http_buffer_new(); o->zo.handlers = &php_http_header_parser_object_handlers; return o; } void php_http_header_parser_object_free(zend_object *object) { php_http_header_parser_object_t *o = PHP_HTTP_OBJ(object, NULL); if (o->parser) { php_http_header_parser_free(&o->parser); } if (o->buffer) { php_http_buffer_free(&o->buffer); } zend_object_std_dtor(object); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpHeaderParser_getState, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpHeaderParser, getState) { php_http_header_parser_object_t *parser_obj = PHP_HTTP_OBJ(NULL, getThis()); zend_parse_parameters_none(); /* always return the real state */ RETVAL_LONG(php_http_header_parser_state_is(parser_obj->parser)); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpHeaderParser_parse, 0, 0, 3) ZEND_ARG_INFO(0, data) ZEND_ARG_INFO(0, flags) ZEND_ARG_ARRAY_INFO(1, headers, 1) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpHeaderParser, parse) { php_http_header_parser_object_t *parser_obj; zval *zmsg; char *data_str; size_t data_len; zend_long flags; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "slz", &data_str, &data_len, &flags, &zmsg), invalid_arg, return); ZVAL_DEREF(zmsg); if (Z_TYPE_P(zmsg) != IS_ARRAY) { zval_dtor(zmsg); array_init(zmsg); } parser_obj = PHP_HTTP_OBJ(NULL, getThis()); php_http_buffer_append(parser_obj->buffer, data_str, data_len); RETVAL_LONG(php_http_header_parser_parse(parser_obj->parser, parser_obj->buffer, flags, Z_ARRVAL_P(zmsg), NULL, NULL)); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpHeaderParser_stream, 0, 0, 3) ZEND_ARG_INFO(0, stream) ZEND_ARG_INFO(0, flags) ZEND_ARG_ARRAY_INFO(1, headers, 1) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpHeaderParser, stream) { php_http_header_parser_object_t *parser_obj; zend_error_handling zeh; zval *zmsg, *zstream; php_stream *s; zend_long flags; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "rlz", &zstream, &flags, &zmsg), invalid_arg, return); zend_replace_error_handling(EH_THROW, php_http_get_exception_unexpected_val_class_entry(), &zeh); php_stream_from_zval(s, zstream); zend_restore_error_handling(&zeh); ZVAL_DEREF(zmsg); if (Z_TYPE_P(zmsg) != IS_ARRAY) { zval_dtor(zmsg); array_init(zmsg); } parser_obj = PHP_HTTP_OBJ(NULL, getThis()); RETVAL_LONG(php_http_header_parser_parse_stream(parser_obj->parser, parser_obj->buffer, s, flags, Z_ARRVAL_P(zmsg), NULL, NULL)); } static zend_function_entry php_http_header_parser_methods[] = { PHP_ME(HttpHeaderParser, getState, ai_HttpHeaderParser_getState, ZEND_ACC_PUBLIC) PHP_ME(HttpHeaderParser, parse, ai_HttpHeaderParser_parse, ZEND_ACC_PUBLIC) PHP_ME(HttpHeaderParser, stream, ai_HttpHeaderParser_stream, ZEND_ACC_PUBLIC) {0} }; PHP_MINIT_FUNCTION(http_header_parser) { zend_class_entry ce; INIT_NS_CLASS_ENTRY(ce, "http\\Header", "Parser", php_http_header_parser_methods); php_http_header_parser_class_entry = zend_register_internal_class(&ce); memcpy(&php_http_header_parser_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); php_http_header_parser_class_entry->create_object = php_http_header_parser_object_new; php_http_header_parser_object_handlers.offset = XtOffsetOf(php_http_header_parser_object_t, zo); php_http_header_parser_object_handlers.clone_obj = NULL; php_http_header_parser_object_handlers.free_obj = php_http_header_parser_object_free; zend_declare_class_constant_long(php_http_header_parser_class_entry, ZEND_STRL("CLEANUP"), PHP_HTTP_HEADER_PARSER_CLEANUP); zend_declare_class_constant_long(php_http_header_parser_class_entry, ZEND_STRL("STATE_FAILURE"), PHP_HTTP_HEADER_PARSER_STATE_FAILURE); zend_declare_class_constant_long(php_http_header_parser_class_entry, ZEND_STRL("STATE_START"), PHP_HTTP_HEADER_PARSER_STATE_START); zend_declare_class_constant_long(php_http_header_parser_class_entry, ZEND_STRL("STATE_KEY"), PHP_HTTP_HEADER_PARSER_STATE_KEY); zend_declare_class_constant_long(php_http_header_parser_class_entry, ZEND_STRL("STATE_VALUE"), PHP_HTTP_HEADER_PARSER_STATE_VALUE); zend_declare_class_constant_long(php_http_header_parser_class_entry, ZEND_STRL("STATE_VALUE_EX"), PHP_HTTP_HEADER_PARSER_STATE_VALUE_EX); zend_declare_class_constant_long(php_http_header_parser_class_entry, ZEND_STRL("STATE_HEADER_DONE"), PHP_HTTP_HEADER_PARSER_STATE_HEADER_DONE); zend_declare_class_constant_long(php_http_header_parser_class_entry, ZEND_STRL("STATE_DONE"), PHP_HTTP_HEADER_PARSER_STATE_DONE); 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 */ pecl_http-4.2.1/src/php_http_header_parser.h0000644000076500000240000000562514117626035017737 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_HTTP_HEADER_PARSER_H #define PHP_HTTP_HEADER_PARSER_H #include "php_http_info.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_VALUE_EX, 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_ptr_stack stack; php_http_info_t info; struct { char *str; size_t len; } _key; struct { char *str; size_t len; } _val; } php_http_header_parser_t; PHP_HTTP_API php_http_header_parser_t *php_http_header_parser_init(php_http_header_parser_t *parser); PHP_HTTP_API php_http_header_parser_state_t php_http_header_parser_state_is(php_http_header_parser_t *parser); PHP_HTTP_API void php_http_header_parser_dtor(php_http_header_parser_t *parser); PHP_HTTP_API void php_http_header_parser_free(php_http_header_parser_t **parser); PHP_HTTP_API php_http_header_parser_state_t php_http_header_parser_parse(php_http_header_parser_t *parser, php_http_buffer_t *buffer, unsigned flags, HashTable *headers, php_http_info_callback_t callback_func, void *callback_arg); PHP_HTTP_API php_http_header_parser_state_t php_http_headerparser_parse_stream(php_http_header_parser_t *parser, php_http_buffer_t *buffer, php_stream *s, unsigned flags, HashTable *headers, php_http_info_callback_t callback_func, void *callback_arg); typedef struct php_http_header_parser_object { php_http_buffer_t *buffer; php_http_header_parser_t *parser; zend_object zo; } php_http_header_parser_object_t; PHP_HTTP_API zend_class_entry *php_http_get_header_parser_class_entry(void); PHP_MINIT_FUNCTION(http_header_parser); zend_object *php_http_header_parser_object_new(zend_class_entry *ce); php_http_header_parser_object_t *php_http_header_parser_object_new_ex(zend_class_entry *ce, php_http_header_parser_t *parser); void php_http_header_parser_object_free(zend_object *object); #endif /* PHP_HTTP_HEADER_PARSER_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 */ pecl_http-4.2.1/src/php_http_header.c0000644000076500000240000003572014117626035016355 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #include "php_http_api.h" ZEND_RESULT_CODE php_http_header_parse(const char *header, size_t length, HashTable *headers, php_http_info_callback_t callback_func, void **callback_data) { php_http_header_parser_t ctx; php_http_buffer_t buf; php_http_header_parser_state_t rs; if (!php_http_buffer_from_string_ex(&buf, header, length)) { php_error_docref(NULL, E_WARNING, "Could not allocate buffer"); return FAILURE; } if (!php_http_header_parser_init(&ctx)) { php_http_buffer_dtor(&buf); php_error_docref(NULL, E_WARNING, "Could not initialize header parser"); return FAILURE; } rs = 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); return rs == PHP_HTTP_HEADER_PARSER_STATE_FAILURE ? FAILURE : SUCCESS; } void php_http_header_to_callback(HashTable *headers, zend_bool crlf, php_http_pass_format_callback_t cb, void *cb_arg) { php_http_arrkey_t key; zval *header; ZEND_HASH_FOREACH_KEY_VAL(headers, key.h, key.key, header) { if (key.key) { php_http_header_to_callback_ex(key.key->val, header, crlf, cb, cb_arg); } } ZEND_HASH_FOREACH_END(); /* <<<<<<< HEAD php_http_arrkey_t key; zval *header, *single_header; ZEND_HASH_FOREACH_KEY_VAL(headers, key.h, key.key, header) { if (key.key) { if (zend_string_equals_literal(key.key, "Set-Cookie") && Z_TYPE_P(header) == IS_ARRAY) { ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(header), single_header) { if (Z_TYPE_P(single_header) == IS_ARRAY) { php_http_cookie_list_t *cookie = php_http_cookie_list_from_struct(NULL, single_header); if (cookie) { char *buf; size_t len; php_http_cookie_list_to_string(cookie, &buf, &len); cb(cb_arg, crlf ? "Set-Cookie: %s" PHP_HTTP_CRLF : "Set-Cookie: %s", buf); php_http_cookie_list_free(&cookie); efree(buf); } } else { zend_string *zs = php_http_header_value_to_string(single_header); cb(cb_arg, crlf ? "Set-Cookie: %s" PHP_HTTP_CRLF : "Set-Cookie: %s", zs->val); zend_string_release(zs); } } ZEND_HASH_FOREACH_END(); } else { zend_string *zs = php_http_header_value_to_string(header); cb(cb_arg, crlf ? "%s: %s" PHP_HTTP_CRLF : "%s: %s", key.key->val, zs->val); zend_string_release(zs); } ======= >>>>>>> 343738ad56eb70017704fdac57cf0d74da3d0f2e */ } void php_http_header_to_string(php_http_buffer_t *str, HashTable *headers) { php_http_header_to_callback(headers, 1, (php_http_pass_format_callback_t) php_http_buffer_appendf, str); } void php_http_header_to_callback_ex(const char *key, zval *val, zend_bool crlf, php_http_pass_format_callback_t cb, void *cb_arg) { zval *aval; zend_string *str; ZVAL_DEREF(val); switch (Z_TYPE_P(val)) { case IS_ARRAY: ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(val), aval) { php_http_header_to_callback_ex(key, aval, crlf, cb, cb_arg); } ZEND_HASH_FOREACH_END(); break; case IS_TRUE: cb(cb_arg, "%s: true%s", key, crlf ? PHP_HTTP_CRLF:""); break; case IS_FALSE: cb(cb_arg, "%s: false%s", key, crlf ? PHP_HTTP_CRLF:""); break; default: str = zval_get_string(val); cb(cb_arg, "%s: %s%s", key, str->val, crlf ? PHP_HTTP_CRLF:""); zend_string_release(str); break; } } void php_http_header_to_string_ex(php_http_buffer_t *str, const char *key, zval *val) { php_http_header_to_callback_ex(key, val, 1, (php_http_pass_format_callback_t) php_http_buffer_appendf, str); } zend_string *php_http_header_value_array_to_string(zval *header) { zval *val; php_http_buffer_t str; php_http_buffer_init(&str); ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(header), val) { zend_string *zs = php_http_header_value_to_string(val); php_http_buffer_appendf(&str, str.used ? ", %s":"%s", zs->val); zend_string_release(zs); } ZEND_HASH_FOREACH_END(); php_http_buffer_fix(&str); return php_http_cs2zs(str.data, str.used); } zend_string *php_http_header_value_to_string(zval *header) { switch (Z_TYPE_P(header)) { case IS_TRUE: return zend_string_init(ZEND_STRL("true"), 0); case IS_FALSE: return zend_string_init(ZEND_STRL("false"), 0); case IS_ARRAY: return php_http_header_value_array_to_string(header); default: return zval_get_string(header); } } static zend_class_entry *php_http_header_class_entry; zend_class_entry *php_http_header_get_class_entry(void) { return php_http_header_class_entry; } ZEND_BEGIN_ARG_INFO_EX(ai_HttpHeader___construct, 0, 0, 0) ZEND_ARG_INFO(0, name) ZEND_ARG_INFO(0, value) ZEND_END_ARG_INFO(); PHP_METHOD(HttpHeader, __construct) { char *name_str = NULL, *value_str = NULL; size_t name_len = 0, value_len = 0; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|s!s!", &name_str, &name_len, &value_str, &value_len), invalid_arg, return); if (name_str && name_len) { char *pretty_str = estrndup(name_str, name_len); zend_update_property_stringl(php_http_header_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("name"), php_http_pretty_key(pretty_str, name_len, 1, 1), name_len); efree(pretty_str); } if (value_str && value_len) { zend_update_property_stringl(php_http_header_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("value"), value_str, value_len); } } ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(ai_HttpHeader___serialize, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO(); PHP_METHOD(HttpHeader, __serialize) { zval name, value, *ptr; zend_parse_parameters_none(); array_init(return_value); ptr = zend_read_property(php_http_header_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("name"), 0, &name); Z_TRY_ADDREF_P(ptr); add_next_index_zval(return_value, ptr); ptr = zend_read_property(php_http_header_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("value"), 0, &value); Z_TRY_ADDREF_P(ptr); add_next_index_zval(return_value, ptr); } ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(ai_HttpHeader___unserialize, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, data, IS_ARRAY, 0) ZEND_END_ARG_INFO(); PHP_METHOD(HttpHeader, __unserialize) { HashTable *ha; zval *name, *value; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "h", &ha), invalid_arg, return); name = zend_hash_index_find(ha, 0); value = zend_hash_index_find(ha, 1); if (name && value) { zend_update_property(php_http_header_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("name"), name); zend_update_property(php_http_header_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("value"), value); } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpHeader_serialize, 0, 0, 0) ZEND_END_ARG_INFO(); PHP_METHOD(HttpHeader, serialize) { if (SUCCESS == zend_parse_parameters_none()) { php_http_buffer_t buf; zend_string *zs; zval name_tmp, value_tmp; php_http_buffer_init(&buf); zs = zval_get_string(zend_read_property(php_http_header_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("name"), 0, &name_tmp)); php_http_buffer_appendz(&buf, zs); zend_string_release(zs); zs = zval_get_string(zend_read_property(php_http_header_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("value"), 0, &value_tmp)); if (zs->len) { php_http_buffer_appends(&buf, ": "); php_http_buffer_appendz(&buf, zs); } else { php_http_buffer_appends(&buf, ":"); } zend_string_release(zs); RETURN_STR(php_http_cs2zs(buf.data, buf.used)); } RETURN_EMPTY_STRING(); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpHeader_unserialize, 0, 0, 1) ZEND_ARG_INFO(0, serialized) ZEND_END_ARG_INFO(); PHP_METHOD(HttpHeader, unserialize) { char *serialized_str; size_t serialized_len; if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &serialized_str, &serialized_len)) { HashTable ht; zend_hash_init(&ht, 1, NULL, ZVAL_PTR_DTOR, 0); if (SUCCESS == php_http_header_parse(serialized_str, serialized_len, &ht, NULL, NULL)) { if (zend_hash_num_elements(&ht)) { zend_string *zs, *key; zend_ulong idx; zend_hash_internal_pointer_reset(&ht); switch (zend_hash_get_current_key(&ht, &key, &idx)) { case HASH_KEY_IS_STRING: zend_update_property_str(php_http_header_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("name"), key); break; case HASH_KEY_IS_LONG: zend_update_property_long(php_http_header_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("name"), idx); break; default: break; } zs = zval_get_string(zend_hash_get_current_data(&ht)); zend_update_property_str(php_http_header_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("value"), zs); zend_string_release(zs); } } zend_hash_destroy(&ht); } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpHeader_match, 0, 0, 1) ZEND_ARG_INFO(0, value) ZEND_ARG_INFO(0, flags) ZEND_END_ARG_INFO(); PHP_METHOD(HttpHeader, match) { char *val_str = NULL; size_t val_len = 0; zend_long flags = PHP_HTTP_MATCH_LOOSE; zend_string *zs; zval value_tmp; if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "|sl", &val_str, &val_len, &flags)) { return; } zs = zval_get_string(zend_read_property(php_http_header_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("value"), 0, &value_tmp)); RETVAL_BOOL(php_http_match(zs->val, val_str, flags)); zend_string_release(zs); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpHeader_negotiate, 0, 0, 1) ZEND_ARG_INFO(0, supported) ZEND_ARG_INFO(1, result) ZEND_END_ARG_INFO(); PHP_METHOD(HttpHeader, negotiate) { HashTable *supported, *rs; zval name_tmp, value_tmp, *rs_array = NULL; zend_string *zs; char *sep_str = NULL; size_t sep_len = 0; if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "H|z", &supported, &rs_array)) { return; } if (rs_array) { ZVAL_DEREF(rs_array); zval_dtor(rs_array); array_init(rs_array); } zs = zval_get_string(zend_read_property(php_http_header_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("name"), 0, &name_tmp)); if (zend_string_equals_literal(zs, "Accept")) { sep_str = "/"; sep_len = 1; } else if (zend_string_equals_literal(zs, "Accept-Language")) { sep_str = "-"; sep_len = 1; } zend_string_release(zs); zs = zval_get_string(zend_read_property(php_http_header_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("value"), 0, &value_tmp)); if ((rs = php_http_negotiate(zs->val, zs->len, supported, sep_str, sep_len))) { PHP_HTTP_DO_NEGOTIATE_HANDLE_RESULT(rs, supported, rs_array); } else { PHP_HTTP_DO_NEGOTIATE_HANDLE_DEFAULT(supported, rs_array); } zend_string_release(zs); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpHeader_getParams, 0, 0, 0) ZEND_ARG_INFO(0, param_sep) ZEND_ARG_INFO(0, arg_sep) ZEND_ARG_INFO(0, val_sep) ZEND_ARG_INFO(0, flags) ZEND_END_ARG_INFO(); PHP_METHOD(HttpHeader, getParams) { zval value_tmp, zctor, zparams_obj, *zargs = NULL; ZVAL_STRINGL(&zctor, "__construct", lenof("__construct")); object_init_ex(&zparams_obj, php_http_params_get_class_entry()); zargs = (zval *) ecalloc(ZEND_NUM_ARGS()+1, sizeof(zval)); ZVAL_COPY_VALUE(&zargs[0], zend_read_property(php_http_header_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("value"), 0, &value_tmp)); if (ZEND_NUM_ARGS()) { zend_get_parameters_array(ZEND_NUM_ARGS(), ZEND_NUM_ARGS(), &zargs[1]); } if (SUCCESS == call_user_function(NULL, &zparams_obj, &zctor, return_value, ZEND_NUM_ARGS()+1, zargs)) { RETVAL_ZVAL(&zparams_obj, 0, 1); } zval_ptr_dtor(&zctor); if (zargs) { efree(zargs); } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpHeader_parse, 0, 0, 1) ZEND_ARG_INFO(0, string) ZEND_ARG_INFO(0, header_class) ZEND_END_ARG_INFO(); PHP_METHOD(HttpHeader, parse) { char *header_str; size_t header_len; zend_class_entry *ce = NULL; if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s|C", &header_str, &header_len, &ce)) { array_init(return_value); if (SUCCESS != php_http_header_parse(header_str, header_len, Z_ARRVAL_P(return_value), NULL, NULL)) { zval_dtor(return_value); RETURN_FALSE; } else { if (ce && instanceof_function(ce, php_http_header_class_entry)) { php_http_arrkey_t key; zval *val; ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(return_value), key.h, key.key, val) { zval zkey, zho; if (key.key) { ZVAL_STR_COPY(&zkey, key.key); } else { ZVAL_LONG(&zkey, key.h); } object_init_ex(&zho, ce); Z_TRY_ADDREF_P(val); zend_call_method_with_2_params(Z_OBJ(zho), ce, NULL, "__construct", NULL, &zkey, val); zval_ptr_dtor(val); zval_ptr_dtor(&zkey); if (key.key) { add_assoc_zval_ex(return_value, key.key->val, key.key->len, &zho); } else { add_index_zval(return_value, key.h, &zho); } } ZEND_HASH_FOREACH_END(); } } } } static zend_function_entry php_http_header_methods[] = { PHP_ME(HttpHeader, __construct, ai_HttpHeader___construct, ZEND_ACC_PUBLIC) PHP_ME(HttpHeader, __unserialize, ai_HttpHeader___unserialize, ZEND_ACC_PUBLIC) PHP_ME(HttpHeader, __serialize, ai_HttpHeader___serialize, ZEND_ACC_PUBLIC) PHP_ME(HttpHeader, unserialize, ai_HttpHeader_unserialize, ZEND_ACC_PUBLIC) PHP_ME(HttpHeader, serialize, ai_HttpHeader_serialize, ZEND_ACC_PUBLIC) ZEND_MALIAS(HttpHeader, __toString, serialize, ai_HttpHeader_serialize, ZEND_ACC_PUBLIC) ZEND_MALIAS(HttpHeader, toString, serialize, ai_HttpHeader_serialize, ZEND_ACC_PUBLIC) PHP_ME(HttpHeader, match, ai_HttpHeader_match, ZEND_ACC_PUBLIC) PHP_ME(HttpHeader, negotiate, ai_HttpHeader_negotiate, ZEND_ACC_PUBLIC) PHP_ME(HttpHeader, getParams, ai_HttpHeader_getParams, ZEND_ACC_PUBLIC) PHP_ME(HttpHeader, parse, ai_HttpHeader_parse, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) EMPTY_FUNCTION_ENTRY }; PHP_MINIT_FUNCTION(http_header) { zend_class_entry ce = {0}; INIT_NS_CLASS_ENTRY(ce, "http", "Header", php_http_header_methods); php_http_header_class_entry = zend_register_internal_class(&ce); zend_class_implements(php_http_header_class_entry, 1, zend_ce_serializable); zend_declare_class_constant_long(php_http_header_class_entry, ZEND_STRL("MATCH_LOOSE"), PHP_HTTP_MATCH_LOOSE); zend_declare_class_constant_long(php_http_header_class_entry, ZEND_STRL("MATCH_CASE"), PHP_HTTP_MATCH_CASE); zend_declare_class_constant_long(php_http_header_class_entry, ZEND_STRL("MATCH_WORD"), PHP_HTTP_MATCH_WORD); zend_declare_class_constant_long(php_http_header_class_entry, ZEND_STRL("MATCH_FULL"), PHP_HTTP_MATCH_FULL); zend_declare_class_constant_long(php_http_header_class_entry, ZEND_STRL("MATCH_STRICT"), PHP_HTTP_MATCH_STRICT); zend_declare_property_null(php_http_header_class_entry, ZEND_STRL("name"), ZEND_ACC_PUBLIC); zend_declare_property_null(php_http_header_class_entry, ZEND_STRL("value"), ZEND_ACC_PUBLIC); 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 */ pecl_http-4.2.1/src/php_http_header.h0000644000076500000240000000341514117626035016356 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_HTTP_HEADERS_H #define PHP_HTTP_HEADERS_H #include "php_http_info.h" PHP_HTTP_API ZEND_RESULT_CODE php_http_header_parse(const char *header, size_t length, HashTable *headers, php_http_info_callback_t callback_func, void **callback_data); PHP_HTTP_API void php_http_header_to_callback(HashTable *headers, zend_bool crlf, php_http_pass_format_callback_t cb, void *cb_arg); PHP_HTTP_API void php_http_header_to_callback_ex(const char *key, zval *val, zend_bool crlf, php_http_pass_format_callback_t cb, void *cb_arg); PHP_HTTP_API void php_http_header_to_string(php_http_buffer_t *str, HashTable *headers); PHP_HTTP_API void php_http_header_to_string_ex(php_http_buffer_t *str, const char *key, zval *val); PHP_HTTP_API zend_string *php_http_header_value_to_string(zval *header); PHP_HTTP_API zend_string *php_http_header_value_array_to_string(zval *header); PHP_HTTP_API zend_class_entry *php_http_header_get_class_entry(void); PHP_MINIT_FUNCTION(http_header); #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 */ pecl_http-4.2.1/src/php_http_info.c0000644000076500000240000001554014117626035016056 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #include "php_http_api.h" php_http_info_t *php_http_info_init(php_http_info_t *i) { if (!i) { i = emalloc(sizeof(*i)); } memset(i, 0, sizeof(*i)); return i; } void php_http_info_dtor(php_http_info_t *i) { switch (i->type) { case PHP_HTTP_REQUEST: PTR_SET(PHP_HTTP_INFO(i).request.method, NULL); PTR_SET(PHP_HTTP_INFO(i).request.url, NULL); break; case PHP_HTTP_RESPONSE: PTR_SET(PHP_HTTP_INFO(i).response.status, NULL); break; default: break; } } void php_http_info_free(php_http_info_t **i) { if (*i) { php_http_info_dtor(*i); efree(*i); *i = NULL; } } void php_http_info_to_string(php_http_info_t *info, char **str, size_t *len, const char *eol) { char *tmp = NULL; if (info->http.version.major == 2) { if (info->type == PHP_HTTP_REQUEST) { *len = spprintf(str, 0, "%s %s HTTP/2%s", info->http.info.request.method?info->http.info.request.method:"UNKNOWN", info->http.info.request.method&&!strcasecmp(info->http.info.request.method,"CONNECT")?( info->http.info.request.url?php_http_url_authority_to_string(info->http.info.request.url, &(tmp), NULL):"0"):( info->http.info.request.url?php_http_url_to_string(info->http.info.request.url, &(tmp), NULL, 0):"/"), eol); } else if (info->type == PHP_HTTP_RESPONSE) { *len = spprintf(str, 0, "HTTP/2 %d%s%s%s", info->http.info.response.code?info->http.info.response.code:200, info->http.info.response.status&&*info->http.info.response.status ? " ":"", STR_PTR(info->http.info.response.status), eol); } } else if (info->type == PHP_HTTP_REQUEST) { *len = spprintf(str, 0, "%s %s HTTP/%u.%u%s", info->http.info.request.method?info->http.info.request.method:"UNKNOWN", info->http.info.request.method&&!strcasecmp(info->http.info.request.method,"CONNECT")?( info->http.info.request.url?php_http_url_authority_to_string(info->http.info.request.url, &(tmp), NULL):"0"):( info->http.info.request.url?php_http_url_to_string(info->http.info.request.url, &(tmp), NULL, 0):"/"), info->http.version.major||info->http.version.minor?info->http.version.major:1, info->http.version.major||info->http.version.minor?info->http.version.minor:1, eol); } else if (info->type == PHP_HTTP_RESPONSE){ *len = spprintf(str, 0, "HTTP/%u.%u %d%s%s%s", info->http.version.major||info->http.version.minor?info->http.version.major:1, info->http.version.major||info->http.version.minor?info->http.version.minor:1, info->http.info.response.code?info->http.info.response.code:200, info->http.info.response.status&&*info->http.info.response.status ? " ":"", STR_PTR(info->http.info.response.status), eol); } PTR_FREE(tmp); } php_http_info_t *php_http_info_parse(php_http_info_t *info, const char *pre_header) { const char *end, *http, *off; zend_bool free_info = !info; /* sane parameter */ if (UNEXPECTED((!pre_header) || (!*pre_header))) { return NULL; } /* where's the end of the line */ if (UNEXPECTED(!(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/", lenof("HTTP/")))) { return NULL; } info = php_http_info_init(info); if (UNEXPECTED(!php_http_version_parse(&info->http.version, http))) { if (free_info) { php_http_info_free(&info); } return NULL; } /* clumsy fix for changed libcurl behaviour in 7.49.1, see https://github.com/curl/curl/issues/888 */ off = &http[lenof("HTTP/X")]; if (info->http.version.major < 2 || (info->http.version.major == 2 && *off == '.')) { off += 2; } /* and nothing than SPACE or NUL after HTTP/X(.x) */ if (UNEXPECTED(*off && (!PHP_HTTP_IS_CTYPE(space, *off)))) { 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) { const char *status = NULL, *code = off; info->type = PHP_HTTP_RESPONSE; while (code < end && ' ' == *code) ++code; if (EXPECTED(end > code)) { /* rfc7230#3.1.2 The status-code element is a 3-digit integer code */ PHP_HTTP_INFO(info).response.code = 100*(*code++ - '0'); PHP_HTTP_INFO(info).response.code += 10*(*code++ - '0'); PHP_HTTP_INFO(info).response.code += *code++ - '0'; if (PHP_HTTP_INFO(info).response.code < 100 || PHP_HTTP_INFO(info).response.code > 599) { if (free_info) { php_http_info_free(&info); } return NULL; } status = code; } else { PHP_HTTP_INFO(info).response.code = 0; } if (EXPECTED(status && end > status)) { while (' ' == *status && end > status) ++status; PHP_HTTP_INFO(info).response.status = estrndup(status, end - status); } else { PHP_HTTP_INFO(info).response.status = NULL; } return info; } /* is request */ else if (*(http - 1) == ' ' && (!*off || *off == '\r' || *off == '\n')) { const char *url = strchr(pre_header, ' '); info->type = PHP_HTTP_REQUEST; if (EXPECTED(url && http > url)) { size_t url_len = url - pre_header; PHP_HTTP_INFO(info).request.method = estrndup(pre_header, url_len); while (' ' == *url && http > url) ++url; while (' ' == *(http-1)) --http; if (EXPECTED(http > url)) { /* CONNECT presents an authority only */ if (UNEXPECTED(strcasecmp(PHP_HTTP_INFO(info).request.method, "CONNECT"))) { PHP_HTTP_INFO(info).request.url = php_http_url_parse(url, http - url, PHP_HTTP_URL_STDFLAGS); } else { PHP_HTTP_INFO(info).request.url = php_http_url_parse_authority(url, http - url, PHP_HTTP_URL_STDFLAGS); } if (!PHP_HTTP_INFO(info).request.url) { PTR_SET(PHP_HTTP_INFO(info).request.method, NULL); return NULL; } } else { PTR_SET(PHP_HTTP_INFO(info).request.method, NULL); return NULL; } } else { PHP_HTTP_INFO(info).request.method = NULL; PHP_HTTP_INFO(info).request.url = NULL; } return info; } /* some darn header containing HTTP/X(.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 */ pecl_http-4.2.1/src/php_http_info.h0000644000076500000240000000406414117626035016062 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_HTTP_INFO_H #define PHP_HTTP_INFO_H #include "php_http_version.h" #include "php_http_url.h" typedef struct php_http_info_data { union { /* GET /foo/bar */ struct { char *method; php_http_url_t *url; } request; /* 200 Ok */ struct { unsigned code; char *status; } response; } info; php_http_version_t version; } php_http_info_data_t; #undef PHP_HTTP_REQUEST #undef PHP_HTTP_RESPONSE 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); PHP_HTTP_API php_http_info_t *php_http_info_init(php_http_info_t *info); PHP_HTTP_API php_http_info_t *php_http_info_parse(php_http_info_t *info, const char *pre_header); PHP_HTTP_API void php_http_info_to_string(php_http_info_t *info, char **str, size_t *len, const char *eol); 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 */ pecl_http-4.2.1/src/php_http_message_body.c0000644000076500000240000007000114117626035017555 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #include "php_http_api.h" #include "ext/standard/php_lcg.h" #define BOUNDARY_OPEN(body) \ do {\ size_t size = php_http_message_body_size(body); \ if (size) { \ php_stream_truncate_set_size(php_http_message_body_stream(body), size - lenof("--" PHP_HTTP_CRLF)); \ php_http_message_body_append(body, ZEND_STRL(PHP_HTTP_CRLF)); \ } else { \ php_http_message_body_appendf(body, "--%s" PHP_HTTP_CRLF, php_http_message_body_boundary(body)); \ } \ } while(0) #define BOUNDARY_CLOSE(body) \ php_http_message_body_appendf(body, PHP_HTTP_CRLF "--%s--" PHP_HTTP_CRLF, php_http_message_body_boundary(body)) static ZEND_RESULT_CODE add_recursive_fields(php_http_message_body_t *body, const char *name, HashTable *fields); static ZEND_RESULT_CODE add_recursive_files(php_http_message_body_t *body, const char *name, HashTable *files); php_http_message_body_t *php_http_message_body_init(php_http_message_body_t **body_ptr, php_stream *stream) { php_http_message_body_t *body; if (body_ptr && *body_ptr) { body = *body_ptr; php_http_message_body_addref(body); return body; } body = ecalloc(1, sizeof(php_http_message_body_t)); body->refcount = 1; if (stream) { body->res = stream->res; GC_ADDREF(body->res); } else { body->res = php_stream_temp_create(TEMP_STREAM_DEFAULT, 0xffff)->res; } php_stream_auto_cleanup(php_http_message_body_stream(body)); if (body_ptr) { *body_ptr = body; } return body; } unsigned php_http_message_body_addref(php_http_message_body_t *body) { return ++body->refcount; } php_http_message_body_t *php_http_message_body_copy(php_http_message_body_t *from, php_http_message_body_t *to) { if (from) { if (to) { php_stream_truncate_set_size(php_http_message_body_stream(to), 0); } else { to = php_http_message_body_init(NULL, NULL); } php_http_message_body_to_stream(from, php_http_message_body_stream(to), 0, 0); if (to->boundary) { efree(to->boundary); } if (from->boundary) { to->boundary = estrdup(from->boundary); } } else { to = NULL; } return to; } void php_http_message_body_free(php_http_message_body_t **body_ptr) { if (*body_ptr) { php_http_message_body_t *body = *body_ptr; if (!--body->refcount) { zend_list_delete(body->res); body->res = NULL; PTR_FREE(body->boundary); efree(body); } *body_ptr = NULL; } } const php_stream_statbuf *php_http_message_body_stat(php_http_message_body_t *body) { php_stream_stat(php_http_message_body_stream(body), &body->ssb); return &body->ssb; } const char *php_http_message_body_boundary(php_http_message_body_t *body) { if (!body->boundary) { union { double dbl; int num[2]; } data; data.dbl = php_combined_lcg(); spprintf(&body->boundary, 0, "%x.%x", data.num[0], data.num[1]); } return body->boundary; } char *php_http_message_body_etag(php_http_message_body_t *body) { php_http_etag_t *etag; php_stream *s = php_http_message_body_stream(body); /* real file or temp buffer ? */ if (s->ops != &php_stream_temp_ops && s->ops != &php_stream_memory_ops) { php_stream_stat(php_http_message_body_stream(body), &body->ssb); if (body->ssb.sb.st_mtime) { char *etag; spprintf(&etag, 0, "%lx-%lx-%lx", body->ssb.sb.st_ino, body->ssb.sb.st_mtime, body->ssb.sb.st_size); return etag; } } /* content based */ if ((etag = php_http_etag_init(PHP_HTTP_G->env.etag_mode))) { php_http_message_body_to_callback(body, (php_http_pass_callback_t) php_http_etag_update, etag, 0, 0); return php_http_etag_finish(etag); } return NULL; } zend_string *php_http_message_body_to_string(php_http_message_body_t *body, off_t offset, size_t forlen) { php_stream *s = php_http_message_body_stream(body); php_stream_seek(s, offset, SEEK_SET); if (!forlen) { forlen = -1; } return php_stream_copy_to_mem(s, forlen, 0); } ZEND_RESULT_CODE php_http_message_body_to_stream(php_http_message_body_t *body, php_stream *dst, off_t offset, size_t forlen) { php_stream *s = php_http_message_body_stream(body); php_stream_seek(s, offset, SEEK_SET); if (!forlen) { forlen = -1; } return php_stream_copy_to_stream_ex(s, dst, forlen, NULL); } ZEND_RESULT_CODE php_http_message_body_to_callback(php_http_message_body_t *body, php_http_pass_callback_t cb, void *cb_arg, off_t offset, size_t forlen) { php_stream *s = php_http_message_body_stream(body); char *buf = emalloc(0x1000); php_stream_seek(s, offset, SEEK_SET); if (!forlen) { forlen = -1; } while (!php_stream_eof(s)) { size_t read = php_stream_read(s, buf, MIN(forlen, 0x1000)); if (read) { if (-1 == cb(cb_arg, buf, read)) { return FAILURE; } } if (read < MIN(forlen, sizeof(buf))) { break; } if (forlen && !(forlen -= read)) { break; } } efree(buf); return SUCCESS; } size_t php_http_message_body_append(php_http_message_body_t *body, const char *buf, size_t len) { php_stream *s; size_t written; if (!(s = php_http_message_body_stream(body))) { return -1; } if (s->ops->seek) { php_stream_seek(s, 0, SEEK_END); } written = php_stream_write(s, buf, len); if (written != len) { php_error_docref(NULL, E_WARNING, "Failed to append %zu bytes to body; wrote %zu", len, written == (size_t) -1 ? 0 : written); } return len; } size_t php_http_message_body_appendf(php_http_message_body_t *body, const char *fmt, ...) { va_list argv; char *print_str; size_t print_len; va_start(argv, fmt); print_len = vspprintf(&print_str, 0, fmt, argv); va_end(argv); print_len = php_http_message_body_append(body, print_str, print_len); efree(print_str); return print_len; } ZEND_RESULT_CODE php_http_message_body_add_form(php_http_message_body_t *body, HashTable *fields, HashTable *files) { if (fields) { if (SUCCESS != add_recursive_fields(body, NULL, fields)) { return FAILURE; } } if (files) { if (SUCCESS != add_recursive_files(body, NULL, files)) { return FAILURE; } } return SUCCESS; } void php_http_message_body_add_part(php_http_message_body_t *body, php_http_message_t *part) { BOUNDARY_OPEN(body); php_http_message_to_callback(part, (php_http_pass_callback_t) php_http_message_body_append, body); BOUNDARY_CLOSE(body); } ZEND_RESULT_CODE php_http_message_body_add_form_field(php_http_message_body_t *body, const char *name, const char *value_str, size_t value_len) { zend_string *safe_name, *zstr_name = zend_string_init(name, strlen(name), 0); #if PHP_VERSION_ID < 70300 safe_name = php_addslashes(zstr_name, 1); #else safe_name = php_addslashes(zstr_name); zend_string_release_ex(zstr_name, 0); #endif BOUNDARY_OPEN(body); php_http_message_body_appendf( body, "Content-Disposition: form-data; name=\"%s\"" PHP_HTTP_CRLF "" PHP_HTTP_CRLF, safe_name->val ); php_http_message_body_append(body, value_str, value_len); BOUNDARY_CLOSE(body); zend_string_release(safe_name); return SUCCESS; } ZEND_RESULT_CODE php_http_message_body_add_form_file(php_http_message_body_t *body, const char *name, const char *ctype, const char *path, php_stream *in) { size_t path_len = strlen(path); char *path_dup = estrndup(path, path_len); zend_string *base_name, *safe_name, *zstr_name = zend_string_init(name, strlen(name), 0); #if PHP_VERSION_ID < 70300 safe_name = php_addslashes(zstr_name, 1); #else safe_name = php_addslashes(zstr_name); zend_string_release_ex(zstr_name, 0); #endif base_name = php_basename(path_dup, path_len, NULL, 0); BOUNDARY_OPEN(body); php_http_message_body_appendf( body, "Content-Disposition: form-data; name=\"%s\"; filename=\"%s\"" PHP_HTTP_CRLF "Content-Transfer-Encoding: binary" PHP_HTTP_CRLF "Content-Type: %s" PHP_HTTP_CRLF PHP_HTTP_CRLF, safe_name->val, base_name->val, ctype ); php_stream_copy_to_stream_ex(in, php_http_message_body_stream(body), PHP_STREAM_COPY_ALL, NULL); BOUNDARY_CLOSE(body); zend_string_release(safe_name); zend_string_release(base_name); efree(path_dup); return SUCCESS; } static inline char *format_key(php_http_arrkey_t *key, const char *prefix) { char *new_key = NULL; if (prefix && *prefix) { if (key->key) { spprintf(&new_key, 0, "%s[%s]", prefix, key->key->val); } else { spprintf(&new_key, 0, "%s[%lu]", prefix, key->h); } } else if (key->key) { new_key = estrdup(key->key->val); } else { spprintf(&new_key, 0, "%lu", key->h); } return new_key; } static ZEND_RESULT_CODE add_recursive_field_value(php_http_message_body_t *body, const char *name, zval *value) { zend_string *zs = zval_get_string(value); ZEND_RESULT_CODE rc = php_http_message_body_add_form_field(body, name, zs->val, zs->len); zend_string_release(zs); return rc; } static ZEND_RESULT_CODE add_recursive_fields(php_http_message_body_t *body, const char *name, HashTable *fields) { zval *val; php_http_arrkey_t key; if (!HT_IS_RECURSIVE(fields)) { HT_PROTECT_RECURSION(fields); ZEND_HASH_FOREACH_KEY_VAL_IND(fields, key.h, key.key, val) { char *str = format_key(&key, name); if (Z_TYPE_P(val) != IS_ARRAY && Z_TYPE_P(val) != IS_OBJECT) { if (SUCCESS != add_recursive_field_value(body, str, val)) { efree(str); HT_UNPROTECT_RECURSION(fields); return FAILURE; } } else if (SUCCESS != add_recursive_fields(body, str, HASH_OF(val))) { efree(str); HT_UNPROTECT_RECURSION(fields); return FAILURE; } efree(str); } ZEND_HASH_FOREACH_END(); HT_UNPROTECT_RECURSION(fields); } return SUCCESS; } static ZEND_RESULT_CODE add_recursive_files(php_http_message_body_t *body, const char *name, HashTable *files) { zval *zdata = NULL, *zfile, *zname, *ztype; /* single entry */ if (!(zname = zend_hash_str_find(files, ZEND_STRL("name"))) || !(ztype = zend_hash_str_find(files, ZEND_STRL("type"))) || !(zfile = zend_hash_str_find(files, ZEND_STRL("file"))) ) { zval *val; php_http_arrkey_t key; if (!HT_IS_RECURSIVE(files)) { HT_PROTECT_RECURSION(files); ZEND_HASH_FOREACH_KEY_VAL_IND(files, key.h, key.key, val) { if (Z_TYPE_P(val) == IS_ARRAY || Z_TYPE_P(val) == IS_OBJECT) { char *str = key.key ? format_key(&key, name) : NULL; const char *prefix = str ? str : name; if (SUCCESS != add_recursive_files(body, prefix, HASH_OF(val))) { efree(str); HT_UNPROTECT_RECURSION(files); return FAILURE; } if (str) { efree(str); } } } ZEND_HASH_FOREACH_END(); HT_UNPROTECT_RECURSION(files); } return SUCCESS; } else { /* stream entry */ php_stream *stream; zend_string *zfc = zval_get_string(zfile); if ((zdata = zend_hash_str_find(files, ZEND_STRL("data")))) { if (Z_TYPE_P(zdata) == IS_RESOURCE) { php_stream_from_zval_no_verify(stream, zdata); } else { zend_string *tmp = zval_get_string(zdata); stream = php_http_mem_stream_open(TEMP_STREAM_READONLY, tmp); zend_string_release(tmp); } } else { stream = php_stream_open_wrapper(zfc->val, "r", REPORT_ERRORS|USE_PATH, NULL); } if (!stream) { zend_string_release(zfc); return FAILURE; } else { zend_string *znc = zval_get_string(zname), *ztc = zval_get_string(ztype); php_http_arrkey_t arrkey = {0, znc, 0, 0}; char *key = format_key(&arrkey, name); ZEND_RESULT_CODE ret = php_http_message_body_add_form_file(body, key, ztc->val, zfc->val, stream); efree(key); zend_string_release(znc); zend_string_release(ztc); zend_string_release(zfc); if (!zdata || Z_TYPE_P(zdata) != IS_RESOURCE) { php_stream_close(stream); } return ret; } } } struct splitbody_arg { php_http_buffer_t buf; php_http_message_parser_t *parser; char *boundary_str; size_t boundary_len; size_t consumed; }; static size_t splitbody(void *opaque, char *buf, size_t len) { struct splitbody_arg *arg = opaque; const char *boundary = NULL; size_t consumed = 0; int first_boundary; do { first_boundary = !(consumed || arg->consumed); if ((boundary = php_http_locate_str(buf, len, arg->boundary_str + first_boundary, arg->boundary_len - first_boundary))) { size_t real_boundary_len = arg->boundary_len - 1, cut; const char *real_boundary = boundary + !first_boundary; int eol_len = 0; if (buf + len <= real_boundary + real_boundary_len) { /* if we just have enough data for the boundary, it's just a byte too less */ arg->consumed += consumed; return consumed; } if (!first_boundary) { /* this is not the first boundary, read rest of this message */ php_http_buffer_append(&arg->buf, buf, real_boundary - buf); php_http_message_parser_parse(arg->parser, &arg->buf, 0, &arg->parser->message); } /* move after the boundary */ cut = real_boundary - buf + real_boundary_len; buf += cut; len -= cut; consumed += cut; if (buf == php_http_locate_bin_eol(buf, len, &eol_len)) { /* skip CRLF */ buf += eol_len; len -= eol_len; consumed += eol_len; if (!first_boundary) { /* advance messages */ php_http_message_t *msg; msg = php_http_message_init(NULL, 0, NULL); msg->parent = arg->parser->message; arg->parser->message = msg; } } else { /* is this the last boundary? */ if (*buf == '-') { /* ignore the rest */ consumed += len; len = 0; } else { /* let this be garbage */ php_error_docref(NULL, E_WARNING, "Malformed multipart boundary at pos %zu", consumed); return -1; } } } } while (boundary && len); /* let there be room for the next boundary */ if (len > arg->boundary_len) { consumed += len - arg->boundary_len; php_http_buffer_append(&arg->buf, buf, len - arg->boundary_len); php_http_message_parser_parse(arg->parser, &arg->buf, 0, &arg->parser->message); } arg->consumed += consumed; return consumed; } php_http_message_t *php_http_message_body_split(php_http_message_body_t *body, const char *boundary) { php_stream *s = php_http_message_body_stream(body); php_http_buffer_t *tmp = NULL; php_http_message_t *msg = NULL; struct splitbody_arg arg; php_http_buffer_init(&arg.buf); arg.parser = php_http_message_parser_init(NULL); arg.boundary_len = spprintf(&arg.boundary_str, 0, "\n--%s", boundary); arg.consumed = 0; php_stream_rewind(s); while (!php_stream_eof(s)) { php_http_buffer_passthru(&tmp, 0x1000, (php_http_buffer_pass_func_t) _php_stream_read, s, splitbody, &arg); } msg = arg.parser->message; arg.parser->message = NULL; php_http_buffer_free(&tmp); php_http_message_parser_free(&arg.parser); php_http_buffer_dtor(&arg.buf); PTR_FREE(arg.boundary_str); return msg; } static zend_class_entry *php_http_message_body_class_entry; zend_class_entry *php_http_get_message_body_class_entry(void) { return php_http_message_body_class_entry; } static zend_object_handlers php_http_message_body_object_handlers; zend_object *php_http_message_body_object_new(zend_class_entry *ce) { return &php_http_message_body_object_new_ex(ce, NULL)->zo; } php_http_message_body_object_t *php_http_message_body_object_new_ex(zend_class_entry *ce, php_http_message_body_t *body) { php_http_message_body_object_t *o; o = ecalloc(1, sizeof(*o) + zend_object_properties_size(ce)); zend_object_std_init(&o->zo, php_http_message_body_class_entry); object_properties_init(&o->zo, ce); o->gc = emalloc(sizeof(zval)); if (body) { o->body = body; } o->zo.handlers = &php_http_message_body_object_handlers; return o; } zend_object *php_http_message_body_object_clone(zend_object *object) { php_http_message_body_object_t *new_obj; php_http_message_body_object_t *old_obj = PHP_HTTP_OBJ(object, NULL); php_http_message_body_t *body = php_http_message_body_copy(old_obj->body, NULL); new_obj = php_http_message_body_object_new_ex(old_obj->zo.ce, body); zend_objects_clone_members(&new_obj->zo, &old_obj->zo); return &new_obj->zo; } static HashTable *php_http_message_body_object_get_gc(zend_object *object, zval **table, int *n) { php_http_message_body_object_t *obj = PHP_HTTP_OBJ(object, NULL); HashTable *props = object->handlers->get_properties(object); uint32_t count = zend_hash_num_elements(props); obj->gc = erealloc(obj->gc, (1 + count) * sizeof(zval)); if (php_http_message_body_stream(obj->body)) { *n = 1; php_stream_to_zval(php_http_message_body_stream(obj->body), obj->gc); } else { *n = 0; } if (count) { zval *val; ZEND_HASH_FOREACH_VAL(props, val) { ZVAL_COPY_VALUE(&obj->gc[(*n)++], val); } ZEND_HASH_FOREACH_END(); } *table = obj->gc; return NULL; } void php_http_message_body_object_free(zend_object *object) { php_http_message_body_object_t *obj = PHP_HTTP_OBJ(object, NULL); PTR_FREE(obj->gc); php_http_message_body_free(&obj->body); zend_object_std_dtor(object); } #define PHP_HTTP_MESSAGE_BODY_OBJECT_INIT(obj) \ do { \ if (!obj->body) { \ obj->body = php_http_message_body_init(NULL, NULL); \ php_stream_to_zval(php_http_message_body_stream(obj->body), obj->gc); \ } \ } while(0) ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessageBody___construct, 0, 0, 0) ZEND_ARG_INFO(0, stream) ZEND_END_ARG_INFO(); PHP_METHOD(HttpMessageBody, __construct) { php_http_message_body_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); zval *zstream = NULL; php_stream *stream; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|r!", &zstream), invalid_arg, return); if (zstream) { php_http_expect(php_stream_from_zval_no_verify(stream, zstream), unexpected_val, return); if (obj->body) { php_http_message_body_free(&obj->body); } obj->body = php_http_message_body_init(NULL, stream); php_stream_to_zval(stream, obj->gc); } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessageBody___toString, 0, 0, 0) ZEND_END_ARG_INFO(); PHP_METHOD(HttpMessageBody, __toString) { if (SUCCESS == zend_parse_parameters_none()) { php_http_message_body_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); zend_string *zs; PHP_HTTP_MESSAGE_BODY_OBJECT_INIT(obj); zs = php_http_message_body_to_string(obj->body, 0, 0); if (zs) { RETURN_STR(zs); } } RETURN_EMPTY_STRING(); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessageBody_unserialize, 0, 0, 1) ZEND_ARG_INFO(0, serialized) ZEND_END_ARG_INFO(); PHP_METHOD(HttpMessageBody, unserialize) { zend_string *us_str; if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "S", &us_str)) { php_http_message_body_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); php_stream *s = php_http_mem_stream_open(0, us_str); obj->body = php_http_message_body_init(NULL, s); php_stream_to_zval(s, obj->gc); } } ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(ai_HttpMessageBody___unserialize, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, data, IS_ARRAY, 0) ZEND_END_ARG_INFO(); PHP_METHOD(HttpMessageBody, __unserialize) { HashTable *arr; if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "h", &arr)) { zval *zv = zend_hash_index_find(arr, 0); if (zv) { zend_string *zs = zval_get_string(zv); php_stream *s = php_http_mem_stream_open(0, zs); php_http_message_body_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); obj->body = php_http_message_body_init(NULL, s); php_stream_to_zval(s, obj->gc); zend_string_release(zs); } } } ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(ai_HttpMessageBody___serialize, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO(); PHP_METHOD(HttpMessageBody, __serialize) { php_http_message_body_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); zend_string *zs; zend_parse_parameters_none(); PHP_HTTP_MESSAGE_BODY_OBJECT_INIT(obj); array_init(return_value); zs = php_http_message_body_to_string(obj->body, 0, 0); if (zs) { add_index_str(return_value, 0, zs); } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessageBody_toStream, 0, 0, 1) ZEND_ARG_INFO(0, stream) ZEND_ARG_INFO(0, offset) ZEND_ARG_INFO(0, maxlen) ZEND_END_ARG_INFO(); PHP_METHOD(HttpMessageBody, toStream) { zval *zstream; zend_long offset = 0, forlen = 0; if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "r|ll", &zstream, &offset, &forlen)) { php_stream *stream; php_http_message_body_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_MESSAGE_BODY_OBJECT_INIT(obj); php_stream_from_zval(stream, zstream); php_http_message_body_to_stream(obj->body, stream, offset, forlen); RETURN_ZVAL(getThis(), 1, 0); } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessageBody_toCallback, 0, 0, 1) ZEND_ARG_INFO(0, callback) ZEND_ARG_INFO(0, offset) ZEND_ARG_INFO(0, maxlen) ZEND_END_ARG_INFO(); PHP_METHOD(HttpMessageBody, toCallback) { php_http_pass_fcall_arg_t fcd; zend_long offset = 0, forlen = 0; if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "f|ll", &fcd.fci, &fcd.fcc, &offset, &forlen)) { php_http_message_body_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_MESSAGE_BODY_OBJECT_INIT(obj); ZVAL_COPY(&fcd.fcz, getThis()); php_http_message_body_to_callback(obj->body, php_http_pass_fcall_callback, &fcd, offset, forlen); zend_fcall_info_args_clear(&fcd.fci, 1); zval_ptr_dtor(&fcd.fcz); RETURN_ZVAL(getThis(), 1, 0); } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessageBody_getResource, 0, 0, 0) ZEND_END_ARG_INFO(); PHP_METHOD(HttpMessageBody, getResource) { if (SUCCESS == zend_parse_parameters_none()) { php_http_message_body_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_MESSAGE_BODY_OBJECT_INIT(obj); php_stream_to_zval(php_http_message_body_stream(obj->body), return_value); Z_ADDREF_P(return_value); } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessageBody_getBoundary, 0, 0, 0) ZEND_END_ARG_INFO(); PHP_METHOD(HttpMessageBody, getBoundary) { if (SUCCESS == zend_parse_parameters_none()) { php_http_message_body_object_t * obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_MESSAGE_BODY_OBJECT_INIT(obj); if (obj->body->boundary) { RETURN_STRING(obj->body->boundary); } } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessageBody_append, 0, 0, 1) ZEND_ARG_INFO(0, string) ZEND_END_ARG_INFO(); PHP_METHOD(HttpMessageBody, append) { char *str; size_t len; php_http_message_body_object_t *obj; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &str, &len), invalid_arg, return); obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_MESSAGE_BODY_OBJECT_INIT(obj); php_http_expect(len == php_http_message_body_append(obj->body, str, len), runtime, return); RETURN_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessageBody_addForm, 0, 0, 0) ZEND_ARG_ARRAY_INFO(0, fields, 1) ZEND_ARG_ARRAY_INFO(0, files, 1) ZEND_END_ARG_INFO(); PHP_METHOD(HttpMessageBody, addForm) { HashTable *fields = NULL, *files = NULL; php_http_message_body_object_t *obj; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|h!h!", &fields, &files), invalid_arg, return); obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_MESSAGE_BODY_OBJECT_INIT(obj); php_http_expect(SUCCESS == php_http_message_body_add_form(obj->body, fields, files), runtime, return); RETURN_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessageBody_addPart, 0, 0, 1) ZEND_ARG_OBJ_INFO(0, message, http\\Message, 0) ZEND_END_ARG_INFO(); PHP_METHOD(HttpMessageBody, addPart) { zval *zobj; php_http_message_body_object_t *obj; php_http_message_object_t *mobj; zend_error_handling zeh; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O", &zobj, php_http_message_get_class_entry()), invalid_arg, return); obj = PHP_HTTP_OBJ(NULL, getThis()); mobj = PHP_HTTP_OBJ(NULL, zobj); PHP_HTTP_MESSAGE_BODY_OBJECT_INIT(obj); zend_replace_error_handling(EH_THROW, php_http_get_exception_runtime_class_entry(), &zeh); php_http_message_body_add_part(obj->body, mobj->message); zend_restore_error_handling(&zeh); if (!EG(exception)) { RETURN_ZVAL(getThis(), 1, 0); } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessageBody_etag, 0, 0, 0) ZEND_END_ARG_INFO(); PHP_METHOD(HttpMessageBody, etag) { if (SUCCESS == zend_parse_parameters_none()) { php_http_message_body_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); char *etag; PHP_HTTP_MESSAGE_BODY_OBJECT_INIT(obj); if ((etag = php_http_message_body_etag(obj->body))) { RETURN_STR(php_http_cs2zs(etag, strlen(etag))); } else { RETURN_FALSE; } } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessageBody_stat, 0, 0, 0) ZEND_ARG_INFO(0, field) ZEND_END_ARG_INFO(); PHP_METHOD(HttpMessageBody, stat) { char *field_str = NULL; size_t field_len = 0; if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|s", &field_str, &field_len)) { php_http_message_body_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); const php_stream_statbuf *sb; PHP_HTTP_MESSAGE_BODY_OBJECT_INIT(obj); if ((sb = php_http_message_body_stat(obj->body))) { if (field_str && field_len) { switch (*field_str) { case 's': case 'S': RETURN_LONG(sb->sb.st_size); break; case 'a': case 'A': RETURN_LONG(sb->sb.st_atime); break; case 'm': case 'M': RETURN_LONG(sb->sb.st_mtime); break; case 'c': case 'C': RETURN_LONG(sb->sb.st_ctime); break; default: php_error_docref(NULL, E_WARNING, "Unknown stat field: '%s' (should be one of [s]ize, [a]time, [m]time or [c]time)", field_str); break; } } else { object_init(return_value); add_property_long_ex(return_value, ZEND_STRL("size"), sb->sb.st_size); add_property_long_ex(return_value, ZEND_STRL("atime"), sb->sb.st_atime); add_property_long_ex(return_value, ZEND_STRL("mtime"), sb->sb.st_mtime); add_property_long_ex(return_value, ZEND_STRL("ctime"), sb->sb.st_ctime); } } } } static zend_function_entry php_http_message_body_methods[] = { PHP_ME(HttpMessageBody, __construct, ai_HttpMessageBody___construct, ZEND_ACC_PUBLIC) PHP_ME(HttpMessageBody, __toString, ai_HttpMessageBody___toString, ZEND_ACC_PUBLIC) PHP_MALIAS(HttpMessageBody, toString, __toString, ai_HttpMessageBody___toString, ZEND_ACC_PUBLIC) PHP_MALIAS(HttpMessageBody, serialize, __toString, ai_HttpMessageBody___toString, ZEND_ACC_PUBLIC) PHP_ME(HttpMessageBody, unserialize, ai_HttpMessageBody_unserialize, ZEND_ACC_PUBLIC) PHP_ME(HttpMessageBody, __serialize, ai_HttpMessageBody___serialize, ZEND_ACC_PUBLIC) PHP_ME(HttpMessageBody, __unserialize,ai_HttpMessageBody___unserialize,ZEND_ACC_PUBLIC) PHP_ME(HttpMessageBody, toStream, ai_HttpMessageBody_toStream, ZEND_ACC_PUBLIC) PHP_ME(HttpMessageBody, toCallback, ai_HttpMessageBody_toCallback, ZEND_ACC_PUBLIC) PHP_ME(HttpMessageBody, getResource, ai_HttpMessageBody_getResource, ZEND_ACC_PUBLIC) PHP_ME(HttpMessageBody, getBoundary, ai_HttpMessageBody_getBoundary, ZEND_ACC_PUBLIC) PHP_ME(HttpMessageBody, append, ai_HttpMessageBody_append, ZEND_ACC_PUBLIC) PHP_ME(HttpMessageBody, addForm, ai_HttpMessageBody_addForm, ZEND_ACC_PUBLIC) PHP_ME(HttpMessageBody, addPart, ai_HttpMessageBody_addPart, ZEND_ACC_PUBLIC) PHP_ME(HttpMessageBody, etag, ai_HttpMessageBody_etag, ZEND_ACC_PUBLIC) PHP_ME(HttpMessageBody, stat, ai_HttpMessageBody_stat, ZEND_ACC_PUBLIC) EMPTY_FUNCTION_ENTRY }; PHP_MINIT_FUNCTION(http_message_body) { zend_class_entry ce = {0}; INIT_NS_CLASS_ENTRY(ce, "http\\Message", "Body", php_http_message_body_methods); php_http_message_body_class_entry = zend_register_internal_class(&ce); php_http_message_body_class_entry->create_object = php_http_message_body_object_new; memcpy(&php_http_message_body_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); php_http_message_body_object_handlers.offset = XtOffsetOf(php_http_message_body_object_t, zo); php_http_message_body_object_handlers.clone_obj = php_http_message_body_object_clone; php_http_message_body_object_handlers.free_obj = php_http_message_body_object_free; php_http_message_body_object_handlers.get_gc = php_http_message_body_object_get_gc; zend_class_implements(php_http_message_body_class_entry, 1, zend_ce_serializable); 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 */ pecl_http-4.2.1/src/php_http_message_body.h0000644000076500000240000001013314117626035017562 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_HTTP_MESSAGE_BODY_H #define PHP_HTTP_MESSAGE_BODY_H typedef struct php_http_message_body { php_stream_statbuf ssb; zend_resource *res; char *boundary; unsigned refcount; } php_http_message_body_t; struct php_http_message; PHP_HTTP_API php_http_message_body_t *php_http_message_body_init(php_http_message_body_t **body, php_stream *stream); PHP_HTTP_API unsigned php_http_message_body_addref(php_http_message_body_t *body); PHP_HTTP_API php_http_message_body_t *php_http_message_body_copy(php_http_message_body_t *from, php_http_message_body_t *to); PHP_HTTP_API ZEND_RESULT_CODE php_http_message_body_add_form(php_http_message_body_t *body, HashTable *fields, HashTable *files); PHP_HTTP_API ZEND_RESULT_CODE php_http_message_body_add_form_field(php_http_message_body_t *body, const char *name, const char *value_str, size_t value_len); PHP_HTTP_API ZEND_RESULT_CODE php_http_message_body_add_form_file(php_http_message_body_t *body, const char *name, const char *ctype, const char *file, php_stream *stream); PHP_HTTP_API void php_http_message_body_add_part(php_http_message_body_t *body, struct php_http_message *part); PHP_HTTP_API size_t php_http_message_body_append(php_http_message_body_t *body, const char *buf, size_t len); PHP_HTTP_API size_t php_http_message_body_appendf(php_http_message_body_t *body, const char *fmt, ...); PHP_HTTP_API zend_string *php_http_message_body_to_string(php_http_message_body_t *body, off_t offset, size_t forlen); PHP_HTTP_API ZEND_RESULT_CODE php_http_message_body_to_stream(php_http_message_body_t *body, php_stream *s, off_t offset, size_t forlen); PHP_HTTP_API ZEND_RESULT_CODE php_http_message_body_to_callback(php_http_message_body_t *body, php_http_pass_callback_t cb, void *cb_arg, off_t offset, size_t forlen); PHP_HTTP_API void php_http_message_body_free(php_http_message_body_t **body); PHP_HTTP_API const php_stream_statbuf *php_http_message_body_stat(php_http_message_body_t *body); PHP_HTTP_API char *php_http_message_body_etag(php_http_message_body_t *body); PHP_HTTP_API const char *php_http_message_body_boundary(php_http_message_body_t *body); PHP_HTTP_API struct php_http_message *php_http_message_body_split(php_http_message_body_t *body, const char *boundary); static inline size_t php_http_message_body_size(php_http_message_body_t *b) { return php_http_message_body_stat(b)->sb.st_size; } static inline time_t php_http_message_body_mtime(php_http_message_body_t *b) { return php_http_message_body_stat(b)->sb.st_mtime; } static inline php_stream *php_http_message_body_stream(php_http_message_body_t *body) { return body && body->res ? body->res->ptr : NULL; } static inline zend_resource *php_http_message_body_resource(php_http_message_body_t *body) { return body ? body->res : NULL; } typedef struct php_http_message_body_object { php_http_message_body_t *body; zval *gc; zend_object zo; } php_http_message_body_object_t; PHP_HTTP_API zend_class_entry *php_http_get_message_body_class_entry(void); PHP_MINIT_FUNCTION(http_message_body); zend_object *php_http_message_body_object_new(zend_class_entry *ce); php_http_message_body_object_t *php_http_message_body_object_new_ex(zend_class_entry *ce, php_http_message_body_t *body); zend_object *php_http_message_body_object_clone(zend_object *object); void php_http_message_body_object_free(zend_object *object); #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 */ pecl_http-4.2.1/src/php_http_message.c0000644000076500000240000020755114117626035016554 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #include "php_http_api.h" static void message_headers(php_http_message_t *msg, php_http_buffer_t *str); zend_bool php_http_message_info_callback(php_http_message_t **message, HashTable **headers, php_http_info_t *info) { php_http_message_t *old = *message; /* advance message */ if (!old || old->type || zend_hash_num_elements(&old->hdrs)) { (*message) = php_http_message_init(NULL, 0, NULL); (*message)->parent = old; if (headers) { (*headers) = &((*message)->hdrs); } } if (info) { php_http_message_set_info(*message, info); } return old != *message; } php_http_message_t *php_http_message_init(php_http_message_t *message, php_http_message_type_t type, php_http_message_body_t *body) { if (!message) { message = emalloc(sizeof(*message)); } memset(message, 0, sizeof(*message)); php_http_message_set_type(message, type); message->http.version.major = 1; message->http.version.minor = 1; zend_hash_init(&message->hdrs, 0, NULL, ZVAL_PTR_DTOR, 0); message->body = body ? body : php_http_message_body_init(NULL, NULL); return message; } php_http_message_t *php_http_message_init_env(php_http_message_t *message, php_http_message_type_t type) { int free_msg = !message; zval *sval, tval; php_http_message_body_t *mbody; switch (type) { case PHP_HTTP_REQUEST: mbody = php_http_env_get_request_body(); php_http_message_body_addref(mbody); message = php_http_message_init(message, type, mbody); if ((sval = php_http_env_get_server_var(ZEND_STRL("SERVER_PROTOCOL"), 1)) && !strncmp(Z_STRVAL_P(sval), "HTTP/", lenof("HTTP/"))) { php_http_version_parse(&message->http.version, Z_STRVAL_P(sval)); } if ((sval = php_http_env_get_server_var(ZEND_STRL("REQUEST_METHOD"), 1))) { message->http.info.request.method = estrdup(Z_STRVAL_P(sval)); } if ((sval = php_http_env_get_server_var(ZEND_STRL("REQUEST_URI"), 1))) { message->http.info.request.url = php_http_url_parse(Z_STRVAL_P(sval), Z_STRLEN_P(sval), PHP_HTTP_URL_STDFLAGS); } php_http_env_get_request_headers(&message->hdrs); break; case PHP_HTTP_RESPONSE: message = php_http_message_init(message, type, NULL); if (!SG(sapi_headers).http_status_line || !php_http_info_parse((php_http_info_t *) &message->http, SG(sapi_headers).http_status_line)) { if (!(message->http.info.response.code = SG(sapi_headers).http_response_code)) { message->http.info.response.code = 200; } message->http.info.response.status = estrdup(php_http_env_get_response_status_for_code(message->http.info.response.code)); } php_http_env_get_response_headers(&message->hdrs); if (php_output_get_level()) { if (php_output_get_status() & PHP_OUTPUT_SENT) { php_error_docref(NULL, E_WARNING, "Could not fetch response body, output has already been sent at %s:%d", php_output_get_start_filename(), php_output_get_start_lineno()); goto error; } else if (SUCCESS != php_output_get_contents(&tval)) { php_error_docref(NULL, E_WARNING, "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) { if (message) { php_http_message_free(&message); } } else { message = NULL; } break; } return message; } php_http_message_t *php_http_message_parse(php_http_message_t *msg, const char *str, size_t len, zend_bool greedy) { php_http_message_parser_t p; php_http_buffer_t buf; unsigned flags = PHP_HTTP_MESSAGE_PARSER_CLEANUP; int free_msg; php_http_buffer_from_string_ex(&buf, str, len); php_http_message_parser_init(&p); if ((free_msg = !msg)) { msg = php_http_message_init(NULL, 0, NULL); } if (greedy) { flags |= PHP_HTTP_MESSAGE_PARSER_GREEDY; } if (PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE == php_http_message_parser_parse(&p, &buf, flags, &msg)) { if (free_msg) { php_http_message_free(&msg); } msg = NULL; } php_http_message_parser_dtor(&p); php_http_buffer_dtor(&buf); return msg; } zval *php_http_message_header(php_http_message_t *msg, const char *key_str, size_t key_len) { zval *ret; char *key; ALLOCA_FLAG(free_key); key = do_alloca(key_len + 1, free_key); memcpy(key, key_str, key_len); key[key_len] = '\0'; php_http_pretty_key(key, key_len, 1, 1); ret = zend_symtable_str_find(&msg->hdrs, key, key_len); free_alloca(key, free_key); return ret; } zend_bool php_http_message_is_multipart(php_http_message_t *msg, char **boundary) { zend_string *ct = php_http_message_header_string(msg, ZEND_STRL("Content-Type")); zend_bool is_multipart = 0; if (ct) { php_http_params_opts_t popts; HashTable params; ZEND_INIT_SYMTABLE(¶ms); php_http_params_opts_default_get(&popts); popts.input.str = ct->val; popts.input.len = ct->len; if (EXPECTED(php_http_params_parse(¶ms, &popts))) { zval *cur, *arg; zend_string *ct_str; zend_ulong index; zend_hash_internal_pointer_reset(¶ms); if (EXPECTED((cur = zend_hash_get_current_data(¶ms)) && (Z_TYPE_P(cur) == IS_ARRAY) && (HASH_KEY_IS_STRING == zend_hash_get_current_key(¶ms, &ct_str, &index))) ) { if (php_http_match(ct_str->val, "multipart", PHP_HTTP_MATCH_WORD)) { is_multipart = 1; /* get boundary */ if (EXPECTED(boundary && (arg = zend_hash_str_find(Z_ARRVAL_P(cur), ZEND_STRL("arguments"))) && Z_TYPE_P(arg) == IS_ARRAY) ) { zval *val; php_http_arrkey_t key; ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(arg), key.h, key.key, val) { if (key.key && key.key->len == lenof("boundary") && !strcasecmp(key.key->val, "boundary")) { zend_string *bnd = zval_get_string(val); if (EXPECTED(bnd->len)) { *boundary = estrndup(bnd->val, bnd->len); } zend_string_release(bnd); } } ZEND_HASH_FOREACH_END(); } } } } zend_hash_destroy(¶ms); zend_string_release(ct); } return is_multipart; } /* */ void php_http_message_set_type(php_http_message_t *message, php_http_message_type_t type) { /* just act if different */ if (type != message->type) { /* free request info */ switch (message->type) { case PHP_HTTP_REQUEST: PTR_FREE(message->http.info.request.method); PTR_FREE(message->http.info.request.url); break; case PHP_HTTP_RESPONSE: PTR_FREE(message->http.info.response.status); break; default: break; } message->type = type; memset(&message->http, 0, sizeof(message->http)); } } void php_http_message_set_info(php_http_message_t *message, php_http_info_t *info) { php_http_message_set_type(message, info->type); message->http.version = info->http.version; switch (message->type) { case PHP_HTTP_REQUEST: PTR_SET(PHP_HTTP_INFO(message).request.url, PHP_HTTP_INFO(info).request.url ? php_http_url_copy(PHP_HTTP_INFO(info).request.url, 0) : NULL); PTR_SET(PHP_HTTP_INFO(message).request.method, PHP_HTTP_INFO(info).request.method ? estrdup(PHP_HTTP_INFO(info).request.method) : NULL); break; case PHP_HTTP_RESPONSE: PHP_HTTP_INFO(message).response.code = PHP_HTTP_INFO(info).response.code; PTR_SET(PHP_HTTP_INFO(message).response.status, PHP_HTTP_INFO(info).response.status ? estrdup(PHP_HTTP_INFO(info).response.status) : NULL); break; default: break; } } void php_http_message_update_headers(php_http_message_t *msg) { zval h; size_t size; zend_string *cl; if (php_http_message_body_stream(msg->body)->readfilters.head) { /* if a read stream filter is attached to the body the caller must also care for the headers */ } else if (php_http_message_header(msg, ZEND_STRL("Content-Range"))) { /* don't mess around with a Content-Range message */ } else if ((size = php_http_message_body_size(msg->body))) { ZVAL_LONG(&h, size); zend_hash_str_update(&msg->hdrs, "Content-Length", lenof("Content-Length"), &h); if (msg->body->boundary) { char *str; size_t len; zend_string *ct; if (!(ct = php_http_message_header_string(msg, ZEND_STRL("Content-Type")))) { len = spprintf(&str, 0, "multipart/form-data; boundary=\"%s\"", msg->body->boundary); ZVAL_STR(&h, php_http_cs2zs(str, len)); zend_hash_str_update(&msg->hdrs, "Content-Type", lenof("Content-Type"), &h); } else if (!php_http_match(ct->val, "boundary=", PHP_HTTP_MATCH_WORD)) { len = spprintf(&str, 0, "%s; boundary=\"%s\"", ct->val, msg->body->boundary); ZVAL_STR(&h, php_http_cs2zs(str, len)); zend_hash_str_update(&msg->hdrs, "Content-Type", lenof("Content-Type"), &h); zend_string_release(ct); } else { zend_string_release(ct); } } } else if ((cl = php_http_message_header_string(msg, ZEND_STRL("Content-Length")))) { if (!zend_string_equals_literal(cl, "0")) { /* body->size == 0, so get rid of old Content-Length */ zend_hash_str_del(&msg->hdrs, ZEND_STRL("Content-Length")); } zend_string_release(cl); } else if (msg->type == PHP_HTTP_REQUEST) { if (!php_http_message_header(msg, ZEND_STRL("Transfer-Encoding"))) { /* no filter, no CR, no size, no TE, no CL */ if (0 <= php_http_select_str(msg->http.info.request.method, 3, "POST", "PUT", "PATCH")) { /* quoting RFC7230#section-3.3.2 A user agent SHOULD send a Content-Length in a request message when no Transfer-Encoding is sent and the request method defines a meaning for an enclosed payload body. For example, a Content-Length header field is normally sent in a POST request even when the value is 0 (indicating an empty payload body). A user agent SHOULD NOT send a Content-Length header field when the request message does not contain a payload body and the method semantics do not anticipate such a body. */ ZVAL_LONG(&h, 0); zend_hash_str_update(&msg->hdrs, "Content-Length", lenof("Content-Length"), &h); } } } } static void message_headers(php_http_message_t *msg, php_http_buffer_t *str) { char *tmp = NULL; size_t len = 0; php_http_info_to_string((php_http_info_t *) msg, &tmp, &len, PHP_HTTP_CRLF); php_http_message_update_headers(msg); php_http_buffer_append(str, tmp, len); php_http_header_to_string(str, &msg->hdrs); PTR_FREE(tmp); } void php_http_message_to_callback(php_http_message_t *msg, php_http_pass_callback_t cb, void *cb_arg) { php_http_buffer_t str; php_http_buffer_init_ex(&str, 0x1000, 0); message_headers(msg, &str); cb(cb_arg, str.data, str.used); php_http_buffer_dtor(&str); if (php_http_message_body_size(msg->body)) { cb(cb_arg, ZEND_STRL(PHP_HTTP_CRLF)); php_http_message_body_to_callback(msg->body, cb, cb_arg, 0, 0); } } void php_http_message_to_string(php_http_message_t *msg, char **string, size_t *length) { php_http_buffer_t str; char *data; php_http_buffer_init_ex(&str, 0x1000, 0); message_headers(msg, &str); if (php_http_message_body_size(msg->body)) { php_http_buffer_appends(&str, PHP_HTTP_CRLF); php_http_message_body_to_callback(msg->body, (php_http_pass_callback_t) php_http_buffer_append, &str, 0, 0); } data = php_http_buffer_data(&str, string, length); if (!string) { efree(data); } php_http_buffer_dtor(&str); } void php_http_message_serialize(php_http_message_t *message, char **string, size_t *length) { char *buf; php_http_buffer_t str; php_http_message_t *msg; php_http_buffer_init(&str); msg = message = php_http_message_reverse(message); do { php_http_message_to_callback(message, (php_http_pass_callback_t) php_http_buffer_append, &str); php_http_buffer_appends(&str, PHP_HTTP_CRLF); } while ((message = message->parent)); php_http_message_reverse(msg); buf = php_http_buffer_data(&str, string, length); if (!string) { efree(buf); } php_http_buffer_dtor(&str); } php_http_message_t *php_http_message_reverse(php_http_message_t *msg) { size_t i, c = php_http_message_count(msg); if (c > 1) { php_http_message_t *tmp = msg, **arr; arr = ecalloc(c, sizeof(*arr)); for (i = 0; i < c; ++i) { arr[i] = tmp; tmp = tmp->parent; } arr[0]->parent = NULL; for (i = 0; i < c-1; ++i) { arr[i+1]->parent = arr[i]; } msg = arr[c-1]; efree(arr); } return msg; } php_http_message_t *php_http_message_zip(php_http_message_t *dst, php_http_message_t *src) { php_http_message_t *tmp_dst, *tmp_src, *ret = dst; while (dst && src) { tmp_dst = dst->parent; tmp_src = src->parent; dst->parent = src; if (tmp_dst) { src->parent = tmp_dst; } src = tmp_src; dst = tmp_dst; } return ret; } php_http_message_t *php_http_message_copy_ex(php_http_message_t *from, php_http_message_t *to, zend_bool parents) { php_http_message_t *temp, *copy = NULL; php_http_info_t info; if (from) { info.type = from->type; info.http = from->http; copy = temp = php_http_message_init(to, 0, php_http_message_body_copy(from->body, NULL)); php_http_message_set_info(temp, &info); array_copy(&from->hdrs, &temp->hdrs); if (parents) while (from->parent) { info.type = from->parent->type; info.http = from->parent->http; temp->parent = php_http_message_init(NULL, 0, php_http_message_body_copy(from->parent->body, NULL)); php_http_message_set_info(temp->parent, &info); array_copy(&from->parent->hdrs, &temp->parent->hdrs); temp = temp->parent; from = from->parent; } } return copy; } void php_http_message_dtor(php_http_message_t *message) { if (EXPECTED(message)) { zend_hash_destroy(&message->hdrs); php_http_message_body_free(&message->body); switch (message->type) { case PHP_HTTP_REQUEST: PTR_SET(message->http.info.request.method, NULL); PTR_SET(message->http.info.request.url, NULL); break; case PHP_HTTP_RESPONSE: PTR_SET(message->http.info.response.status, NULL); break; default: break; } } } void php_http_message_free(php_http_message_t **message) { if (EXPECTED(*message)) { if ((*message)->parent) { php_http_message_free(&(*message)->parent); } php_http_message_dtor(*message); efree(*message); *message = NULL; } } static zend_class_entry *php_http_message_class_entry; zend_class_entry *php_http_message_get_class_entry(void) { return php_http_message_class_entry; } static zval *php_http_message_object_read_prop(zend_object *object, zend_string *member, int type, void **cache_slot, zval *rv); static zval *php_http_message_object_write_prop(zend_object *object, zend_string *member, zval *value, void **cache_slot); static zend_object_handlers php_http_message_object_handlers; static HashTable php_http_message_object_prophandlers; static void php_http_message_object_prophandler_hash_dtor(zval *pData) { pefree(Z_PTR_P(pData), 1); } typedef void (*php_http_message_object_prophandler_func_t)(php_http_message_object_t *o, zval *v); typedef struct php_http_message_object_prophandler { php_http_message_object_prophandler_func_t read; php_http_message_object_prophandler_func_t write; } php_http_message_object_prophandler_t; static ZEND_RESULT_CODE php_http_message_object_add_prophandler(const char *prop_str, size_t prop_len, php_http_message_object_prophandler_func_t read, php_http_message_object_prophandler_func_t write) { php_http_message_object_prophandler_t h = { read, write }; if (!zend_hash_str_add_mem(&php_http_message_object_prophandlers, prop_str, prop_len, (void *) &h, sizeof(h))) { return FAILURE; } return SUCCESS; } static php_http_message_object_prophandler_t *php_http_message_object_get_prophandler(zend_string *name_str) { return zend_hash_str_find_ptr(&php_http_message_object_prophandlers, name_str->val, name_str->len); } static void php_http_message_object_prophandler_get_type(php_http_message_object_t *obj, zval *return_value) { zval_ptr_dtor(return_value); RETVAL_LONG(obj->message->type); } static void php_http_message_object_prophandler_set_type(php_http_message_object_t *obj, zval *value) { php_http_message_set_type(obj->message, zval_get_long(value)); } static void php_http_message_object_prophandler_get_request_method(php_http_message_object_t *obj, zval *return_value) { zval_ptr_dtor(return_value); if (PHP_HTTP_MESSAGE_TYPE(REQUEST, obj->message) && obj->message->http.info.request.method) { RETVAL_STRING(obj->message->http.info.request.method); } else { RETVAL_NULL(); } } static void php_http_message_object_prophandler_set_request_method(php_http_message_object_t *obj, zval *value) { if (PHP_HTTP_MESSAGE_TYPE(REQUEST, obj->message)) { zend_string *zs = zval_get_string(value); PTR_SET(obj->message->http.info.request.method, estrndup(zs->val, zs->len)); zend_string_release(zs); } } static void php_http_message_object_prophandler_get_request_url(php_http_message_object_t *obj, zval *return_value) { char *url_str; size_t url_len; zval_ptr_dtor(return_value); if (PHP_HTTP_MESSAGE_TYPE(REQUEST, obj->message) && obj->message->http.info.request.url && php_http_url_to_string(obj->message->http.info.request.url, &url_str, &url_len, 0)) { RETVAL_STR(php_http_cs2zs(url_str, url_len)); } else { RETVAL_NULL(); } } static void php_http_message_object_prophandler_set_request_url(php_http_message_object_t *obj, zval *value) { if (PHP_HTTP_MESSAGE_TYPE(REQUEST, obj->message)) { PTR_SET(obj->message->http.info.request.url, php_http_url_from_zval(value, PHP_HTTP_URL_STDFLAGS)); } } static void php_http_message_object_prophandler_get_response_status(php_http_message_object_t *obj, zval *return_value) { zval_ptr_dtor(return_value); if (PHP_HTTP_MESSAGE_TYPE(RESPONSE, obj->message) && obj->message->http.info.response.status) { RETVAL_STRING(obj->message->http.info.response.status); } else { RETVAL_NULL(); } } static void php_http_message_object_prophandler_set_response_status(php_http_message_object_t *obj, zval *value) { if (PHP_HTTP_MESSAGE_TYPE(RESPONSE, obj->message)) { zend_string *zs = zval_get_string(value); PTR_SET(obj->message->http.info.response.status, estrndup(zs->val, zs->len)); zend_string_release(zs); } } static void php_http_message_object_prophandler_get_response_code(php_http_message_object_t *obj, zval *return_value) { zval_ptr_dtor(return_value); if (PHP_HTTP_MESSAGE_TYPE(RESPONSE, obj->message)) { RETVAL_LONG(obj->message->http.info.response.code); } else { RETVAL_NULL(); } } static void php_http_message_object_prophandler_set_response_code(php_http_message_object_t *obj, zval *value) { if (PHP_HTTP_MESSAGE_TYPE(RESPONSE, obj->message)) { obj->message->http.info.response.code = zval_get_long(value); PTR_SET(obj->message->http.info.response.status, estrdup(php_http_env_get_response_status_for_code(obj->message->http.info.response.code))); } } static void php_http_message_object_prophandler_get_http_version(php_http_message_object_t *obj, zval *return_value) { char *version_str; size_t version_len; zval_ptr_dtor(return_value); php_http_version_to_string(&obj->message->http.version, &version_str, &version_len, NULL, NULL); RETVAL_STR(php_http_cs2zs(version_str, version_len)); } static void php_http_message_object_prophandler_set_http_version(php_http_message_object_t *obj, zval *value) { zend_string *zs = zval_get_string(value); php_http_version_parse(&obj->message->http.version, zs->val); zend_string_release(zs); } static void php_http_message_object_prophandler_get_headers(php_http_message_object_t *obj, zval *return_value ) { zval tmp; ZVAL_COPY_VALUE(&tmp, return_value); array_init(return_value); array_copy(&obj->message->hdrs, Z_ARRVAL_P(return_value)); zval_ptr_dtor(&tmp); } static void php_http_message_object_prophandler_set_headers(php_http_message_object_t *obj, zval *value) { int converted = 0; HashTable garbage, *src; if (Z_TYPE_P(value) != IS_ARRAY && Z_TYPE_P(value) != IS_OBJECT) { converted = 1; SEPARATE_ZVAL(value); convert_to_array(value); } src = HASH_OF(value); garbage = obj->message->hdrs; zend_hash_init(&obj->message->hdrs, zend_hash_num_elements(src), NULL, ZVAL_PTR_DTOR, 0); array_copy(HASH_OF(value), &obj->message->hdrs); zend_hash_destroy(&garbage); if (converted) { zval_ptr_dtor(value); } } static void php_http_message_object_prophandler_get_body(php_http_message_object_t *obj, zval *return_value) { zval tmp; if (!obj->body) { RETURN_NULL(); } ZVAL_COPY_VALUE(&tmp, return_value); RETVAL_OBJECT(&obj->body->zo, 1); zval_ptr_dtor(&tmp); } static void php_http_message_object_prophandler_set_body(php_http_message_object_t *obj, zval *value) { php_http_message_object_set_body(obj, value); } static void php_http_message_object_prophandler_get_parent_message(php_http_message_object_t *obj, zval *return_value) { if (obj->message->parent) { zval tmp; ZVAL_COPY_VALUE(&tmp, return_value); RETVAL_OBJECT(&obj->parent->zo, 1); zval_ptr_dtor(&tmp); } else { RETVAL_NULL(); } } static void php_http_message_object_prophandler_set_parent_message(php_http_message_object_t *obj, zval *value) { if (Z_TYPE_P(value) == IS_OBJECT && instanceof_function(Z_OBJCE_P(value), php_http_message_class_entry)) { php_http_message_object_t *parent_obj = PHP_HTTP_OBJ(NULL, value); Z_ADDREF_P(value); if (obj->message->parent) { zend_object_release(&obj->parent->zo); } obj->parent = parent_obj; obj->message->parent = parent_obj->message; } } #define PHP_HTTP_MESSAGE_OBJECT_INIT(obj) \ do { \ if (!obj->message) { \ obj->message = php_http_message_init(NULL, 0, NULL); \ } else if (!obj->body && php_http_message_body_size(obj->message->body)) { \ php_http_message_object_init_body_object(obj); \ } \ } while(0) void php_http_message_object_reverse(zval *zmsg, zval *return_value) { size_t i; php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, zmsg); PHP_HTTP_MESSAGE_OBJECT_INIT(obj); /* count */ i = php_http_message_count(obj->message); if (i > 1) { php_http_message_object_t **objects; int last; objects = ecalloc(i, sizeof(*objects)); /* we are the first message */ objects[0] = obj; /* fetch parents */ for (i = 1; obj->parent; ++i) { objects[i] = obj = obj->parent; } /* reorder parents */ for (last = --i; i; --i) { objects[i]->message->parent = objects[i-1]->message; objects[i]->parent = objects[i-1]; } objects[0]->message->parent = NULL; objects[0]->parent = NULL; /* add ref, because we previously have not been a parent message */ Z_ADDREF_P(zmsg); /* no addref, because we've been a parent message previously */ RETVAL_OBJECT(&objects[last]->zo, 0); efree(objects); } else { RETURN_ZVAL(zmsg, 1, 0); } } void php_http_message_object_prepend(zval *this_ptr, zval *prepend, zend_bool top) { php_http_message_t *save_parent_msg = NULL; php_http_message_object_t *save_parent_obj = NULL, *obj = PHP_HTTP_OBJ(NULL, this_ptr); php_http_message_object_t *prepend_obj = PHP_HTTP_OBJ(NULL, prepend); if (!top) { save_parent_obj = obj->parent; save_parent_msg = obj->message->parent; } else { /* iterate to the most parent object */ while (obj->parent) { obj = obj->parent; } } /* prepend */ obj->parent = prepend_obj; obj->message->parent = prepend_obj->message; /* add ref */ Z_ADDREF_P(prepend); if (!top) { prepend_obj->parent = save_parent_obj; prepend_obj->message->parent = save_parent_msg; } } ZEND_RESULT_CODE php_http_message_object_set_body(php_http_message_object_t *msg_obj, zval *zbody) { php_stream *s; zend_string *body_str; php_http_message_body_t *body; php_http_message_body_object_t *body_obj; switch (Z_TYPE_P(zbody)) { case IS_RESOURCE: php_stream_from_zval_no_verify(s, zbody); if (!s) { php_http_throw(unexpected_val, "The stream is not a valid resource"); return FAILURE; } is_resource: body = php_http_message_body_init(NULL, s); if (!(body_obj = php_http_message_body_object_new_ex(php_http_get_message_body_class_entry(), body))) { php_http_message_body_free(&body); return FAILURE; } break; case IS_OBJECT: if (instanceof_function(Z_OBJCE_P(zbody), php_http_get_message_body_class_entry())) { Z_ADDREF_P(zbody); body_obj = PHP_HTTP_OBJ(NULL, zbody); break; } /* no break */ default: body_str = zval_get_string(zbody); s = php_stream_temp_new(); php_stream_write(s, body_str->val, body_str->len); zend_string_release(body_str); goto is_resource; } if (!body_obj->body) { body_obj->body = php_http_message_body_init(NULL, NULL); } if (msg_obj->body) { zend_object_release(&msg_obj->body->zo); } if (msg_obj->message) { php_http_message_body_free(&msg_obj->message->body); msg_obj->message->body = body_obj->body; } else { msg_obj->message = php_http_message_init(NULL, 0, body_obj->body); } php_http_message_body_addref(body_obj->body); msg_obj->body = body_obj; return SUCCESS; } ZEND_RESULT_CODE php_http_message_object_init_body_object(php_http_message_object_t *obj) { php_http_message_body_addref(obj->message->body); return php_http_new((void *) &obj->body, php_http_get_message_body_class_entry(), (php_http_new_t) php_http_message_body_object_new_ex, NULL, obj->message->body); } zend_object *php_http_message_object_new(zend_class_entry *ce) { return &php_http_message_object_new_ex(ce, NULL)->zo; } php_http_message_object_t *php_http_message_object_new_ex(zend_class_entry *ce, php_http_message_t *msg) { php_http_message_object_t *o; o = ecalloc(1, sizeof(*o) + zend_object_properties_size(ce)); zend_object_std_init(&o->zo, ce); object_properties_init(&o->zo, ce); if (msg) { o->message = msg; if (msg->parent) { o->parent = php_http_message_object_new_ex(ce, msg->parent); } o->body = php_http_message_body_object_new_ex(php_http_get_message_body_class_entry(), php_http_message_body_init(&msg->body, NULL)); } o->zo.handlers = &php_http_message_object_handlers; return o; } zend_object *php_http_message_object_clone(zend_object *this_ptr) { php_http_message_object_t *new_obj; php_http_message_object_t *old_obj = PHP_HTTP_OBJ(this_ptr, NULL); new_obj = php_http_message_object_new_ex(old_obj->zo.ce, php_http_message_copy(old_obj->message, NULL)); zend_objects_clone_members(&new_obj->zo, &old_obj->zo); return &new_obj->zo; } void php_http_message_object_free(zend_object *object) { php_http_message_object_t *o = PHP_HTTP_OBJ(object, NULL); PTR_FREE(o->gc); if (!Z_ISUNDEF(o->iterator)) { zval_ptr_dtor(&o->iterator); ZVAL_UNDEF(&o->iterator); } if (o->message) { /* do NOT free recursivly */ php_http_message_dtor(o->message); efree(o->message); o->message = NULL; } if (o->parent) { zend_object_release(&o->parent->zo); o->parent = NULL; } if (o->body) { zend_object_release(&o->body->zo); o->body = NULL; } zend_object_std_dtor(object); } static zval *php_http_message_object_get_prop_ptr(zend_object *object, zend_string *member, int type, void **cache_slot) { return NULL; } static zval *php_http_message_object_read_prop(zend_object *object, zend_string *member, int type, void **cache_slot, zval *tmp) { zval *return_value; php_http_message_object_prophandler_t *handler = php_http_message_object_get_prophandler(member); return_value = zend_get_std_object_handlers()->read_property(object, member, type, cache_slot, tmp); if (handler && handler->read) { php_http_message_object_t *obj = PHP_HTTP_OBJ(object, NULL); handler->read(obj, return_value); } return return_value; } static zval *php_http_message_object_write_prop(zend_object *object, zend_string *member, zval *value, void **cache_slot) { php_http_message_object_t *obj = PHP_HTTP_OBJ(object, NULL); php_http_message_object_prophandler_t *handler; PHP_HTTP_MESSAGE_OBJECT_INIT(obj); if ((handler = php_http_message_object_get_prophandler(member))) { handler->write(obj, value); } else { zend_get_std_object_handlers()->write_property(object, member, value, cache_slot); } return value; } static HashTable *php_http_message_object_get_debug_info(zend_object *object, int *is_temp) { php_http_message_object_t *obj = PHP_HTTP_OBJ(object, NULL); HashTable *props = zend_get_std_object_handlers()->get_properties(object); char *ver_str, *url_str = NULL; size_t ver_len, url_len = 0; zval tmp; PHP_HTTP_MESSAGE_OBJECT_INIT(obj); if (is_temp) { *is_temp = 0; } #define UPDATE_PROP(name_str, action_with_tmp) \ do { \ zend_property_info *pi; \ if ((pi = zend_hash_str_find_ptr(&obj->zo.ce->properties_info, name_str, lenof(name_str)))) { \ action_with_tmp; \ zend_hash_update_ind(props, pi->name, &tmp); \ } \ } while(0) UPDATE_PROP("type", ZVAL_LONG(&tmp, obj->message->type)); ver_len = spprintf(&ver_str, 0, "%u.%u", obj->message->http.version.major, obj->message->http.version.minor); UPDATE_PROP("httpVersion", ZVAL_STR(&tmp, php_http_cs2zs(ver_str, ver_len))); switch (obj->message->type) { case PHP_HTTP_REQUEST: UPDATE_PROP("responseCode", ZVAL_LONG(&tmp, 0)); UPDATE_PROP("responseStatus", ZVAL_EMPTY_STRING(&tmp)); UPDATE_PROP("requestMethod", ZVAL_STRING(&tmp, STR_PTR(obj->message->http.info.request.method))); if (obj->message->http.info.request.url) { php_http_url_to_string(obj->message->http.info.request.url, &url_str, &url_len, 0); UPDATE_PROP("requestUrl", ZVAL_STR(&tmp, php_http_cs2zs(url_str, url_len))); } else { UPDATE_PROP("requestUrl", ZVAL_EMPTY_STRING(&tmp)); } break; case PHP_HTTP_RESPONSE: UPDATE_PROP("responseCode", ZVAL_LONG(&tmp, obj->message->http.info.response.code)); UPDATE_PROP("responseStatus", ZVAL_STRING(&tmp, STR_PTR(obj->message->http.info.response.status))); UPDATE_PROP("requestMethod", ZVAL_EMPTY_STRING(&tmp)); UPDATE_PROP("requestUrl", ZVAL_EMPTY_STRING(&tmp)); break; case PHP_HTTP_NONE: default: UPDATE_PROP("responseCode", ZVAL_LONG(&tmp, 0)); UPDATE_PROP("responseStatus", ZVAL_EMPTY_STRING(&tmp)); UPDATE_PROP("requestMethod", ZVAL_EMPTY_STRING(&tmp)); UPDATE_PROP("requestUrl", ZVAL_EMPTY_STRING(&tmp)); break; } UPDATE_PROP("headers", array_init(&tmp); array_copy(&obj->message->hdrs, Z_ARRVAL(tmp)); ); UPDATE_PROP("body", if (obj->body) { ZVAL_OBJECT(&tmp, &obj->body->zo, 1); } else { ZVAL_NULL(&tmp); } ); UPDATE_PROP("parentMessage", if (obj->message->parent) { ZVAL_OBJECT(&tmp, &obj->parent->zo, 1); } else { ZVAL_NULL(&tmp); } ); return props; } static HashTable *php_http_message_object_get_gc(zend_object *object, zval **table, int *n) { php_http_message_object_t *obj = PHP_HTTP_OBJ(object, NULL); HashTable *props = object->handlers->get_properties(object); uint32_t count = 2 + zend_hash_num_elements(props); zval *val; *n = 0; *table = obj->gc = erealloc(obj->gc, count * sizeof(zval)); if (obj->body) { ZVAL_OBJ(&obj->gc[(*n)++], &obj->body->zo); } if (obj->parent) { ZVAL_OBJ(&obj->gc[(*n)++], &obj->parent->zo); } ZEND_HASH_FOREACH_VAL(props, val) { ZVAL_COPY_VALUE(&obj->gc[(*n)++], val); } ZEND_HASH_FOREACH_END(); return NULL; } static int php_http_message_object_cast(zend_object *object, zval *return_value, int type) { php_http_message_object_t *obj = PHP_HTTP_OBJ(object, NULL); char *string; size_t length; switch (type) { case IS_STRING: PHP_HTTP_MESSAGE_OBJECT_INIT(obj); php_http_message_to_string(obj->message, &string, &length); if (string) { RETVAL_STR(php_http_cs2zs(string, length)); } else { RETVAL_EMPTY_STRING(); } return SUCCESS; case _IS_BOOL: RETVAL_TRUE; return SUCCESS; default: return FAILURE; } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage___construct, 0, 0, 0) ZEND_ARG_INFO(0, message) ZEND_ARG_INFO(0, greedy) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessage, __construct) { zend_bool greedy = 1; zval *zmessage = NULL; php_http_message_t *msg = NULL; php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); zend_error_handling zeh; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|z!b", &zmessage, &greedy), invalid_arg, return); zend_replace_error_handling(EH_THROW, php_http_get_exception_bad_message_class_entry(), &zeh); if (zmessage && Z_TYPE_P(zmessage) == IS_RESOURCE) { php_stream *s; php_http_message_parser_t p; zend_error_handling zeh; zend_replace_error_handling(EH_THROW, php_http_get_exception_unexpected_val_class_entry(), &zeh); php_stream_from_zval(s, zmessage); zend_restore_error_handling(&zeh); if (s && php_http_message_parser_init(&p)) { unsigned flags = (greedy ? PHP_HTTP_MESSAGE_PARSER_GREEDY : 0); php_http_buffer_t buf; php_http_buffer_init_ex(&buf, 0x1000, PHP_HTTP_BUFFER_INIT_PREALLOC); if (PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE == php_http_message_parser_parse_stream(&p, &buf, s, flags, &msg)) { if (!EG(exception)) { php_http_throw(bad_message, "Could not parse message from stream"); } } php_http_buffer_dtor(&buf); php_http_message_parser_dtor(&p); } if (!msg && !EG(exception)) { php_http_throw(bad_message, "Empty message received from stream"); } } else if (zmessage) { zend_string *zs_msg = zval_get_string(zmessage); msg = php_http_message_parse(NULL, zs_msg->val, zs_msg->len, greedy); if (!msg && !EG(exception)) { php_http_throw(bad_message, "Could not parse message: %.*s", (int) MIN(25, zs_msg->len), zs_msg->val); } zend_string_release(zs_msg); } if (msg) { php_http_message_dtor(obj->message); obj->message = msg; if (obj->message->parent) { obj->parent = php_http_message_object_new_ex(obj->zo.ce, obj->message->parent); } } zend_restore_error_handling(&zeh); PHP_HTTP_MESSAGE_OBJECT_INIT(obj); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getBody, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessage, getBody) { php_http_message_object_t *obj; php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return); obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_MESSAGE_OBJECT_INIT(obj); if (!obj->body) { php_http_message_object_init_body_object(obj); } if (obj->body) { RETVAL_OBJECT(&obj->body->zo, 1); } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setBody, 0, 0, 1) ZEND_ARG_OBJ_INFO(0, body, http\\Message\\Body, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessage, setBody) { zval *zbody; if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O", &zbody, php_http_get_message_body_class_entry())) { php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_MESSAGE_OBJECT_INIT(obj); php_http_message_object_prophandler_set_body(obj, zbody); } RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_addBody, 0, 0, 1) ZEND_ARG_OBJ_INFO(0, body, http\\Message\\Body, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessage, addBody) { zval *new_body; if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O", &new_body, php_http_get_message_body_class_entry())) { php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); php_http_message_body_object_t *new_obj = PHP_HTTP_OBJ(NULL, new_body); PHP_HTTP_MESSAGE_OBJECT_INIT(obj); php_http_message_body_to_callback(new_obj->body, (php_http_pass_callback_t) php_http_message_body_append, obj->message->body, 0, 0); } RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getHeader, 0, 0, 1) ZEND_ARG_INFO(0, header) ZEND_ARG_INFO(0, into_class) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessage, getHeader) { char *header_str; size_t header_len; zend_class_entry *header_ce = NULL; if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s|C!", &header_str, &header_len, &header_ce)) { php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); zval *header; PHP_HTTP_MESSAGE_OBJECT_INIT(obj); if ((header = php_http_message_header(obj->message, header_str, header_len))) { if (!header_ce) { RETURN_ZVAL(header, 1, 0); } else if (instanceof_function(header_ce, php_http_header_get_class_entry())) { php_http_object_method_t cb; zval argv[2]; ZVAL_STRINGL(&argv[0], header_str, header_len); ZVAL_COPY(&argv[1], header); object_init_ex(return_value, header_ce); php_http_object_method_init(&cb, return_value, ZEND_STRL("__construct")); php_http_object_method_call(&cb, return_value, NULL, 2, argv); php_http_object_method_dtor(&cb); zval_ptr_dtor(&argv[0]); zval_ptr_dtor(&argv[1]); return; } else { php_error_docref(NULL, E_WARNING, "Class '%s' is not as descendant of http\\Header", header_ce->name->val); } } } RETURN_FALSE; } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getHeaders, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessage, getHeaders) { if (SUCCESS == zend_parse_parameters_none()) { php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_MESSAGE_OBJECT_INIT(obj); array_init(return_value); array_copy(&obj->message->hdrs, Z_ARRVAL_P(return_value)); } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setHeader, 0, 0, 1) ZEND_ARG_INFO(0, header) ZEND_ARG_INFO(0, value) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessage, setHeader) { zval *zvalue = NULL; char *name_str; size_t name_len; if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s|z!", &name_str, &name_len, &zvalue)) { php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); char *name = php_http_pretty_key(estrndup(name_str, name_len), name_len, 1, 1); PHP_HTTP_MESSAGE_OBJECT_INIT(obj); if (!zvalue) { zend_symtable_str_del(&obj->message->hdrs, name, name_len); } else { Z_TRY_ADDREF_P(zvalue); zend_symtable_str_update(&obj->message->hdrs, name, name_len, zvalue); } efree(name); } RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setHeaders, 0, 0, 1) ZEND_ARG_ARRAY_INFO(0, headers, 1) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessage, setHeaders) { zval *new_headers = NULL; if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "a/!", &new_headers)) { php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_MESSAGE_OBJECT_INIT(obj); zend_hash_clean(&obj->message->hdrs); if (new_headers) { array_join(Z_ARRVAL_P(new_headers), &obj->message->hdrs, 0, ARRAY_JOIN_PRETTIFY|ARRAY_JOIN_STRONLY); } } RETVAL_ZVAL(getThis(), 1, 0); } static inline void php_http_message_object_add_header(php_http_message_object_t *obj, const char *name_str, size_t name_len, zval *zvalue) { char *name = php_http_pretty_key(estrndup(name_str, name_len), name_len, 1, 1); zend_string *hstr, *vstr; zval *header, tmp; if (Z_TYPE_P(zvalue) == IS_NULL) { return; } vstr = php_http_header_value_to_string(zvalue); if ((name_len != lenof("Set-Cookie") && strcmp(name, "Set-Cookie")) && (hstr = php_http_message_header_string(obj->message, name, name_len))) { char *hdr_str; size_t hdr_len = spprintf(&hdr_str, 0, "%s, %s", hstr->val, vstr->val); ZVAL_STR(&tmp, php_http_cs2zs(hdr_str, hdr_len)); zend_symtable_str_update(&obj->message->hdrs, name, name_len, &tmp); zend_string_release(hstr); zend_string_release(vstr); } else if ((header = php_http_message_header(obj->message, name, name_len))) { convert_to_array(header); ZVAL_STR(&tmp, vstr); zend_hash_next_index_insert(Z_ARRVAL_P(header), &tmp); } else { ZVAL_STR(&tmp, vstr); zend_symtable_str_update(&obj->message->hdrs, name, name_len, &tmp); } efree(name); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_addHeader, 0, 0, 2) ZEND_ARG_INFO(0, header) ZEND_ARG_INFO(0, value) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessage, addHeader) { zval *zvalue; char *name_str; size_t name_len; if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "sz", &name_str, &name_len, &zvalue)) { php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_MESSAGE_OBJECT_INIT(obj); php_http_message_object_add_header(obj, name_str, name_len, zvalue); } RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_addHeaders, 0, 0, 1) ZEND_ARG_ARRAY_INFO(0, headers, 0) ZEND_ARG_INFO(0, append) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessage, addHeaders) { zval *new_headers; zend_bool append = 0; if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "a|b", &new_headers, &append)) { php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_MESSAGE_OBJECT_INIT(obj); if (append) { php_http_arrkey_t key = {0}; zval *val; ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(new_headers), key.h, key.key, val) { php_http_arrkey_stringify(&key, NULL); php_http_message_object_add_header(obj, key.key->val, key.key->len, val); php_http_arrkey_dtor(&key); } ZEND_HASH_FOREACH_END(); } else { array_join(Z_ARRVAL_P(new_headers), &obj->message->hdrs, 0, ARRAY_JOIN_PRETTIFY|ARRAY_JOIN_STRONLY); } } RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getType, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessage, getType) { if (SUCCESS == zend_parse_parameters_none()) { php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_MESSAGE_OBJECT_INIT(obj); RETURN_LONG(obj->message->type); } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setType, 0, 0, 1) ZEND_ARG_INFO(0, type) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessage, setType) { zend_long type; if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "l", &type)) { php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_MESSAGE_OBJECT_INIT(obj); php_http_message_set_type(obj->message, type); } RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getInfo, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessage, getInfo) { if (SUCCESS == zend_parse_parameters_none()) { char *str = NULL; size_t len = 0; php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_MESSAGE_OBJECT_INIT(obj); php_http_info_to_string((php_http_info_t *) obj->message, &str, &len, ""); RETVAL_STR(php_http_cs2zs(str, len)); } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setInfo, 0, 0, 1) ZEND_ARG_INFO(0, http_info) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessage, setInfo) { char *str; size_t len; php_http_message_object_t *obj; php_http_info_t inf; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &str, &len), invalid_arg, return); obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_MESSAGE_OBJECT_INIT(obj); if (!php_http_info_parse(&inf, str)) { php_http_throw(bad_header, "Could not parse message info '%s'", str); return; } php_http_message_set_info(obj->message, &inf); php_http_info_dtor(&inf); RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getHttpVersion, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessage, getHttpVersion) { if (SUCCESS == zend_parse_parameters_none()) { char *str; size_t len; php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_MESSAGE_OBJECT_INIT(obj); php_http_version_to_string(&obj->message->http.version, &str, &len, NULL, NULL); RETURN_STR(php_http_cs2zs(str, len)); } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setHttpVersion, 0, 0, 1) ZEND_ARG_INFO(0, http_version) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessage, setHttpVersion) { char *v_str; size_t v_len; php_http_version_t version; php_http_message_object_t *obj; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &v_str, &v_len), invalid_arg, return); obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_MESSAGE_OBJECT_INIT(obj); php_http_expect(php_http_version_parse(&version, v_str), unexpected_val, return); obj->message->http.version = version; RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getResponseCode, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessage, getResponseCode) { if (SUCCESS == zend_parse_parameters_none()) { php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_MESSAGE_OBJECT_INIT(obj); if (obj->message->type != PHP_HTTP_RESPONSE) { php_error_docref(NULL, E_WARNING, "http\\Message is not of type response"); RETURN_FALSE; } RETURN_LONG(obj->message->http.info.response.code); } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setResponseCode, 0, 0, 1) ZEND_ARG_INFO(0, response_code) ZEND_ARG_INFO(0, strict) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessage, setResponseCode) { zend_long code; zend_bool strict = 1; php_http_message_object_t *obj; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "l|b", &code, &strict), invalid_arg, return); obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_MESSAGE_OBJECT_INIT(obj); if (obj->message->type != PHP_HTTP_RESPONSE) { php_http_throw(bad_method_call, "http\\Message is not of type response"); return; } if (strict && (code < 100 || code > 599)) { php_http_throw(invalid_arg, "Invalid response code (100-599): %ld", code); return; } obj->message->http.info.response.code = code; PTR_SET(obj->message->http.info.response.status, estrdup(php_http_env_get_response_status_for_code(code))); RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getResponseStatus, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessage, getResponseStatus) { if (SUCCESS == zend_parse_parameters_none()) { php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_MESSAGE_OBJECT_INIT(obj); if (obj->message->type != PHP_HTTP_RESPONSE) { php_error_docref(NULL, E_WARNING, "http\\Message is not of type response"); } if (obj->message->http.info.response.status) { RETURN_STRING(obj->message->http.info.response.status); } else { RETURN_EMPTY_STRING(); } } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setResponseStatus, 0, 0, 1) ZEND_ARG_INFO(0, response_status) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessage, setResponseStatus) { char *status; size_t status_len; php_http_message_object_t *obj; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &status, &status_len), invalid_arg, return); obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_MESSAGE_OBJECT_INIT(obj); if (obj->message->type != PHP_HTTP_RESPONSE) { php_http_throw(bad_method_call, "http\\Message is not of type response"); } PTR_SET(obj->message->http.info.response.status, estrndup(status, status_len)); RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getRequestMethod, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessage, getRequestMethod) { if (SUCCESS == zend_parse_parameters_none()) { php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_MESSAGE_OBJECT_INIT(obj); if (obj->message->type != PHP_HTTP_REQUEST) { php_error_docref(NULL, E_WARNING, "http\\Message is not of type request"); RETURN_FALSE; } if (obj->message->http.info.request.method) { RETURN_STRING(obj->message->http.info.request.method); } else { RETURN_EMPTY_STRING(); } } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setRequestMethod, 0, 0, 1) ZEND_ARG_INFO(0, request_method) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessage, setRequestMethod) { char *method; size_t method_len; php_http_message_object_t *obj; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &method, &method_len), invalid_arg, return); obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_MESSAGE_OBJECT_INIT(obj); if (obj->message->type != PHP_HTTP_REQUEST) { php_http_throw(bad_method_call, "http\\Message is not of type request"); return; } if (method_len < 1) { php_http_throw(invalid_arg, "Cannot set http\\Message's request method to an empty string"); return; } PTR_SET(obj->message->http.info.request.method, estrndup(method, method_len)); RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getRequestUrl, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessage, getRequestUrl) { if (SUCCESS == zend_parse_parameters_none()) { php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_MESSAGE_OBJECT_INIT(obj); if (obj->message->type != PHP_HTTP_REQUEST) { php_error_docref(NULL, E_WARNING, "http\\Message is not of type request"); RETURN_FALSE; } if (obj->message->http.info.request.url) { char *url_str; size_t url_len; php_http_url_to_string(obj->message->http.info.request.url, &url_str, &url_len, 0); RETURN_STR(php_http_cs2zs(url_str, url_len)); } else { RETURN_EMPTY_STRING(); } } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setRequestUrl, 0, 0, 1) ZEND_ARG_INFO(0, url) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessage, setRequestUrl) { zval *zurl; php_http_url_t *url; php_http_message_object_t *obj; zend_error_handling zeh; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "z", &zurl), invalid_arg, return); obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_MESSAGE_OBJECT_INIT(obj); if (obj->message->type != PHP_HTTP_REQUEST) { php_http_throw(bad_method_call, "http\\Message is not of type request"); return; } zend_replace_error_handling(EH_THROW, php_http_get_exception_bad_url_class_entry(), &zeh); url = php_http_url_from_zval(zurl, PHP_HTTP_URL_STDFLAGS); zend_restore_error_handling(&zeh); if (url && php_http_url_is_empty(url)) { php_http_url_free(&url); php_http_throw(invalid_arg, "Cannot set http\\Message's request url to an empty string"); } else if (url) { PTR_SET(obj->message->http.info.request.url, url); } RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getParentMessage, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessage, getParentMessage) { php_http_message_object_t *obj; php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return); obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_MESSAGE_OBJECT_INIT(obj); if (!obj->message->parent) { php_http_throw(unexpected_val, "http\\Message has no parent message"); return; } RETVAL_OBJECT(&obj->parent->zo, 1); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage___toString, 0, 0, 0) ZEND_END_ARG_INFO(); ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_toString, 0, 0, 0) ZEND_ARG_INFO(0, include_parent) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessage, toString) { zend_bool include_parent = 0; if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &include_parent)) { php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); char *string; size_t length; PHP_HTTP_MESSAGE_OBJECT_INIT(obj); if (include_parent) { php_http_message_serialize(obj->message, &string, &length); } else { php_http_message_to_string(obj->message, &string, &length); } if (string) { RETURN_STR(php_http_cs2zs(string, length)); } } RETURN_EMPTY_STRING(); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_toStream, 0, 0, 1) ZEND_ARG_INFO(0, stream) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessage, toStream) { zval *zstream; if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "r", &zstream)) { php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); php_stream *s; PHP_HTTP_MESSAGE_OBJECT_INIT(obj); php_stream_from_zval(s, zstream); php_http_message_to_callback(obj->message, (php_http_pass_callback_t) _php_stream_write, s); } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_toCallback, 0, 0, 1) ZEND_ARG_INFO(0, callback) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessage, toCallback) { php_http_pass_fcall_arg_t fcd; if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "f", &fcd.fci, &fcd.fcc)) { php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_MESSAGE_OBJECT_INIT(obj); ZVAL_COPY(&fcd.fcz, getThis()); php_http_message_to_callback(obj->message, php_http_pass_fcall_callback, &fcd); zend_fcall_info_args_clear(&fcd.fci, 1); zval_ptr_dtor(&fcd.fcz); RETURN_ZVAL(&fcd.fcz, 1, 0); } } ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(ai_HttpMessage___serialize, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessage, __serialize) { zend_ulong num_index; zend_string *str_index; zend_property_info *pi; php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); HashTable *props = php_http_message_object_get_debug_info(&obj->zo, NULL); zend_parse_parameters_none(); array_init(return_value); ZEND_HASH_FOREACH_KEY_PTR(&obj->zo.ce->properties_info, num_index, str_index, pi) { zval *val; if (str_index && (val = zend_hash_find_ind(props, pi->name))) { Z_TRY_ADDREF_P(val); zend_hash_update(Z_ARRVAL_P(return_value), str_index, val); } } ZEND_HASH_FOREACH_END(); } ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(ai_HttpMessage___unserialize, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, data, IS_ARRAY, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessage, __unserialize) { HashTable *arr; zend_string *key; zval *val; php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "h", &arr), invalid_arg, return); PHP_HTTP_MESSAGE_OBJECT_INIT(obj); ZEND_HASH_FOREACH_STR_KEY_VAL(arr, key, val) { php_http_message_object_prophandler_t *ph = php_http_message_object_get_prophandler(key); if (ph) { ph->write(obj, val); } else { zend_update_property_ex(php_http_message_class_entry, &obj->zo, key, val); } } ZEND_HASH_FOREACH_END(); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_serialize, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessage, serialize) { if (SUCCESS == zend_parse_parameters_none()) { php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); char *string; size_t length; PHP_HTTP_MESSAGE_OBJECT_INIT(obj); php_http_message_serialize(obj->message, &string, &length); RETURN_STR(php_http_cs2zs(string, length)); } RETURN_EMPTY_STRING(); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_unserialize, 0, 0, 1) ZEND_ARG_INFO(0, serialized) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessage, unserialize) { size_t length; char *serialized; if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &serialized, &length)) { php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); php_http_message_t *msg; if (obj->message) { /* do not free recursively */ php_http_message_dtor(obj->message); efree(obj->message); } if ((msg = php_http_message_parse(NULL, serialized, length, 1))) { obj->message = msg; } else { obj->message = php_http_message_init(NULL, 0, NULL); php_error_docref(NULL, E_ERROR, "Could not unserialize http\\Message"); } } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_detach, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessage, detach) { php_http_message_object_t *obj, *new_obj; php_http_message_t *msg_cpy; php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return); obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_MESSAGE_OBJECT_INIT(obj); msg_cpy = php_http_message_copy_ex(obj->message, NULL, 0); new_obj = php_http_message_object_new_ex(obj->zo.ce, msg_cpy); RETVAL_OBJ(&new_obj->zo); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_prepend, 0, 0, 1) ZEND_ARG_OBJ_INFO(0, message, http\\Message, 0) ZEND_ARG_INFO(0, top) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessage, prepend) { zval *prepend; zend_bool top = 1; php_http_message_t *msg[2]; php_http_message_object_t *obj, *prepend_obj; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O|b", &prepend, php_http_message_class_entry, &top), invalid_arg, return); obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_MESSAGE_OBJECT_INIT(obj); prepend_obj = PHP_HTTP_OBJ(NULL, prepend); PHP_HTTP_MESSAGE_OBJECT_INIT(prepend_obj); /* safety check */ for (msg[0] = obj->message; msg[0]; msg[0] = msg[0]->parent) { for (msg[1] = prepend_obj->message; msg[1]; msg[1] = msg[1]->parent) { if (msg[0] == msg[1]) { php_http_throw(unexpected_val, "Cannot prepend a message located within the same message chain"); return; } } } php_http_message_object_prepend(getThis(), prepend, top); RETURN_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_reverse, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessage, reverse) { php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return); php_http_message_object_reverse(getThis(), return_value); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_isMultipart, 0, 0, 0) ZEND_ARG_INFO(1, boundary) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessage, isMultipart) { zval *zboundary = NULL; if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|z!", &zboundary)) { php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); char *boundary = NULL; PHP_HTTP_MESSAGE_OBJECT_INIT(obj); if (php_http_message_is_multipart(obj->message, zboundary ? &boundary : NULL)) { RETVAL_TRUE; } else { RETVAL_FALSE; } if (zboundary && boundary) { ZVAL_DEREF(zboundary); zval_dtor(zboundary); ZVAL_STR(zboundary, php_http_cs2zs(boundary, strlen(boundary))); } } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_splitMultipartBody, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessage, splitMultipartBody) { php_http_message_object_t *obj; php_http_message_t *msg; char *boundary = NULL; php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return); obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_MESSAGE_OBJECT_INIT(obj); if (!php_http_message_is_multipart(obj->message, &boundary)) { php_http_throw(bad_method_call, "http\\Message is not a multipart message"); return; } php_http_expect(msg = php_http_message_body_split(obj->message->body, boundary), bad_message, return); PTR_FREE(boundary); RETURN_OBJ(&php_http_message_object_new_ex(obj->zo.ce, msg)->zo); } ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(ai_HttpMessage_count, 0, 0, IS_LONG, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessage, count) { zend_long count_mode = -1; if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &count_mode)) { php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); PHP_HTTP_MESSAGE_OBJECT_INIT(obj); RETURN_LONG(php_http_message_count(obj->message)); } } ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(ai_HttpMessage_rewind, 0, 0, IS_VOID, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessage, rewind) { if (SUCCESS == zend_parse_parameters_none()) { zval *zobj = getThis(); php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); if (!Z_ISUNDEF(obj->iterator)) { zval_ptr_dtor(&obj->iterator); } ZVAL_COPY(&obj->iterator, zobj); } } ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(ai_HttpMessage_valid, 0, 0, _IS_BOOL, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessage, valid) { if (SUCCESS == zend_parse_parameters_none()) { php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); RETURN_BOOL(!Z_ISUNDEF(obj->iterator)); } } ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(ai_HttpMessage_next, 0, 0, IS_VOID, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessage, next) { if (SUCCESS == zend_parse_parameters_none()) { php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); if (!Z_ISUNDEF(obj->iterator)) { php_http_message_object_t *itr = PHP_HTTP_OBJ(NULL, &obj->iterator); if (itr->parent) { zval tmp; ZVAL_OBJECT(&tmp, &itr->parent->zo, 1); zval_ptr_dtor(&obj->iterator); obj->iterator = tmp; } else { zval_ptr_dtor(&obj->iterator); ZVAL_UNDEF(&obj->iterator); } } } } ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(ai_HttpMessage_key, 0, 0, IS_LONG, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessage, key) { if (SUCCESS == zend_parse_parameters_none()) { php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); RETURN_LONG(Z_ISUNDEF(obj->iterator) ? 0 : Z_OBJ_HANDLE(obj->iterator)); } } ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_OBJ_INFO_EX(ai_HttpMessage_current, 0, 0, http\\Message, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessage, current) { if (SUCCESS == zend_parse_parameters_none()) { php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); if (!Z_ISUNDEF(obj->iterator)) { RETURN_ZVAL(&obj->iterator, 1, 0); } } } static zend_function_entry php_http_message_methods[] = { PHP_ME(HttpMessage, __construct, ai_HttpMessage___construct, ZEND_ACC_PUBLIC) PHP_ME(HttpMessage, getBody, ai_HttpMessage_getBody, ZEND_ACC_PUBLIC) PHP_ME(HttpMessage, setBody, ai_HttpMessage_setBody, ZEND_ACC_PUBLIC) PHP_ME(HttpMessage, addBody, ai_HttpMessage_addBody, ZEND_ACC_PUBLIC) PHP_ME(HttpMessage, getHeader, ai_HttpMessage_getHeader, ZEND_ACC_PUBLIC) PHP_ME(HttpMessage, setHeader, ai_HttpMessage_setHeader, ZEND_ACC_PUBLIC) PHP_ME(HttpMessage, addHeader, ai_HttpMessage_addHeader, ZEND_ACC_PUBLIC) PHP_ME(HttpMessage, getHeaders, ai_HttpMessage_getHeaders, ZEND_ACC_PUBLIC) PHP_ME(HttpMessage, setHeaders, ai_HttpMessage_setHeaders, ZEND_ACC_PUBLIC) PHP_ME(HttpMessage, addHeaders, ai_HttpMessage_addHeaders, ZEND_ACC_PUBLIC) PHP_ME(HttpMessage, getType, ai_HttpMessage_getType, ZEND_ACC_PUBLIC) PHP_ME(HttpMessage, setType, ai_HttpMessage_setType, ZEND_ACC_PUBLIC) PHP_ME(HttpMessage, getInfo, ai_HttpMessage_getInfo, ZEND_ACC_PUBLIC) PHP_ME(HttpMessage, setInfo, ai_HttpMessage_setInfo, ZEND_ACC_PUBLIC) PHP_ME(HttpMessage, getResponseCode, ai_HttpMessage_getResponseCode, ZEND_ACC_PUBLIC) PHP_ME(HttpMessage, setResponseCode, ai_HttpMessage_setResponseCode, ZEND_ACC_PUBLIC) PHP_ME(HttpMessage, getResponseStatus, ai_HttpMessage_getResponseStatus, ZEND_ACC_PUBLIC) PHP_ME(HttpMessage, setResponseStatus, ai_HttpMessage_setResponseStatus, ZEND_ACC_PUBLIC) PHP_ME(HttpMessage, getRequestMethod, ai_HttpMessage_getRequestMethod, ZEND_ACC_PUBLIC) PHP_ME(HttpMessage, setRequestMethod, ai_HttpMessage_setRequestMethod, ZEND_ACC_PUBLIC) PHP_ME(HttpMessage, getRequestUrl, ai_HttpMessage_getRequestUrl, ZEND_ACC_PUBLIC) PHP_ME(HttpMessage, setRequestUrl, ai_HttpMessage_setRequestUrl, ZEND_ACC_PUBLIC) PHP_ME(HttpMessage, getHttpVersion, ai_HttpMessage_getHttpVersion, ZEND_ACC_PUBLIC) PHP_ME(HttpMessage, setHttpVersion, ai_HttpMessage_setHttpVersion, ZEND_ACC_PUBLIC) PHP_ME(HttpMessage, getParentMessage, ai_HttpMessage_getParentMessage, ZEND_ACC_PUBLIC) PHP_ME(HttpMessage, toString, ai_HttpMessage_toString, ZEND_ACC_PUBLIC) PHP_ME(HttpMessage, toCallback, ai_HttpMessage_toCallback, ZEND_ACC_PUBLIC) PHP_ME(HttpMessage, toStream, ai_HttpMessage_toStream, ZEND_ACC_PUBLIC) /* implements Countable */ PHP_ME(HttpMessage, count, ai_HttpMessage_count, ZEND_ACC_PUBLIC) /* implements Serializable */ PHP_ME(HttpMessage, serialize, ai_HttpMessage_serialize, ZEND_ACC_PUBLIC) PHP_ME(HttpMessage, unserialize, ai_HttpMessage_unserialize, ZEND_ACC_PUBLIC) PHP_ME(HttpMessage, __serialize, ai_HttpMessage___serialize, ZEND_ACC_PUBLIC) PHP_ME(HttpMessage, __unserialize, ai_HttpMessage___unserialize, ZEND_ACC_PUBLIC) /* implements Iterator */ PHP_ME(HttpMessage, rewind, ai_HttpMessage_rewind, ZEND_ACC_PUBLIC) PHP_ME(HttpMessage, valid, ai_HttpMessage_valid, ZEND_ACC_PUBLIC) PHP_ME(HttpMessage, current, ai_HttpMessage_current, ZEND_ACC_PUBLIC) PHP_ME(HttpMessage, key, ai_HttpMessage_key, ZEND_ACC_PUBLIC) PHP_ME(HttpMessage, next, ai_HttpMessage_next, ZEND_ACC_PUBLIC) ZEND_MALIAS(HttpMessage, __toString, toString, ai_HttpMessage___toString, ZEND_ACC_PUBLIC) PHP_ME(HttpMessage, detach, ai_HttpMessage_detach, ZEND_ACC_PUBLIC) PHP_ME(HttpMessage, prepend, ai_HttpMessage_prepend, ZEND_ACC_PUBLIC) PHP_ME(HttpMessage, reverse, ai_HttpMessage_reverse, ZEND_ACC_PUBLIC) PHP_ME(HttpMessage, isMultipart, ai_HttpMessage_isMultipart, ZEND_ACC_PUBLIC) PHP_ME(HttpMessage, splitMultipartBody, ai_HttpMessage_splitMultipartBody, ZEND_ACC_PUBLIC) EMPTY_FUNCTION_ENTRY }; PHP_MINIT_FUNCTION(http_message) { zend_class_entry ce = {0}; INIT_NS_CLASS_ENTRY(ce, "http", "Message", php_http_message_methods); php_http_message_class_entry = zend_register_internal_class(&ce); php_http_message_class_entry->create_object = php_http_message_object_new; memcpy(&php_http_message_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); php_http_message_object_handlers.offset = XtOffsetOf(php_http_message_object_t, zo); php_http_message_object_handlers.clone_obj = php_http_message_object_clone; php_http_message_object_handlers.free_obj = php_http_message_object_free; php_http_message_object_handlers.read_property = php_http_message_object_read_prop; php_http_message_object_handlers.write_property = php_http_message_object_write_prop; php_http_message_object_handlers.get_debug_info = php_http_message_object_get_debug_info; php_http_message_object_handlers.get_property_ptr_ptr = php_http_message_object_get_prop_ptr; php_http_message_object_handlers.get_gc = php_http_message_object_get_gc; php_http_message_object_handlers.cast_object = php_http_message_object_cast; zend_class_implements(php_http_message_class_entry, 3, zend_ce_countable, zend_ce_serializable, zend_ce_iterator); zend_hash_init(&php_http_message_object_prophandlers, 9, NULL, php_http_message_object_prophandler_hash_dtor, 1); zend_declare_property_long(php_http_message_class_entry, ZEND_STRL("type"), PHP_HTTP_NONE, ZEND_ACC_PROTECTED); php_http_message_object_add_prophandler(ZEND_STRL("type"), php_http_message_object_prophandler_get_type, php_http_message_object_prophandler_set_type); zend_declare_property_null(php_http_message_class_entry, ZEND_STRL("body"), ZEND_ACC_PROTECTED); php_http_message_object_add_prophandler(ZEND_STRL("body"), php_http_message_object_prophandler_get_body, php_http_message_object_prophandler_set_body); zend_declare_property_string(php_http_message_class_entry, ZEND_STRL("requestMethod"), "", ZEND_ACC_PROTECTED); php_http_message_object_add_prophandler(ZEND_STRL("requestMethod"), php_http_message_object_prophandler_get_request_method, php_http_message_object_prophandler_set_request_method); zend_declare_property_string(php_http_message_class_entry, ZEND_STRL("requestUrl"), "", ZEND_ACC_PROTECTED); php_http_message_object_add_prophandler(ZEND_STRL("requestUrl"), php_http_message_object_prophandler_get_request_url, php_http_message_object_prophandler_set_request_url); zend_declare_property_string(php_http_message_class_entry, ZEND_STRL("responseStatus"), "", ZEND_ACC_PROTECTED); php_http_message_object_add_prophandler(ZEND_STRL("responseStatus"), php_http_message_object_prophandler_get_response_status, php_http_message_object_prophandler_set_response_status); zend_declare_property_long(php_http_message_class_entry, ZEND_STRL("responseCode"), 0, ZEND_ACC_PROTECTED); php_http_message_object_add_prophandler(ZEND_STRL("responseCode"), php_http_message_object_prophandler_get_response_code, php_http_message_object_prophandler_set_response_code); zend_declare_property_null(php_http_message_class_entry, ZEND_STRL("httpVersion"), ZEND_ACC_PROTECTED); php_http_message_object_add_prophandler(ZEND_STRL("httpVersion"), php_http_message_object_prophandler_get_http_version, php_http_message_object_prophandler_set_http_version); zend_declare_property_null(php_http_message_class_entry, ZEND_STRL("headers"), ZEND_ACC_PROTECTED); php_http_message_object_add_prophandler(ZEND_STRL("headers"), php_http_message_object_prophandler_get_headers, php_http_message_object_prophandler_set_headers); zend_declare_property_null(php_http_message_class_entry, ZEND_STRL("parentMessage"), ZEND_ACC_PROTECTED); php_http_message_object_add_prophandler(ZEND_STRL("parentMessage"), php_http_message_object_prophandler_get_parent_message, php_http_message_object_prophandler_set_parent_message); zend_declare_class_constant_long(php_http_message_class_entry, ZEND_STRL("TYPE_NONE"), PHP_HTTP_NONE); zend_declare_class_constant_long(php_http_message_class_entry, ZEND_STRL("TYPE_REQUEST"), PHP_HTTP_REQUEST); zend_declare_class_constant_long(php_http_message_class_entry, ZEND_STRL("TYPE_RESPONSE"), PHP_HTTP_RESPONSE); return SUCCESS; } PHP_MSHUTDOWN_FUNCTION(http_message) { zend_hash_destroy(&php_http_message_object_prophandlers); 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 */ pecl_http-4.2.1/src/php_http_message.h0000644000076500000240000001132714117626035016553 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_HTTP_MESSAGE_H #define PHP_HTTP_MESSAGE_H #include "php_http_message_body.h" #include "php_http_header.h" /* required minimum length of an HTTP message "HTTP/1.1" */ #define PHP_HTTP_MESSAGE_MIN_SIZE 8 #define PHP_HTTP_MESSAGE_TYPE(TYPE, msg) ((msg) && ((msg)->type == PHP_HTTP_ ##TYPE)) typedef php_http_info_type_t php_http_message_type_t; typedef struct php_http_message php_http_message_t; struct php_http_message { PHP_HTTP_INFO_IMPL(http, type) HashTable hdrs; php_http_message_body_t *body; php_http_message_t *parent; void *opaque; }; PHP_HTTP_API zend_bool php_http_message_info_callback(php_http_message_t **message, HashTable **headers, php_http_info_t *info); PHP_HTTP_API php_http_message_t *php_http_message_init(php_http_message_t *m, php_http_message_type_t t, php_http_message_body_t *body); PHP_HTTP_API php_http_message_t *php_http_message_init_env(php_http_message_t *m, php_http_message_type_t t); PHP_HTTP_API php_http_message_t *php_http_message_copy_ex(php_http_message_t *from, php_http_message_t *to, zend_bool parents); static inline php_http_message_t *php_http_message_copy(php_http_message_t *from, php_http_message_t *to) { return php_http_message_copy_ex(from, to, 1); } PHP_HTTP_API void php_http_message_dtor(php_http_message_t *message); PHP_HTTP_API void php_http_message_free(php_http_message_t **message); PHP_HTTP_API void php_http_message_set_type(php_http_message_t *m, php_http_message_type_t t); PHP_HTTP_API void php_http_message_set_info(php_http_message_t *message, php_http_info_t *info); PHP_HTTP_API void php_http_message_update_headers(php_http_message_t *msg); PHP_HTTP_API zval *php_http_message_header(php_http_message_t *msg, const char *key_str, size_t key_len); static inline zend_string *php_http_message_header_string(php_http_message_t *msg, const char *key_str, size_t key_len) { zval *header; if ((header = php_http_message_header(msg, key_str, key_len))) { return php_http_header_value_to_string(header); } return NULL; } PHP_HTTP_API zend_bool php_http_message_is_multipart(php_http_message_t *msg, char **boundary); PHP_HTTP_API void php_http_message_to_string(php_http_message_t *msg, char **string, size_t *length); PHP_HTTP_API void php_http_message_to_struct(php_http_message_t *msg, zval *strct); PHP_HTTP_API void php_http_message_to_callback(php_http_message_t *msg, php_http_pass_callback_t cb, void *cb_arg); PHP_HTTP_API void php_http_message_serialize(php_http_message_t *message, char **string, size_t *length); PHP_HTTP_API php_http_message_t *php_http_message_reverse(php_http_message_t *msg); PHP_HTTP_API php_http_message_t *php_http_message_zip(php_http_message_t *one, php_http_message_t *two); static inline size_t php_http_message_count(php_http_message_t *m) { size_t c = 1; while ((m = m->parent)) { ++c; } return c; } PHP_HTTP_API php_http_message_t *php_http_message_parse(php_http_message_t *msg, const char *str, size_t len, zend_bool greedy); typedef struct php_http_message_object { php_http_message_t *message; struct php_http_message_object *parent; php_http_message_body_object_t *body; zval iterator, *gc; zend_object zo; } php_http_message_object_t; PHP_HTTP_API zend_class_entry *php_http_message_get_class_entry(void); PHP_MINIT_FUNCTION(http_message); PHP_MSHUTDOWN_FUNCTION(http_message); void php_http_message_object_prepend(zval *this_ptr, zval *prepend, zend_bool top /* = 1 */); void php_http_message_object_reverse(zval *this_ptr, zval *return_value); ZEND_RESULT_CODE php_http_message_object_set_body(php_http_message_object_t *obj, zval *zbody); ZEND_RESULT_CODE php_http_message_object_init_body_object(php_http_message_object_t *obj); zend_object *php_http_message_object_new(zend_class_entry *ce); php_http_message_object_t *php_http_message_object_new_ex(zend_class_entry *ce, php_http_message_t *msg); zend_object *php_http_message_object_clone(zend_object *object); void php_http_message_object_free(zend_object *object); #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 */ pecl_http-4.2.1/src/php_http_message_parser.c0000644000076500000240000006027414117626035020127 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #include "php_http_api.h" #ifndef DBG_PARSER # define DBG_PARSER 0 #endif typedef struct php_http_message_parser_state_spec { php_http_message_parser_state_t state; unsigned need_data:1; } php_http_message_parser_state_spec_t; static const php_http_message_parser_state_spec_t php_http_message_parser_states[] = { {PHP_HTTP_MESSAGE_PARSER_STATE_START, 1}, {PHP_HTTP_MESSAGE_PARSER_STATE_HEADER, 0}, {PHP_HTTP_MESSAGE_PARSER_STATE_HEADER_DONE, 0}, {PHP_HTTP_MESSAGE_PARSER_STATE_BODY, 0}, {PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DUMB, 1}, {PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH, 1}, {PHP_HTTP_MESSAGE_PARSER_STATE_BODY_CHUNKED, 1}, {PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE, 0}, {PHP_HTTP_MESSAGE_PARSER_STATE_UPDATE_CL, 0}, {PHP_HTTP_MESSAGE_PARSER_STATE_DONE, 0} }; #if DBG_PARSER const char *php_http_message_parser_state_name(php_http_message_parser_state_t state) { const char *states[] = {"START", "HEADER", "HEADER_DONE", "BODY", "BODY_DUMB", "BODY_LENGTH", "BODY_CHUNK", "BODY_DONE", "UPDATE_CL", "DONE"}; if (state < 0 || state > (sizeof(states)/sizeof(char*))-1) { return "FAILURE"; } return states[state]; } #endif php_http_message_parser_t *php_http_message_parser_init(php_http_message_parser_t *parser) { if (!parser) { parser = emalloc(sizeof(*parser)); } memset(parser, 0, sizeof(*parser)); php_http_header_parser_init(&parser->header); return parser; } static inline php_http_message_parser_state_t php_http_message_parser_state_push(php_http_message_parser_t *parser, php_http_message_parser_state_t state) { zend_ptr_stack_push(&parser->stack, (void *) state); return state; } #define php_http_message_parser_state_pop(parser) ((parser)->stack.top \ ? (php_http_message_parser_state_t) zend_ptr_stack_pop(&parser->stack) \ : PHP_HTTP_MESSAGE_PARSER_STATE_START) #define php_http_message_parser_state_is_ex(parser) ((parser)->stack.top \ ? (php_http_message_parser_state_t) (parser)->stack.elements[(parser)->stack.top - 1] \ : PHP_HTTP_MESSAGE_PARSER_STATE_START) php_http_message_parser_state_t php_http_message_parser_state_is(php_http_message_parser_t *parser) { return php_http_message_parser_state_is_ex(parser); } void php_http_message_parser_dtor(php_http_message_parser_t *parser) { php_http_header_parser_dtor(&parser->header); zend_ptr_stack_destroy(&parser->stack); php_http_message_free(&parser->message); if (parser->dechunk) { php_http_encoding_stream_free(&parser->dechunk); } if (parser->inflate) { php_http_encoding_stream_free(&parser->inflate); } } void php_http_message_parser_free(php_http_message_parser_t **parser) { if (*parser) { php_http_message_parser_dtor(*parser); efree(*parser); *parser = NULL; } } php_http_message_parser_state_t php_http_message_parser_parse_stream(php_http_message_parser_t *parser, php_http_buffer_t *buf, php_stream *s, unsigned flags, php_http_message_t **message) { php_http_message_parser_state_t state = PHP_HTTP_MESSAGE_PARSER_STATE_START; if (!buf->data) { php_http_buffer_resize_ex(buf, 0x1000, 1, 0); } while (1) { size_t justread = 0; #if DBG_PARSER fprintf(stderr, "#SP: %s (f:%u)\n", php_http_message_parser_state_name(state), flags); #endif /* resize if needed */ if (buf->free < 0x1000) { php_http_buffer_resize_ex(buf, 0x1000, 1, 0); } switch (state) { case PHP_HTTP_MESSAGE_PARSER_STATE_START: case PHP_HTTP_MESSAGE_PARSER_STATE_HEADER: case PHP_HTTP_MESSAGE_PARSER_STATE_HEADER_DONE: /* read line */ php_stream_get_line(s, buf->data + buf->used, buf->free, &justread); /* if we fail reading a whole line, try a single char */ if (!justread) { int c = php_stream_getc(s); if (c != EOF) { char s[1] = {c}; justread = php_http_buffer_append(buf, s, 1); } } php_http_buffer_account(buf, justread); break; case PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DUMB: /* read all */ justread = php_stream_read(s, buf->data + buf->used, buf->free); php_http_buffer_account(buf, justread); break; case PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH: /* read body_length */ justread = php_stream_read(s, buf->data + buf->used, MIN(buf->free, parser->body_length)); php_http_buffer_account(buf, justread); break; case PHP_HTTP_MESSAGE_PARSER_STATE_BODY_CHUNKED: /* duh, this is very naive */ if (parser->body_length) { justread = php_stream_read(s, buf->data + buf->used, MIN(parser->body_length, buf->free)); php_http_buffer_account(buf, justread); parser->body_length -= justread; } else { php_http_buffer_resize(buf, 24); php_stream_get_line(s, buf->data, buf->free, &justread); php_http_buffer_account(buf, justread); parser->body_length = strtoul(buf->data + buf->used - justread, NULL, 16); } break; case PHP_HTTP_MESSAGE_PARSER_STATE_BODY: case PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE: case PHP_HTTP_MESSAGE_PARSER_STATE_UPDATE_CL: /* should not occur */ abort(); break; case PHP_HTTP_MESSAGE_PARSER_STATE_DONE: case PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE: return php_http_message_parser_state_is_ex(parser); } if (justread) { state = php_http_message_parser_parse(parser, buf, flags, message); } else if (php_stream_eof(s)) { return php_http_message_parser_parse(parser, buf, flags | PHP_HTTP_MESSAGE_PARSER_CLEANUP, message); } else { return state; } } return PHP_HTTP_MESSAGE_PARSER_STATE_DONE; } php_http_message_parser_state_t php_http_message_parser_parse(php_http_message_parser_t *parser, php_http_buffer_t *buffer, unsigned flags, php_http_message_t **message) { char *str = NULL; size_t len = 0; size_t cut = 0; while (buffer->used || !php_http_message_parser_states[php_http_message_parser_state_is_ex(parser)].need_data) { #if DBG_PARSER fprintf(stderr, "#MP: %s (f: %u, t:%d, l:%zu)\n", php_http_message_parser_state_name(php_http_message_parser_state_is(parser)), flags, message && *message ? (*message)->type : -1, buffer->used ); _dpf(0, buffer->data, buffer->used); #endif switch (php_http_message_parser_state_pop(parser)) { case PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE: return php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE); case PHP_HTTP_MESSAGE_PARSER_STATE_START: { char *ptr = buffer->data; while (ptr - buffer->data < buffer->used && PHP_HTTP_IS_CTYPE(space, *ptr)) { ++ptr; } php_http_buffer_cut(buffer, 0, ptr - buffer->data); if (buffer->used) { php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_HEADER); } break; } case PHP_HTTP_MESSAGE_PARSER_STATE_HEADER: { unsigned header_parser_flags = (flags & PHP_HTTP_MESSAGE_PARSER_CLEANUP) ? PHP_HTTP_HEADER_PARSER_CLEANUP : 0; switch (php_http_header_parser_parse(&parser->header, buffer, header_parser_flags, *message ? &(*message)->hdrs : NULL, (php_http_info_callback_t) php_http_message_info_callback, message)) { case PHP_HTTP_HEADER_PARSER_STATE_FAILURE: return PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE; case PHP_HTTP_HEADER_PARSER_STATE_DONE: php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_HEADER_DONE); break; default: if (buffer->used || !(flags & PHP_HTTP_MESSAGE_PARSER_CLEANUP)) { return php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_HEADER); } else { php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_HEADER_DONE); } } break; } case PHP_HTTP_MESSAGE_PARSER_STATE_HEADER_DONE: { zval h, *h_ptr, *h_loc = NULL, *h_con = NULL, *h_ce; zend_bool chunked = 0; zend_long content_length = -1; zend_string *content_range = NULL; /* Content-Range has higher precedence than Content-Length, * and content-length denotes the original length of the entity, * so let's *NOT* remove CR/CL, because that would fundamentally * change the meaning of the whole message */ if ((h_ptr = php_http_message_header(*message, ZEND_STRL("Transfer-Encoding")))) { zend_string *zs = zval_get_string(h_ptr); chunked = zend_string_equals_literal(zs, "chunked"); zend_string_release(zs); Z_TRY_ADDREF_P(h_ptr); zend_hash_str_update(&(*message)->hdrs, "X-Original-Transfer-Encoding", lenof("X-Original-Transfer-Encoding"), h_ptr); zend_hash_str_del(&(*message)->hdrs, "Transfer-Encoding", lenof("Transfer-Encoding")); /* reset */ ZVAL_LONG(&h, 0); zend_hash_str_update(&(*message)->hdrs, "Content-Length", lenof("Content-Length"), &h); } else if ((h_ptr = php_http_message_header(*message, ZEND_STRL("Content-Length")))) { content_length = zval_get_long(h_ptr); Z_TRY_ADDREF_P(h_ptr); zend_hash_str_update(&(*message)->hdrs, "X-Original-Content-Length", lenof("X-Original-Content-Length"), h_ptr); } if ((content_range = php_http_message_header_string(*message, ZEND_STRL("Content-Range")))) { ZVAL_STR_COPY(&h, content_range); zend_hash_str_update(&(*message)->hdrs, "Content-Range", lenof("Content-Range"), &h); } /* so, if curl sees a 3xx code, a Location header and a Connection:close header * it decides not to read the response body. */ if ((flags & PHP_HTTP_MESSAGE_PARSER_EMPTY_REDIRECTS) && (*message)->type == PHP_HTTP_RESPONSE && (*message)->http.info.response.code/100 == 3 && (h_loc = php_http_message_header(*message, ZEND_STRL("Location"))) && (h_con = php_http_message_header(*message, ZEND_STRL("Connection"))) ) { zend_string *con = zval_get_string(h_con); if (php_http_match(con->val, "close", PHP_HTTP_MATCH_WORD)) { zend_string_release(con); php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_DONE); break; } zend_string_release(con); } if ((h_ce = php_http_message_header(*message, ZEND_STRL("Content-Encoding")))) { zend_string *ce = zval_get_string(h_ce); if (php_http_match(ce->val, "gzip", PHP_HTTP_MATCH_WORD) || php_http_match(ce->val, "x-gzip", PHP_HTTP_MATCH_WORD) || php_http_match(ce->val, "deflate", PHP_HTTP_MATCH_WORD) ) { if (parser->inflate) { php_http_encoding_stream_reset(&parser->inflate); } else { parser->inflate = php_http_encoding_stream_init(NULL, php_http_encoding_stream_get_inflate_ops(), 0); } Z_TRY_ADDREF_P(h_ce); zend_hash_str_update(&(*message)->hdrs, "X-Original-Content-Encoding", lenof("X-Original-Content-Encoding"), h_ce); zend_hash_str_del(&(*message)->hdrs, "Content-Encoding", lenof("Content-Encoding")); } zend_string_release(ce); } if ((flags & PHP_HTTP_MESSAGE_PARSER_DUMB_BODIES)) { php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DUMB); } else { if (chunked) { parser->dechunk = php_http_encoding_stream_init(parser->dechunk, php_http_encoding_stream_get_dechunk_ops(), 0); php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_CHUNKED); break; } if (content_range) { unsigned long total = 0, start = 0, end = 0; if (!strncasecmp(content_range->val, "bytes", lenof("bytes")) && ( content_range->val[lenof("bytes")] == ':' || content_range->val[lenof("bytes")] == ' ' || content_range->val[lenof("bytes")] == '=' ) ) { char *total_at = NULL, *end_at = NULL; char *start_at = content_range->val + sizeof("bytes"); start = strtoul(start_at, &end_at, 10); if (end_at) { end = strtoul(end_at + 1, &total_at, 10); if (total_at && strncmp(total_at + 1, "*", 1)) { total = strtoul(total_at + 1, NULL, 10); } if (end >= start && (!total || end <= total)) { parser->body_length = end + 1 - start; if (parser->body_length) { php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH); } else { php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE); } zend_string_release(content_range); break; } } } zend_string_release(content_range); } if (content_length >= 0) { parser->body_length = content_length; if (parser->body_length) { php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH); } else { php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE); } break; } if ((*message)->type == PHP_HTTP_REQUEST) { php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_DONE); } else { php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DUMB); } } break; } case PHP_HTTP_MESSAGE_PARSER_STATE_BODY: { if (len) { if (parser->inflate) { char *dec_str = NULL; size_t dec_len; if (SUCCESS != php_http_encoding_stream_update(parser->inflate, str, len, &dec_str, &dec_len)) { return php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE); } if (str != buffer->data) { PTR_FREE(str); } str = dec_str; len = dec_len; } php_stream_write(php_http_message_body_stream((*message)->body), str, len); } if (cut) { php_http_buffer_cut(buffer, 0, cut); } if (str != buffer->data) { PTR_FREE(str); } str = NULL; len = 0; cut = 0; break; } case PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DUMB: { str = buffer->data; len = buffer->used; cut = len; php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE); php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY); break; } case PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH: { len = MIN(parser->body_length, buffer->used); str = buffer->data; cut = len; parser->body_length -= len; if (parser->body_length) { php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH); } else { php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE); } php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY); break; } case PHP_HTTP_MESSAGE_PARSER_STATE_BODY_CHUNKED: { /* * - pass available data through the dechunk stream * - pass decoded data along * - if stream zeroed: * Y: - cut processed string out of buffer, but leave length of unprocessed dechunk stream data untouched * - body done * N: - parse ahaed */ char *dec_str = NULL; size_t dec_len; if (SUCCESS != php_http_encoding_stream_update(parser->dechunk, buffer->data, buffer->used, &dec_str, &dec_len)) { return PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE; } str = dec_str; len = dec_len; if (php_http_encoding_stream_done(parser->dechunk)) { cut = buffer->used - PHP_HTTP_BUFFER(parser->dechunk->ctx)->used; php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE); php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY); } else { cut = buffer->used; php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_CHUNKED); php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY); } break; } case PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE: { php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_DONE); if (parser->dechunk && parser->dechunk->ctx) { char *dec_str = NULL; size_t dec_len; if (SUCCESS != php_http_encoding_stream_finish(parser->dechunk, &dec_str, &dec_len)) { return php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE); } php_http_encoding_stream_dtor(parser->dechunk); if (dec_str && dec_len) { str = dec_str; len = dec_len; cut = 0; php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_UPDATE_CL); php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY); } } break; } case PHP_HTTP_MESSAGE_PARSER_STATE_UPDATE_CL: { zval zcl; ZVAL_LONG(&zcl, php_http_message_body_size((*message)->body)); zend_hash_str_update(&(*message)->hdrs, "Content-Length", lenof("Content-Length"), &zcl); break; } case PHP_HTTP_MESSAGE_PARSER_STATE_DONE: { char *ptr = buffer->data; while (ptr - buffer->data < buffer->used && PHP_HTTP_IS_CTYPE(space, *ptr)) { ++ptr; } php_http_buffer_cut(buffer, 0, ptr - buffer->data); if (!(flags & PHP_HTTP_MESSAGE_PARSER_GREEDY)) { return PHP_HTTP_MESSAGE_PARSER_STATE_DONE; } break; } } } return php_http_message_parser_state_is_ex(parser); } static zend_class_entry *php_http_message_parser_class_entry; zend_class_entry *php_http_get_message_parser_class_entry(void) { return php_http_message_parser_class_entry; } static zend_object_handlers php_http_message_parser_object_handlers; zend_object *php_http_message_parser_object_new(zend_class_entry *ce) { return &php_http_message_parser_object_new_ex(ce, NULL)->zo; } php_http_message_parser_object_t *php_http_message_parser_object_new_ex(zend_class_entry *ce, php_http_message_parser_t *parser) { php_http_message_parser_object_t *o; o = ecalloc(1, sizeof(*o) + zend_object_properties_size(ce)); zend_object_std_init(&o->zo, ce); object_properties_init(&o->zo, ce); if (parser) { o->parser = parser; } else { o->parser = php_http_message_parser_init(NULL); } php_http_buffer_init(&o->buffer); o->zo.handlers = &php_http_message_parser_object_handlers; return o; } void php_http_message_parser_object_free(zend_object *object) { php_http_message_parser_object_t *o = PHP_HTTP_OBJ(object, NULL); if (o->parser) { php_http_message_parser_free(&o->parser); } php_http_buffer_dtor(&o->buffer); zend_object_std_dtor(object); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessageParser_getState, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessageParser, getState) { php_http_message_parser_object_t *parser_obj = PHP_HTTP_OBJ(NULL, getThis()); zend_parse_parameters_none(); /* always return the real state */ RETVAL_LONG(php_http_message_parser_state_is_ex(parser_obj->parser)); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessageParser_parse, 0, 0, 3) ZEND_ARG_INFO(0, data) ZEND_ARG_INFO(0, flags) ZEND_ARG_INFO(1, message) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessageParser, parse) { php_http_message_parser_object_t *parser_obj; zval *zmsg; char *data_str; size_t data_len; zend_long flags; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "slz", &data_str, &data_len, &flags, &zmsg), invalid_arg, return); parser_obj = PHP_HTTP_OBJ(NULL, getThis()); php_http_buffer_append(&parser_obj->buffer, data_str, data_len); RETVAL_LONG(php_http_message_parser_parse(parser_obj->parser, &parser_obj->buffer, flags, &parser_obj->parser->message)); ZVAL_DEREF(zmsg); zval_dtor(zmsg); ZVAL_NULL(zmsg); if (parser_obj->parser->message) { php_http_message_t *msg_cpy = php_http_message_copy(parser_obj->parser->message, NULL); php_http_message_object_t *msg_obj = php_http_message_object_new_ex(php_http_message_get_class_entry(), msg_cpy); ZVAL_OBJ(zmsg, &msg_obj->zo); } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessageParser_stream, 0, 0, 3) ZEND_ARG_INFO(0, stream) ZEND_ARG_INFO(0, flags) ZEND_ARG_INFO(1, message) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessageParser, stream) { php_http_message_parser_object_t *parser_obj; zend_error_handling zeh; zval *zmsg, *zstream; php_stream *s; zend_long flags; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "rlz", &zstream, &flags, &zmsg), invalid_arg, return); zend_replace_error_handling(EH_THROW, php_http_get_exception_unexpected_val_class_entry(), &zeh); php_stream_from_zval(s, zstream); zend_restore_error_handling(&zeh); parser_obj = PHP_HTTP_OBJ(NULL, getThis()); RETVAL_LONG(php_http_message_parser_parse_stream(parser_obj->parser, &parser_obj->buffer, s, flags, &parser_obj->parser->message)); ZVAL_DEREF(zmsg); zval_dtor(zmsg); ZVAL_NULL(zmsg); if (parser_obj->parser->message) { php_http_message_t *msg_cpy = php_http_message_copy(parser_obj->parser->message, NULL); php_http_message_object_t *msg_obj = php_http_message_object_new_ex(php_http_message_get_class_entry(), msg_cpy); ZVAL_OBJ(zmsg, &msg_obj->zo); } } static zend_function_entry php_http_message_parser_methods[] = { PHP_ME(HttpMessageParser, getState, ai_HttpMessageParser_getState, ZEND_ACC_PUBLIC) PHP_ME(HttpMessageParser, parse, ai_HttpMessageParser_parse, ZEND_ACC_PUBLIC) PHP_ME(HttpMessageParser, stream, ai_HttpMessageParser_stream, ZEND_ACC_PUBLIC) {0} }; PHP_MINIT_FUNCTION(http_message_parser) { zend_class_entry ce; INIT_NS_CLASS_ENTRY(ce, "http\\Message", "Parser", php_http_message_parser_methods); php_http_message_parser_class_entry = zend_register_internal_class(&ce); memcpy(&php_http_message_parser_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); php_http_message_parser_class_entry->create_object = php_http_message_parser_object_new; php_http_message_parser_object_handlers.clone_obj = NULL; php_http_message_parser_object_handlers.free_obj = php_http_message_parser_object_free; php_http_message_parser_object_handlers.offset = XtOffsetOf(php_http_message_parser_object_t, zo); zend_declare_class_constant_long(php_http_message_parser_class_entry, ZEND_STRL("CLEANUP"), PHP_HTTP_MESSAGE_PARSER_CLEANUP); zend_declare_class_constant_long(php_http_message_parser_class_entry, ZEND_STRL("DUMB_BODIES"), PHP_HTTP_MESSAGE_PARSER_DUMB_BODIES); zend_declare_class_constant_long(php_http_message_parser_class_entry, ZEND_STRL("EMPTY_REDIRECTS"), PHP_HTTP_MESSAGE_PARSER_EMPTY_REDIRECTS); zend_declare_class_constant_long(php_http_message_parser_class_entry, ZEND_STRL("GREEDY"), PHP_HTTP_MESSAGE_PARSER_GREEDY); zend_declare_class_constant_long(php_http_message_parser_class_entry, ZEND_STRL("STATE_FAILURE"), PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE); zend_declare_class_constant_long(php_http_message_parser_class_entry, ZEND_STRL("STATE_START"), PHP_HTTP_MESSAGE_PARSER_STATE_START); zend_declare_class_constant_long(php_http_message_parser_class_entry, ZEND_STRL("STATE_HEADER"), PHP_HTTP_MESSAGE_PARSER_STATE_HEADER); zend_declare_class_constant_long(php_http_message_parser_class_entry, ZEND_STRL("STATE_HEADER_DONE"), PHP_HTTP_MESSAGE_PARSER_STATE_HEADER_DONE); zend_declare_class_constant_long(php_http_message_parser_class_entry, ZEND_STRL("STATE_BODY"), PHP_HTTP_MESSAGE_PARSER_STATE_BODY); zend_declare_class_constant_long(php_http_message_parser_class_entry, ZEND_STRL("STATE_BODY_DUMB"), PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DUMB); zend_declare_class_constant_long(php_http_message_parser_class_entry, ZEND_STRL("STATE_BODY_LENGTH"), PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH); zend_declare_class_constant_long(php_http_message_parser_class_entry, ZEND_STRL("STATE_BODY_CHUNKED"), PHP_HTTP_MESSAGE_PARSER_STATE_BODY_CHUNKED); zend_declare_class_constant_long(php_http_message_parser_class_entry, ZEND_STRL("STATE_BODY_DONE"), PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE); zend_declare_class_constant_long(php_http_message_parser_class_entry, ZEND_STRL("STATE_UPDATE_CL"), PHP_HTTP_MESSAGE_PARSER_STATE_UPDATE_CL); zend_declare_class_constant_long(php_http_message_parser_class_entry, ZEND_STRL("STATE_DONE"), PHP_HTTP_MESSAGE_PARSER_STATE_DONE); 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 */ pecl_http-4.2.1/src/php_http_message_parser.h0000644000076500000240000000636214117626035020132 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_HTTP_MESSAGE_PARSER_H #define PHP_HTTP_MESSAGE_PARSER_H #include "php_http_header_parser.h" #include "php_http_encoding.h" #include "php_http_message.h" typedef enum php_http_message_parser_state { PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE = FAILURE, PHP_HTTP_MESSAGE_PARSER_STATE_START = 0, PHP_HTTP_MESSAGE_PARSER_STATE_HEADER, PHP_HTTP_MESSAGE_PARSER_STATE_HEADER_DONE, PHP_HTTP_MESSAGE_PARSER_STATE_BODY, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DUMB, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_CHUNKED, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE, PHP_HTTP_MESSAGE_PARSER_STATE_UPDATE_CL, PHP_HTTP_MESSAGE_PARSER_STATE_DONE } php_http_message_parser_state_t; #define PHP_HTTP_MESSAGE_PARSER_CLEANUP 0x1 #define PHP_HTTP_MESSAGE_PARSER_DUMB_BODIES 0x2 #define PHP_HTTP_MESSAGE_PARSER_EMPTY_REDIRECTS 0x4 #define PHP_HTTP_MESSAGE_PARSER_GREEDY 0x8 typedef struct php_http_message_parser { php_http_header_parser_t header; zend_ptr_stack stack; size_t body_length; php_http_message_t *message; php_http_encoding_stream_t *dechunk; php_http_encoding_stream_t *inflate; } php_http_message_parser_t; PHP_HTTP_API php_http_message_parser_t *php_http_message_parser_init(php_http_message_parser_t *parser); PHP_HTTP_API php_http_message_parser_state_t php_http_message_parser_state_is(php_http_message_parser_t *parser); PHP_HTTP_API void php_http_message_parser_dtor(php_http_message_parser_t *parser); PHP_HTTP_API void php_http_message_parser_free(php_http_message_parser_t **parser); PHP_HTTP_API php_http_message_parser_state_t php_http_message_parser_parse(php_http_message_parser_t *parser, php_http_buffer_t *buffer, unsigned flags, php_http_message_t **message); PHP_HTTP_API php_http_message_parser_state_t php_http_message_parser_parse_stream(php_http_message_parser_t *parser, php_http_buffer_t *buffer, php_stream *s, unsigned flags, php_http_message_t **message); typedef struct php_http_message_parser_object { php_http_buffer_t buffer; php_http_message_parser_t *parser; zend_object zo; } php_http_message_parser_object_t; PHP_HTTP_API zend_class_entry *php_http_get_message_parser_class_entry(void); PHP_MINIT_FUNCTION(http_message_parser); zend_object *php_http_message_parser_object_new(zend_class_entry *ce); php_http_message_parser_object_t *php_http_message_parser_object_new_ex(zend_class_entry *ce, php_http_message_parser_t *parser); void php_http_message_parser_object_free(zend_object *object); #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 */ pecl_http-4.2.1/src/php_http_misc.c0000644000076500000240000001505214117626035016054 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #include "php_http_api.h" #include "ext/standard/php_lcg.h" #include "zend_exceptions.h" /* SLEEP */ void php_http_sleep(double s) { #if PHP_WIN32 Sleep((DWORD) PHP_HTTP_MSEC(s)); #elif HAVE_USLEEP usleep(PHP_HTTP_USEC(s)); #elif HAVE_NANOSLEEP struct timespec req, rem; req.tv_sec = (time_t) s; req.tv_nsec = PHP_HTTP_NSEC(s) % PHP_HTTP_NANOSEC; while (nanosleep(&req, &rem) && (errno == EINTR) && (PHP_HTTP_NSEC(rem.tv_sec) + rem.tv_nsec) > PHP_HTTP_NSEC(PHP_HTTP_DIFFSEC))) { req.tv_sec = rem.tv_sec; req.tv_nsec = rem.tv_nsec; } #else struct timeval timeout; timeout.tv_sec = (time_t) s; timeout.tv_usec = PHP_HTTP_USEC(s) % PHP_HTTP_MCROSEC; select(0, NULL, NULL, NULL, &timeout); #endif } /* STRING UTILITIES */ int php_http_match(const char *haystack_str, const char *needle_str, int flags) { int result = 0; if (UNEXPECTED(!haystack_str || !needle_str)) { return result; } if (UNEXPECTED(flags & PHP_HTTP_MATCH_FULL)) { if (flags & PHP_HTTP_MATCH_CASE) { result = !strcmp(haystack_str, needle_str); } else { result = !strcasecmp(haystack_str, needle_str); } } else { const char *found; char *haystack = estrdup(haystack_str), *needle = estrdup(needle_str); if (UNEXPECTED(flags & PHP_HTTP_MATCH_CASE)) { found = zend_memnstr(haystack, needle, strlen(needle), haystack+strlen(haystack)); } else { found = php_stristr(haystack, needle, strlen(haystack), strlen(needle)); } if (found) { if (!(flags & PHP_HTTP_MATCH_WORD) || ( (found == haystack || !PHP_HTTP_IS_CTYPE(alnum, *(found - 1))) && EXPECTED(!*(found + strlen(needle)) || !PHP_HTTP_IS_CTYPE(alnum, *(found + strlen(needle)))) ) ) { result = 1; } } PTR_FREE(haystack); PTR_FREE(needle); } return result; } char *php_http_pretty_key(char *key, size_t key_len, zend_bool uctitle, zend_bool xhyphen) { size_t i; int wasalpha; if (key && key_len) { if (EXPECTED(wasalpha = PHP_HTTP_IS_CTYPE(alpha, key[0]))) { if (EXPECTED(uctitle)) { key[0] = PHP_HTTP_TO_CTYPE(upper, key[0]); } else { key[0] = PHP_HTTP_TO_CTYPE(lower, key[0]); } } for (i = 1; i < key_len; ++i) { if (EXPECTED(PHP_HTTP_IS_CTYPE(alpha, key[i]))) { if (EXPECTED(wasalpha)) { key[i] = PHP_HTTP_TO_CTYPE(lower, key[i]); } else if (EXPECTED(uctitle)) { key[i] = PHP_HTTP_TO_CTYPE(upper, key[i]); wasalpha = 1; } else { key[i] = PHP_HTTP_TO_CTYPE(lower, key[i]); wasalpha = 1; } } else { if (EXPECTED(xhyphen && (key[i] == '_'))) { key[i] = '-'; } wasalpha = 0; } } } return key; } size_t php_http_boundary(char *buf, size_t buf_len) { return snprintf(buf, buf_len, "%15.15F", sapi_get_request_time() * php_combined_lcg()); } int php_http_select_str(const char *cmp, int argc, ...) { va_list argv; int match = -1; if (cmp && argc > 0) { int i; va_start(argv, argc); for (i = 0; i < argc; ++i) { const char *test = va_arg(argv, const char *); if (!strcasecmp(cmp, test)) { match = i; break; } } va_end(argv); } return match; } /* ARRAYS */ unsigned php_http_array_list(HashTable *ht, unsigned argc, ...) { unsigned argl = 0; va_list argv; zval *data; va_start(argv, argc); ZEND_HASH_FOREACH_VAL(ht, data) { zval **argp = (zval **) va_arg(argv, zval **); *argp = data; ++argl; } ZEND_HASH_FOREACH_END(); va_end(argv); return argl; } void php_http_array_copy_strings(zval *zp) { Z_TRY_ADDREF_P(zp); convert_to_string_ex(zp); } int php_http_array_apply_append_func(zval *value, int num_args, va_list args, zend_hash_key *hash_key) { int flags; char *key = NULL; HashTable *dst; zval *data = NULL; dst = va_arg(args, HashTable *); flags = va_arg(args, int); if ((!(flags & ARRAY_JOIN_STRONLY)) || hash_key->key) { if ((flags & ARRAY_JOIN_PRETTIFY) && hash_key->key) { key = php_http_pretty_key(estrndup(hash_key->key->val, hash_key->key->len), hash_key->key->len, 1, 1); data = zend_hash_str_find(dst, key, hash_key->key->len); } else if (hash_key->key) { data = zend_hash_find(dst, hash_key->key); } else { data = zend_hash_index_find(dst, hash_key->h); } if (flags & ARRAY_JOIN_STRINGIFY) { convert_to_string_ex(value); } Z_TRY_ADDREF_P(value); if (data) { if (Z_TYPE_P(data) != IS_ARRAY) { convert_to_array(data); } add_next_index_zval(data, value); } else if (key) { zend_hash_str_update(dst, key, hash_key->key->len, value); } else if (hash_key->key) { zend_hash_update(dst, hash_key->key, value); } else { zend_hash_index_update(dst, hash_key->h, value); } if (key) { efree(key); } } return ZEND_HASH_APPLY_KEEP; } int php_http_array_apply_merge_func(zval *value, int num_args, va_list args, zend_hash_key *hash_key) { int flags; char *key = NULL; HashTable *dst; dst = va_arg(args, HashTable *); flags = va_arg(args, int); if ((!(flags & ARRAY_JOIN_STRONLY)) || hash_key->key) { if (flags & ARRAY_JOIN_STRINGIFY) { convert_to_string_ex(value); } Z_TRY_ADDREF_P(value); if ((flags & ARRAY_JOIN_PRETTIFY) && hash_key->key) { key = php_http_pretty_key(estrndup(hash_key->key->val, hash_key->key->len), hash_key->key->len, 1, 1); zend_hash_str_update(dst, key, hash_key->key->len, value); efree(key); } else if (hash_key->key) { zend_hash_update(dst, hash_key->key, value); } else { zend_hash_index_update(dst, hash_key->h, value); } } return ZEND_HASH_APPLY_KEEP; } /* PASS CALLBACK */ size_t php_http_pass_fcall_callback(void *cb_arg, const char *str, size_t len) { php_http_pass_fcall_arg_t *fcd = cb_arg; zval zdata; ZVAL_STRINGL(&zdata, str, len); zend_fcall_info_argn(&fcd->fci, 2, &fcd->fcz, &zdata); zend_fcall_info_call(&fcd->fci, &fcd->fcc, NULL, NULL); zend_fcall_info_args_clear(&fcd->fci, 0); zval_ptr_dtor(&zdata); return len; } /* ZEND */ /* * 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 */ pecl_http-4.2.1/src/php_http_misc.h0000644000076500000240000001757414117626035016074 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_HTTP_MISC_H #define PHP_HTTP_MISC_H /* DEFAULTS */ /* DATE FORMAT RFC1123 */ #define PHP_HTTP_DATE_FORMAT "D, d M Y H:i:s \\G\\M\\T" /* CR LF */ #define PHP_HTTP_CRLF "\r\n" /* def URL arg separator */ #define PHP_HTTP_URL_ARGSEP "&" /* send buffer size */ #define PHP_HTTP_SENDBUF_SIZE 40960 /* allowed characters of header field names */ #define PHP_HTTP_HEADER_NAME_CHARS "!#$%&'*+-.^_`|~1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" /* SLEEP */ #define PHP_HTTP_DIFFSEC (0.001) #define PHP_HTTP_MLLISEC (1000) #define PHP_HTTP_MCROSEC (1000 * 1000) #define PHP_HTTP_NANOSEC (1000 * 1000 * 1000) #define PHP_HTTP_MSEC(s) ((long)(s * PHP_HTTP_MLLISEC)) #define PHP_HTTP_USEC(s) ((long)(s * PHP_HTTP_MCROSEC)) #define PHP_HTTP_NSEC(s) ((long)(s * PHP_HTTP_NANOSEC)) PHP_HTTP_API void php_http_sleep(double s); /* STRING UTILITIES */ #ifndef PTR_SET # define PTR_SET(STR, SET) \ { \ PTR_FREE(STR); \ STR = SET; \ } #endif #define STR_PTR(s) (s?s:"") #define lenof(S) (sizeof(S) - 1) #define PHP_HTTP_MATCH_LOOSE 0 #define PHP_HTTP_MATCH_CASE 0x01 #define PHP_HTTP_MATCH_WORD 0x10 #define PHP_HTTP_MATCH_FULL 0x20 #define PHP_HTTP_MATCH_STRICT (PHP_HTTP_MATCH_CASE|PHP_HTTP_MATCH_FULL) int php_http_match(const char *haystack, const char *needle, int flags); char *php_http_pretty_key(register char *key, size_t key_len, zend_bool uctitle, zend_bool xhyphen); size_t php_http_boundary(char *buf, size_t len); int php_http_select_str(const char *cmp, int argc, ...); #define php_http_locate_str(h, h_len, n, n_len) zend_memnstr((h), (n), (n_len), (h)+(h_len)) static inline const char *php_http_locate_eol(const char *line, int *eol_len) { const char *eol = strpbrk(line, "\r\n"); if (eol_len) { *eol_len = eol ? ((eol[0] == '\r' && eol[1] == '\n') ? 2 : 1) : 0; } return eol; } static inline const char *php_http_locate_bin_eol(const char *bin, size_t len, int *eol_len) { register const char *eol = bin; while (len--) { if (UNEXPECTED(*eol == '\r' || *eol == '\n')) { if (EXPECTED(eol_len)) { *eol_len = (EXPECTED(eol[0] == '\r' && eol[1] == '\n') ? 2 : 1); } return eol; } ++eol; } return NULL; } /* ZEND */ #if PHP_DEBUG # undef HASH_OF # define HASH_OF(p) ((HashTable*)(Z_TYPE_P(p)==IS_ARRAY ? Z_ARRVAL_P(p) : ((Z_TYPE_P(p)==IS_OBJECT ? Z_OBJ_HT_P(p)->get_properties(Z_OBJ_P(p)) : NULL)))) #endif #if PHP_VERSION_ID >= 80100 # define php_http_mem_stream_open(type, zstr) php_stream_memory_open((type), (zstr)) #else # define php_http_mem_stream_open(type, zstr) php_stream_memory_open((type), (zstr)->val, (zstr)->len) # define ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(name, return_reference, required_num_args, type, allow_null) \ ZEND_BEGIN_ARG_INFO_EX(name, 0, return_reference, required_num_args) # define ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_OBJ_INFO_EX(name, return_reference, required_num_args, type, allow_null) \ ZEND_BEGIN_ARG_INFO_EX(name, 0, return_reference, required_num_args) #endif #define HT_IS_RECURSIVE(ht) GC_IS_RECURSIVE(ht) #define HT_PROTECT_RECURSION(ht) GC_PROTECT_RECURSION(ht) #define HT_UNPROTECT_RECURSION(ht) GC_UNPROTECT_RECURSION(ht) #ifndef convert_to_explicit_type # define convert_to_explicit_type(pzv, type) \ do { \ switch (type) { \ case IS_NULL: \ convert_to_null(pzv); \ break; \ case IS_LONG: \ convert_to_long(pzv); \ break; \ case IS_DOUBLE: \ convert_to_double(pzv); \ break; \ case _IS_BOOL: \ convert_to_boolean(pzv); \ break; \ case IS_ARRAY: \ convert_to_array(pzv); \ break; \ case IS_OBJECT: \ convert_to_object(pzv); \ break; \ case IS_STRING: \ convert_to_string(pzv); \ break; \ default: \ assert(0); \ break; \ } \ } while (0); #endif static inline void *PHP_HTTP_OBJ(zend_object *zo, zval *zv) { if (!zo) { zo = Z_OBJ_P(zv); } return (char *) zo - zo->handlers->offset; } static inline zend_string *php_http_cs2zs(char *s, size_t l) { zend_string *str = zend_string_init(s, l, 0); efree(s); return str; } static inline ZEND_RESULT_CODE php_http_ini_entry(const char *name_str, size_t name_len, const char **val_str, size_t *val_len, zend_bool orig) { zend_ini_entry *ini_entry; if ((ini_entry = zend_hash_str_find_ptr(EG(ini_directives), name_str, name_len))) { if (orig && ini_entry->modified) { *val_str = ini_entry->orig_value->val; *val_len = ini_entry->orig_value->len; } else { *val_str = ini_entry->value->val; *val_len = ini_entry->value->len; } return SUCCESS; } return FAILURE; } /* return object(values) */ #define ZVAL_OBJECT(z, o, addref) \ ZVAL_OBJ(z, o); \ if (addref) { \ Z_ADDREF_P(z); \ } #define RETVAL_OBJECT(o, addref) \ ZVAL_OBJECT(return_value, o, addref) #define RETURN_OBJECT(o, addref) \ RETVAL_OBJECT(o, addref); \ return #define EMPTY_FUNCTION_ENTRY {NULL, NULL, NULL, 0, 0} #define PHP_MINIT_CALL(func) PHP_MINIT(func)(INIT_FUNC_ARGS_PASSTHRU) #define PHP_RINIT_CALL(func) PHP_RINIT(func)(INIT_FUNC_ARGS_PASSTHRU) #define PHP_MSHUTDOWN_CALL(func) PHP_MSHUTDOWN(func)(SHUTDOWN_FUNC_ARGS_PASSTHRU) #define PHP_RSHUTDOWN_CALL(func) PHP_RSHUTDOWN(func)(SHUTDOWN_FUNC_ARGS_PASSTHRU) /* ARRAYS */ PHP_HTTP_API unsigned php_http_array_list(HashTable *ht, unsigned argc, ...); typedef struct php_http_arrkey { zend_ulong h; zend_string *key; unsigned allocated:1; unsigned stringified:1; } php_http_arrkey_t; static inline void *php_http_arrkey_stringify(php_http_arrkey_t *arrkey, zend_hash_key *key) { if (arrkey) { arrkey->allocated = 0; } else { arrkey = emalloc(sizeof(*arrkey)); arrkey->allocated = 1; } if (key) { memcpy(arrkey, key, sizeof(*key)); } if ((arrkey->stringified = !arrkey->key)) { arrkey->key = zend_long_to_str(arrkey->h); } return arrkey; } static inline void php_http_arrkey_dtor(php_http_arrkey_t *arrkey) { if (arrkey->stringified) { zend_string_release(arrkey->key); } if (arrkey->allocated) { efree(arrkey); } } #define array_copy(src, dst) zend_hash_copy(dst, src, (copy_ctor_func_t) zval_add_ref) #define array_copy_strings(src, dst) zend_hash_copy(dst, src, php_http_array_copy_strings) #define ARRAY_JOIN_STRONLY 0x01 #define ARRAY_JOIN_PRETTIFY 0x02 #define ARRAY_JOIN_STRINGIFY 0x04 #define array_join(src, dst, append, flags) zend_hash_apply_with_arguments(src, (append)?php_http_array_apply_append_func:php_http_array_apply_merge_func, 2, dst, (int)flags) void php_http_array_copy_strings(zval *zp); int php_http_array_apply_append_func(zval *pDest, int num_args, va_list args, zend_hash_key *hash_key); int php_http_array_apply_merge_func(zval *pDest, int num_args, va_list args, zend_hash_key *hash_key); /* PASS CALLBACK */ typedef size_t (*php_http_pass_callback_t)(void *cb_arg, const char *str, size_t len); typedef size_t (*php_http_pass_php_http_buffer_callback_t)(void *cb_arg, php_http_buffer_t *str); typedef size_t (*php_http_pass_format_callback_t)(void *cb_arg, const char *fmt, ...); typedef struct php_http_pass_fcall_arg { zval fcz; zend_fcall_info fci; zend_fcall_info_cache fcc; } php_http_pass_fcall_arg_t; PHP_HTTP_API size_t php_http_pass_fcall_callback(void *cb_arg, const char *str, size_t len); #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 */ pecl_http-4.2.1/src/php_http_negotiate.c0000644000076500000240000001257414117626035017106 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #include "php_http_api.h" #ifndef PHP_HTTP_DEBUG_NEG # define PHP_HTTP_DEBUG_NEG 0 #endif static int php_http_negotiate_sort(Bucket *b1, Bucket *b2) { int result = numeric_compare_function(&b1->val, &b2->val); return (result > 0 ? -1 : (result < 0 ? 1 : 0)); } #define M_PRI 5 #define M_SEC 2 #define M_ANY -1 #define M_NOT 0 #define M_ALL ~0 static inline unsigned php_http_negotiate_match(const char *param_str, size_t param_len, const char *supported_str, size_t supported_len, const char *sep_str, size_t sep_len) { unsigned match = M_NOT; if (param_len == supported_len && !strncasecmp(param_str, supported_str, param_len)) { /* that was easy */ match = M_ALL; } else if (sep_str && sep_len) { const char *param_sec = php_http_locate_str(param_str, param_len, sep_str, sep_len); size_t param_pri_len = param_sec ? param_sec - param_str : param_len; const char *supported_sec = php_http_locate_str(supported_str, supported_len, sep_str, sep_len); size_t supported_pri_len = supported_sec ? supported_sec - supported_str : supported_len; size_t cmp_len = MIN(param_pri_len, supported_pri_len); if (((*param_str == '*') || (*supported_str == '*')) || ((param_pri_len == supported_pri_len) && !strncasecmp(param_str, supported_str, param_pri_len)) || ((!param_sec || !supported_sec) && cmp_len && !strncasecmp(param_str, supported_str, cmp_len)) ) { match += M_PRI; } if (param_sec && supported_sec && ((*(param_sec + sep_len) == '*' || *(supported_sec + sep_len) == '*') || !strcasecmp(param_sec, supported_sec) ) ) { match += M_SEC; } if ((param_sec && *(param_sec + sep_len) == '*') || (supported_sec && *(supported_sec + sep_len) == '*') || ((*param_str == '*') || (*supported_str == '*')) ) { match += M_ANY; } } #if PHP_HTTP_DEBUG_NEG fprintf(stderr, "match: %s == %s => %u\n", supported_str, param_str, match); #endif return match; } static int php_http_negotiate_reduce(zval *p, int num_args, va_list args, zend_hash_key *hash_key) { unsigned best_match = 0; double q = 0; php_http_arrkey_t key; zval *value; zend_string *supported = zval_get_string(p); HashTable *params = va_arg(args, HashTable *); HashTable *result = va_arg(args, HashTable *); const char *sep_str = va_arg(args, const char *); size_t sep_len = va_arg(args, size_t); ZEND_HASH_FOREACH_KEY_VAL(params, key.h, key.key, value) { unsigned match; #if PHP_HTTP_DEBUG_NEG fprintf(stderr, "match(%u) > best_match(%u) = %u (q=%f)\n", match, best_match, match>best_match, Z_DVAL_PP(val)); #endif php_http_arrkey_stringify(&key, NULL); match = php_http_negotiate_match(key.key->val, key.key->len, supported->val, supported->len, sep_str, sep_len); if (match > best_match) { best_match = match; q = Z_DVAL_P(value) - 0.1 / match; } php_http_arrkey_dtor(&key); } ZEND_HASH_FOREACH_END(); if (q > 0) { zval tmp; ZVAL_DOUBLE(&tmp, q); zend_hash_update(result, supported, &tmp); } zend_string_release(supported); return ZEND_HASH_APPLY_KEEP; } HashTable *php_http_negotiate(const char *value_str, size_t value_len, HashTable *supported, const char *primary_sep_str, size_t primary_sep_len) { HashTable *result = NULL; if (value_str && value_len) { unsigned i = 0; zval arr, *val, *arg, *zq; HashTable params; php_http_arrkey_t key; php_http_params_opts_t opts; zend_hash_init(¶ms, 10, NULL, ZVAL_PTR_DTOR, 0); php_http_params_opts_default_get(&opts); opts.input.str = estrndup(value_str, value_len); opts.input.len = value_len; opts.flags &= ~PHP_HTTP_PARAMS_RFC5987; php_http_params_parse(¶ms, &opts); efree(opts.input.str); array_init(&arr); ZEND_HASH_FOREACH_KEY_VAL(¶ms, key.h, key.key, val) { double q; if ((arg = zend_hash_str_find(Z_ARRVAL_P(val), ZEND_STRL("arguments"))) && (IS_ARRAY == Z_TYPE_P(arg)) && (zq = zend_hash_str_find(Z_ARRVAL_P(arg), ZEND_STRL("q")))) { q = zval_get_double(zq); } else { q = 1.0 - (((double) ++i) / 100.0); } #if 0 fprintf(stderr, "Q: %s=%1.3f\n", key.key->val, q); #endif if (key.key) { add_assoc_double_ex(&arr, key.key->val, key.key->len, q); } else { add_index_double(&arr, key.h, q); } } ZEND_HASH_FOREACH_END(); #if PHP_HTTP_DEBUG_NEG zend_print_zval_r(&arr, 1); #endif ALLOC_HASHTABLE(result); zend_hash_init(result, zend_hash_num_elements(supported), NULL, ZVAL_PTR_DTOR, 0); zend_hash_apply_with_arguments(supported, php_http_negotiate_reduce, 4, Z_ARRVAL(arr), result, primary_sep_str, primary_sep_len); zend_hash_destroy(¶ms); zval_dtor(&arr); zend_hash_sort(result, php_http_negotiate_sort, 0); } return result; } /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ pecl_http-4.2.1/src/php_http_negotiate.h0000644000076500000240000000765614117626035017120 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_HTTP_NEGOTIATE_H #define PHP_HTTP_NEGOTIATE_H PHP_HTTP_API HashTable *php_http_negotiate(const char *value_str, size_t value_len, HashTable *supported, const char *primary_sep_str, size_t primary_sep_len); static inline HashTable *php_http_negotiate_language(HashTable *supported, php_http_message_t *request) { HashTable *result = NULL; size_t length; char *value = php_http_env_get_request_header(ZEND_STRL("Accept-Language"), &length, request); if (value) { result = php_http_negotiate(value, length, supported, "-", 1); } PTR_FREE(value); return result; } static inline HashTable *php_http_negotiate_encoding(HashTable *supported, php_http_message_t *request) { HashTable *result = NULL; size_t length; char *value = php_http_env_get_request_header(ZEND_STRL("Accept-Encoding"), &length, request); if (value) { result = php_http_negotiate(value, length, supported, NULL, 0); } PTR_FREE(value); return result; } static inline HashTable *php_http_negotiate_charset(HashTable *supported, php_http_message_t *request) { HashTable *result = NULL; size_t length; char *value = php_http_env_get_request_header(ZEND_STRL("Accept-Charset"), &length, request); if (value) { result = php_http_negotiate(value, length, supported, NULL, 0); } PTR_FREE(value); return result; } static inline HashTable *php_http_negotiate_content_type(HashTable *supported, php_http_message_t *request) { HashTable *result = NULL; size_t length; char *value = php_http_env_get_request_header(ZEND_STRL("Accept"), &length, request); if (value) { result = php_http_negotiate(value, length, supported, "/", 1); } PTR_FREE(value); return result; } #define PHP_HTTP_DO_NEGOTIATE_DEFAULT(supported) \ { \ zval *value; \ HashPosition pos; \ \ zend_hash_internal_pointer_reset_ex((supported), &pos); \ if ((value = zend_hash_get_current_data_ex((supported), &pos))) { \ 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) { \ zval *value; \ \ ZEND_HASH_FOREACH_VAL(supported, value) \ { \ zend_string *zs = zval_get_string(value); \ add_assoc_double_ex(rs_array, zs->val, zs->len, 1.0); \ zend_string_release(zs); \ } \ ZEND_HASH_FOREACH_END(); \ } #define PHP_HTTP_DO_NEGOTIATE_HANDLE_RESULT(result, supported, rs_array) \ { \ zend_string *key; \ zend_ulong idx; \ \ if (zend_hash_num_elements(result) && HASH_KEY_IS_STRING == zend_hash_get_current_key(result, &key, &idx)) { \ RETVAL_STR_COPY(key); \ } 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); \ } \ \ 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, NULL))) { \ PHP_HTTP_DO_NEGOTIATE_HANDLE_RESULT(result, supported, rs_array); \ } else { \ PHP_HTTP_DO_NEGOTIATE_HANDLE_DEFAULT(supported, rs_array); \ } \ } #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 */ pecl_http-4.2.1/src/php_http_object.c0000644000076500000240000000720014117626035016363 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #include "php_http_api.h" static zend_object_handlers php_http_object_handlers; zend_object *php_http_object_new(zend_class_entry *ce) { return &php_http_object_new_ex(ce, NULL)->zo; } php_http_object_t *php_http_object_new_ex(zend_class_entry *ce, void *intern) { php_http_object_t *o; o = ecalloc(1, sizeof(*o) + zend_object_properties_size(ce)); zend_object_std_init(&o->zo, ce); object_properties_init(&o->zo, ce); o->intern = intern; o->zo.handlers = &php_http_object_handlers; return o; } void php_http_object_free(zend_object *object) { zend_object_std_dtor(object); } ZEND_RESULT_CODE php_http_new(void **obj_ptr, zend_class_entry *ce, php_http_new_t create, zend_class_entry *parent_ce, void *intern_ptr) { void *obj; if (!ce) { ce = parent_ce; } else if (parent_ce && !instanceof_function(ce, parent_ce)) { php_http_throw(unexpected_val, "Class %s does not extend %s", ce->name->val, parent_ce->name->val); return FAILURE; } obj = create(ce, intern_ptr); if (obj_ptr) { *obj_ptr = obj; } return SUCCESS; } php_http_object_method_t *php_http_object_method_init(php_http_object_method_t *cb, zval *zobject, const char *method_str, size_t method_len) { if (!cb) { cb = ecalloc(1, sizeof(*cb)); } else { memset(cb, 0, sizeof(*cb)); } cb->fci.size = sizeof(cb->fci); ZVAL_STRINGL(&cb->fci.function_name, method_str, method_len); #if PHP_VERSION_ID < 70300 cb->fcc.initialized = 1; #endif cb->fcc.calling_scope = cb->fcc.called_scope = Z_OBJCE_P(zobject); cb->fcc.function_handler = Z_OBJ_HT_P(zobject)->get_method(&Z_OBJ_P(zobject), Z_STR(cb->fci.function_name), NULL); return cb; } void php_http_object_method_dtor(php_http_object_method_t *cb) { zval_ptr_dtor(&cb->fci.function_name); } void php_http_object_method_free(php_http_object_method_t **cb) { if (*cb) { php_http_object_method_dtor(*cb); efree(*cb); *cb = NULL; } } ZEND_RESULT_CODE php_http_object_method_call(php_http_object_method_t *cb, zval *zobject, zval *retval_ptr, int argc, zval *args) { ZEND_RESULT_CODE rv; zval retval; ZVAL_UNDEF(&retval); Z_ADDREF_P(zobject); cb->fci.object = Z_OBJ_P(zobject); cb->fcc.object = Z_OBJ_P(zobject); cb->fci.retval = retval_ptr ? retval_ptr : &retval; cb->fci.param_count = argc; cb->fci.params = args; if (cb->fcc.called_scope != Z_OBJCE_P(zobject)) { cb->fcc.called_scope = Z_OBJCE_P(zobject); cb->fcc.function_handler = Z_OBJ_HT_P(zobject)->get_method(&Z_OBJ_P(zobject), Z_STR(cb->fci.function_name), NULL); } rv = zend_call_function(&cb->fci, &cb->fcc); zval_ptr_dtor(zobject); if (!retval_ptr && !Z_ISUNDEF(retval)) { zval_ptr_dtor(&retval); } return rv; } PHP_MINIT_FUNCTION(http_object) { memcpy(&php_http_object_handlers, zend_get_std_object_handlers(), sizeof(php_http_object_handlers)); php_http_object_handlers.offset = XtOffsetOf(php_http_object_t, zo); 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 */ pecl_http-4.2.1/src/php_http_object.h0000644000076500000240000000347714117626035016404 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_HTTP_OBJECT_H #define PHP_HTTP_OBJECT_H typedef struct php_http_object { void *intern; zend_object zo; } php_http_object_t; zend_object *php_http_object_new(zend_class_entry *ce); php_http_object_t *php_http_object_new_ex(zend_class_entry *ce, void *nothing); typedef void *(*php_http_new_t)(zend_class_entry *ce, void *); ZEND_RESULT_CODE php_http_new(void **obj_ptr, zend_class_entry *ce, php_http_new_t create, zend_class_entry *parent_ce, void *intern_ptr); PHP_MINIT_FUNCTION(http_object); typedef struct php_http_method { zend_fcall_info fci; zend_fcall_info_cache fcc; } php_http_object_method_t; php_http_object_method_t *php_http_object_method_init(php_http_object_method_t *cb, zval *zobject, const char *method_str, size_t method_len); ZEND_RESULT_CODE php_http_object_method_call(php_http_object_method_t *cb, zval *zobject, zval *retval, int argc, zval *args); void php_http_object_method_dtor(php_http_object_method_t *cb); void php_http_object_method_free(php_http_object_method_t **cb); #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 */ pecl_http-4.2.1/src/php_http_options.c0000644000076500000240000000647514117626035016625 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #include "php_http_api.h" static void php_http_options_hash_dtor(zval *pData) { php_http_option_t *opt = Z_PTR_P(pData); zval_internal_ptr_dtor(&opt->defval); zend_hash_destroy(&opt->suboptions.options); zend_string_release(opt->name); pefree(opt, opt->persistent); } php_http_options_t *php_http_options_init(php_http_options_t *registry, zend_bool persistent) { if (!registry) { registry = pecalloc(1, sizeof(*registry), persistent); } else { memset(registry, 0, sizeof(*registry)); } registry->persistent = persistent; zend_hash_init(®istry->options, 0, NULL, php_http_options_hash_dtor, persistent); return registry; } ZEND_RESULT_CODE php_http_options_apply(php_http_options_t *registry, HashTable *options, void *userdata) { zval *entry, *val; php_http_option_t *opt; ZEND_HASH_FOREACH_VAL(®istry->options, entry) { opt = Z_PTR_P(entry); if (!(val = registry->getter(opt, options, userdata))) { val = &opt->defval; } if (registry->setter) { if (SUCCESS != registry->setter(opt, val, userdata)) { return FAILURE; } } else if (!opt->setter || SUCCESS != opt->setter(opt, val, userdata)) { return FAILURE; } } ZEND_HASH_FOREACH_END(); return SUCCESS; } void php_http_options_dtor(php_http_options_t *registry) { zend_hash_destroy(®istry->options); } void php_http_options_free(php_http_options_t **registry) { if (*registry) { php_http_options_dtor(*registry); pefree(*registry, (*registry)->persistent); *registry = NULL; } } php_http_option_t *php_http_option_register(php_http_options_t *registry, const char *name_str, size_t name_len, unsigned long option, zend_uchar type) { php_http_option_t opt; memset(&opt, 0, sizeof(opt)); php_http_options_init(&opt.suboptions, registry->persistent); opt.suboptions.getter = registry->getter; opt.suboptions.setter = registry->setter; opt.persistent = registry->persistent; opt.name = zend_string_init(name_str, name_len, registry->persistent); opt.type = type; opt.option = option; switch ((opt.type = type)) { case IS_TRUE: ZVAL_TRUE(&opt.defval); break; case IS_FALSE: ZVAL_FALSE(&opt.defval); break; case IS_LONG: ZVAL_LONG(&opt.defval, 0); break; case IS_DOUBLE: ZVAL_DOUBLE(&opt.defval, 0); break; default: ZVAL_NULL(&opt.defval); break; } return zend_hash_update_mem(®istry->options, opt.name, &opt, sizeof(opt)); } zval *php_http_option_get(php_http_option_t *opt, HashTable *options, void *userdata) { if (options) { return zend_hash_find(options, opt->name); } 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 */ pecl_http-4.2.1/src/php_http_options.h0000644000076500000240000000430414117626035016617 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_HTTP_OPTIONS_H #define PHP_HTTP_OPTIONS_H typedef struct php_http_option php_http_option_t; typedef struct php_http_options php_http_options_t; typedef ZEND_RESULT_CODE (*php_http_option_set_callback_t)(php_http_option_t *opt, zval *val, void *userdata); typedef zval *(*php_http_option_get_callback_t)(php_http_option_t *opt, HashTable *options, void *userdata); struct php_http_options { HashTable options; php_http_option_get_callback_t getter; php_http_option_set_callback_t setter; unsigned persistent:1; }; struct php_http_option { php_http_options_t suboptions; zend_string *name; unsigned long option; zend_uchar type; unsigned flags; zval defval; php_http_option_set_callback_t setter; unsigned persistent:1; }; PHP_HTTP_API php_http_options_t *php_http_options_init(php_http_options_t *registry, zend_bool persistent); PHP_HTTP_API ZEND_RESULT_CODE php_http_options_apply(php_http_options_t *registry, HashTable *options, void *userdata); PHP_HTTP_API void php_http_options_dtor(php_http_options_t *registry); PHP_HTTP_API void php_http_options_free(php_http_options_t **registry); PHP_HTTP_API php_http_option_t *php_http_option_register(php_http_options_t *registry, const char *name_str, size_t name_len, unsigned long option, zend_uchar type); PHP_HTTP_API zval *php_http_option_get(php_http_option_t *opt, HashTable *options, void *userdata); #endif /* PHP_HTTP_OPTIONS_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 */ pecl_http-4.2.1/src/php_http_params.c0000644000076500000240000011243614117626035016410 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #include "php_http_api.h" static php_http_params_token_t def_param_sep = {",", 1}, *def_param_sep_ptr[] = {&def_param_sep, NULL}; static php_http_params_token_t def_arg_sep = {";", 1}, *def_arg_sep_ptr[] = {&def_arg_sep, NULL}; static php_http_params_token_t def_val_sep = {"=", 1}, *def_val_sep_ptr[] = {&def_val_sep, NULL}; static php_http_params_opts_t def_opts = { {NULL, 0}, def_param_sep_ptr, def_arg_sep_ptr, def_val_sep_ptr, {{0}, {0}, {0}}, PHP_HTTP_PARAMS_DEFAULT }; php_http_params_opts_t *php_http_params_opts_default_get(php_http_params_opts_t *opts) { if (!opts) { opts = emalloc(sizeof(*opts)); } memcpy(opts, &def_opts, sizeof(def_opts)); return opts; } typedef struct php_http_params_state { php_http_params_token_t input; php_http_params_token_t param; php_http_params_token_t arg; php_http_params_token_t val; struct { zval *param; zval *args; zval *val; } current; unsigned quotes:1; unsigned escape:1; unsigned rfc5987:1; } php_http_params_state_t; static inline void sanitize_escaped(zval *zv) { if (Z_STRVAL_P(zv)[0] == '"' && Z_STRVAL_P(zv)[Z_STRLEN_P(zv) - 1] == '"') { size_t deq_len = Z_STRLEN_P(zv) - 2; char *deq = estrndup(Z_STRVAL_P(zv) + 1, deq_len); zval_dtor(zv); ZVAL_STR(zv, php_http_cs2zs(deq, deq_len)); } php_stripcslashes(Z_STR_P(zv)); } static inline zend_string *quote_string(zend_string *zs, zend_bool force) { size_t len = (zs)->len; #if PHP_VERSION_ID < 70300 zs = php_addcslashes(zs, 0, ZEND_STRL("\0..\37\173\\\"")); #else zs = php_addcslashes(zs, ZEND_STRL("\0..\37\173\\\"")); #endif if (force || len != (zs)->len || strpbrk((zs)->val, "()<>@,;:\"[]?={} ")) { int len = (zs)->len + 2; zs = zend_string_extend(zs, len, 0); memmove(&(zs)->val[1], (zs)->val, (zs)->len); (zs)->val[0] = '"'; (zs)->val[len-1] = '"'; (zs)->val[len] = '\0'; zend_string_forget_hash_val(zs); } return zs; } /* if (Z_TYPE_P(zv) == IS_STRING) { size_t len = Z_STRLEN_P(zv); zend_string *stripped = php_addcslashes(Z_STR_P(zv), 0, ZEND_STRL("\0..\37\173\\\"")); if (len != stripped->len || strpbrk(stripped->val, "()<>@,;:\"[]?={} ")) { size_t len = stripped->len + 2; char *str = emalloc(len + 1); str[0] = '"'; memcpy(&str[1], stripped->val, stripped->len); str[len-1] = '"'; str[len] = '\0'; zval_dtor(zv); zend_string_release(stripped); ZVAL_STR(zv, php_http_cs2zs(str, len)); } else { zval_dtor(zv); ZVAL_STR(zv, stripped); } */ static inline void prepare_escaped(zval *zv) { if (Z_TYPE_P(zv) == IS_STRING) { zend_string *str = quote_string(Z_STR_P(zv), 0); zval_dtor(zv); ZVAL_STR(zv, str); } else { zval_dtor(zv); ZVAL_EMPTY_STRING(zv); } } static inline void sanitize_urlencoded(zval *zv) { Z_STRLEN_P(zv) = php_url_decode(Z_STRVAL_P(zv), Z_STRLEN_P(zv)); } static inline void prepare_urlencoded(zval *zv) { zend_string *str = php_raw_url_encode(Z_STRVAL_P(zv), Z_STRLEN_P(zv)); zval_dtor(zv); ZVAL_STR(zv, str); } static void sanitize_dimension(zval *zv) { zval arr, tmp, *cur = &arr; char *var = NULL, *ptr = Z_STRVAL_P(zv), *end = Z_STRVAL_P(zv) + Z_STRLEN_P(zv); long level = 0; array_init(&arr); while (ptr < end) { if (!var) { var = ptr; } switch (*ptr) { case '[': if (++level > PG(max_input_nesting_level)) { zval_ptr_dtor(&arr); php_error_docref(NULL, E_WARNING, "Max input nesting level of %ld exceeded", (long) PG(max_input_nesting_level)); return; } if (ptr - var == 0) { ++var; break; } /* no break */ case ']': ZVAL_NULL(&tmp); convert_to_array(cur); if (ptr - var) { char chr = *ptr; *ptr = '\0'; cur = zend_symtable_str_update(Z_ARRVAL_P(cur), var, ptr - var, &tmp); *ptr = chr; } else { cur = zend_hash_next_index_insert(Z_ARRVAL_P(cur), &tmp); } var = NULL; break; } ++ptr; } if (zend_hash_num_elements(Z_ARRVAL(arr))) { zval_dtor(zv); ZVAL_COPY_VALUE(zv, &arr); } else { zval_ptr_dtor(&arr); } } static inline void shift_key(php_http_buffer_t *buf, char *key_str, size_t key_len, const char *ass, size_t asl, unsigned flags); static inline void shift_val(php_http_buffer_t *buf, zval *zvalue, const char *vss, size_t vsl, unsigned flags); static void prepare_dimension(php_http_buffer_t *buf, php_http_buffer_t *keybuf, zval *zvalue, const char *pss, size_t psl, const char *vss, size_t vsl, unsigned flags) { HashTable *ht = HASH_OF(zvalue); php_http_arrkey_t key; zval *val; php_http_buffer_t prefix; if (!HT_IS_RECURSIVE(ht)) { HT_PROTECT_RECURSION(ht); php_http_buffer_init(&prefix); php_http_buffer_append(&prefix, keybuf->data, keybuf->used); ZEND_HASH_FOREACH_KEY_VAL_IND(ht, key.h, key.key, val) { if (key.key && !*key.key->val) { /* only public properties */ continue; } php_http_buffer_appends(&prefix, "["); if (key.key) { php_http_buffer_append(&prefix, key.key->val, key.key->len); } else { php_http_buffer_appendf(&prefix, "%lu", key.h); } php_http_buffer_appends(&prefix, "]"); if (Z_TYPE_P(val) == IS_ARRAY || Z_TYPE_P(val) == IS_OBJECT) { prepare_dimension(buf, &prefix, val, pss, psl, vss, vsl, flags); } else { zend_string *cpy = zval_get_string(val); zval tmp; ZVAL_STR(&tmp, cpy); shift_key(buf, prefix.data, prefix.used, pss, psl, flags); shift_val(buf, &tmp, vss, vsl, flags); zend_string_release(cpy); } php_http_buffer_cut(&prefix, keybuf->used, prefix.used - keybuf->used); } ZEND_HASH_FOREACH_END(); HT_UNPROTECT_RECURSION(ht); php_http_buffer_dtor(&prefix); } } static inline void sanitize_key(unsigned flags, const char *str, size_t len, zval *zv, zend_bool *rfc5987) { char *eos; zend_string *zs = zend_string_init(str, len, 0); zval_dtor(zv); ZVAL_STR(zv, php_trim(zs, NULL, 0, 3)); zend_string_release(zs); if (flags & PHP_HTTP_PARAMS_ESCAPED) { sanitize_escaped(zv); } if (!Z_STRLEN_P(zv)) { return; } if (flags & PHP_HTTP_PARAMS_RFC5987) { eos = &Z_STRVAL_P(zv)[Z_STRLEN_P(zv)-1]; if (*eos == '*') { *eos = '\0'; *rfc5987 = 1; Z_STRLEN_P(zv) -= 1; } } if (flags & PHP_HTTP_PARAMS_URLENCODED) { sanitize_urlencoded(zv); } if (flags & PHP_HTTP_PARAMS_DIMENSION) { sanitize_dimension(zv); } } static inline void sanitize_rfc5987(zval *zv, char **language, zend_bool *latin1) { char *ptr; /* examples: * iso-8850-1'de'bl%f6der%20schei%df%21 * utf-8'de-DE'bl%c3%b6der%20schei%c3%9f%21 */ switch (Z_STRVAL_P(zv)[0]) { case 'I': case 'i': if (!strncasecmp(Z_STRVAL_P(zv), "iso-8859-1", lenof("iso-8859-1"))) { *latin1 = 1; ptr = Z_STRVAL_P(zv) + lenof("iso-8859-1"); break; } /* no break */ case 'U': case 'u': if (!strncasecmp(Z_STRVAL_P(zv), "utf-8", lenof("utf-8"))) { *latin1 = 0; ptr = Z_STRVAL_P(zv) + lenof("utf-8"); break; } /* no break */ default: return; } /* extract language */ if (*ptr == '\'') { for (*language = ++ptr; *ptr && *ptr != '\''; ++ptr); if (!*ptr) { *language = NULL; return; } *language = estrndup(*language, ptr - *language); /* remainder */ ptr = estrdup(++ptr); zval_dtor(zv); ZVAL_STR(zv, php_http_cs2zs(ptr, strlen(ptr))); } } static inline void sanitize_rfc5988(char *str, size_t len, zval *zv) { zend_string *zs = zend_string_init(str, len, 0); zval_dtor(zv); ZVAL_STR(zv, php_trim(zs, " ><", 3, 3)); zend_string_release(zs); } static inline void prepare_rfc5988(zval *zv) { if (Z_TYPE_P(zv) != IS_STRING) { zval_dtor(zv); ZVAL_EMPTY_STRING(zv); } } static void utf8encode(zval *zv) { size_t pos, len = 0; unsigned char *ptr = (unsigned char *) Z_STRVAL_P(zv); while (*ptr) { if (*ptr++ >= 0x80) { ++len; } ++len; } ptr = safe_emalloc(1, len, 1); for (len = 0, pos = 0; len <= Z_STRLEN_P(zv); ++len, ++pos) { ptr[pos] = Z_STRVAL_P(zv)[len]; if ((ptr[pos]) >= 0x80) { ptr[pos + 1] = 0x80 | (ptr[pos] & 0x3f); ptr[pos] = 0xc0 | ((ptr[pos] >> 6) & 0x1f); ++pos; } } zval_dtor(zv); ZVAL_STR(zv, php_http_cs2zs((char *) ptr, pos-1)); } static inline void sanitize_value(unsigned flags, const char *str, size_t len, zval *zv, zend_bool rfc5987) { char *language = NULL; zend_bool latin1 = 0; zend_string *zs = zend_string_init(str, len, 0); zval_dtor(zv); ZVAL_STR(zv, php_trim(zs, NULL, 0, 3)); zend_string_release(zs); if (rfc5987) { sanitize_rfc5987(zv, &language, &latin1); } if (flags & PHP_HTTP_PARAMS_ESCAPED) { sanitize_escaped(zv); } if ((flags & PHP_HTTP_PARAMS_URLENCODED) || (rfc5987 && language)) { sanitize_urlencoded(zv); } if (rfc5987 && language) { zval tmp; if (latin1) { utf8encode(zv); } ZVAL_COPY_VALUE(&tmp, zv); array_init(zv); add_assoc_zval(zv, language, &tmp); efree(language); } } static inline void prepare_key(unsigned flags, char *old_key, size_t old_len, char **new_key, size_t *new_len) { zval zv; ZVAL_STRINGL(&zv, old_key, old_len); if (flags & PHP_HTTP_PARAMS_URLENCODED) { prepare_urlencoded(&zv); } if (flags & PHP_HTTP_PARAMS_ESCAPED) { if (flags & PHP_HTTP_PARAMS_RFC5988) { prepare_rfc5988(&zv); } else { prepare_escaped(&zv); } } *new_key = estrndup(Z_STRVAL(zv), Z_STRLEN(zv)); *new_len = Z_STRLEN(zv); zval_ptr_dtor(&zv); } static inline void prepare_value(unsigned flags, zval *zv) { if (flags & PHP_HTTP_PARAMS_URLENCODED) { prepare_urlencoded(zv); } if (flags & PHP_HTTP_PARAMS_ESCAPED) { prepare_escaped(zv); } } static void merge_param(HashTable *params, zval *zdata, zval **current_param, zval **current_args) { zval *ptr, *zdata_ptr; php_http_arrkey_t hkey = {0}; #if 0 { zval tmp; INIT_PZVAL_ARRAY(&tmp, params); fprintf(stderr, "params = "); zend_print_zval_r(&tmp, 1); fprintf(stderr, "\n"); } #endif zend_hash_get_current_key(Z_ARRVAL_P(zdata), &hkey.key, &hkey.h); if ((hkey.key && !zend_hash_exists(params, hkey.key)) || (!hkey.key && !zend_hash_index_exists(params, hkey.h)) ) { zval tmp, arg, *args; /* create the entry if it doesn't exist */ ptr = zend_hash_get_current_data(Z_ARRVAL_P(zdata)); Z_TRY_ADDREF_P(ptr); array_init(&tmp); add_assoc_zval_ex(&tmp, ZEND_STRL("value"), ptr); array_init(&arg); args = zend_hash_str_update(Z_ARRVAL(tmp), "arguments", lenof("arguments"), &arg); *current_args = args; if (hkey.key) { ptr = zend_hash_update(params, hkey.key, &tmp); } else { ptr = zend_hash_index_update(params, hkey.h, &tmp); } } else { /* merge */ if (hkey.key) { ptr = zend_hash_find(params, hkey.key); } else { ptr = zend_hash_index_find(params, hkey.h); } zdata_ptr = zdata; if (Z_TYPE_P(ptr) == IS_ARRAY && (ptr = zend_hash_str_find(Z_ARRVAL_P(ptr), "value", lenof("value"))) && (zdata_ptr = zend_hash_get_current_data(Z_ARRVAL_P(zdata_ptr))) ) { /* * params = [arr => [value => [0 => 1]]] * ^- ptr * zdata = [arr => [0 => NULL]] * ^- zdata_ptr */ zval *test_ptr; while (Z_TYPE_P(zdata_ptr) == IS_ARRAY && (test_ptr = zend_hash_get_current_data(Z_ARRVAL_P(zdata_ptr)))) { if (Z_TYPE_P(test_ptr) == IS_ARRAY && Z_TYPE_P(ptr) == IS_ARRAY) { zval *tmp_ptr = ptr; /* now find key in ptr */ if (HASH_KEY_IS_STRING == zend_hash_get_current_key(Z_ARRVAL_P(zdata_ptr), &hkey.key, &hkey.h)) { if ((ptr = zend_hash_find(Z_ARRVAL_P(ptr), hkey.key))) { zdata_ptr = test_ptr; } else { ptr = tmp_ptr; Z_TRY_ADDREF_P(test_ptr); ptr = zend_hash_update(Z_ARRVAL_P(ptr), hkey.key, test_ptr); break; } } else { if ((ptr = zend_hash_index_find(Z_ARRVAL_P(ptr), hkey.h))) { zdata_ptr = test_ptr; } else if (hkey.h) { ptr = tmp_ptr; Z_TRY_ADDREF_P(test_ptr); ptr = zend_hash_index_update(Z_ARRVAL_P(ptr), hkey.h, test_ptr); break; } else { ptr = tmp_ptr; Z_TRY_ADDREF_P(test_ptr); ptr = zend_hash_next_index_insert(Z_ARRVAL_P(ptr), test_ptr); break; } } } else { /* this is the leaf */ Z_TRY_ADDREF_P(test_ptr); if (Z_TYPE_P(ptr) != IS_ARRAY) { zval_dtor(ptr); array_init(ptr); } if (HASH_KEY_IS_STRING == zend_hash_get_current_key(Z_ARRVAL_P(zdata_ptr), &hkey.key, &hkey.h)) { ptr = zend_hash_update(Z_ARRVAL_P(ptr), hkey.key, test_ptr); } else if (hkey.h) { ptr = zend_hash_index_update(Z_ARRVAL_P(ptr), hkey.h, test_ptr); } else { ptr = zend_hash_next_index_insert(Z_ARRVAL_P(ptr), test_ptr); } break; } } } } /* bubble up */ while (Z_TYPE_P(ptr) == IS_ARRAY) { zval *tmp = zend_hash_get_current_data(Z_ARRVAL_P(ptr)); if (tmp) { ptr = tmp; } else { break; } } *current_param = ptr; } static void push_param(HashTable *params, php_http_params_state_t *state, const php_http_params_opts_t *opts) { if (state->val.str) { if (!state->current.val) { return; } else if (0 < (state->val.len = state->input.str - state->val.str)) { sanitize_value(opts->flags, state->val.str, state->val.len, state->current.val, state->rfc5987); } else { ZVAL_EMPTY_STRING(state->current.val); } state->rfc5987 = 0; } else if (state->arg.str) { if (0 < (state->arg.len = state->input.str - state->arg.str)) { zval val, key; zend_bool rfc5987 = 0; ZVAL_NULL(&key); sanitize_key(opts->flags, state->arg.str, state->arg.len, &key, &rfc5987); state->rfc5987 = rfc5987; if (Z_TYPE(key) == IS_STRING && Z_STRLEN(key)) { ZVAL_TRUE(&val); if (rfc5987) { zval *rfc; if ((rfc = zend_hash_str_find(Z_ARRVAL_P(state->current.args), ZEND_STRL("*rfc5987*")))) { state->current.val = zend_symtable_str_update(Z_ARRVAL_P(rfc), Z_STRVAL(key), Z_STRLEN(key), &val); } else { zval tmp; array_init_size(&tmp, 1); state->current.val = zend_symtable_str_update(Z_ARRVAL(tmp), Z_STRVAL(key), Z_STRLEN(key), &val); zend_symtable_str_update(Z_ARRVAL_P(state->current.args), ZEND_STRL("*rfc5987*"), &tmp); } } else { state->current.val = zend_symtable_str_update(Z_ARRVAL_P(state->current.args), Z_STRVAL(key), Z_STRLEN(key), &val); } } zval_dtor(&key); } } else if (state->param.str) { if (0 < (state->param.len = state->input.str - state->param.str)) { zval prm, arg, val, key; zend_bool rfc5987 = 0; ZVAL_NULL(&key); if (opts->flags & PHP_HTTP_PARAMS_RFC5988) { sanitize_rfc5988(state->param.str, state->param.len, &key); } else { sanitize_key(opts->flags, state->param.str, state->param.len, &key, &rfc5987); state->rfc5987 = rfc5987; } if (Z_TYPE(key) == IS_ARRAY) { merge_param(params, &key, &state->current.val, &state->current.args); } else if (Z_TYPE(key) == IS_STRING && Z_STRLEN(key)) { // FIXME: array_init_size(&prm, 2); array_init(&prm); if (!Z_ISUNDEF(opts->defval)) { ZVAL_COPY_VALUE(&val, &opts->defval); zval_copy_ctor(&val); } else { ZVAL_TRUE(&val); } if (rfc5987 && (opts->flags & PHP_HTTP_PARAMS_RFC5987)) { state->current.val = zend_hash_str_update(Z_ARRVAL(prm), "*rfc5987*", lenof("*rfc5987*"), &val); } else { state->current.val = zend_hash_str_update(Z_ARRVAL(prm), "value", lenof("value"), &val); } // FIXME: array_init_size(&arg, 3); array_init(&arg); state->current.args = zend_hash_str_update(Z_ARRVAL(prm), "arguments", lenof("arguments"), &arg); state->current.param = zend_symtable_str_update(params, Z_STRVAL(key), Z_STRLEN(key), &prm); } zval_ptr_dtor(&key); } } } static inline zend_bool check_str(const char *chk_str, size_t chk_len, const char *sep_str, size_t sep_len) { return 0 < sep_len && chk_len >= sep_len && *chk_str == *sep_str && !memcmp(chk_str + 1, sep_str + 1, sep_len - 1); } static size_t check_sep(php_http_params_state_t *state, php_http_params_token_t **separators) { php_http_params_token_t **sep = separators; if (state->quotes || state->escape) { return 0; } if (sep) while (*sep) { if (check_str(state->input.str, state->input.len, (*sep)->str, (*sep)->len)) { return (*sep)->len; } ++sep; } return 0; } static void skip_sep(size_t skip, php_http_params_state_t *state, php_http_params_token_t **param, php_http_params_token_t **arg, php_http_params_token_t **val) { size_t sep_len; state->input.str += skip; state->input.len -= skip; while ( (param && (sep_len = check_sep(state, param))) || (arg && (sep_len = check_sep(state, arg))) || (val && (sep_len = check_sep(state, val))) ) { state->input.str += sep_len; state->input.len -= sep_len; } } HashTable *php_http_params_parse(HashTable *params, const php_http_params_opts_t *opts) { php_http_params_state_t state; memset(&state, 0, sizeof(state)); state.input.str = opts->input.str; state.input.len = opts->input.len; if (!params) { ALLOC_HASHTABLE(params); ZEND_INIT_SYMTABLE(params); } while (state.input.len) { if ((opts->flags & PHP_HTTP_PARAMS_RFC5988) && !state.arg.str) { if (*state.input.str == '<') { state.quotes = 1; } else if (*state.input.str == '>') { state.quotes = 0; } } else if (*state.input.str == '"' && !state.escape) { state.quotes = !state.quotes; } else { state.escape = (*state.input.str == '\\'); } if (!state.param.str) { /* initialize */ skip_sep(0, &state, opts->param, opts->arg, opts->val); state.param.str = state.input.str; } else { size_t sep_len; /* are we at a param separator? */ if (0 < (sep_len = check_sep(&state, opts->param))) { push_param(params, &state, opts); skip_sep(sep_len, &state, opts->param, opts->arg, opts->val); /* start off with a new param */ state.param.str = state.input.str; state.param.len = 0; state.arg.str = NULL; state.arg.len = 0; state.val.str = NULL; state.val.len = 0; continue; } else /* are we at an arg separator? */ if (0 < (sep_len = check_sep(&state, opts->arg))) { push_param(params, &state, opts); skip_sep(sep_len, &state, NULL, opts->arg, opts->val); /* continue with a new arg */ state.arg.str = state.input.str; state.arg.len = 0; state.val.str = NULL; state.val.len = 0; continue; } else /* are we at a val separator? */ if (0 < (sep_len = check_sep(&state, opts->val))) { /* only handle separator if we're not already reading in a val */ if (!state.val.str) { push_param(params, &state, opts); skip_sep(sep_len, &state, NULL, NULL, opts->val); state.val.str = state.input.str; state.val.len = 0; continue; } } } if (state.input.len) { ++state.input.str; --state.input.len; } } /* finalize */ push_param(params, &state, opts); return params; } static inline void shift_key(php_http_buffer_t *buf, char *key_str, size_t key_len, const char *ass, size_t asl, unsigned flags) { char *str; size_t len; if (buf->used) { php_http_buffer_append(buf, ass, asl); } prepare_key(flags, key_str, key_len, &str, &len); php_http_buffer_append(buf, str, len); efree(str); } static inline void shift_rfc5987(php_http_buffer_t *buf, zval *zvalue, const char *vss, size_t vsl, unsigned flags) { HashTable *ht = HASH_OF(zvalue); zval *zdata, tmp; zend_string *zs; php_http_arrkey_t key = {0}; if ((zdata = zend_hash_get_current_data(ht)) && HASH_KEY_NON_EXISTENT != zend_hash_get_current_key(ht, &key.key, &key.h) ) { php_http_arrkey_stringify(&key, NULL); php_http_buffer_appendf(buf, "*%.*sutf-8'%.*s'", (int) (vsl > INT_MAX ? INT_MAX : vsl), vss, (int) (key.key->len > INT_MAX ? INT_MAX : key.key->len), key.key->val); php_http_arrkey_dtor(&key); if (Z_TYPE_P(zdata) == IS_INDIRECT) { zdata = Z_INDIRECT_P(zdata); } zs = zval_get_string(zdata); ZVAL_STR(&tmp, zs); prepare_value(flags | PHP_HTTP_PARAMS_URLENCODED, &tmp); php_http_buffer_append(buf, Z_STRVAL(tmp), Z_STRLEN(tmp)); zval_ptr_dtor(&tmp); } } static inline void shift_rfc5988(php_http_buffer_t *buf, char *key_str, size_t key_len, const char *ass, size_t asl, unsigned flags) { char *str; size_t len; if (buf->used) { php_http_buffer_append(buf, ass, asl); } prepare_key(flags, key_str, key_len, &str, &len); php_http_buffer_appends(buf, "<"); php_http_buffer_append(buf, str, len); php_http_buffer_appends(buf, ">"); efree(str); } static inline void shift_rfc5988_val(php_http_buffer_t *buf, zval *zv, const char *vss, size_t vsl, unsigned flags) { zend_string *str, *zs = zval_get_string(zv); str = quote_string(zs, 1); zend_string_release(zs); php_http_buffer_append(buf, vss, vsl); php_http_buffer_append(buf, str->val, str->len); zend_string_release(str); } static inline void shift_val(php_http_buffer_t *buf, zval *zvalue, const char *vss, size_t vsl, unsigned flags) { zval tmp; zend_string *zs; switch (Z_TYPE_P(zvalue)) { case IS_TRUE: break; case IS_FALSE: php_http_buffer_append(buf, vss, vsl); php_http_buffer_appends(buf, "0"); break; default: zs = zval_get_string(zvalue); ZVAL_STR(&tmp, zs); prepare_value(flags, &tmp); php_http_buffer_append(buf, vss, vsl); php_http_buffer_append(buf, Z_STRVAL(tmp), Z_STRLEN(tmp)); zval_ptr_dtor(&tmp); break; } } static void shift_arg(php_http_buffer_t *buf, char *key_str, size_t key_len, zval *zvalue, const char *ass, size_t asl, const char *vss, size_t vsl, unsigned flags) { if (Z_TYPE_P(zvalue) == IS_ARRAY || Z_TYPE_P(zvalue) == IS_OBJECT) { php_http_arrkey_t key; HashTable *ht = HASH_OF(zvalue); zval *val; zend_bool rfc5987 = !strcmp(key_str, "*rfc5987*"); if (!rfc5987) { shift_key(buf, key_str, key_len, ass, asl, flags); } ZEND_HASH_FOREACH_KEY_VAL_IND(ht, key.h, key.key, val) { /* did you mean recursion? */ php_http_arrkey_stringify(&key, NULL); if (rfc5987 && (Z_TYPE_P(val) == IS_ARRAY || Z_TYPE_P(val) == IS_OBJECT)) { shift_key(buf, key.key->val, key.key->len, ass, asl, flags); shift_rfc5987(buf, val, vss, vsl, flags); } else { shift_arg(buf, key.key->val, key.key->len, val, ass, asl, vss, vsl, flags); } php_http_arrkey_dtor(&key); } ZEND_HASH_FOREACH_END(); } else { shift_key(buf, key_str, key_len, ass, asl, flags); if (flags & PHP_HTTP_PARAMS_RFC5988) { switch (key_len) { case lenof("rel"): case lenof("title"): case lenof("anchor"): /* some args must be quoted */ if (0 <= php_http_select_str(key_str, 3, "rel", "title", "anchor")) { shift_rfc5988_val(buf, zvalue, vss, vsl, flags); return; } break; } } shift_val(buf, zvalue, vss, vsl, flags); } } static void shift_param(php_http_buffer_t *buf, char *key_str, size_t key_len, zval *zvalue, const char *pss, size_t psl, const char *ass, size_t asl, const char *vss, size_t vsl, unsigned flags, zend_bool rfc5987) { if (Z_TYPE_P(zvalue) == IS_ARRAY || Z_TYPE_P(zvalue) == IS_OBJECT) { /* treat as arguments, unless we care for dimensions or rfc5987 */ if (flags & PHP_HTTP_PARAMS_DIMENSION) { php_http_buffer_t *keybuf = php_http_buffer_from_string(key_str, key_len); prepare_dimension(buf, keybuf, zvalue, pss, psl, vss, vsl, flags); php_http_buffer_free(&keybuf); } else if (rfc5987) { shift_key(buf, key_str, key_len, pss, psl, flags); shift_rfc5987(buf, zvalue, vss, vsl, flags); } else { shift_arg(buf, key_str, key_len, zvalue, ass, asl, vss, vsl, flags); } } else { if (flags & PHP_HTTP_PARAMS_RFC5988) { shift_rfc5988(buf, key_str, key_len, pss, psl, flags); } else { shift_key(buf, key_str, key_len, pss, psl, flags); } shift_val(buf, zvalue, vss, vsl, flags); } } php_http_buffer_t *php_http_params_to_string(php_http_buffer_t *buf, HashTable *params, const char *pss, size_t psl, const char *ass, size_t asl, const char *vss, size_t vsl, unsigned flags) { zval *zparam; php_http_arrkey_t key; zend_bool rfc5987 = 0; if (!buf) { buf = php_http_buffer_init(NULL); } ZEND_HASH_FOREACH_KEY_VAL(params, key.h, key.key, zparam) { zval *zvalue, *zargs; if (Z_TYPE_P(zparam) != IS_ARRAY) { zvalue = zparam; } else { if (!(zvalue = zend_hash_str_find(Z_ARRVAL_P(zparam), ZEND_STRL("value")))) { if (!(zvalue = zend_hash_str_find(Z_ARRVAL_P(zparam), ZEND_STRL("*rfc5987*")))) { zvalue = zparam; } else { rfc5987 = 1; } } } php_http_arrkey_stringify(&key, NULL); shift_param(buf, key.key->val, key.key->len, zvalue, pss, psl, ass, asl, vss, vsl, flags, rfc5987); php_http_arrkey_dtor(&key); if (Z_TYPE_P(zparam) == IS_ARRAY) { zval *tmp = zend_hash_str_find(Z_ARRVAL_P(zparam), ZEND_STRL("arguments")); if (tmp) { zvalue = tmp; } else if (zvalue == zparam) { continue; } else { zvalue = zparam; } } if (Z_TYPE_P(zvalue) == IS_ARRAY) { ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(zvalue), key.h, key.key, zargs) { if (zvalue == zparam && key.key && zend_string_equals_literal(key.key, "value")) { continue; } php_http_arrkey_stringify(&key, NULL); shift_arg(buf, key.key->val, key.key->len, zargs, ass, asl, vss, vsl, flags); php_http_arrkey_dtor(&key); } ZEND_HASH_FOREACH_END(); } } ZEND_HASH_FOREACH_END(); php_http_buffer_shrink(buf); php_http_buffer_fix(buf); return buf; } php_http_params_token_t **php_http_params_separator_init(zval *zv) { zval *sep, ztmp; php_http_params_token_t **ret, **tmp; if (!zv) { return NULL; } ZVAL_DUP(&ztmp, zv); zv = &ztmp; convert_to_array(zv); ret = ecalloc(zend_hash_num_elements(Z_ARRVAL_P(zv)) + 1, sizeof(*ret)); tmp = ret; ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(zv), sep) { zend_string *zs = zval_get_string(sep); if (zs->len) { *tmp = emalloc(sizeof(**tmp)); (*tmp)->str = estrndup(zs->val, (*tmp)->len = zs->len); ++tmp; } zend_string_release(zs); } ZEND_HASH_FOREACH_END(); zval_ptr_dtor(&ztmp); *tmp = NULL; return ret; } void php_http_params_separator_free(php_http_params_token_t **separator) { php_http_params_token_t **sep = separator; if (sep) { while (*sep) { PTR_FREE((*sep)->str); efree(*sep); ++sep; } efree(separator); } } static zend_class_entry *php_http_params_class_entry; zend_class_entry *php_http_params_get_class_entry(void) { return php_http_params_class_entry; } ZEND_BEGIN_ARG_INFO_EX(ai_HttpParams___construct, 0, 0, 0) ZEND_ARG_INFO(0, params) ZEND_ARG_INFO(0, param_sep) ZEND_ARG_INFO(0, arg_sep) ZEND_ARG_INFO(0, val_sep) ZEND_ARG_INFO(0, flags) ZEND_END_ARG_INFO(); PHP_METHOD(HttpParams, __construct) { zval *zparams = NULL, *param_sep = NULL, *arg_sep = NULL, *val_sep = NULL; zend_long flags = PHP_HTTP_PARAMS_DEFAULT; zend_error_handling zeh; zend_string *zs; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|z!/z/z/z/l", &zparams, ¶m_sep, &arg_sep, &val_sep, &flags), invalid_arg, return); zend_replace_error_handling(EH_THROW, php_http_get_exception_runtime_class_entry(), &zeh); { switch (ZEND_NUM_ARGS()) { case 5: zend_update_property_long(php_http_params_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("flags"), flags); /* no break */ case 4: zend_update_property(php_http_params_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("val_sep"), val_sep); /* no break */ case 3: zend_update_property(php_http_params_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("arg_sep"), arg_sep); /* no break */ case 2: zend_update_property(php_http_params_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("param_sep"), param_sep); /* no break */ } if (zparams) { switch (Z_TYPE_P(zparams)) { case IS_OBJECT: case IS_ARRAY: convert_to_array(zparams); zend_update_property(php_http_params_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("params"), zparams); break; default: zs = zval_get_string(zparams); if (zs->len) { zval tmp; php_http_params_opts_t opts = { {zs->val, zs->len}, php_http_params_separator_init(zend_read_property(php_http_params_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("param_sep"), 0, &tmp)), php_http_params_separator_init(zend_read_property(php_http_params_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("arg_sep"), 0, &tmp)), php_http_params_separator_init(zend_read_property(php_http_params_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("val_sep"), 0, &tmp)), {{0}, {0}, {0}}, flags }; array_init(&tmp); php_http_params_parse(Z_ARRVAL(tmp), &opts); zend_update_property(php_http_params_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("params"), &tmp); zval_ptr_dtor(&tmp); php_http_params_separator_free(opts.param); php_http_params_separator_free(opts.arg); php_http_params_separator_free(opts.val); } zend_string_release(zs); break; } } else { zval tmp; array_init(&tmp); zend_update_property(php_http_params_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("params"), &tmp); zval_ptr_dtor(&tmp); } } zend_restore_error_handling(&zeh); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpParams_toArray, 0, 0, 0) ZEND_END_ARG_INFO(); PHP_METHOD(HttpParams, toArray) { zval zparams_tmp, *zparams; if (SUCCESS != zend_parse_parameters_none()) { return; } zparams = zend_read_property(php_http_params_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("params"), 0, &zparams_tmp); RETURN_ZVAL(zparams, 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpParams_toString, 0, 0, 0) ZEND_END_ARG_INFO(); PHP_METHOD(HttpParams, toString) { zval *tmp, *zparams, *zpsep, *zasep, *zvsep; zval zparams_tmp, flags_tmp, psep_tmp, asep_tmp, vsep_tmp; zend_string *psep, *asep, *vsep; long flags; php_http_buffer_t buf; zparams = zend_read_property(php_http_params_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("params"), 0, &zparams_tmp); convert_to_array_ex(zparams); flags = zval_get_long(zend_read_property(php_http_params_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("flags"), 0, &flags_tmp)); zpsep = zend_read_property(php_http_params_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("param_sep"), 0, &psep_tmp); if (Z_TYPE_P(zpsep) == IS_ARRAY && (tmp = zend_hash_get_current_data(Z_ARRVAL_P(zpsep)))) { psep = zval_get_string(tmp); } else { psep = zval_get_string(zpsep); } zasep = zend_read_property(php_http_params_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("arg_sep"), 0, &asep_tmp); if (Z_TYPE_P(zasep) == IS_ARRAY && (tmp = zend_hash_get_current_data(Z_ARRVAL_P(zasep)))) { asep = zval_get_string(tmp); } else { asep = zval_get_string(zasep); } zvsep = zend_read_property(php_http_params_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("val_sep"), 0, &vsep_tmp); if (Z_TYPE_P(zvsep) == IS_ARRAY && (tmp = zend_hash_get_current_data(Z_ARRVAL_P(zvsep)))) { vsep = zval_get_string(tmp); } else { vsep = zval_get_string(zvsep); } php_http_buffer_init(&buf); php_http_params_to_string(&buf, Z_ARRVAL_P(zparams), psep->val, psep->len, asep->val, asep->len, vsep->val, vsep->len, flags); zend_string_release(psep); zend_string_release(asep); zend_string_release(vsep); RETVAL_STR(php_http_cs2zs(buf.data, buf.used)); } ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(ai_HttpParams_offsetExists, 0, 1, _IS_BOOL, 0) ZEND_ARG_INFO(0, name) ZEND_END_ARG_INFO(); PHP_METHOD(HttpParams, offsetExists) { zend_string *name; zval zparams_tmp, *zparam, *zparams; if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name)) { return; } zparams = zend_read_property(php_http_params_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("params"), 0, &zparams_tmp); if (Z_TYPE_P(zparams) == IS_ARRAY && (zparam = zend_symtable_find(Z_ARRVAL_P(zparams), name))) { RETVAL_BOOL(Z_TYPE_P(zparam) != IS_NULL); } else { RETVAL_FALSE; } } ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(ai_HttpParams_offsetGet, 0, 1, IS_MIXED, 1) ZEND_ARG_INFO(0, name) ZEND_END_ARG_INFO(); PHP_METHOD(HttpParams, offsetGet) { zend_string *name; zval zparams_tmp, *zparam, *zparams; if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name)) { return; } zparams = zend_read_property(php_http_params_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("params"), 0, &zparams_tmp); if (Z_TYPE_P(zparams) == IS_ARRAY && (zparam = zend_symtable_find(Z_ARRVAL_P(zparams), name))) { RETVAL_ZVAL(zparam, 1, 0); } } ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(ai_HttpParams_offsetUnset, 0, 1, IS_VOID, 0) ZEND_ARG_INFO(0, name) ZEND_END_ARG_INFO(); PHP_METHOD(HttpParams, offsetUnset) { zend_string *name; zval zparams_tmp, *zparams; if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name)) { return; } zparams = zend_read_property(php_http_params_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("params"), 0, &zparams_tmp); if (Z_TYPE_P(zparams) == IS_ARRAY) { zend_symtable_del(Z_ARRVAL_P(zparams), name); } } ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(ai_HttpParams_offsetSet, 0, 2, IS_VOID, 0) ZEND_ARG_INFO(0, name) ZEND_ARG_INFO(0, value) ZEND_END_ARG_INFO(); PHP_METHOD(HttpParams, offsetSet) { zend_string *name; zval zparams_tmp, *zparam, *zparams, *nvalue; if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "S!z", &name, &nvalue)) { return; } zparams = zend_read_property(php_http_params_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("params"), 0, &zparams_tmp); convert_to_array(zparams); if (name && name->len) { if (Z_TYPE_P(nvalue) == IS_ARRAY) { if ((zparam = zend_symtable_find(Z_ARRVAL_P(zparams), name))) { convert_to_array(zparam); array_join(Z_ARRVAL_P(nvalue), Z_ARRVAL_P(zparam), 0, 0); } else { Z_TRY_ADDREF_P(nvalue); add_assoc_zval_ex(zparams, name->val, name->len, nvalue); } } else { zval tmp; if ((zparam = zend_symtable_find(Z_ARRVAL_P(zparams), name))) { ZVAL_DUP(&tmp, zparam); convert_to_array(&tmp); } else { array_init(&tmp); } Z_TRY_ADDREF_P(nvalue); add_assoc_zval_ex(&tmp, ZEND_STRL("value"), nvalue); add_assoc_zval_ex(zparams, name->val, name->len, &tmp); } } else { zval arr; zend_string *zs = zval_get_string(nvalue); array_init(&arr); add_assoc_bool_ex(&arr, ZEND_STRL("value"), 1); add_assoc_zval_ex(zparams, zs->val, zs->len, &arr); zend_string_release(zs); } } static zend_function_entry php_http_params_methods[] = { PHP_ME(HttpParams, __construct, ai_HttpParams___construct, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) PHP_ME(HttpParams, toArray, ai_HttpParams_toArray, ZEND_ACC_PUBLIC) PHP_ME(HttpParams, toString, ai_HttpParams_toString, ZEND_ACC_PUBLIC) ZEND_MALIAS(HttpParams, __toString, toString, ai_HttpParams_toString, ZEND_ACC_PUBLIC) PHP_ME(HttpParams, offsetExists, ai_HttpParams_offsetExists, ZEND_ACC_PUBLIC) PHP_ME(HttpParams, offsetUnset, ai_HttpParams_offsetUnset, ZEND_ACC_PUBLIC) PHP_ME(HttpParams, offsetSet, ai_HttpParams_offsetSet, ZEND_ACC_PUBLIC) PHP_ME(HttpParams, offsetGet, ai_HttpParams_offsetGet, ZEND_ACC_PUBLIC) EMPTY_FUNCTION_ENTRY }; PHP_MINIT_FUNCTION(http_params) { zend_class_entry ce = {0}; INIT_NS_CLASS_ENTRY(ce, "http", "Params", php_http_params_methods); php_http_params_class_entry = zend_register_internal_class(&ce); php_http_params_class_entry->create_object = php_http_params_object_new; zend_class_implements(php_http_params_class_entry, 1, zend_ce_arrayaccess); zend_declare_class_constant_stringl(php_http_params_class_entry, ZEND_STRL("DEF_PARAM_SEP"), ZEND_STRL(",")); zend_declare_class_constant_stringl(php_http_params_class_entry, ZEND_STRL("DEF_ARG_SEP"), ZEND_STRL(";")); zend_declare_class_constant_stringl(php_http_params_class_entry, ZEND_STRL("DEF_VAL_SEP"), ZEND_STRL("=")); zend_declare_class_constant_stringl(php_http_params_class_entry, ZEND_STRL("COOKIE_PARAM_SEP"), ZEND_STRL("")); zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_RAW"), PHP_HTTP_PARAMS_RAW); zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_ESCAPED"), PHP_HTTP_PARAMS_ESCAPED); zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_URLENCODED"), PHP_HTTP_PARAMS_URLENCODED); zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_DIMENSION"), PHP_HTTP_PARAMS_DIMENSION); zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_RFC5987"), PHP_HTTP_PARAMS_RFC5987); zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_RFC5988"), PHP_HTTP_PARAMS_RFC5988); zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_DEFAULT"), PHP_HTTP_PARAMS_DEFAULT); zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_QUERY"), PHP_HTTP_PARAMS_QUERY); zend_declare_property_null(php_http_params_class_entry, ZEND_STRL("params"), ZEND_ACC_PUBLIC); zend_declare_property_stringl(php_http_params_class_entry, ZEND_STRL("param_sep"), ZEND_STRL(","), ZEND_ACC_PUBLIC); zend_declare_property_stringl(php_http_params_class_entry, ZEND_STRL("arg_sep"), ZEND_STRL(";"), ZEND_ACC_PUBLIC); zend_declare_property_stringl(php_http_params_class_entry, ZEND_STRL("val_sep"), ZEND_STRL("="), ZEND_ACC_PUBLIC); zend_declare_property_long(php_http_params_class_entry, ZEND_STRL("flags"), PHP_HTTP_PARAMS_DEFAULT, ZEND_ACC_PUBLIC); 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 */ pecl_http-4.2.1/src/php_http_params.h0000644000076500000240000000462114117626035016411 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_HTTP_PARAMS_H #define PHP_HTTP_PARAMS_H typedef struct php_http_params_token { char *str; size_t len; } php_http_params_token_t; #define PHP_HTTP_PARAMS_RAW 0x00 #define PHP_HTTP_PARAMS_ESCAPED 0x01 #define PHP_HTTP_PARAMS_URLENCODED 0x04 #define PHP_HTTP_PARAMS_DIMENSION 0x08 #define PHP_HTTP_PARAMS_RFC5987 0x10 #define PHP_HTTP_PARAMS_RFC5988 0x20 #define PHP_HTTP_PARAMS_QUERY (PHP_HTTP_PARAMS_URLENCODED|PHP_HTTP_PARAMS_DIMENSION) #define PHP_HTTP_PARAMS_DEFAULT (PHP_HTTP_PARAMS_ESCAPED|PHP_HTTP_PARAMS_RFC5987) typedef struct php_http_params_opts { php_http_params_token_t input; php_http_params_token_t **param; php_http_params_token_t **arg; php_http_params_token_t **val; zval defval; unsigned flags; } php_http_params_opts_t; PHP_HTTP_API php_http_params_opts_t *php_http_params_opts_default_get(php_http_params_opts_t *opts); PHP_HTTP_API HashTable *php_http_params_parse(HashTable *params, const php_http_params_opts_t *opts); PHP_HTTP_API php_http_buffer_t *php_http_params_to_string(php_http_buffer_t *buf, HashTable *params, const char *pss, size_t psl, const char *ass, size_t asl, const char *vss, size_t vsl, unsigned flags); PHP_HTTP_API php_http_params_token_t **php_http_params_separator_init(zval *zv); PHP_HTTP_API void php_http_params_separator_free(php_http_params_token_t **separator); typedef php_http_object_t php_http_params_object_t; PHP_HTTP_API zend_class_entry *php_http_params_get_class_entry(void); PHP_MINIT_FUNCTION(http_params); #define php_http_params_object_new php_http_object_new #define php_http_params_object_new_ex php_http_object_new_ex #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 */ pecl_http-4.2.1/src/php_http_querystring.c0000644000076500000240000005700314117626035017517 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #include "php_http_api.h" #include "php_variables.h" #include "ext/spl/spl_array.h" #if PHP_HTTP_HAVE_ICONV # ifndef HAVE_ICONV # define HAVE_ICONV 1 # endif # undef PHP_ATOM_INC # include "ext/iconv/php_iconv.h" #endif static zend_class_entry *php_http_querystring_class_entry; zend_class_entry *php_http_querystring_get_class_entry(void) { return php_http_querystring_class_entry; } #define QS_MERGE 1 static inline void php_http_querystring_set(zval *instance, zval *params, int flags) { zval qa; array_init(&qa); if (flags & QS_MERGE) { zval old_tmp, *old = zend_read_property(php_http_querystring_class_entry, Z_OBJ_P(instance), ZEND_STRL("queryArray"), 0, &old_tmp); ZVAL_DEREF(old); if (Z_TYPE_P(old) == IS_ARRAY) { array_copy(Z_ARRVAL_P(old), Z_ARRVAL(qa)); } } php_http_querystring_update(&qa, params, NULL); zend_update_property(php_http_querystring_class_entry, Z_OBJ_P(instance), ZEND_STRL("queryArray"), &qa); zval_ptr_dtor(&qa); } static inline void php_http_querystring_str(zval *instance, zval *return_value) { zval qa_tmp, *qa = zend_read_property(php_http_querystring_class_entry, Z_OBJ_P(instance), ZEND_STRL("queryArray"), 0, &qa_tmp); ZVAL_DEREF(qa); if (Z_TYPE_P(qa) == IS_ARRAY) { php_http_querystring_update(qa, NULL, return_value); } else { RETURN_EMPTY_STRING(); } } static inline void php_http_querystring_get(zval *instance, int type, char *name, uint32_t name_len, zval *defval, zend_bool del, zval *return_value) { zval *arrval, qarray_tmp, *qarray = zend_read_property(php_http_querystring_class_entry, Z_OBJ_P(instance), ZEND_STRL("queryArray"), 0, &qarray_tmp); ZVAL_DEREF(qarray); if ((Z_TYPE_P(qarray) == IS_ARRAY) && (arrval = zend_symtable_str_find(Z_ARRVAL_P(qarray), name, name_len))) { if (type && type != Z_TYPE_P(arrval)) { zval tmp; ZVAL_DUP(&tmp, arrval); convert_to_explicit_type(&tmp, type); RETVAL_ZVAL(&tmp, 0, 0); } else { RETVAL_ZVAL(arrval, 1, 0); } if (del) { zval delarr; array_init(&delarr); add_assoc_null_ex(&delarr, name, name_len); php_http_querystring_set(instance, &delarr, QS_MERGE); zval_ptr_dtor(&delarr); } } else if(defval) { RETURN_ZVAL(defval, 1, 0); } } #if PHP_HTTP_HAVE_ICONV ZEND_RESULT_CODE php_http_querystring_xlate(zval *dst, zval *src, const char *ie, const char *oe) { zval *entry; zend_string *xkey, *xstr; php_http_arrkey_t key; ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(src), key.h, key.key, entry) { if (key.key) { if (PHP_ICONV_ERR_SUCCESS != php_iconv_string(key.key->val, key.key->len, &xkey, oe, ie)) { php_error_docref(NULL, E_WARNING, "Failed to convert '%.*s' from '%s' to '%s'", (int) key.key->len, key.key->val, ie, oe); return FAILURE; } } if (Z_TYPE_P(entry) == IS_STRING) { if (PHP_ICONV_ERR_SUCCESS != php_iconv_string(Z_STRVAL_P(entry), Z_STRLEN_P(entry), &xstr, oe, ie)) { if (key.key) { zend_string_release(xkey); } php_error_docref(NULL, E_WARNING, "Failed to convert '%.*s' from '%s' to '%s'", (int) Z_STRLEN_P(entry), Z_STRVAL_P(entry), ie, oe); return FAILURE; } if (key.key) { add_assoc_str_ex(dst, xkey->val, xkey->len, xstr); } else { add_index_str(dst, key.h, xstr); } } else if (Z_TYPE_P(entry) == IS_ARRAY) { zval subarray; array_init(&subarray); if (key.key) { add_assoc_zval_ex(dst, xkey->val, xkey->len, &subarray); } else { add_index_zval(dst, key.h, &subarray); } if (SUCCESS != php_http_querystring_xlate(&subarray, entry, ie, oe)) { if (key.key) { zend_string_release(xkey); } return FAILURE; } } if (key.key) { zend_string_release(xkey); } } ZEND_HASH_FOREACH_END(); return SUCCESS; } #endif /* HAVE_ICONV */ ZEND_RESULT_CODE php_http_querystring_ctor(zval *instance, zval *params) { php_http_querystring_set(instance, params, 0); return SUCCESS; } static int apply_querystring(zval *val) { if (Z_TYPE_P(val) == IS_ARRAY) { zval *zvalue; if ((zvalue = zend_hash_str_find(Z_ARRVAL_P(val), ZEND_STRL("value")))) { zval tmp = {0}; ZVAL_COPY(&tmp, zvalue); zval_dtor(val); ZVAL_COPY_VALUE(val, &tmp); } } return ZEND_HASH_APPLY_KEEP; } static int apply_querystring_filter(zval *val) { switch (Z_TYPE_P(val)) { case IS_NULL: return ZEND_HASH_APPLY_REMOVE; case IS_ARRAY: case IS_OBJECT: zend_hash_apply(HASH_OF(val), apply_querystring_filter); if (!zend_hash_num_elements(HASH_OF(val))) { return ZEND_HASH_APPLY_REMOVE; } break; default: break; } return ZEND_HASH_APPLY_KEEP; } ZEND_RESULT_CODE php_http_querystring_parse(HashTable *ht, const char *str, size_t len) { ZEND_RESULT_CODE rv = FAILURE; php_http_params_opts_t opts; php_http_params_token_t psep = { ZEND_STRL("&") }, *psepp[] = { &psep, NULL }; php_http_params_token_t vsep = { ZEND_STRL("=") }, *vsepp[] = { &vsep, NULL }; const char *asi_str = NULL; size_t asi_len = 0; opts.input.str = estrndup(str, len); opts.input.len = len; opts.param = psepp; opts.arg = NULL; opts.val = vsepp; opts.flags = PHP_HTTP_PARAMS_QUERY; if (SUCCESS == php_http_ini_entry(ZEND_STRL("arg_separator.input"), &asi_str, &asi_len, 0) && asi_len) { zval arr; array_init_size(&arr, asi_len); do { add_next_index_stringl(&arr, asi_str++, 1); } while (*asi_str); opts.param = php_http_params_separator_init(&arr); zval_ptr_dtor(&arr); } ZVAL_TRUE(&opts.defval); if (php_http_params_parse(ht, &opts)) { zend_hash_apply(ht, apply_querystring); rv = SUCCESS; } if (asi_len) { php_http_params_separator_free(opts.param); } zval_ptr_dtor(&opts.defval); efree(opts.input.str); return rv; } ZEND_RESULT_CODE php_http_querystring_update(zval *qarray, zval *params, zval *outstring) { /* enforce proper type */ if (Z_TYPE_P(qarray) != IS_ARRAY) { convert_to_array(qarray); } /* modify qarray */ if (!params) { zend_hash_apply(Z_ARRVAL_P(qarray), apply_querystring_filter); } else { HashTable *ht; php_http_arrkey_t key; zval zv, *params_entry, *qarray_entry; ZVAL_NULL(&zv); /* squeeze the hash out of the zval */ if (Z_TYPE_P(params) == IS_OBJECT && instanceof_function(Z_OBJCE_P(params), php_http_querystring_class_entry)) { zval qa_tmp, *qa = zend_read_property(php_http_querystring_class_entry, Z_OBJ_P(params), ZEND_STRL("queryArray"), 0, &qa_tmp); ZVAL_DEREF(qa); convert_to_array(qa); ht = Z_ARRVAL_P(qa); } else if (Z_TYPE_P(params) == IS_OBJECT || Z_TYPE_P(params) == IS_ARRAY) { ht = HASH_OF(params); } else { zend_string *zs = zval_get_string(params); array_init(&zv); php_http_querystring_parse(Z_ARRVAL(zv), zs->val, zs->len); zend_string_release(zs); ht = Z_ARRVAL(zv); } ZEND_HASH_FOREACH_KEY_VAL_IND(ht, key.h, key.key, params_entry) { /* only public properties */ if (!key.key || *key.key->val) { if (Z_TYPE_P(params_entry) == IS_NULL) { /* * delete */ if (key.key) { zend_hash_del(Z_ARRVAL_P(qarray), key.key); } else { zend_hash_index_del(Z_ARRVAL_P(qarray), key.h); } } else if ( ((key.key) && (qarray_entry = zend_hash_find(Z_ARRVAL_P(qarray), key.key))) || ((!key.key) && (qarray_entry = zend_hash_index_find(Z_ARRVAL_P(qarray), key.h)))) { /* * update */ zval equal, tmp, *entry = NULL; ZVAL_UNDEF(&tmp); /* recursive */ if (Z_TYPE_P(params_entry) == IS_ARRAY || Z_TYPE_P(params_entry) == IS_OBJECT) { ZVAL_DUP(&tmp, qarray_entry); convert_to_array(&tmp); php_http_querystring_update(&tmp, params_entry, NULL); entry = &tmp; } else if ((FAILURE == is_identical_function(&equal, qarray_entry, params_entry)) || Z_TYPE(equal) != IS_TRUE) { Z_TRY_ADDREF_P(params_entry); entry = params_entry; } if (key.key) { zend_hash_update(Z_ARRVAL_P(qarray), key.key, entry ? entry : &tmp); } else { zend_hash_index_update(Z_ARRVAL_P(qarray), key.h, entry ? entry : &tmp); } } else { zval entry, *entry_ptr = &entry; /* * add */ if (Z_TYPE_P(params_entry) == IS_OBJECT) { array_init(&entry); php_http_querystring_update(&entry, params_entry, NULL); } else { Z_TRY_ADDREF_P(params_entry); entry_ptr = params_entry; } if (key.key) { add_assoc_zval_ex(qarray, key.key->val, key.key->len, entry_ptr); } else { add_index_zval(qarray, key.h, entry_ptr); } } } } ZEND_HASH_FOREACH_END(); zval_dtor(&zv); } /* serialize to string */ if (outstring) { char *s; size_t l; if (SUCCESS == php_http_url_encode_hash(Z_ARRVAL_P(qarray), NULL, 0, &s, &l)) { zval_dtor(outstring); ZVAL_STR(outstring, php_http_cs2zs(s, l)); } else { php_error_docref(NULL, E_WARNING, "Failed to encode query string"); return FAILURE; } } return SUCCESS; } ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString___construct, 0, 0, 0) ZEND_ARG_INFO(0, params) ZEND_END_ARG_INFO(); PHP_METHOD(HttpQueryString, __construct) { zval *params = NULL; zend_error_handling zeh; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|z", ¶ms), invalid_arg, return); zend_replace_error_handling(EH_THROW, php_http_get_exception_bad_querystring_class_entry(), &zeh); php_http_querystring_set(getThis(), params, 0); zend_restore_error_handling(&zeh); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString_getGlobalInstance, 0, 0, 0) ZEND_END_ARG_INFO(); PHP_METHOD(HttpQueryString, getGlobalInstance) { zval *instance, *_GET; php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return); instance = zend_read_static_property(php_http_querystring_class_entry, ZEND_STRL("instance"), 0); if (Z_TYPE_P(instance) == IS_OBJECT) { RETVAL_ZVAL(instance, 1, 0); } else if ((_GET = php_http_env_get_superglobal(ZEND_STRL("_GET")))) { zval *qa; zend_string *qa_str = zend_string_init(ZEND_STRL("queryArray"), 0); ZVAL_OBJ(return_value, php_http_querystring_object_new(php_http_querystring_class_entry)); qa = Z_OBJ_HT_P(return_value)->get_property_ptr_ptr(Z_OBJ_P(return_value), qa_str, BP_VAR_RW, NULL); zend_string_release(qa_str); ZVAL_NEW_REF(_GET, _GET); ZVAL_COPY(qa, _GET); zend_update_static_property(php_http_querystring_class_entry, ZEND_STRL("instance"), return_value); } else { php_http_throw(unexpected_val, "Could not acquire reference to superglobal GET array"); } } ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(ai_HttpQueryString_getIterator, 0, 0, Traversable, 0) ZEND_END_ARG_INFO(); PHP_METHOD(HttpQueryString, getIterator) { zval qa_tmp, *qa; php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return); qa = zend_read_property(php_http_querystring_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("queryArray"), 0, &qa_tmp); object_init_ex(return_value, spl_ce_RecursiveArrayIterator); zend_call_method_with_1_params(Z_OBJ_P(return_value), spl_ce_RecursiveArrayIterator, NULL, "__construct", NULL, qa); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString_toString, 0, 0, 0) ZEND_END_ARG_INFO(); PHP_METHOD(HttpQueryString, toString) { if (SUCCESS != zend_parse_parameters_none()) { return; } php_http_querystring_str(getThis(), return_value); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString_toArray, 0, 0, 0) ZEND_END_ARG_INFO(); PHP_METHOD(HttpQueryString, toArray) { zval zqa_tmp, *zqa; if (SUCCESS != zend_parse_parameters_none()) { return; } zqa = zend_read_property(php_http_querystring_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("queryArray"), 0, &zqa_tmp); RETURN_ZVAL(zqa, 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString_get, 0, 0, 0) ZEND_ARG_INFO(0, name) ZEND_ARG_INFO(0, type) ZEND_ARG_INFO(0, defval) ZEND_ARG_INFO(0, delete) ZEND_END_ARG_INFO(); PHP_METHOD(HttpQueryString, get) { char *name_str = NULL; size_t name_len = 0; zend_long type = 0; zend_bool del = 0; zval *ztype = NULL, *defval = NULL; if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|szzb", &name_str, &name_len, &ztype, &defval, &del)) { if (name_str && name_len) { if (ztype) { if (Z_TYPE_P(ztype) == IS_LONG) { type = Z_LVAL_P(ztype); } else if(Z_TYPE_P(ztype) == IS_STRING) { switch (Z_STRVAL_P(ztype)[0]) { case 'B': case 'b': type = PHP_HTTP_QUERYSTRING_TYPE_BOOL; break; case 'L': case 'l': case 'I': case 'i': type = PHP_HTTP_QUERYSTRING_TYPE_INT; break; case 'd': case 'D': case 'F': case 'f': type = PHP_HTTP_QUERYSTRING_TYPE_FLOAT; break; case 'S': case 's': type = PHP_HTTP_QUERYSTRING_TYPE_STRING; break; case 'A': case 'a': type = PHP_HTTP_QUERYSTRING_TYPE_ARRAY; break; case 'O': case 'o': type = PHP_HTTP_QUERYSTRING_TYPE_OBJECT; break; } } } php_http_querystring_get(getThis(), type, name_str, name_len, defval, del, return_value); } else { php_http_querystring_str(getThis(), return_value); } } } ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString_set, 0, 0, 1) ZEND_ARG_INFO(0, params) ZEND_END_ARG_INFO(); PHP_METHOD(HttpQueryString, set) { zval *params; if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "z", ¶ms)) { return; } php_http_querystring_set(getThis(), params, QS_MERGE); RETVAL_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString_mod, 0, 0, 0) ZEND_ARG_INFO(0, params) ZEND_END_ARG_INFO(); PHP_METHOD(HttpQueryString, mod) { zval qa_tmp, *params, *instance = getThis(); zend_error_handling zeh; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "z", ¶ms), invalid_arg, return); zend_replace_error_handling(EH_THROW, php_http_get_exception_bad_querystring_class_entry(), &zeh); ZVAL_OBJ(return_value, Z_OBJ_HT_P(instance)->clone_obj(Z_OBJ_P(instance))); /* make sure we do not inherit the reference to _GET */ SEPARATE_ZVAL(zend_read_property(Z_OBJCE_P(return_value), Z_OBJ_P(return_value), ZEND_STRL("queryArray"), 0, &qa_tmp)); php_http_querystring_set(return_value, params, QS_MERGE); zend_restore_error_handling(&zeh); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString___getter, 0, 0, 1) ZEND_ARG_INFO(0, name) ZEND_ARG_INFO(0, defval) ZEND_ARG_INFO(0, delete) ZEND_END_ARG_INFO(); #define PHP_HTTP_QUERYSTRING_GETTER(method, TYPE) \ PHP_METHOD(HttpQueryString, method) \ { \ char *name; \ size_t name_len; \ zval *defval = NULL; \ zend_bool del = 0; \ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s|zb", &name, &name_len, &defval, &del)) { \ php_http_querystring_get(getThis(), TYPE, name, name_len, defval, del, return_value); \ } \ } PHP_HTTP_QUERYSTRING_GETTER(getBool, _IS_BOOL); PHP_HTTP_QUERYSTRING_GETTER(getInt, IS_LONG); PHP_HTTP_QUERYSTRING_GETTER(getFloat, IS_DOUBLE); PHP_HTTP_QUERYSTRING_GETTER(getString, IS_STRING); PHP_HTTP_QUERYSTRING_GETTER(getArray, IS_ARRAY); PHP_HTTP_QUERYSTRING_GETTER(getObject, IS_OBJECT); #if PHP_HTTP_HAVE_ICONV ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString_xlate, 0, 0, 2) ZEND_ARG_INFO(0, from_encoding) ZEND_ARG_INFO(0, to_encoding) ZEND_END_ARG_INFO(); PHP_METHOD(HttpQueryString, xlate) { char *ie, *oe; size_t ie_len, oe_len; zval na, qa_tmp, *qa; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "ss", &ie, &ie_len, &oe, &oe_len), invalid_arg, return); array_init(&na); qa = zend_read_property(php_http_querystring_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("queryArray"), 0, &qa_tmp); ZVAL_DEREF(qa); convert_to_array(qa); php_http_expect(SUCCESS == php_http_querystring_xlate(&na, qa, ie, oe), bad_conversion, zval_ptr_dtor(&na); return; ); php_http_querystring_set(getThis(), &na, 0); RETVAL_ZVAL(getThis(), 1, 0); zval_ptr_dtor(&na); } #endif /* HAVE_ICONV */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(ai_HttpQueryString___serialize, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO(); PHP_METHOD(HttpQueryString, __serialize) { zval *zqa, zqa_tmp; zend_parse_parameters_none(); zqa = zend_read_property(php_http_querystring_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("queryArray"), 0, &zqa_tmp); RETURN_ZVAL(zqa, 1, 0); } ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(ai_HttpQueryString___unserialize, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, data, IS_ARRAY, 0) ZEND_END_ARG_INFO(); PHP_METHOD(HttpQueryString, __unserialize) { zval *qa; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "a", &qa), invalid_arg, return); php_http_querystring_set(getThis(), qa, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString_serialize, 0, 0, 0) ZEND_END_ARG_INFO(); PHP_METHOD(HttpQueryString, serialize) { if (SUCCESS != zend_parse_parameters_none()) { return; } php_http_querystring_str(getThis(), return_value); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString_unserialize, 0, 0, 1) ZEND_ARG_INFO(0, serialized) ZEND_END_ARG_INFO(); PHP_METHOD(HttpQueryString, unserialize) { zval *serialized; if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "z", &serialized)) { return; } if (Z_TYPE_P(serialized) == IS_STRING) { php_http_querystring_set(getThis(), serialized, 0); } else { php_error_docref(NULL, E_WARNING, "Expected a string as parameter"); } } ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(ai_HttpQueryString_offsetGet, 0, 1, IS_MIXED, 1) ZEND_ARG_INFO(0, name) ZEND_END_ARG_INFO(); PHP_METHOD(HttpQueryString, offsetGet) { zend_string *offset; zval *value, qa_tmp, *qa; if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "S", &offset)) { return; } qa = zend_read_property(php_http_querystring_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("queryArray"), 0, &qa_tmp); ZVAL_DEREF(qa); if (Z_TYPE_P(qa) == IS_ARRAY) { if ((value = zend_symtable_find(Z_ARRVAL_P(qa), offset))) { RETVAL_ZVAL(value, 1, 0); } } } ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(ai_HttpQueryString_offsetSet, 0, 2, IS_VOID, 0) ZEND_ARG_INFO(0, name) ZEND_ARG_INFO(0, value) ZEND_END_ARG_INFO(); PHP_METHOD(HttpQueryString, offsetSet) { zend_string *offset; zval *value, param, znull; if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "Sz", &offset, &value)) { return; } array_init_size(¶m, 1); /* unset first */ ZVAL_NULL(&znull); zend_symtable_update(Z_ARRVAL(param), offset, &znull); php_http_querystring_set(getThis(), ¶m, QS_MERGE); /* then update, else QS_MERGE would merge sub-arrrays */ Z_TRY_ADDREF_P(value); zend_symtable_update(Z_ARRVAL(param), offset, value); php_http_querystring_set(getThis(), ¶m, QS_MERGE); zval_ptr_dtor(¶m); } ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(ai_HttpQueryString_offsetExists, 0, 1, _IS_BOOL, 0) ZEND_ARG_INFO(0, name) ZEND_END_ARG_INFO(); PHP_METHOD(HttpQueryString, offsetExists) { zend_string *offset; zval *value, qa_tmp, *qa; if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "S", &offset)) { return; } qa = zend_read_property(php_http_querystring_class_entry, Z_OBJ_P(ZEND_THIS), ZEND_STRL("queryArray"), 0, &qa_tmp); ZVAL_DEREF(qa); if (Z_TYPE_P(qa) == IS_ARRAY) { if ((value = zend_symtable_find(Z_ARRVAL_P(qa), offset))) { RETURN_BOOL(Z_TYPE_P(value) != IS_NULL); } } RETURN_FALSE; } ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(ai_HttpQueryString_offsetUnset, 0, 1, IS_VOID, 0) ZEND_ARG_INFO(0, name) ZEND_END_ARG_INFO(); PHP_METHOD(HttpQueryString, offsetUnset) { zend_string *offset; zval param, znull; if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "S", &offset)) { return; } array_init(¶m); ZVAL_NULL(&znull); zend_symtable_update(Z_ARRVAL(param), offset, &znull); php_http_querystring_set(getThis(), ¶m, QS_MERGE); zval_ptr_dtor(¶m); } static zend_function_entry php_http_querystring_methods[] = { PHP_ME(HttpQueryString, __construct, ai_HttpQueryString___construct, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) PHP_ME(HttpQueryString, toArray, ai_HttpQueryString_toArray, ZEND_ACC_PUBLIC) PHP_ME(HttpQueryString, toString, ai_HttpQueryString_toString, ZEND_ACC_PUBLIC) ZEND_MALIAS(HttpQueryString, __toString, toString, ai_HttpQueryString_toString, ZEND_ACC_PUBLIC) PHP_ME(HttpQueryString, get, ai_HttpQueryString_get, ZEND_ACC_PUBLIC) PHP_ME(HttpQueryString, set, ai_HttpQueryString_set, ZEND_ACC_PUBLIC) PHP_ME(HttpQueryString, mod, ai_HttpQueryString_mod, ZEND_ACC_PUBLIC) PHP_ME(HttpQueryString, getBool, ai_HttpQueryString___getter, ZEND_ACC_PUBLIC) PHP_ME(HttpQueryString, getInt, ai_HttpQueryString___getter, ZEND_ACC_PUBLIC) PHP_ME(HttpQueryString, getFloat, ai_HttpQueryString___getter, ZEND_ACC_PUBLIC) PHP_ME(HttpQueryString, getString, ai_HttpQueryString___getter, ZEND_ACC_PUBLIC) PHP_ME(HttpQueryString, getArray, ai_HttpQueryString___getter, ZEND_ACC_PUBLIC) PHP_ME(HttpQueryString, getObject, ai_HttpQueryString___getter, ZEND_ACC_PUBLIC) PHP_ME(HttpQueryString, getIterator, ai_HttpQueryString_getIterator, ZEND_ACC_PUBLIC) PHP_ME(HttpQueryString, getGlobalInstance, ai_HttpQueryString_getGlobalInstance, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) #if PHP_HTTP_HAVE_ICONV PHP_ME(HttpQueryString, xlate, ai_HttpQueryString_xlate, ZEND_ACC_PUBLIC) #endif /* Implements Serializable */ PHP_ME(HttpQueryString, serialize, ai_HttpQueryString_serialize, ZEND_ACC_PUBLIC) PHP_ME(HttpQueryString, unserialize, ai_HttpQueryString_unserialize, ZEND_ACC_PUBLIC) PHP_ME(HttpQueryString, __serialize, ai_HttpQueryString___serialize, ZEND_ACC_PUBLIC) PHP_ME(HttpQueryString, __unserialize, ai_HttpQueryString___unserialize, ZEND_ACC_PUBLIC) /* Implements ArrayAccess */ PHP_ME(HttpQueryString, offsetGet, ai_HttpQueryString_offsetGet, ZEND_ACC_PUBLIC) PHP_ME(HttpQueryString, offsetSet, ai_HttpQueryString_offsetSet, ZEND_ACC_PUBLIC) PHP_ME(HttpQueryString, offsetExists, ai_HttpQueryString_offsetExists, ZEND_ACC_PUBLIC) PHP_ME(HttpQueryString, offsetUnset, ai_HttpQueryString_offsetUnset, ZEND_ACC_PUBLIC) EMPTY_FUNCTION_ENTRY }; PHP_MINIT_FUNCTION(http_querystring) { zend_class_entry ce = {0}; INIT_NS_CLASS_ENTRY(ce, "http", "QueryString", php_http_querystring_methods); php_http_querystring_class_entry = zend_register_internal_class(&ce); php_http_querystring_class_entry->create_object = php_http_querystring_object_new; zend_class_implements(php_http_querystring_class_entry, 3, zend_ce_serializable, zend_ce_arrayaccess, zend_ce_aggregate); zend_declare_property_null(php_http_querystring_class_entry, ZEND_STRL("instance"), (ZEND_ACC_STATIC|ZEND_ACC_PRIVATE)); zend_declare_property_null(php_http_querystring_class_entry, ZEND_STRL("queryArray"), ZEND_ACC_PRIVATE); zend_declare_class_constant_long(php_http_querystring_class_entry, ZEND_STRL("TYPE_BOOL"), PHP_HTTP_QUERYSTRING_TYPE_BOOL); zend_declare_class_constant_long(php_http_querystring_class_entry, ZEND_STRL("TYPE_INT"), PHP_HTTP_QUERYSTRING_TYPE_INT); zend_declare_class_constant_long(php_http_querystring_class_entry, ZEND_STRL("TYPE_FLOAT"), PHP_HTTP_QUERYSTRING_TYPE_FLOAT); zend_declare_class_constant_long(php_http_querystring_class_entry, ZEND_STRL("TYPE_STRING"), PHP_HTTP_QUERYSTRING_TYPE_STRING); zend_declare_class_constant_long(php_http_querystring_class_entry, ZEND_STRL("TYPE_ARRAY"), PHP_HTTP_QUERYSTRING_TYPE_ARRAY); zend_declare_class_constant_long(php_http_querystring_class_entry, ZEND_STRL("TYPE_OBJECT"), PHP_HTTP_QUERYSTRING_TYPE_OBJECT); 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 */ pecl_http-4.2.1/src/php_http_querystring.h0000644000076500000240000000352514117626035017524 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_HTTP_QUERYSTRING_H #define PHP_HTTP_QUERYSTRING_H #if PHP_HTTP_HAVE_ICONV PHP_HTTP_API ZEND_RESULT_CODE php_http_querystring_xlate(zval *dst, zval *src, const char *ie, const char *oe); #endif /* PHP_HTTP_HAVE_ICONV */ PHP_HTTP_API ZEND_RESULT_CODE php_http_querystring_update(zval *qarray, zval *params, zval *qstring); PHP_HTTP_API ZEND_RESULT_CODE php_http_querystring_ctor(zval *instance, zval *params); typedef php_http_object_t php_http_querystring_object_t; #define PHP_HTTP_QUERYSTRING_TYPE_BOOL _IS_BOOL #define PHP_HTTP_QUERYSTRING_TYPE_INT IS_LONG #define PHP_HTTP_QUERYSTRING_TYPE_FLOAT IS_DOUBLE #define PHP_HTTP_QUERYSTRING_TYPE_STRING IS_STRING #define PHP_HTTP_QUERYSTRING_TYPE_ARRAY IS_ARRAY #define PHP_HTTP_QUERYSTRING_TYPE_OBJECT IS_OBJECT PHP_HTTP_API zend_class_entry *php_http_querystring_get_class_entry(void); PHP_MINIT_FUNCTION(http_querystring); #define php_http_querystring_object_new php_http_object_new #define php_http_querystring_object_new_ex php_http_object_new_ex #endif /* PHP_HTTP_QUERYSTRING_H */ /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ pecl_http-4.2.1/src/php_http_response_codes.h0000644000076500000240000000704114117626035020140 0ustar Mikestaff/* +--------------------------------------------------------------------+ | 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-2015, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_HTTP_RESPONSE_CODE # define PHP_HTTP_RESPONSE_CODE(code, status) #endif PHP_HTTP_RESPONSE_CODE(100, "Continue") PHP_HTTP_RESPONSE_CODE(101, "Switching Protocols") PHP_HTTP_RESPONSE_CODE(102, "Processing") PHP_HTTP_RESPONSE_CODE(200, "OK") PHP_HTTP_RESPONSE_CODE(201, "Created") PHP_HTTP_RESPONSE_CODE(202, "Accepted") PHP_HTTP_RESPONSE_CODE(203, "Non-Authoritative Information") PHP_HTTP_RESPONSE_CODE(204, "No Content") PHP_HTTP_RESPONSE_CODE(205, "Reset Content") PHP_HTTP_RESPONSE_CODE(206, "Partial Content") PHP_HTTP_RESPONSE_CODE(207, "Multi-Status") PHP_HTTP_RESPONSE_CODE(208, "Already Reported") PHP_HTTP_RESPONSE_CODE(226, "IM Used") PHP_HTTP_RESPONSE_CODE(300, "Multiple Choices") PHP_HTTP_RESPONSE_CODE(301, "Moved Permanently") PHP_HTTP_RESPONSE_CODE(302, "Found") PHP_HTTP_RESPONSE_CODE(303, "See Other") PHP_HTTP_RESPONSE_CODE(304, "Not Modified") PHP_HTTP_RESPONSE_CODE(305, "Use Proxy") PHP_HTTP_RESPONSE_CODE(307, "Temporary Redirect") PHP_HTTP_RESPONSE_CODE(308, "Permanent Redirect") PHP_HTTP_RESPONSE_CODE(400, "Bad Request") PHP_HTTP_RESPONSE_CODE(401, "Unauthorized") PHP_HTTP_RESPONSE_CODE(402, "Payment Required") PHP_HTTP_RESPONSE_CODE(403, "Forbidden") PHP_HTTP_RESPONSE_CODE(404, "Not Found") PHP_HTTP_RESPONSE_CODE(405, "Method Not Allowed") PHP_HTTP_RESPONSE_CODE(406, "Not Acceptable") PHP_HTTP_RESPONSE_CODE(407, "Proxy Authentication Required") PHP_HTTP_RESPONSE_CODE(408, "Request Timeout") PHP_HTTP_RESPONSE_CODE(409, "Conflict") PHP_HTTP_RESPONSE_CODE(410, "Gone") PHP_HTTP_RESPONSE_CODE(411, "Length Required") PHP_HTTP_RESPONSE_CODE(412, "Precondition Failed") PHP_HTTP_RESPONSE_CODE(413, "Request Entity Too Large") PHP_HTTP_RESPONSE_CODE(414, "Request URI Too Long") PHP_HTTP_RESPONSE_CODE(415, "Unsupported Media Type") PHP_HTTP_RESPONSE_CODE(416, "Requested Range Not Satisfiable") PHP_HTTP_RESPONSE_CODE(417, "Expectation Failed") PHP_HTTP_RESPONSE_CODE(422, "Unprocessible Entity") PHP_HTTP_RESPONSE_CODE(423, "Locked") PHP_HTTP_RESPONSE_CODE(424, "Failed Dependency") PHP_HTTP_RESPONSE_CODE(426, "Upgrade Required") PHP_HTTP_RESPONSE_CODE(428, "Precondition Required") PHP_HTTP_RESPONSE_CODE(429, "Too Many Requests") PHP_HTTP_RESPONSE_CODE(431, "Request Header Fields Too Large") PHP_HTTP_RESPONSE_CODE(500, "Internal Server Error") PHP_HTTP_RESPONSE_CODE(501, "Not Implemented") PHP_HTTP_RESPONSE_CODE(502, "Bad Gateway") PHP_HTTP_RESPONSE_CODE(503, "Service Unavailable") PHP_HTTP_RESPONSE_CODE(504, "Gateway Timeout") PHP_HTTP_RESPONSE_CODE(505, "HTTP Version Not Supported") PHP_HTTP_RESPONSE_CODE(506, "Variant Also Negotiates") PHP_HTTP_RESPONSE_CODE(507, "Insufficient Storage") PHP_HTTP_RESPONSE_CODE(508, "Loop Detected") PHP_HTTP_RESPONSE_CODE(510, "Not Extended") PHP_HTTP_RESPONSE_CODE(511, "Network Authentication Required") /* * 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 */ pecl_http-4.2.1/src/php_http_url.c0000644000076500000240000016604314117626035015732 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #include "php_http_api.h" #if PHP_HTTP_HAVE_LIBIDN # include #endif #if PHP_HTTP_HAVE_LIBIDN2 # include #endif #if PHP_HTTP_HAVE_LIBICU # include # include #endif #if PHP_HTTP_HAVE_LIBIDNKIT || PHP_HTTP_HAVE_LIBIDNKIT2 # include # include #endif #if PHP_HTTP_HAVE_WCHAR # include # include #endif #if HAVE_ARPA_INET_H # include #endif #include "php_http_utf8.h" static inline char *localhostname(void) { char hostname[1024] = {0}; #if PHP_WIN32 if (SUCCESS == gethostname(hostname, lenof(hostname))) { return estrdup(hostname); } #elif HAVE_GETHOSTNAME if (SUCCESS == gethostname(hostname, lenof(hostname))) { # if HAVE_GETDOMAINNAME size_t hlen = strlen(hostname); if (hlen <= lenof(hostname) - lenof("(none)")) { hostname[hlen++] = '.'; if (SUCCESS == getdomainname(&hostname[hlen], lenof(hostname) - hlen)) { if (!strcmp(&hostname[hlen], "(none)")) { hostname[hlen - 1] = '\0'; } return estrdup(hostname); } } # endif if (strcmp(hostname, "(none)")) { return estrdup(hostname); } } #endif return estrndup("localhost", lenof("localhost")); } #define url(buf) ((php_http_url_t *) (buf).data) static php_http_url_t *php_http_url_from_env(void) { zval *https, *zhost, *zport; long port; php_http_buffer_t buf; php_http_buffer_init_ex(&buf, MAX(PHP_HTTP_BUFFER_DEFAULT_SIZE, sizeof(php_http_url_t)<<2), PHP_HTTP_BUFFER_INIT_PREALLOC); php_http_buffer_account(&buf, sizeof(php_http_url_t)); memset(buf.data, 0, buf.used); /* scheme */ url(buf)->scheme = &buf.data[buf.used]; https = php_http_env_get_server_var(ZEND_STRL("HTTPS"), 1); if (https && !strcasecmp(Z_STRVAL_P(https), "ON")) { php_http_buffer_append(&buf, "https", sizeof("https")); } else { php_http_buffer_append(&buf, "http", sizeof("http")); } /* host */ url(buf)->host = &buf.data[buf.used]; if ((((zhost = php_http_env_get_server_var(ZEND_STRL("HTTP_HOST"), 1)) || (zhost = php_http_env_get_server_var(ZEND_STRL("SERVER_NAME"), 1)) || (zhost = php_http_env_get_server_var(ZEND_STRL("SERVER_ADDR"), 1)))) && Z_STRLEN_P(zhost)) { size_t stop_at = strspn(Z_STRVAL_P(zhost), "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-."); php_http_buffer_append(&buf, Z_STRVAL_P(zhost), stop_at); php_http_buffer_append(&buf, "", 1); } else { char *host_str = localhostname(); php_http_buffer_append(&buf, host_str, strlen(host_str) + 1); efree(host_str); } /* port */ zport = php_http_env_get_server_var(ZEND_STRL("SERVER_PORT"), 1); if (zport && IS_LONG == is_numeric_string(Z_STRVAL_P(zport), Z_STRLEN_P(zport), &port, NULL, 0)) { url(buf)->port = port; } /* path */ if (SG(request_info).request_uri && SG(request_info).request_uri[0]) { const char *q = strchr(SG(request_info).request_uri, '?'); url(buf)->path = &buf.data[buf.used]; if (q) { php_http_buffer_append(&buf, SG(request_info).request_uri, q - SG(request_info).request_uri); php_http_buffer_append(&buf, "", 1); } else { php_http_buffer_append(&buf, SG(request_info).request_uri, strlen(SG(request_info).request_uri) + 1); } } /* query */ if (SG(request_info).query_string && SG(request_info).query_string[0]) { url(buf)->query = &buf.data[buf.used]; php_http_buffer_append(&buf, SG(request_info).query_string, strlen(SG(request_info).query_string) + 1); } return url(buf); } #define url_isset(u,n) \ ((u)&&(u)->n) #define url_append(buf, append) do { \ char *_ptr = (buf)->data; \ php_http_url_t *_url = (php_http_url_t *) _ptr, _mem = *_url; \ append; \ /* relocate */ \ if (_ptr != (buf)->data) { \ ptrdiff_t diff = (buf)->data - _ptr; \ _url = (php_http_url_t *) (buf)->data; \ if (_mem.scheme) _url->scheme += diff; \ if (_mem.user) _url->user += diff; \ if (_mem.pass) _url->pass += diff; \ if (_mem.host) _url->host += diff; \ if (_mem.path) _url->path += diff; \ if (_mem.query) _url->query += diff; \ if (_mem.fragment) _url->fragment += diff; \ } \ } while (0) #define url_copy(n) do { \ if (url_isset(new_url, n)) { \ url(buf)->n = &buf.data[buf.used]; \ url_append(&buf, php_http_buffer_append(&buf, new_url->n, strlen(new_url->n) + 1)); \ } else if (url_isset(old_url, n)) { \ url(buf)->n = &buf.data[buf.used]; \ url_append(&buf, php_http_buffer_append(&buf, old_url->n, strlen(old_url->n) + 1)); \ } \ } while (0) php_http_url_t *php_http_url_mod(const php_http_url_t *old_url, const php_http_url_t *new_url, unsigned flags) { php_http_url_t *tmp_url = NULL; php_http_buffer_t buf; php_http_buffer_init_ex(&buf, MAX(PHP_HTTP_BUFFER_DEFAULT_SIZE, sizeof(php_http_url_t)<<2), PHP_HTTP_BUFFER_INIT_PREALLOC); php_http_buffer_account(&buf, sizeof(php_http_url_t)); memset(buf.data, 0, buf.used); /* set from env if requested */ if (flags & PHP_HTTP_URL_FROM_ENV) { php_http_url_t *env_url = php_http_url_from_env(); old_url = tmp_url = php_http_url_mod(env_url, old_url, flags ^ PHP_HTTP_URL_FROM_ENV); php_http_url_free(&env_url); } url_copy(scheme); if (!(flags & PHP_HTTP_URL_STRIP_USER)) { url_copy(user); } if (!(flags & PHP_HTTP_URL_STRIP_PASS)) { url_copy(pass); } url_copy(host); if (!(flags & PHP_HTTP_URL_STRIP_PORT)) { url(buf)->port = url_isset(new_url, port) ? new_url->port : ((old_url) ? old_url->port : 0); } if (!(flags & PHP_HTTP_URL_STRIP_PATH)) { if ((flags & PHP_HTTP_URL_JOIN_PATH) && url_isset(old_url, path) && url_isset(new_url, path) && *new_url->path != '/') { size_t old_path_len = strlen(old_url->path), new_path_len = strlen(new_url->path); char *path = ecalloc(1, old_path_len + new_path_len + 1 + 1); strcat(path, old_url->path); if (path[old_path_len - 1] != '/') { php_dirname(path, old_path_len); strcat(path, "/"); } strcat(path, new_url->path); url(buf)->path = &buf.data[buf.used]; if (path[0] != '/') { url_append(&buf, php_http_buffer_append(&buf, "/", 1)); } url_append(&buf, php_http_buffer_append(&buf, path, strlen(path) + 1)); efree(path); } else { const char *path = NULL; if (url_isset(new_url, path)) { path = new_url->path; } else if (url_isset(old_url, path)) { path = old_url->path; } if (path) { url(buf)->path = &buf.data[buf.used]; url_append(&buf, php_http_buffer_append(&buf, path, strlen(path) + 1)); } } } if (!(flags & PHP_HTTP_URL_STRIP_QUERY)) { if ((flags & PHP_HTTP_URL_JOIN_QUERY) && url_isset(new_url, query) && url_isset(old_url, query)) { zval qarr, qstr; array_init(&qarr); ZVAL_STRING(&qstr, old_url->query); php_http_querystring_update(&qarr, &qstr, NULL); zval_ptr_dtor(&qstr); ZVAL_STRING(&qstr, new_url->query); php_http_querystring_update(&qarr, &qstr, NULL); zval_ptr_dtor(&qstr); ZVAL_NULL(&qstr); php_http_querystring_update(&qarr, NULL, &qstr); url(buf)->query = &buf.data[buf.used]; url_append(&buf, php_http_buffer_append(&buf, Z_STRVAL(qstr), Z_STRLEN(qstr) + 1)); zval_dtor(&qstr); zval_dtor(&qarr); } else { url_copy(query); } } if (!(flags & PHP_HTTP_URL_STRIP_FRAGMENT)) { url_copy(fragment); } /* done with copy & combine & strip */ if (flags & PHP_HTTP_URL_FROM_ENV) { /* free old_url we tainted above */ php_http_url_free(&tmp_url); } /* replace directory references if path is not a single slash */ if ((flags & PHP_HTTP_URL_SANITIZE_PATH) && url(buf)->path && url(buf)->path[0] && url(buf)->path[1]) { char *ptr, *end = url(buf)->path + strlen(url(buf)->path) + 1; for (ptr = strchr(url(buf)->path, '/'); ptr; ptr = strchr(ptr, '/')) { switch (ptr[1]) { case '/': memmove(&ptr[1], &ptr[2], end - &ptr[2]); break; case '.': switch (ptr[2]) { case '\0': ptr[1] = '\0'; break; case '/': memmove(&ptr[1], &ptr[3], end - &ptr[3]); break; case '.': if (ptr[3] == '/') { char *pos = &ptr[4]; while (ptr != url(buf)->path) { if (*--ptr == '/') { break; } } memmove(&ptr[1], pos, end - pos); break; } else if (!ptr[3]) { /* .. at the end */ ptr[1] = '\0'; } /* no break */ default: /* something else */ ++ptr; break; } break; default: ++ptr; break; } } } /* unset default ports */ if (url(buf)->port) { if ( ((url(buf)->port == 80) && url(buf)->scheme && !strcmp(url(buf)->scheme, "http")) || ((url(buf)->port ==443) && url(buf)->scheme && !strcmp(url(buf)->scheme, "https")) ) { url(buf)->port = 0; } } return url(buf); } char *php_http_url_to_string(const php_http_url_t *url, char **url_str, size_t *url_len, zend_bool persistent) { php_http_buffer_t buf; php_http_buffer_init_ex(&buf, PHP_HTTP_BUFFER_DEFAULT_SIZE, persistent ? PHP_HTTP_BUFFER_INIT_PERSISTENT : 0); if (url->scheme && *url->scheme) { php_http_buffer_appendl(&buf, url->scheme); php_http_buffer_appends(&buf, "://"); } else if ((url->user && *url->user) || (url->host && *url->host)) { php_http_buffer_appends(&buf, "//"); } if (url->user && *url->user) { php_http_buffer_appendl(&buf, url->user); if (url->pass && *url->pass) { php_http_buffer_appends(&buf, ":"); php_http_buffer_appendl(&buf, url->pass); } php_http_buffer_appends(&buf, "@"); } if (url->host && *url->host) { php_http_buffer_appendl(&buf, url->host); if (url->port) { php_http_buffer_appendf(&buf, ":%hu", url->port); } } if (url->path && *url->path) { if (*url->path != '/') { php_http_buffer_appends(&buf, "/"); } php_http_buffer_appendl(&buf, url->path); } else if (buf.used) { php_http_buffer_appends(&buf, "/"); } if (url->query && *url->query) { php_http_buffer_appends(&buf, "?"); php_http_buffer_appendl(&buf, url->query); } if (url->fragment && *url->fragment) { php_http_buffer_appends(&buf, "#"); php_http_buffer_appendl(&buf, url->fragment); } php_http_buffer_shrink(&buf); php_http_buffer_fix(&buf); if (url_len) { *url_len = buf.used; } if (url_str) { *url_str = buf.data; } return buf.data; } char *php_http_url_authority_to_string(const php_http_url_t *url, char **url_str, size_t *url_len) { php_http_buffer_t buf; php_http_buffer_init(&buf); if (url->user && *url->user) { php_http_buffer_appendl(&buf, url->user); if (url->pass && *url->pass) { php_http_buffer_appends(&buf, ":"); php_http_buffer_appendl(&buf, url->pass); } php_http_buffer_appends(&buf, "@"); } if (url->host && *url->host) { php_http_buffer_appendl(&buf, url->host); if (url->port) { php_http_buffer_appendf(&buf, ":%hu", url->port); } } php_http_buffer_shrink(&buf); php_http_buffer_fix(&buf); if (url_len) { *url_len = buf.used; } if (url_str) { *url_str = buf.data; } return buf.data; } php_http_url_t *php_http_url_from_zval(zval *value, unsigned flags) { zend_string *zs; php_http_url_t *purl; switch (Z_TYPE_P(value)) { case IS_ARRAY: case IS_OBJECT: purl = php_http_url_from_struct(HASH_OF(value)); break; default: zs = zval_get_string(value); purl = php_http_url_parse(zs->val, zs->len, flags); zend_string_release(zs); } return purl; } php_http_url_t *php_http_url_from_struct(HashTable *ht) { zval *e; php_http_buffer_t buf; php_http_buffer_init_ex(&buf, MAX(PHP_HTTP_BUFFER_DEFAULT_SIZE, sizeof(php_http_url_t)<<2), PHP_HTTP_BUFFER_INIT_PREALLOC); php_http_buffer_account(&buf, sizeof(php_http_url_t)); memset(buf.data, 0, buf.used); if ((e = zend_hash_str_find_ind(ht, ZEND_STRL("scheme")))) { zend_string *zs = zval_get_string(e); url(buf)->scheme = &buf.data[buf.used]; url_append(&buf, php_http_buffer_append(&buf, zs->val, zs->len + 1)); zend_string_release(zs); } if ((e = zend_hash_str_find_ind(ht, ZEND_STRL("user")))) { zend_string *zs = zval_get_string(e); url(buf)->user = &buf.data[buf.used]; url_append(&buf, php_http_buffer_append(&buf, zs->val, zs->len + 1)); zend_string_release(zs); } if ((e = zend_hash_str_find_ind(ht, ZEND_STRL("pass")))) { zend_string *zs = zval_get_string(e); url(buf)->pass = &buf.data[buf.used]; url_append(&buf, php_http_buffer_append(&buf, zs->val, zs->len + 1)); zend_string_release(zs); } if ((e = zend_hash_str_find_ind(ht, ZEND_STRL("host")))) { zend_string *zs = zval_get_string(e); url(buf)->host = &buf.data[buf.used]; url_append(&buf, php_http_buffer_append(&buf, zs->val, zs->len + 1)); zend_string_release(zs); } if ((e = zend_hash_str_find_ind(ht, ZEND_STRL("port")))) { url(buf)->port = (unsigned short) zval_get_long(e); } if ((e = zend_hash_str_find_ind(ht, ZEND_STRL("path")))) { zend_string *zs = zval_get_string(e); url(buf)->path = &buf.data[buf.used]; url_append(&buf, php_http_buffer_append(&buf, zs->val, zs->len + 1)); zend_string_release(zs); } if ((e = zend_hash_str_find_ind(ht, ZEND_STRL("query")))) { zend_string *zs = zval_get_string(e); url(buf)->query = &buf.data[buf.used]; url_append(&buf, php_http_buffer_append(&buf, zs->val, zs->len + 1)); zend_string_release(zs); } if ((e = zend_hash_str_find_ind(ht, ZEND_STRL("fragment")))) { zend_string *zs = zval_get_string(e); url(buf)->fragment = &buf.data[buf.used]; url_append(&buf, php_http_buffer_append(&buf, zs->val, zs->len + 1)); zend_string_release(zs); } return url(buf); } HashTable *php_http_url_to_struct(const php_http_url_t *url, zval *strct) { HashTable *ht = NULL; zval tmp; if (strct) { switch (Z_TYPE_P(strct)) { default: zval_dtor(strct); array_init(strct); /* no break */ case IS_ARRAY: case IS_OBJECT: ht = HASH_OF(strct); break; } } else { ALLOC_HASHTABLE(ht); zend_hash_init(ht, 8, NULL, ZVAL_PTR_DTOR, 0); } #define url_struct_add(part) \ if (!strct || Z_TYPE_P(strct) == IS_ARRAY) { \ zend_hash_str_update(ht, part, lenof(part), &tmp); \ } else { \ zend_update_property(Z_OBJCE_P(strct), Z_OBJ_P(strct), part, lenof(part), &tmp); \ zval_ptr_dtor(&tmp); \ } if (url) { if (url->scheme) { ZVAL_STRING(&tmp, url->scheme); url_struct_add("scheme"); } if (url->user) { ZVAL_STRING(&tmp, url->user); url_struct_add("user"); } if (url->pass) { ZVAL_STRING(&tmp, url->pass); url_struct_add("pass"); } if (url->host) { ZVAL_STRING(&tmp, url->host); url_struct_add("host"); } if (url->port) { ZVAL_LONG(&tmp, url->port); url_struct_add("port"); } if (url->path) { ZVAL_STRING(&tmp, url->path); url_struct_add("path"); } if (url->query) { ZVAL_STRING(&tmp, url->query); url_struct_add("query"); } if (url->fragment) { ZVAL_STRING(&tmp, url->fragment); url_struct_add("fragment"); } } return ht; } ZEND_RESULT_CODE php_http_url_encode_hash(HashTable *hash, const char *pre_encoded_str, size_t pre_encoded_len, char **encoded_str, size_t *encoded_len) { const char *arg_sep_str = "&"; size_t arg_sep_len = 1; php_http_buffer_t *qstr = php_http_buffer_new(); php_http_url_argsep(&arg_sep_str, &arg_sep_len); if (SUCCESS != php_http_url_encode_hash_ex(hash, qstr, arg_sep_str, arg_sep_len, "=", 1, pre_encoded_str, pre_encoded_len)) { php_http_buffer_free(&qstr); return FAILURE; } php_http_buffer_data(qstr, encoded_str, encoded_len); php_http_buffer_free(&qstr); return SUCCESS; } ZEND_RESULT_CODE php_http_url_encode_hash_ex(HashTable *hash, php_http_buffer_t *qstr, const char *arg_sep_str, size_t arg_sep_len, const char *val_sep_str, size_t val_sep_len, const char *pre_encoded_str, size_t pre_encoded_len) { if (pre_encoded_len && pre_encoded_str) { php_http_buffer_append(qstr, pre_encoded_str, pre_encoded_len); } if (!php_http_params_to_string(qstr, hash, arg_sep_str, arg_sep_len, "", 0, val_sep_str, val_sep_len, PHP_HTTP_PARAMS_QUERY)) { return FAILURE; } return SUCCESS; } struct parse_state { php_http_url_t url; const char *ptr; const char *end; size_t maxlen; off_t offset; unsigned flags; char buffer[1]; /* last member */ }; void php_http_url_free(php_http_url_t **url) { if (*url) { efree(*url); *url = NULL; } } php_http_url_t *php_http_url_copy(const php_http_url_t *url, zend_bool persistent) { php_http_url_t *cpy; const char *end = NULL, *url_ptr = (const char *) url; char *cpy_ptr; end = MAX(url->scheme, end); end = MAX(url->pass, end); end = MAX(url->user, end); end = MAX(url->host, end); end = MAX(url->path, end); end = MAX(url->query, end); end = MAX(url->fragment, end); if (end) { end += strlen(end) + 1; cpy_ptr = pecalloc(1, end - url_ptr, persistent); cpy = (php_http_url_t *) cpy_ptr; memcpy(cpy_ptr + sizeof(*cpy), url_ptr + sizeof(*url), end - url_ptr - sizeof(*url)); cpy->scheme = url->scheme ? cpy_ptr + (url->scheme - url_ptr) : NULL; cpy->pass = url->pass ? cpy_ptr + (url->pass - url_ptr) : NULL; cpy->user = url->user ? cpy_ptr + (url->user - url_ptr) : NULL; cpy->host = url->host ? cpy_ptr + (url->host - url_ptr) : NULL; cpy->path = url->path ? cpy_ptr + (url->path - url_ptr) : NULL; cpy->query = url->query ? cpy_ptr + (url->query - url_ptr) : NULL; cpy->fragment = url->fragment ? cpy_ptr + (url->fragment - url_ptr) : NULL; } else { cpy = ecalloc(1, sizeof(*url)); } cpy->port = url->port; return cpy; } static inline size_t parse_mb_utf8(unsigned *wc, const char *ptr, const char *end) { unsigned wchar; size_t consumed = utf8towc(&wchar, (const unsigned char *) ptr, end - ptr); if (!consumed || consumed == (size_t) -1) { return 0; } if (wc) { *wc = wchar; } return consumed; } #if PHP_HTTP_HAVE_WCHAR static inline size_t parse_mb_loc(unsigned *wc, const char *ptr, const char *end) { wchar_t wchar; size_t consumed = 0; #if HAVE_MBRTOWC mbstate_t ps; memset(&ps, 0, sizeof(ps)); consumed = mbrtowc(&wchar, ptr, end - ptr, &ps); #elif HAVE_MBTOWC consumed = mbtowc(&wchar, ptr, end - ptr); #endif if (!consumed || consumed == (size_t) -1) { return 0; } if (wc) { *wc = wchar; } return consumed; } #endif typedef enum parse_mb_what { PARSE_SCHEME, PARSE_USERINFO, PARSE_HOSTINFO, PARSE_PATH, PARSE_QUERY, PARSE_FRAGMENT } parse_mb_what_t; static const char * const parse_what[] = { "scheme", "userinfo", "hostinfo", "path", "query", "fragment" }; static const char parse_xdigits[] = "0123456789ABCDEF"; static inline size_t parse_mb(struct parse_state *state, parse_mb_what_t what, const char *ptr, const char *end, const char *begin, zend_bool force_silent) { unsigned wchar; size_t consumed = 0; if (state->flags & PHP_HTTP_URL_PARSE_MBUTF8) { consumed = parse_mb_utf8(&wchar, ptr, end); } #if PHP_HTTP_HAVE_WCHAR else if (state->flags & PHP_HTTP_URL_PARSE_MBLOC) { consumed = parse_mb_loc(&wchar, ptr, end); } #endif while (consumed) { if (!(state->flags & PHP_HTTP_URL_PARSE_TOPCT) || what == PARSE_HOSTINFO || what == PARSE_SCHEME) { if (what == PARSE_HOSTINFO && (state->flags & PHP_HTTP_URL_PARSE_TOIDN)) { /* idna */ } else if (state->flags & PHP_HTTP_URL_PARSE_MBUTF8) { #if PHP_HTTP_HAVE_LIBICU if (!u_isalnum(wchar)) { #else if (!isualnum(wchar)) { #endif break; } #if PHP_HTTP_HAVE_WCHAR } else if (state->flags & PHP_HTTP_URL_PARSE_MBLOC) { if (!iswalnum(wchar)) { break; } #endif } memcpy(&state->buffer[state->offset], ptr, consumed); state->offset += consumed; } else { size_t i; for (i = 0; i < consumed; ++i) { state->buffer[state->offset++] = '%'; state->buffer[state->offset++] = parse_xdigits[((unsigned char) ptr[i]) >> 4]; state->buffer[state->offset++] = parse_xdigits[((unsigned char) ptr[i]) & 0xf]; } } return consumed; } if (!force_silent && !(state->flags & PHP_HTTP_URL_SILENT_ERRORS)) { if (consumed) { php_error_docref(NULL, E_WARNING, "Failed to parse %s; unexpected multibyte sequence 0x%x at pos %u in '%s'", parse_what[what], wchar, (unsigned) (ptr - begin), begin); } else { php_error_docref(NULL, E_WARNING, "Failed to parse %s; unexpected byte 0x%02x at pos %u in '%s'", parse_what[what], (unsigned char) *ptr, (unsigned) (ptr - begin), begin); } } if (state->flags & PHP_HTTP_URL_IGNORE_ERRORS) { state->buffer[state->offset++] = *ptr; return 1; } return 0; } static ZEND_RESULT_CODE parse_userinfo(struct parse_state *state, const char *ptr) { size_t mb; const char *password = NULL, *end = state->ptr, *tmp = ptr; state->url.user = &state->buffer[state->offset]; do { switch (*ptr) { case ':': if (password) { if (!(state->flags & PHP_HTTP_URL_SILENT_ERRORS)) { php_error_docref(NULL, E_WARNING, "Failed to parse password; duplicate ':' at pos %u in '%s'", (unsigned) (ptr - tmp), tmp); } if (!(state->flags & PHP_HTTP_URL_IGNORE_ERRORS)) { return FAILURE; } state->buffer[state->offset++] = *ptr; break; } password = ptr + 1; state->buffer[state->offset++] = 0; state->url.pass = &state->buffer[state->offset]; break; case '%': if (ptr[1] != '%' && (end - ptr <= 2 || !isxdigit(*(ptr+1)) || !isxdigit(*(ptr+2)))) { if (!(state->flags & PHP_HTTP_URL_SILENT_ERRORS)) { php_error_docref(NULL, E_WARNING, "Failed to parse userinfo; invalid percent encoding at pos %u in '%s'", (unsigned) (ptr - tmp), tmp); } if (!(state->flags & PHP_HTTP_URL_IGNORE_ERRORS)) { return FAILURE; } state->buffer[state->offset++] = *ptr++; break; } state->buffer[state->offset++] = *ptr++; state->buffer[state->offset++] = *ptr++; state->buffer[state->offset++] = *ptr; break; default: if ((mb = parse_mb(state, PARSE_USERINFO, ptr, end, tmp, 0))) { ptr += mb - 1; break; } if (!(state->flags & PHP_HTTP_URL_IGNORE_ERRORS)) { return FAILURE; } /* no break */ case '!': case '$': case '&': case '\'': case '(': case ')': case '*': case '+': case ',': case ';': case '=': /* sub-delims */ case '-': case '.': case '_': case '~': /* unreserved */ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': /* allowed */ state->buffer[state->offset++] = *ptr; break; } } while(++ptr < end); state->buffer[state->offset++] = 0; return SUCCESS; } #if PHP_WIN32 || HAVE_UIDNA_IDNTOASCII typedef size_t (*parse_mb_func)(unsigned *wc, const char *ptr, const char *end); static ZEND_RESULT_CODE to_utf16(parse_mb_func fn, const char *u8, uint16_t **u16, size_t *len) { size_t offset = 0, u8_len = strlen(u8); *u16 = ecalloc(4 * sizeof(uint16_t), u8_len + 1); *len = 0; while (offset < u8_len) { unsigned wc; uint16_t buf[2], *ptr = buf; size_t consumed = fn(&wc, &u8[offset], &u8[u8_len]); if (!consumed) { efree(*u16); php_error_docref(NULL, E_WARNING, "Failed to parse UTF-8 at pos %zu of '%s'", offset, u8); return FAILURE; } else { offset += consumed; } switch (wctoutf16(buf, wc)) { case 2: (*u16)[(*len)++] = *ptr++; /* no break */ case 1: (*u16)[(*len)++] = *ptr++; break; case 0: default: efree(*u16); php_error_docref(NULL, E_WARNING, "Failed to convert UTF-32 'U+%X' to UTF-16", wc); return FAILURE; } } return SUCCESS; } #endif #if PHP_HTTP_HAVE_LIBIDN2 # if __GNUC__ __attribute__ ((unused)) # endif static ZEND_RESULT_CODE parse_gidn_2008(struct parse_state *state, size_t prev_len) { char *idn = NULL; int rv = -1; if (state->flags & PHP_HTTP_URL_PARSE_MBUTF8) { rv = idn2_lookup_u8((const unsigned char *) state->url.host, (unsigned char **) &idn, IDN2_NFC_INPUT); } # if PHP_HTTP_HAVE_WCHAR else if (state->flags & PHP_HTTP_URL_PARSE_MBLOC) { rv = idn2_lookup_ul(state->url.host, &idn, 0); } # endif if (rv != IDN2_OK) { if (!(state->flags & PHP_HTTP_URL_SILENT_ERRORS)) { php_error_docref(NULL, E_WARNING, "Failed to parse IDN (IDNA2008); %s", idn2_strerror(rv)); } if (!(state->flags & PHP_HTTP_URL_IGNORE_ERRORS)) { return FAILURE; } } else { size_t idnlen = strlen(idn); memcpy(state->url.host, idn, idnlen + 1); free(idn); state->offset += idnlen - prev_len; } return SUCCESS; } #endif #if PHP_HTTP_HAVE_LIBIDN # if __GNUC__ __attribute__ ((unused)) # endif static ZEND_RESULT_CODE parse_gidn_2003(struct parse_state *state, size_t prev_len) { char *idn = NULL; int rv = -1; if (state->flags & PHP_HTTP_URL_PARSE_MBUTF8) { rv = idna_to_ascii_8z(state->url.host, &idn, IDNA_ALLOW_UNASSIGNED); } # if PHP_HTTP_HAVE_WCHAR else if (state->flags & PHP_HTTP_URL_PARSE_MBLOC) { rv = idna_to_ascii_lz(state->url.host, &idn, IDNA_ALLOW_UNASSIGNED); } # endif if (rv != IDNA_SUCCESS) { if (!(state->flags & PHP_HTTP_URL_SILENT_ERRORS)) { php_error_docref(NULL, E_WARNING, "Failed to parse IDN (IDNA2003); %s", idna_strerror(rv)); } if (!(state->flags & PHP_HTTP_URL_IGNORE_ERRORS)) { return FAILURE; } } else { size_t idnlen = strlen(idn); memcpy(state->url.host, idn, idnlen + 1); free(idn); state->offset += idnlen - prev_len; } return SUCCESS; } #endif #if HAVE_UIDNA_IDNTOASCII # if !PHP_HTTP_HAVE_LIBICU typedef uint16_t UChar; typedef enum { U_ZERO_ERROR = 0 } UErrorCode; int32_t uidna_IDNToASCII(const UChar *src, int32_t srcLength, UChar *dest, int32_t destCapacity, int32_t options, void *parseError, UErrorCode *status); # endif static ZEND_RESULT_CODE parse_uidn_2003(struct parse_state *state, size_t prev_len) { char ebuf[64] = {0}, *error = NULL; uint16_t *uhost_str, ahost_str[256]; size_t uhost_len, ahost_len; UErrorCode rc = U_ZERO_ERROR; if (state->flags & PHP_HTTP_URL_PARSE_MBUTF8) { if (SUCCESS != to_utf16(parse_mb_utf8, state->url.host, &uhost_str, &uhost_len)) { error = "failed to convert to UTF-16"; goto error; } #if PHP_HTTP_HAVE_WCHAR } else if (state->flags & PHP_HTTP_URL_PARSE_MBLOC) { if (SUCCESS != to_utf16(parse_mb_loc, state->url.host, &uhost_str, &uhost_len)) { error = "failed to convert to UTF-16"; goto error; } #endif } else { error = "codepage not specified"; goto error; } # if __GNUC__ >= 5 # pragma GCC diagnostic ignored "-Wdeprecated-declarations" # endif ahost_len = uidna_IDNToASCII(uhost_str, uhost_len, ahost_str, 256, 3, NULL, &rc); # if __GNUC__ >= 5 # pragma GCC diagnostic pop # endif efree(uhost_str); if (rc > U_ZERO_ERROR) { goto error; } state->url.host[ahost_len] = '\0'; state->offset += ahost_len - prev_len; while (ahost_len--) { state->url.host[ahost_len] = ahost_str[ahost_len]; } return SUCCESS; error: if (!error) { slprintf(ebuf, sizeof(ebuf)-1, "errorcode: %d", rc); error = ebuf; } php_error_docref(NULL, E_WARNING, "Failed to parse IDN (ICU IDNA2003); %s", error); return FAILURE; } #endif #if PHP_HTTP_HAVE_LIBICU && HAVE_UIDNA_NAMETOASCII_UTF8 static ZEND_RESULT_CODE parse_uidn_2008(struct parse_state *state, size_t prev_len) { char *error = NULL, ebuf[64] = {0}; UErrorCode rc = U_ZERO_ERROR; UIDNAInfo info = UIDNA_INFO_INITIALIZER; UIDNA *uidna = uidna_openUTS46(UIDNA_ALLOW_UNASSIGNED, &rc); if (!uidna || U_FAILURE(rc)) { return FAILURE; } if (state->flags & PHP_HTTP_URL_PARSE_MBUTF8) { char ahost_str[256]; size_t ahost_len = uidna_nameToASCII_UTF8(uidna, state->url.host, -1, ahost_str, sizeof(ahost_str)-1, &info, &rc); if (U_FAILURE(rc) || info.errors) { goto error; } memcpy(state->url.host, ahost_str, ahost_len); state->url.host[ahost_len] = '\0'; state->offset += ahost_len - prev_len; #if PHP_HTTP_HAVE_WCHAR } else if (state->flags & PHP_HTTP_URL_PARSE_MBLOC) { uint16_t *uhost_str, whost_str[256]; size_t uhost_len, whost_len; if (SUCCESS != to_utf16(parse_mb_loc, state->url.host, &uhost_str, &uhost_len)) { error = "could not convert to UTF-16"; goto error; } whost_len = uidna_nameToASCII(uidna, uhost_str, uhost_len, whost_str, sizeof(whost_str)-1, &info, &rc); efree(uhost_str); if (U_FAILURE(rc) || info.errors) { goto error; } state->url.host[whost_len] = '\0'; state->offset += whost_len - prev_len; while (whost_len--) { state->url.host[whost_len] = whost_str[whost_len]; } #endif } else { error = "codepage not specified"; goto error; } uidna_close(uidna); return SUCCESS; error: if (!error) { if (U_FAILURE(rc)) { slprintf(ebuf, sizeof(ebuf)-1, "%s", u_errorName(rc)); error = ebuf; } else if (info.errors) { slprintf(ebuf, sizeof(ebuf)-1, "ICU IDNA error codes: 0x%x", info.errors); error = ebuf; } else { error = "unknown error"; } } php_error_docref(NULL, E_WARNING, "Failed to parse IDN (ICU IDNA2008); %s", error); uidna_close(uidna); return FAILURE; } #endif #if PHP_HTTP_HAVE_LIBIDNKIT || PHP_HTTP_HAVE_LIBIDNKIT2 # if __GNUC__ __attribute__ ((unused)) # endif static ZEND_RESULT_CODE parse_kidn(struct parse_state *state, size_t prev_len) { idn_result_t rc; #if PHP_HTTP_HAVE_LIBIDNKIT int actions = IDN_DELIMMAP|IDN_LOCALMAP|IDN_NAMEPREP|IDN_IDNCONV|IDN_LENCHECK; #elif PHP_HTTP_HAVE_LIBIDNKIT2 int actions = IDN_MAP|IDN_ASCLOWER|IDN_RTCONV|IDN_PROHCHECK|IDN_NFCCHECK|IDN_PREFCHECK|IDN_COMBCHECK|IDN_CTXOLITECHECK|IDN_BIDICHECK|IDN_LOCALCHECK|IDN_IDNCONV|IDN_LENCHECK|IDN_RTCHECK; #endif char ahost_str[256] = {0}; if (state->flags & PHP_HTTP_URL_PARSE_MBLOC) { #if PHP_HTTP_HAVE_LIBIDNKIT actions |= IDN_LOCALCONV; #elif PHP_HTTP_HAVE_LIBIDNKIT2 actions |= IDN_UNICODECONV; #endif } rc = idn_encodename(actions, state->url.host, ahost_str, 256); if (rc == idn_success) { size_t ahost_len = strlen(ahost_str); memcpy(state->url.host, ahost_str, ahost_len + 1); state->offset += ahost_len - prev_len; return SUCCESS; } else { php_error_docref(NULL, E_WARNING, "Failed to parse IDN; %s", idn_result_tostring(rc)); return FAILURE; } } #endif #if 0 && PHP_WIN32 static ZEND_RESULT_CODE parse_widn_2003(struct parse_state *state, size_t prev_len) { char *host_ptr; uint16_t *uhost_str, ahost_str[256]; size_t uhost_len, ahost_len; if (state->flags & PHP_HTTP_URL_PARSE_MBUTF8) { if (SUCCESS != to_utf16(parse_mb_utf8, state->url.host, &uhost_str, &uhost_len)) { php_error_docref(NULL, E_WARNING, "Failed to parse IDN"); return FAILURE; } #if PHP_HTTP_HAVE_WCHAR } else if (state->flags & PHP_HTTP_URL_PARSE_MBLOC) { if (SUCCESS != to_utf16(parse_mb_loc, state->url.host, &uhost_str, &uhost_len)) { php_error_docref(NULL, E_WARNING, "Failed to parse IDN"); return FAILURE; } #endif } else { php_error_docref(NULL, E_WARNING, "Failed to parse IDN"); return FAILURE; } if (!IdnToAscii(IDN_ALLOW_UNASSIGNED, uhost_str, uhost_len, ahost_str, 256)) { efree(uhost_str); php_error_docref(NULL, E_WARNING, "Failed to parse IDN"); return FAILURE; } efree(uhost_str); ahost_len = wcslen(ahost_str); state->url.host[ahost_len] = '\0'; state->offset += ahost_len - prev_len; while (ahost_len--) { state->url.host[ahost_len] = ahost_str[ahost_len]; } return SUCCESS; } #endif static ZEND_RESULT_CODE parse_idna(struct parse_state *state, size_t len) { #if PHP_HTTP_HAVE_IDNA2008 if ((state->flags & PHP_HTTP_URL_PARSE_TOIDN_2008) == PHP_HTTP_URL_PARSE_TOIDN_2008 # if PHP_HTTP_HAVE_IDNA2003 || (state->flags & PHP_HTTP_URL_PARSE_TOIDN_2003) != PHP_HTTP_URL_PARSE_TOIDN_2003 # endif ) { #if PHP_HTTP_HAVE_LIBICU && HAVE_UIDNA_NAMETOASCII_UTF8 return parse_uidn_2008(state, len); #elif PHP_HTTP_HAVE_LIBIDN2 return parse_gidn_2008(state, len); #elif PHP_HTTP_HAVE_LIBIDNKIT2 return parse_kidn(state, len); #endif } #endif #if PHP_HTTP_HAVE_IDNA2003 if ((state->flags & PHP_HTTP_URL_PARSE_TOIDN_2003) == PHP_HTTP_URL_PARSE_TOIDN_2003 # if PHP_HTTP_HAVE_IDNA2008 || (state->flags & PHP_HTTP_URL_PARSE_TOIDN_2008) != PHP_HTTP_URL_PARSE_TOIDN_2008 #endif ) { #if HAVE_UIDNA_IDNTOASCII return parse_uidn_2003(state, len); #elif PHP_HTTP_HAVE_LIBIDN return parse_gidn_2003(state, len); #elif PHP_HTTP_HAVE_LIBIDNKIT return parse_kidn(state, len); #endif } #endif #if 0 && PHP_WIN32 return parse_widn_2003(state, len); #endif #if PHP_HTTP_HAVE_LIBICU && HAVE_UIDNA_NAMETOASCII_UTF8 return parse_uidn_2008(state, len); #elif PHP_HTTP_HAVE_LIBIDN2 return parse_gidn_2008(state, len); #elif PHP_HTTP_HAVE_LIBIDNKIT2 return parse_kidn(state, len); #elif HAVE_UIDNA_IDNTOASCII return parse_uidn_2003(state, len); #elif PHP_HTTP_HAVE_LIBIDN return parse_gidn_2003(state, len); #elif PHP_HTTP_HAVE_LIBIDNKIT return parse_kidn(state, len); #endif return SUCCESS; } #if HAVE_INET_PTON static const char *parse_ip6(struct parse_state *state, const char *ptr) { unsigned pos = 0; const char *error = NULL, *end = state->ptr, *tmp = memchr(ptr, ']', end - ptr); if (tmp) { size_t addrlen = tmp - ptr + 1; char buf[16], *addr = estrndup(ptr + 1, addrlen - 2); int rv = inet_pton(AF_INET6, addr, buf); if (rv == 1) { state->buffer[state->offset] = '['; state->url.host = &state->buffer[state->offset]; inet_ntop(AF_INET6, buf, state->url.host + 1, state->maxlen - state->offset); state->offset += strlen(state->url.host); state->buffer[state->offset++] = ']'; state->buffer[state->offset++] = 0; ptr = tmp + 1; } else if (rv == -1) { pos = 1; error = strerror(errno); } else { error = "unexpected '['"; } efree(addr); } else { pos = end - ptr; error = "expected ']'"; } if (error) { if (!(state->flags & PHP_HTTP_URL_SILENT_ERRORS)) { php_error_docref(NULL, E_WARNING, "Failed to parse hostinfo; %s at pos %u in '%s'", error, pos, ptr); } return NULL; } return ptr; } #endif static ZEND_RESULT_CODE parse_hostinfo(struct parse_state *state, const char *ptr) { size_t mb, len = state->offset; const char *end = state->ptr, *tmp = ptr, *port = NULL, *label = NULL; #if HAVE_INET_PTON if (*ptr == '[' && !(ptr = parse_ip6(state, ptr))) { if (!(state->flags & PHP_HTTP_URL_IGNORE_ERRORS)) { return FAILURE; } ptr = tmp; } #endif if (ptr != end) do { switch (*ptr) { case ':': if (port) { if (!(state->flags & PHP_HTTP_URL_SILENT_ERRORS)) { php_error_docref(NULL, E_WARNING, "Failed to parse port; unexpected ':' at pos %u in '%s'", (unsigned) (ptr - tmp), tmp); } if (!(state->flags & PHP_HTTP_URL_IGNORE_ERRORS)) { return FAILURE; } } port = ptr + 1; break; case '%': if (ptr[1] != '%' && (end - ptr <= 2 || !isxdigit(*(ptr+1)) || !isxdigit(*(ptr+2)))) { if (!(state->flags & PHP_HTTP_URL_SILENT_ERRORS)) { php_error_docref(NULL, E_WARNING, "Failed to parse hostinfo; invalid percent encoding at pos %u in '%s'", (unsigned) (ptr - tmp), tmp); } if (!(state->flags & PHP_HTTP_URL_IGNORE_ERRORS)) { return FAILURE; } state->buffer[state->offset++] = *ptr++; break; } state->buffer[state->offset++] = *ptr++; state->buffer[state->offset++] = *ptr++; state->buffer[state->offset++] = *ptr; break; case '.': if (port || !label) { /* sort of a compromise, just ensure we don't end up * with a dot at the beginning or two consecutive dots */ if (!(state->flags & PHP_HTTP_URL_SILENT_ERRORS)) { php_error_docref(NULL, E_WARNING, "Failed to parse %s; unexpected '%c' at pos %u in '%s'", port ? "port" : "host", (unsigned char) *ptr, (unsigned) (ptr - tmp), tmp); } if (!(state->flags & PHP_HTTP_URL_IGNORE_ERRORS)) { return FAILURE; } break; } state->buffer[state->offset++] = *ptr; label = NULL; break; case '-': if (!label) { /* sort of a compromise, just ensure we don't end up * with a hyphen at the beginning */ if (!(state->flags & PHP_HTTP_URL_SILENT_ERRORS)) { php_error_docref(NULL, E_WARNING, "Failed to parse %s; unexpected '%c' at pos %u in '%s'", port ? "port" : "host", (unsigned char) *ptr, (unsigned) (ptr - tmp), tmp); } if (!(state->flags & PHP_HTTP_URL_IGNORE_ERRORS)) { return FAILURE; } break; } /* no break */ case '_': case '~': /* unreserved */ case '!': case '$': case '&': case '\'': case '(': case ')': case '*': case '+': case ',': case ';': case '=': /* sub-delims */ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': if (port) { if (!(state->flags & PHP_HTTP_URL_SILENT_ERRORS)) { php_error_docref(NULL, E_WARNING, "Failed to parse port; unexpected char '%c' at pos %u in '%s'", (unsigned char) *ptr, (unsigned) (ptr - tmp), tmp); } if (!(state->flags & PHP_HTTP_URL_IGNORE_ERRORS)) { return FAILURE; } break; } /* no break */ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': /* allowed */ if (port) { state->url.port *= 10; state->url.port += *ptr - '0'; } else { label = ptr; state->buffer[state->offset++] = *ptr; } break; default: if (ptr == end) { break; } else if (port) { if (!(state->flags & PHP_HTTP_URL_SILENT_ERRORS)) { php_error_docref(NULL, E_WARNING, "Failed to parse port; unexpected byte 0x%02x at pos %u in '%s'", (unsigned char) *ptr, (unsigned) (ptr - tmp), tmp); } if (!(state->flags & PHP_HTTP_URL_IGNORE_ERRORS)) { return FAILURE; } break; } else if (!(mb = parse_mb(state, PARSE_HOSTINFO, ptr, end, tmp, 0))) { if (!(state->flags & PHP_HTTP_URL_IGNORE_ERRORS)) { return FAILURE; } break; } label = ptr; ptr += mb - 1; } } while (++ptr < end); if (!state->url.host) { len = state->offset - len; state->url.host = &state->buffer[state->offset - len]; state->buffer[state->offset++] = 0; } if (state->flags & PHP_HTTP_URL_PARSE_TOIDN) { return parse_idna(state, len); } return SUCCESS; } static const char *parse_authority(struct parse_state *state) { const char *tmp = state->ptr, *host = NULL; do { switch (*state->ptr) { case '@': /* userinfo delimiter */ if (host) { if (!(state->flags & PHP_HTTP_URL_SILENT_ERRORS)) { php_error_docref(NULL, E_WARNING, "Failed to parse userinfo; unexpected '@'"); } if (!(state->flags & PHP_HTTP_URL_IGNORE_ERRORS)) { return NULL; } break; } host = state->ptr + 1; if (tmp != state->ptr && SUCCESS != parse_userinfo(state, tmp)) { return NULL; } tmp = state->ptr + 1; break; case '/': case '?': case '#': case '\0': EOD: /* host delimiter */ if (tmp != state->ptr && SUCCESS != parse_hostinfo(state, tmp)) { return NULL; } return state->ptr; } } while (++state->ptr <= state->end); --state->ptr; goto EOD; } static const char *parse_path(struct parse_state *state) { size_t mb; const char *tmp; /* is there actually a path to parse? */ if (!*state->ptr) { return state->ptr; } tmp = state->ptr; state->url.path = &state->buffer[state->offset]; do { switch (*state->ptr) { case '#': case '?': goto done; case '%': if (state->ptr[1] != '%' && (state->end - state->ptr <= 2 || !isxdigit(*(state->ptr+1)) || !isxdigit(*(state->ptr+2)))) { if (!(state->flags & PHP_HTTP_URL_SILENT_ERRORS)) { php_error_docref(NULL, E_WARNING, "Failed to parse path; invalid percent encoding at pos %u in '%s'", (unsigned) (state->ptr - tmp), tmp); } if (!(state->flags & PHP_HTTP_URL_IGNORE_ERRORS)) { return NULL; } state->buffer[state->offset++] = *state->ptr; break; } state->buffer[state->offset++] = *state->ptr++; state->buffer[state->offset++] = *state->ptr++; state->buffer[state->offset++] = *state->ptr; break; case '/': /* yeah, well */ case '!': case '$': case '&': case '\'': case '(': case ')': case '*': case '+': case ',': case ';': case '=': /* sub-delims */ case '-': case '.': case '_': case '~': /* unreserved */ case ':': case '@': /* pchar */ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': /* allowed */ state->buffer[state->offset++] = *state->ptr; break; default: if (!(mb = parse_mb(state, PARSE_PATH, state->ptr, state->end, tmp, 0))) { if (!(state->flags & PHP_HTTP_URL_IGNORE_ERRORS)) { return NULL; } break; } state->ptr += mb - 1; } } while (++state->ptr < state->end); done: /* did we have any path component ? */ if (tmp != state->ptr) { state->buffer[state->offset++] = 0; } else { state->url.path = NULL; } return state->ptr; } static const char *parse_query(struct parse_state *state) { size_t mb; const char *tmp = state->ptr + !!*state->ptr; /* is there actually a query to parse? */ if (*state->ptr != '?') { return state->ptr; } /* skip initial '?' */ tmp = ++state->ptr; state->url.query = &state->buffer[state->offset]; while (state->ptr < state->end) { switch (*state->ptr) { case '#': goto done; case '%': if (state->ptr[1] != '%' && (state->end - state->ptr <= 2 || !isxdigit(*(state->ptr+1)) || !isxdigit(*(state->ptr+2)))) { if (!(state->flags & PHP_HTTP_URL_SILENT_ERRORS)) { php_error_docref(NULL, E_WARNING, "Failed to parse query; invalid percent encoding at pos %u in '%s'", (unsigned) (state->ptr - tmp), tmp); } if (!(state->flags & PHP_HTTP_URL_IGNORE_ERRORS)) { return NULL; } /* fallthrough, pct-encode the percent sign */ } else { state->buffer[state->offset++] = *state->ptr++; state->buffer[state->offset++] = *state->ptr++; state->buffer[state->offset++] = *state->ptr; break; } /* no break */ case '{': case '}': case '<': case '>': case '[': case ']': case '|': case '\\': case '^': case '`': case '"': case ' ': /* RFC1738 unsafe */ if (state->flags & PHP_HTTP_URL_PARSE_TOPCT) { state->buffer[state->offset++] = '%'; state->buffer[state->offset++] = parse_xdigits[((unsigned char) *state->ptr) >> 4]; state->buffer[state->offset++] = parse_xdigits[((unsigned char) *state->ptr) & 0xf]; break; } /* no break */ case '?': case '/': /* yeah, well */ case '!': case '$': case '&': case '\'': case '(': case ')': case '*': case '+': case ',': case ';': case '=': /* sub-delims */ case '-': case '.': case '_': case '~': /* unreserved */ case ':': case '@': /* pchar */ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': /* allowed */ state->buffer[state->offset++] = *state->ptr; break; default: if (!(mb = parse_mb(state, PARSE_QUERY, state->ptr, state->end, tmp, 0))) { if (!(state->flags & PHP_HTTP_URL_IGNORE_ERRORS)) { return NULL; } break; } state->ptr += mb - 1; } ++state->ptr; } done: state->buffer[state->offset++] = 0; return state->ptr; } static const char *parse_fragment(struct parse_state *state) { size_t mb; const char *tmp; /* is there actually a fragment to parse? */ if (*state->ptr != '#') { return state->ptr; } /* skip initial '#' */ tmp = ++state->ptr; state->url.fragment = &state->buffer[state->offset]; do { switch (*state->ptr) { case '#': if (!(state->flags & PHP_HTTP_URL_SILENT_ERRORS)) { php_error_docref(NULL, E_WARNING, "Failed to parse fragment; invalid fragment identifier at pos %u in '%s'", (unsigned) (state->ptr - tmp), tmp); } if (!(state->flags & PHP_HTTP_URL_IGNORE_ERRORS)) { return NULL; } state->buffer[state->offset++] = *state->ptr; break; case '%': if (state->ptr[1] != '%' && (state->end - state->ptr <= 2 || !isxdigit(*(state->ptr+1)) || !isxdigit(*(state->ptr+2)))) { if (!(state->flags & PHP_HTTP_URL_SILENT_ERRORS)) { php_error_docref(NULL, E_WARNING, "Failed to parse fragment; invalid percent encoding at pos %u in '%s'", (unsigned) (state->ptr - tmp), tmp); } if (!(state->flags & PHP_HTTP_URL_IGNORE_ERRORS)) { return NULL; } /* fallthrough */ } else { state->buffer[state->offset++] = *state->ptr++; state->buffer[state->offset++] = *state->ptr++; state->buffer[state->offset++] = *state->ptr; break; } /* no break */ case '{': case '}': case '<': case '>': case '[': case ']': case '|': case '\\': case '^': case '`': case '"': case ' ': /* RFC1738 unsafe */ if (state->flags & PHP_HTTP_URL_PARSE_TOPCT) { state->buffer[state->offset++] = '%'; state->buffer[state->offset++] = parse_xdigits[((unsigned char) *state->ptr) >> 4]; state->buffer[state->offset++] = parse_xdigits[((unsigned char) *state->ptr) & 0xf]; break; } /* no break */ case '?': case '/': case '!': case '$': case '&': case '\'': case '(': case ')': case '*': case '+': case ',': case ';': case '=': /* sub-delims */ case '-': case '.': case '_': case '~': /* unreserved */ case ':': case '@': /* pchar */ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': /* allowed */ state->buffer[state->offset++] = *state->ptr; break; default: if (!(mb = parse_mb(state, PARSE_FRAGMENT, state->ptr, state->end, tmp, 0))) { if (!(state->flags & PHP_HTTP_URL_IGNORE_ERRORS)) { return NULL; } break; } state->ptr += mb - 1; } } while (++state->ptr < state->end); state->buffer[state->offset++] = 0; return state->ptr; } static const char *parse_hier(struct parse_state *state) { if (*state->ptr == '/') { if (state->end - state->ptr > 1) { if (*(state->ptr + 1) == '/') { state->ptr += 2; if (!(state->ptr = parse_authority(state))) { return NULL; } } } } return parse_path(state); } static const char *parse_scheme(struct parse_state *state) { size_t mb; const char *tmp = state->ptr; do { switch (*state->ptr) { case ':': /* scheme delimiter */ state->url.scheme = &state->buffer[0]; state->buffer[state->offset++] = 0; return ++state->ptr; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '+': case '-': case '.': if (state->ptr == tmp) { goto softfail; } /* no break */ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': /* scheme part */ state->buffer[state->offset++] = *state->ptr; break; default: if (!(mb = parse_mb(state, PARSE_SCHEME, state->ptr, state->end, tmp, 1))) { goto softfail; } state->ptr += mb - 1; } } while (++state->ptr < state->end); softfail: state->offset = 0; return state->ptr = tmp; } php_http_url_t *php_http_url_parse(const char *str, size_t len, unsigned flags) { size_t maxlen = 3 * len + 8 /* null bytes for all components */; struct parse_state *state = ecalloc(1, sizeof(*state) + maxlen); state->end = str + len; state->ptr = str; state->flags = flags; state->maxlen = maxlen; if (!parse_scheme(state)) { if (!(flags & PHP_HTTP_URL_SILENT_ERRORS)) { php_error_docref(NULL, E_WARNING, "Failed to parse URL scheme: '%s'", state->ptr); } efree(state); return NULL; } if (!parse_hier(state)) { efree(state); return NULL; } if (!parse_query(state)) { if (!(flags & PHP_HTTP_URL_SILENT_ERRORS)) { php_error_docref(NULL, E_WARNING, "Failed to parse URL query: '%s'", state->ptr); } efree(state); return NULL; } if (!parse_fragment(state)) { if (!(flags & PHP_HTTP_URL_SILENT_ERRORS)) { php_error_docref(NULL, E_WARNING, "Failed to parse URL fragment: '%s'", state->ptr); } efree(state); return NULL; } return (php_http_url_t *) state; } php_http_url_t *php_http_url_parse_authority(const char *str, size_t len, unsigned flags) { size_t maxlen = 3 * len; struct parse_state *state = ecalloc(1, sizeof(*state) + maxlen); state->end = str + len; state->ptr = str; state->flags = flags; state->maxlen = maxlen; if (!(state->ptr = parse_authority(state))) { efree(state); return NULL; } if (state->ptr != state->end) { if (!(state->flags & PHP_HTTP_URL_SILENT_ERRORS)) { php_error_docref(NULL, E_WARNING, "Failed to parse URL authority, unexpected character at pos %u in '%s'", (unsigned) (state->ptr - str), str); } if (!(state->flags & PHP_HTTP_URL_IGNORE_ERRORS)) { efree(state); return NULL; } } return (php_http_url_t *) state; } static zend_class_entry *php_http_url_class_entry; static zend_class_entry *php_http_env_url_class_entry; zend_class_entry *php_http_url_get_class_entry(void) { return php_http_url_class_entry; } zend_class_entry *php_http_get_env_url_class_entry(void) { return php_http_env_url_class_entry; } ZEND_BEGIN_ARG_INFO_EX(ai_HttpUrl___construct, 0, 0, 0) ZEND_ARG_INFO(0, old_url) ZEND_ARG_INFO(0, new_url) ZEND_ARG_INFO(0, flags) ZEND_END_ARG_INFO(); PHP_METHOD(HttpUrl, __construct) { zval *new_url = NULL, *old_url = NULL; zend_long flags = 0; zend_error_handling zeh; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|z!z!l", &old_url, &new_url, &flags), invalid_arg, return); /* always set http\Url::FROM_ENV for instances of http\Env\Url */ if (instanceof_function(Z_OBJCE_P(getThis()), php_http_env_url_class_entry)) { flags |= PHP_HTTP_URL_FROM_ENV; } if (flags & (PHP_HTTP_URL_SILENT_ERRORS|PHP_HTTP_URL_IGNORE_ERRORS)) { zend_replace_error_handling(EH_NORMAL, NULL, &zeh); } else { zend_replace_error_handling(EH_THROW, php_http_get_exception_bad_url_class_entry(), &zeh); } { php_http_url_t *res_purl, *new_purl = NULL, *old_purl = NULL; if (new_url) { new_purl = php_http_url_from_zval(new_url, flags); if (!new_purl) { zend_restore_error_handling(&zeh); return; } } if (old_url) { old_purl = php_http_url_from_zval(old_url, flags); if (!old_purl) { if (new_purl) { php_http_url_free(&new_purl); } zend_restore_error_handling(&zeh); return; } } res_purl = php_http_url_mod(old_purl, new_purl, flags); php_http_url_to_struct(res_purl, getThis()); php_http_url_free(&res_purl); if (old_purl) { php_http_url_free(&old_purl); } if (new_purl) { php_http_url_free(&new_purl); } } zend_restore_error_handling(&zeh); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpUrl_mod, 0, 0, 1) ZEND_ARG_INFO(0, more_url_parts) ZEND_ARG_INFO(0, flags) ZEND_END_ARG_INFO(); PHP_METHOD(HttpUrl, mod) { zval *new_url = NULL; zend_long flags = PHP_HTTP_URL_JOIN_PATH | PHP_HTTP_URL_JOIN_QUERY | PHP_HTTP_URL_SANITIZE_PATH; zend_error_handling zeh; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "z!|l", &new_url, &flags), invalid_arg, return); if (flags & (PHP_HTTP_URL_SILENT_ERRORS|PHP_HTTP_URL_IGNORE_ERRORS)) { zend_replace_error_handling(EH_NORMAL, NULL, &zeh); } else { zend_replace_error_handling(EH_THROW, php_http_get_exception_bad_url_class_entry(), &zeh); } { php_http_url_t *new_purl = NULL, *old_purl = NULL; if (new_url) { new_purl = php_http_url_from_zval(new_url, flags); if (!new_purl) { zend_restore_error_handling(&zeh); return; } } if ((old_purl = php_http_url_from_struct(HASH_OF(getThis())))) { php_http_url_t *res_purl; ZVAL_OBJ(return_value, zend_objects_clone_obj(Z_OBJ_P(getThis()))); res_purl = php_http_url_mod(old_purl, new_purl, flags); php_http_url_to_struct(res_purl, return_value); php_http_url_free(&res_purl); php_http_url_free(&old_purl); } if (new_purl) { php_http_url_free(&new_purl); } } zend_restore_error_handling(&zeh); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpUrl_toString, 0, 0, 0) ZEND_END_ARG_INFO(); PHP_METHOD(HttpUrl, toString) { if (SUCCESS == zend_parse_parameters_none()) { php_http_url_t *purl; if ((purl = php_http_url_from_struct(HASH_OF(getThis())))) { char *str; size_t len; php_http_url_to_string(purl, &str, &len, 0); php_http_url_free(&purl); RETURN_STR(php_http_cs2zs(str, len)); } } RETURN_EMPTY_STRING(); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpUrl_toArray, 0, 0, 0) ZEND_END_ARG_INFO(); PHP_METHOD(HttpUrl, toArray) { php_http_url_t *purl; if (SUCCESS != zend_parse_parameters_none()) { return; } /* strip any non-URL properties */ purl = php_http_url_from_struct(HASH_OF(getThis())); php_http_url_to_struct(purl, return_value); php_http_url_free(&purl); } static zend_function_entry php_http_url_methods[] = { PHP_ME(HttpUrl, __construct, ai_HttpUrl___construct, ZEND_ACC_PUBLIC) PHP_ME(HttpUrl, mod, ai_HttpUrl_mod, ZEND_ACC_PUBLIC) PHP_ME(HttpUrl, toString, ai_HttpUrl_toString, ZEND_ACC_PUBLIC) ZEND_MALIAS(HttpUrl, __toString, toString, ai_HttpUrl_toString, ZEND_ACC_PUBLIC) PHP_ME(HttpUrl, toArray, ai_HttpUrl_toArray, ZEND_ACC_PUBLIC) EMPTY_FUNCTION_ENTRY }; PHP_MINIT_FUNCTION(http_url) { zend_class_entry ce = {0}; INIT_NS_CLASS_ENTRY(ce, "http", "Url", php_http_url_methods); php_http_url_class_entry = zend_register_internal_class(&ce); zend_declare_property_null(php_http_url_class_entry, ZEND_STRL("scheme"), ZEND_ACC_PUBLIC); zend_declare_property_null(php_http_url_class_entry, ZEND_STRL("user"), ZEND_ACC_PUBLIC); zend_declare_property_null(php_http_url_class_entry, ZEND_STRL("pass"), ZEND_ACC_PUBLIC); zend_declare_property_null(php_http_url_class_entry, ZEND_STRL("host"), ZEND_ACC_PUBLIC); zend_declare_property_null(php_http_url_class_entry, ZEND_STRL("port"), ZEND_ACC_PUBLIC); zend_declare_property_null(php_http_url_class_entry, ZEND_STRL("path"), ZEND_ACC_PUBLIC); zend_declare_property_null(php_http_url_class_entry, ZEND_STRL("query"), ZEND_ACC_PUBLIC); zend_declare_property_null(php_http_url_class_entry, ZEND_STRL("fragment"), ZEND_ACC_PUBLIC); zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("REPLACE"), PHP_HTTP_URL_REPLACE); zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("JOIN_PATH"), PHP_HTTP_URL_JOIN_PATH); zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("JOIN_QUERY"), PHP_HTTP_URL_JOIN_QUERY); zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STRIP_USER"), PHP_HTTP_URL_STRIP_USER); zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STRIP_PASS"), PHP_HTTP_URL_STRIP_PASS); zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STRIP_AUTH"), PHP_HTTP_URL_STRIP_AUTH); zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STRIP_PORT"), PHP_HTTP_URL_STRIP_PORT); zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STRIP_PATH"), PHP_HTTP_URL_STRIP_PATH); zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STRIP_QUERY"), PHP_HTTP_URL_STRIP_QUERY); zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STRIP_FRAGMENT"), PHP_HTTP_URL_STRIP_FRAGMENT); zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STRIP_ALL"), PHP_HTTP_URL_STRIP_ALL); zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("FROM_ENV"), PHP_HTTP_URL_FROM_ENV); zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("SANITIZE_PATH"), PHP_HTTP_URL_SANITIZE_PATH); #if PHP_HTTP_HAVE_WCHAR zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("PARSE_MBLOC"), PHP_HTTP_URL_PARSE_MBLOC); #endif zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("PARSE_MBUTF8"), PHP_HTTP_URL_PARSE_MBUTF8); #if PHP_HTTP_HAVE_LIBIDN2 || PHP_HTTP_HAVE_LIBIDN || PHP_HTTP_HAVE_LIBIDNKIT || PHP_HTTP_HAVE_LIBIDNKIT2 || HAVE_UIDNA_IDNTOASCII || HAVE_UIDNA_NAMETOASCII_UTF8 zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("PARSE_TOIDN"), PHP_HTTP_URL_PARSE_TOIDN); # if PHP_HTTP_HAVE_IDNA2003 zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("PARSE_TOIDN_2003"), PHP_HTTP_URL_PARSE_TOIDN_2003); # endif # if PHP_HTTP_HAVE_IDNA2008 zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("PARSE_TOIDN_2008"), PHP_HTTP_URL_PARSE_TOIDN_2008); # endif #endif zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("PARSE_TOPCT"), PHP_HTTP_URL_PARSE_TOPCT); zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("IGNORE_ERRORS"), PHP_HTTP_URL_IGNORE_ERRORS); zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("SILENT_ERRORS"), PHP_HTTP_URL_SILENT_ERRORS); zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STDFLAGS"), PHP_HTTP_URL_STDFLAGS); INIT_NS_CLASS_ENTRY(ce, "http\\Env", "Url", NULL); php_http_env_url_class_entry = zend_register_internal_class_ex(&ce, php_http_url_class_entry); 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 */ pecl_http-4.2.1/src/php_http_url.h0000644000076500000240000001107014117626035015724 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_HTTP_URL_H #define PHP_HTTP_URL_H #include "ext/standard/url.h" /* php_http_url_mod() */ #define PHP_HTTP_URL_REPLACE 0x000 #define PHP_HTTP_URL_JOIN_PATH 0x001 #define PHP_HTTP_URL_JOIN_QUERY 0x002 #define PHP_HTTP_URL_STRIP_USER 0x004 #define PHP_HTTP_URL_STRIP_PASS 0x008 #define PHP_HTTP_URL_STRIP_AUTH (PHP_HTTP_URL_STRIP_USER|PHP_HTTP_URL_STRIP_PASS) #define PHP_HTTP_URL_STRIP_PORT 0x020 #define PHP_HTTP_URL_STRIP_PATH 0x040 #define PHP_HTTP_URL_STRIP_QUERY 0x080 #define PHP_HTTP_URL_STRIP_FRAGMENT 0x100 #define PHP_HTTP_URL_STRIP_ALL ( \ PHP_HTTP_URL_STRIP_AUTH | \ PHP_HTTP_URL_STRIP_PORT | \ PHP_HTTP_URL_STRIP_PATH | \ PHP_HTTP_URL_STRIP_QUERY | \ PHP_HTTP_URL_STRIP_FRAGMENT \ ) #define PHP_HTTP_URL_FROM_ENV 0x1000 #define PHP_HTTP_URL_SANITIZE_PATH 0x2000 /* parse multibyte according to locale */ #define PHP_HTTP_URL_PARSE_MBLOC 0x10000 /* parse utf8 multibyte sequences */ #define PHP_HTTP_URL_PARSE_MBUTF8 0x20000 /* convert multibyte hostnames to IDNA */ #define PHP_HTTP_URL_PARSE_TOIDN 0x100000 /* percent encode multibyte sequences in userinfo, path, query and fragment */ #define PHP_HTTP_URL_PARSE_TOPCT 0x200000 #if PHP_HTTP_HAVE_IDNA2008 #define PHP_HTTP_URL_PARSE_TOIDN_2008 \ (PHP_HTTP_URL_PARSE_TOIDN | 0x400000) #endif #if PHP_HTTP_HAVE_IDNA2003 #define PHP_HTTP_URL_PARSE_TOIDN_2003 \ (PHP_HTTP_URL_PARSE_TOIDN | 0x800000) #endif /* ignore errors */ #define PHP_HTTP_URL_IGNORE_ERRORS 0x10000000 /* do not report errors */ #define PHP_HTTP_URL_SILENT_ERRORS 0x20000000 #define PHP_HTTP_URL_STDFLAGS 0x00332003 typedef struct php_http_url { char *scheme; char *user; char *pass; char *host; unsigned short port; char *path; char *query; char *fragment; } php_http_url_t; PHP_HTTP_API php_http_url_t *php_http_url_parse(const char *str, size_t len, unsigned flags); PHP_HTTP_API php_http_url_t *php_http_url_parse_authority(const char *str, size_t len, unsigned flags); PHP_HTTP_API php_http_url_t *php_http_url_mod(const php_http_url_t *old_url, const php_http_url_t *new_url, unsigned flags); PHP_HTTP_API php_http_url_t *php_http_url_copy(const php_http_url_t *url, zend_bool persistent); PHP_HTTP_API php_http_url_t *php_http_url_from_struct(HashTable *ht); PHP_HTTP_API php_http_url_t *php_http_url_from_zval(zval *value, unsigned flags); PHP_HTTP_API HashTable *php_http_url_to_struct(const php_http_url_t *url, zval *strct); PHP_HTTP_API char *php_http_url_to_string(const php_http_url_t *url, char **url_str, size_t *url_len, zend_bool persistent); PHP_HTTP_API char *php_http_url_authority_to_string(const php_http_url_t *url, char **url_str, size_t *url_len); PHP_HTTP_API void php_http_url_free(php_http_url_t **url); PHP_HTTP_API ZEND_RESULT_CODE php_http_url_encode_hash(HashTable *hash, const char *pre_encoded_str, size_t pre_encoded_len, char **encoded_str, size_t *encoded_len); PHP_HTTP_API ZEND_RESULT_CODE php_http_url_encode_hash_ex(HashTable *hash, php_http_buffer_t *qstr, const char *arg_sep_str, size_t arg_sep_len, const char *val_sep_str, size_t val_sep_len, const char *pre_encoded_str, size_t pre_encoded_len); static inline void php_http_url_argsep(const char **str, size_t *len) { if (SUCCESS != php_http_ini_entry(ZEND_STRL("arg_separator.output"), str, len, 0) || !*len) { *str = PHP_HTTP_URL_ARGSEP; *len = lenof(PHP_HTTP_URL_ARGSEP); } } static inline zend_bool php_http_url_is_empty(const php_http_url_t *url) { return !(url->scheme || url->pass || url->user || url->host || url->port || url->path || url->query || url->fragment); } PHP_HTTP_API zend_class_entry *php_http_url_get_class_entry(void); PHP_HTTP_API zend_class_entry *php_http_get_env_url_class_entry(void); PHP_MINIT_FUNCTION(http_url); #define php_http_url_object_new php_http_object_new #define php_http_url_object_new_ex php_http_object_new_ex #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 */ pecl_http-4.2.1/src/php_http_utf8.h0000644000076500000240000005105714117626035016021 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_HTTP_UTF8_H #define PHP_HTTP_UTF8_H static const unsigned char utf8_mblen[256] = { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, 4,4,4,4,4,4,4,4,5,5,5,5,6,6,6,6 }; static const unsigned char utf8_mask[] = { 0, 0x7f, 0x1f, 0x0f, 0x07, 0x03, 0x01 }; typedef struct utf8_range { const unsigned int start; const unsigned int end; } utf8_range_t; /* BEGIN::UTF8TABLE */ static const utf8_range_t utf8_ranges[] = { {0x00000041, 0x0000005A}, {0x00000061, 0x0000007A}, {0x000000C0, 0x000000D6}, {0x000000D8, 0x000000F6}, {0x000000F8, 0x000002C1}, {0x000002C6, 0x000002D1}, {0x000002E0, 0x000002E4}, {0x00000370, 0x00000374}, {0x00000376, 0x00000377}, {0x0000037A, 0x0000037D}, {0x00000388, 0x0000038A}, {0x0000038E, 0x000003A1}, {0x000003A3, 0x000003F5}, {0x000003F7, 0x00000481}, {0x0000048A, 0x0000052F}, {0x00000531, 0x00000556}, {0x00000561, 0x00000587}, {0x000005B0, 0x000005BD}, {0x000005C1, 0x000005C2}, {0x000005C4, 0x000005C5}, {0x000005D0, 0x000005EA}, {0x000005F0, 0x000005F2}, {0x00000610, 0x0000061A}, {0x00000620, 0x00000657}, {0x00000659, 0x00000669}, {0x0000066E, 0x000006D3}, {0x000006D5, 0x000006DC}, {0x000006E1, 0x000006E8}, {0x000006ED, 0x000006FC}, {0x00000710, 0x0000073F}, {0x0000074D, 0x000007B1}, {0x000007C0, 0x000007EA}, {0x000007F4, 0x000007F5}, {0x00000800, 0x00000817}, {0x0000081A, 0x0000082C}, {0x00000840, 0x00000858}, {0x00000860, 0x0000086A}, {0x000008A0, 0x000008B4}, {0x000008B6, 0x000008BD}, {0x000008D4, 0x000008DF}, {0x000008E3, 0x000008E9}, {0x000008F0, 0x0000093B}, {0x0000093D, 0x0000094C}, {0x0000094E, 0x00000950}, {0x00000955, 0x00000963}, {0x00000966, 0x0000096F}, {0x00000971, 0x00000983}, {0x00000985, 0x0000098C}, {0x0000098F, 0x00000990}, {0x00000993, 0x000009A8}, {0x000009AA, 0x000009B0}, {0x000009B6, 0x000009B9}, {0x000009BD, 0x000009C4}, {0x000009C7, 0x000009C8}, {0x000009CB, 0x000009CC}, {0x000009DC, 0x000009DD}, {0x000009DF, 0x000009E3}, {0x000009E6, 0x000009F1}, {0x00000A01, 0x00000A03}, {0x00000A05, 0x00000A0A}, {0x00000A0F, 0x00000A10}, {0x00000A13, 0x00000A28}, {0x00000A2A, 0x00000A30}, {0x00000A32, 0x00000A33}, {0x00000A35, 0x00000A36}, {0x00000A38, 0x00000A39}, {0x00000A3E, 0x00000A42}, {0x00000A47, 0x00000A48}, {0x00000A4B, 0x00000A4C}, {0x00000A59, 0x00000A5C}, {0x00000A66, 0x00000A75}, {0x00000A81, 0x00000A83}, {0x00000A85, 0x00000A8D}, {0x00000A8F, 0x00000A91}, {0x00000A93, 0x00000AA8}, {0x00000AAA, 0x00000AB0}, {0x00000AB2, 0x00000AB3}, {0x00000AB5, 0x00000AB9}, {0x00000ABD, 0x00000AC5}, {0x00000AC7, 0x00000AC9}, {0x00000ACB, 0x00000ACC}, {0x00000AE0, 0x00000AE3}, {0x00000AE6, 0x00000AEF}, {0x00000AF9, 0x00000AFC}, {0x00000B01, 0x00000B03}, {0x00000B05, 0x00000B0C}, {0x00000B0F, 0x00000B10}, {0x00000B13, 0x00000B28}, {0x00000B2A, 0x00000B30}, {0x00000B32, 0x00000B33}, {0x00000B35, 0x00000B39}, {0x00000B3D, 0x00000B44}, {0x00000B47, 0x00000B48}, {0x00000B4B, 0x00000B4C}, {0x00000B56, 0x00000B57}, {0x00000B5C, 0x00000B5D}, {0x00000B5F, 0x00000B63}, {0x00000B66, 0x00000B6F}, {0x00000B82, 0x00000B83}, {0x00000B85, 0x00000B8A}, {0x00000B8E, 0x00000B90}, {0x00000B92, 0x00000B95}, {0x00000B99, 0x00000B9A}, {0x00000B9E, 0x00000B9F}, {0x00000BA3, 0x00000BA4}, {0x00000BA8, 0x00000BAA}, {0x00000BAE, 0x00000BB9}, {0x00000BBE, 0x00000BC2}, {0x00000BC6, 0x00000BC8}, {0x00000BCA, 0x00000BCC}, {0x00000BE6, 0x00000BEF}, {0x00000C00, 0x00000C03}, {0x00000C05, 0x00000C0C}, {0x00000C0E, 0x00000C10}, {0x00000C12, 0x00000C28}, {0x00000C2A, 0x00000C39}, {0x00000C3D, 0x00000C44}, {0x00000C46, 0x00000C48}, {0x00000C4A, 0x00000C4C}, {0x00000C55, 0x00000C56}, {0x00000C58, 0x00000C5A}, {0x00000C60, 0x00000C63}, {0x00000C66, 0x00000C6F}, {0x00000C80, 0x00000C83}, {0x00000C85, 0x00000C8C}, {0x00000C8E, 0x00000C90}, {0x00000C92, 0x00000CA8}, {0x00000CAA, 0x00000CB3}, {0x00000CB5, 0x00000CB9}, {0x00000CBD, 0x00000CC4}, {0x00000CC6, 0x00000CC8}, {0x00000CCA, 0x00000CCC}, {0x00000CD5, 0x00000CD6}, {0x00000CE0, 0x00000CE3}, {0x00000CE6, 0x00000CEF}, {0x00000CF1, 0x00000CF2}, {0x00000D00, 0x00000D03}, {0x00000D05, 0x00000D0C}, {0x00000D0E, 0x00000D10}, {0x00000D12, 0x00000D3A}, {0x00000D3D, 0x00000D44}, {0x00000D46, 0x00000D48}, {0x00000D4A, 0x00000D4C}, {0x00000D54, 0x00000D57}, {0x00000D5F, 0x00000D63}, {0x00000D66, 0x00000D6F}, {0x00000D7A, 0x00000D7F}, {0x00000D82, 0x00000D83}, {0x00000D85, 0x00000D96}, {0x00000D9A, 0x00000DB1}, {0x00000DB3, 0x00000DBB}, {0x00000DC0, 0x00000DC6}, {0x00000DCF, 0x00000DD4}, {0x00000DD8, 0x00000DDF}, {0x00000DE6, 0x00000DEF}, {0x00000DF2, 0x00000DF3}, {0x00000E01, 0x00000E3A}, {0x00000E40, 0x00000E46}, {0x00000E50, 0x00000E59}, {0x00000E81, 0x00000E82}, {0x00000E87, 0x00000E88}, {0x00000E94, 0x00000E97}, {0x00000E99, 0x00000E9F}, {0x00000EA1, 0x00000EA3}, {0x00000EAA, 0x00000EAB}, {0x00000EAD, 0x00000EB9}, {0x00000EBB, 0x00000EBD}, {0x00000EC0, 0x00000EC4}, {0x00000ED0, 0x00000ED9}, {0x00000EDC, 0x00000EDF}, {0x00000F20, 0x00000F29}, {0x00000F40, 0x00000F47}, {0x00000F49, 0x00000F6C}, {0x00000F71, 0x00000F81}, {0x00000F88, 0x00000F97}, {0x00000F99, 0x00000FBC}, {0x00001000, 0x00001036}, {0x0000103B, 0x00001049}, {0x00001050, 0x00001062}, {0x00001065, 0x00001068}, {0x0000106E, 0x00001086}, {0x00001090, 0x00001099}, {0x0000109C, 0x0000109D}, {0x000010A0, 0x000010C5}, {0x000010D0, 0x000010FA}, {0x000010FC, 0x00001248}, {0x0000124A, 0x0000124D}, {0x00001250, 0x00001256}, {0x0000125A, 0x0000125D}, {0x00001260, 0x00001288}, {0x0000128A, 0x0000128D}, {0x00001290, 0x000012B0}, {0x000012B2, 0x000012B5}, {0x000012B8, 0x000012BE}, {0x000012C2, 0x000012C5}, {0x000012C8, 0x000012D6}, {0x000012D8, 0x00001310}, {0x00001312, 0x00001315}, {0x00001318, 0x0000135A}, {0x00001380, 0x0000138F}, {0x000013A0, 0x000013F5}, {0x000013F8, 0x000013FD}, {0x00001401, 0x0000166C}, {0x0000166F, 0x0000167F}, {0x00001681, 0x0000169A}, {0x000016A0, 0x000016EA}, {0x000016EE, 0x000016F8}, {0x00001700, 0x0000170C}, {0x0000170E, 0x00001713}, {0x00001720, 0x00001733}, {0x00001740, 0x00001753}, {0x00001760, 0x0000176C}, {0x0000176E, 0x00001770}, {0x00001772, 0x00001773}, {0x00001780, 0x000017B3}, {0x000017B6, 0x000017C8}, {0x000017E0, 0x000017E9}, {0x00001810, 0x00001819}, {0x00001820, 0x00001877}, {0x00001880, 0x000018AA}, {0x000018B0, 0x000018F5}, {0x00001900, 0x0000191E}, {0x00001920, 0x0000192B}, {0x00001930, 0x00001938}, {0x00001946, 0x0000196D}, {0x00001970, 0x00001974}, {0x00001980, 0x000019AB}, {0x000019B0, 0x000019C9}, {0x000019D0, 0x000019D9}, {0x00001A00, 0x00001A1B}, {0x00001A20, 0x00001A5E}, {0x00001A61, 0x00001A74}, {0x00001A80, 0x00001A89}, {0x00001A90, 0x00001A99}, {0x00001B00, 0x00001B33}, {0x00001B35, 0x00001B43}, {0x00001B45, 0x00001B4B}, {0x00001B50, 0x00001B59}, {0x00001B80, 0x00001BA9}, {0x00001BAC, 0x00001BE5}, {0x00001BE7, 0x00001BF1}, {0x00001C00, 0x00001C35}, {0x00001C40, 0x00001C49}, {0x00001C4D, 0x00001C7D}, {0x00001C80, 0x00001C88}, {0x00001CE9, 0x00001CEC}, {0x00001CEE, 0x00001CF3}, {0x00001CF5, 0x00001CF6}, {0x00001D00, 0x00001DBF}, {0x00001DE7, 0x00001DF4}, {0x00001E00, 0x00001F15}, {0x00001F18, 0x00001F1D}, {0x00001F20, 0x00001F45}, {0x00001F48, 0x00001F4D}, {0x00001F50, 0x00001F57}, {0x00001F5F, 0x00001F7D}, {0x00001F80, 0x00001FB4}, {0x00001FB6, 0x00001FBC}, {0x00001FC2, 0x00001FC4}, {0x00001FC6, 0x00001FCC}, {0x00001FD0, 0x00001FD3}, {0x00001FD6, 0x00001FDB}, {0x00001FE0, 0x00001FEC}, {0x00001FF2, 0x00001FF4}, {0x00001FF6, 0x00001FFC}, {0x00002090, 0x0000209C}, {0x0000210A, 0x00002113}, {0x00002119, 0x0000211D}, {0x0000212A, 0x0000212D}, {0x0000212F, 0x00002139}, {0x0000213C, 0x0000213F}, {0x00002145, 0x00002149}, {0x00002160, 0x00002188}, {0x000024B6, 0x000024E9}, {0x00002C00, 0x00002C2E}, {0x00002C30, 0x00002C5E}, {0x00002C60, 0x00002CE4}, {0x00002CEB, 0x00002CEE}, {0x00002CF2, 0x00002CF3}, {0x00002D00, 0x00002D25}, {0x00002D30, 0x00002D67}, {0x00002D80, 0x00002D96}, {0x00002DA0, 0x00002DA6}, {0x00002DA8, 0x00002DAE}, {0x00002DB0, 0x00002DB6}, {0x00002DB8, 0x00002DBE}, {0x00002DC0, 0x00002DC6}, {0x00002DC8, 0x00002DCE}, {0x00002DD0, 0x00002DD6}, {0x00002DD8, 0x00002DDE}, {0x00002DE0, 0x00002DFF}, {0x00003005, 0x00003007}, {0x00003021, 0x00003029}, {0x00003031, 0x00003035}, {0x00003038, 0x0000303C}, {0x00003041, 0x00003096}, {0x0000309D, 0x0000309F}, {0x000030A1, 0x000030FA}, {0x000030FC, 0x000030FF}, {0x00003105, 0x0000312E}, {0x00003131, 0x0000318E}, {0x000031A0, 0x000031BA}, {0x000031F0, 0x000031FF}, {0x00003400, 0x00004DB5}, {0x00004E00, 0x00009FEA}, {0x0000A000, 0x0000A48C}, {0x0000A4D0, 0x0000A4FD}, {0x0000A500, 0x0000A60C}, {0x0000A610, 0x0000A62B}, {0x0000A640, 0x0000A66E}, {0x0000A674, 0x0000A67B}, {0x0000A67F, 0x0000A6EF}, {0x0000A717, 0x0000A71F}, {0x0000A722, 0x0000A788}, {0x0000A78B, 0x0000A7AE}, {0x0000A7B0, 0x0000A7B7}, {0x0000A7F7, 0x0000A801}, {0x0000A803, 0x0000A805}, {0x0000A807, 0x0000A80A}, {0x0000A80C, 0x0000A827}, {0x0000A840, 0x0000A873}, {0x0000A880, 0x0000A8C3}, {0x0000A8D0, 0x0000A8D9}, {0x0000A8F2, 0x0000A8F7}, {0x0000A900, 0x0000A92A}, {0x0000A930, 0x0000A952}, {0x0000A960, 0x0000A97C}, {0x0000A980, 0x0000A9B2}, {0x0000A9B4, 0x0000A9BF}, {0x0000A9CF, 0x0000A9D9}, {0x0000A9E0, 0x0000A9E4}, {0x0000A9E6, 0x0000A9FE}, {0x0000AA00, 0x0000AA36}, {0x0000AA40, 0x0000AA4D}, {0x0000AA50, 0x0000AA59}, {0x0000AA60, 0x0000AA76}, {0x0000AA7E, 0x0000AABE}, {0x0000AADB, 0x0000AADD}, {0x0000AAE0, 0x0000AAEF}, {0x0000AAF2, 0x0000AAF5}, {0x0000AB01, 0x0000AB06}, {0x0000AB09, 0x0000AB0E}, {0x0000AB11, 0x0000AB16}, {0x0000AB20, 0x0000AB26}, {0x0000AB28, 0x0000AB2E}, {0x0000AB30, 0x0000AB5A}, {0x0000AB5C, 0x0000AB65}, {0x0000AB70, 0x0000ABEA}, {0x0000ABF0, 0x0000ABF9}, {0x0000AC00, 0x0000D7A3}, {0x0000D7B0, 0x0000D7C6}, {0x0000D7CB, 0x0000D7FB}, {0x0000F900, 0x0000FA6D}, {0x0000FA70, 0x0000FAD9}, {0x0000FB00, 0x0000FB06}, {0x0000FB13, 0x0000FB17}, {0x0000FB1D, 0x0000FB28}, {0x0000FB2A, 0x0000FB36}, {0x0000FB38, 0x0000FB3C}, {0x0000FB40, 0x0000FB41}, {0x0000FB43, 0x0000FB44}, {0x0000FB46, 0x0000FBB1}, {0x0000FBD3, 0x0000FD3D}, {0x0000FD50, 0x0000FD8F}, {0x0000FD92, 0x0000FDC7}, {0x0000FDF0, 0x0000FDFB}, {0x0000FE70, 0x0000FE74}, {0x0000FE76, 0x0000FEFC}, {0x0000FF10, 0x0000FF19}, {0x0000FF21, 0x0000FF3A}, {0x0000FF41, 0x0000FF5A}, {0x0000FF66, 0x0000FFBE}, {0x0000FFC2, 0x0000FFC7}, {0x0000FFCA, 0x0000FFCF}, {0x0000FFD2, 0x0000FFD7}, {0x0000FFDA, 0x0000FFDC}, {0x00010000, 0x0001000B}, {0x0001000D, 0x00010026}, {0x00010028, 0x0001003A}, {0x0001003C, 0x0001003D}, {0x0001003F, 0x0001004D}, {0x00010050, 0x0001005D}, {0x00010080, 0x000100FA}, {0x00010140, 0x00010174}, {0x00010280, 0x0001029C}, {0x000102A0, 0x000102D0}, {0x00010300, 0x0001031F}, {0x0001032D, 0x0001034A}, {0x00010350, 0x0001037A}, {0x00010380, 0x0001039D}, {0x000103A0, 0x000103C3}, {0x000103C8, 0x000103CF}, {0x000103D1, 0x000103D5}, {0x00010400, 0x0001049D}, {0x000104A0, 0x000104A9}, {0x000104B0, 0x000104D3}, {0x000104D8, 0x000104FB}, {0x00010500, 0x00010527}, {0x00010530, 0x00010563}, {0x00010600, 0x00010736}, {0x00010740, 0x00010755}, {0x00010760, 0x00010767}, {0x00010800, 0x00010805}, {0x0001080A, 0x00010835}, {0x00010837, 0x00010838}, {0x0001083F, 0x00010855}, {0x00010860, 0x00010876}, {0x00010880, 0x0001089E}, {0x000108E0, 0x000108F2}, {0x000108F4, 0x000108F5}, {0x00010900, 0x00010915}, {0x00010920, 0x00010939}, {0x00010980, 0x000109B7}, {0x000109BE, 0x000109BF}, {0x00010A00, 0x00010A03}, {0x00010A05, 0x00010A06}, {0x00010A0C, 0x00010A13}, {0x00010A15, 0x00010A17}, {0x00010A19, 0x00010A33}, {0x00010A60, 0x00010A7C}, {0x00010A80, 0x00010A9C}, {0x00010AC0, 0x00010AC7}, {0x00010AC9, 0x00010AE4}, {0x00010B00, 0x00010B35}, {0x00010B40, 0x00010B55}, {0x00010B60, 0x00010B72}, {0x00010B80, 0x00010B91}, {0x00010C00, 0x00010C48}, {0x00010C80, 0x00010CB2}, {0x00010CC0, 0x00010CF2}, {0x00011000, 0x00011045}, {0x00011066, 0x0001106F}, {0x00011082, 0x000110B8}, {0x000110D0, 0x000110E8}, {0x000110F0, 0x000110F9}, {0x00011100, 0x00011132}, {0x00011136, 0x0001113F}, {0x00011150, 0x00011172}, {0x00011180, 0x000111BF}, {0x000111C1, 0x000111C4}, {0x000111D0, 0x000111DA}, {0x00011200, 0x00011211}, {0x00011213, 0x00011234}, {0x00011280, 0x00011286}, {0x0001128A, 0x0001128D}, {0x0001128F, 0x0001129D}, {0x0001129F, 0x000112A8}, {0x000112B0, 0x000112E8}, {0x000112F0, 0x000112F9}, {0x00011300, 0x00011303}, {0x00011305, 0x0001130C}, {0x0001130F, 0x00011310}, {0x00011313, 0x00011328}, {0x0001132A, 0x00011330}, {0x00011332, 0x00011333}, {0x00011335, 0x00011339}, {0x0001133D, 0x00011344}, {0x00011347, 0x00011348}, {0x0001134B, 0x0001134C}, {0x0001135D, 0x00011363}, {0x00011400, 0x00011441}, {0x00011443, 0x00011445}, {0x00011447, 0x0001144A}, {0x00011450, 0x00011459}, {0x00011480, 0x000114C1}, {0x000114C4, 0x000114C5}, {0x000114D0, 0x000114D9}, {0x00011580, 0x000115B5}, {0x000115B8, 0x000115BE}, {0x000115D8, 0x000115DD}, {0x00011600, 0x0001163E}, {0x00011650, 0x00011659}, {0x00011680, 0x000116B5}, {0x000116C0, 0x000116C9}, {0x00011700, 0x00011719}, {0x0001171D, 0x0001172A}, {0x00011730, 0x00011739}, {0x000118A0, 0x000118E9}, {0x00011A00, 0x00011A32}, {0x00011A35, 0x00011A3E}, {0x00011A50, 0x00011A83}, {0x00011A86, 0x00011A97}, {0x00011AC0, 0x00011AF8}, {0x00011C00, 0x00011C08}, {0x00011C0A, 0x00011C36}, {0x00011C38, 0x00011C3E}, {0x00011C50, 0x00011C59}, {0x00011C72, 0x00011C8F}, {0x00011C92, 0x00011CA7}, {0x00011CA9, 0x00011CB6}, {0x00011D00, 0x00011D06}, {0x00011D08, 0x00011D09}, {0x00011D0B, 0x00011D36}, {0x00011D3C, 0x00011D3D}, {0x00011D3F, 0x00011D41}, {0x00011D46, 0x00011D47}, {0x00011D50, 0x00011D59}, {0x00012000, 0x00012399}, {0x00012400, 0x0001246E}, {0x00012480, 0x00012543}, {0x00013000, 0x0001342E}, {0x00014400, 0x00014646}, {0x00016800, 0x00016A38}, {0x00016A40, 0x00016A5E}, {0x00016A60, 0x00016A69}, {0x00016AD0, 0x00016AED}, {0x00016B00, 0x00016B36}, {0x00016B40, 0x00016B43}, {0x00016B50, 0x00016B59}, {0x00016B63, 0x00016B77}, {0x00016B7D, 0x00016B8F}, {0x00016F00, 0x00016F44}, {0x00016F50, 0x00016F7E}, {0x00016F93, 0x00016F9F}, {0x00016FE0, 0x00016FE1}, {0x00017000, 0x000187EC}, {0x00018800, 0x00018AF2}, {0x0001B000, 0x0001B11E}, {0x0001B170, 0x0001B2FB}, {0x0001BC00, 0x0001BC6A}, {0x0001BC70, 0x0001BC7C}, {0x0001BC80, 0x0001BC88}, {0x0001BC90, 0x0001BC99}, {0x0001D400, 0x0001D454}, {0x0001D456, 0x0001D49C}, {0x0001D49E, 0x0001D49F}, {0x0001D4A5, 0x0001D4A6}, {0x0001D4A9, 0x0001D4AC}, {0x0001D4AE, 0x0001D4B9}, {0x0001D4BD, 0x0001D4C3}, {0x0001D4C5, 0x0001D505}, {0x0001D507, 0x0001D50A}, {0x0001D50D, 0x0001D514}, {0x0001D516, 0x0001D51C}, {0x0001D51E, 0x0001D539}, {0x0001D53B, 0x0001D53E}, {0x0001D540, 0x0001D544}, {0x0001D54A, 0x0001D550}, {0x0001D552, 0x0001D6A5}, {0x0001D6A8, 0x0001D6C0}, {0x0001D6C2, 0x0001D6DA}, {0x0001D6DC, 0x0001D6FA}, {0x0001D6FC, 0x0001D714}, {0x0001D716, 0x0001D734}, {0x0001D736, 0x0001D74E}, {0x0001D750, 0x0001D76E}, {0x0001D770, 0x0001D788}, {0x0001D78A, 0x0001D7A8}, {0x0001D7AA, 0x0001D7C2}, {0x0001D7C4, 0x0001D7CB}, {0x0001D7CE, 0x0001D7FF}, {0x0001E000, 0x0001E006}, {0x0001E008, 0x0001E018}, {0x0001E01B, 0x0001E021}, {0x0001E023, 0x0001E024}, {0x0001E026, 0x0001E02A}, {0x0001E800, 0x0001E8C4}, {0x0001E900, 0x0001E943}, {0x0001E950, 0x0001E959}, {0x0001EE00, 0x0001EE03}, {0x0001EE05, 0x0001EE1F}, {0x0001EE21, 0x0001EE22}, {0x0001EE29, 0x0001EE32}, {0x0001EE34, 0x0001EE37}, {0x0001EE4D, 0x0001EE4F}, {0x0001EE51, 0x0001EE52}, {0x0001EE61, 0x0001EE62}, {0x0001EE67, 0x0001EE6A}, {0x0001EE6C, 0x0001EE72}, {0x0001EE74, 0x0001EE77}, {0x0001EE79, 0x0001EE7C}, {0x0001EE80, 0x0001EE89}, {0x0001EE8B, 0x0001EE9B}, {0x0001EEA1, 0x0001EEA3}, {0x0001EEA5, 0x0001EEA9}, {0x0001EEAB, 0x0001EEBB}, {0x0001F130, 0x0001F149}, {0x0001F150, 0x0001F169}, {0x0001F170, 0x0001F189}, {0x00020000, 0x0002A6D6}, {0x0002A700, 0x0002B734}, {0x0002B740, 0x0002B81D}, {0x0002B820, 0x0002CEA1}, {0x0002CEB0, 0x0002EBE0}, {0x0002F800, 0x0002FA1D} }; static const unsigned utf8_chars[] = { 0x000000AA, 0x000000B5, 0x000000BA, 0x000002EC, 0x000002EE, 0x00000345, 0x0000037F, 0x00000386, 0x0000038C, 0x00000559, 0x000005BF, 0x000005C7, 0x000006FF, 0x000007FA, 0x000009B2, 0x000009CE, 0x000009D7, 0x000009FC, 0x00000A51, 0x00000A5E, 0x00000AD0, 0x00000B71, 0x00000B9C, 0x00000BD0, 0x00000BD7, 0x00000CDE, 0x00000D4E, 0x00000DBD, 0x00000DD6, 0x00000E4D, 0x00000E84, 0x00000E8A, 0x00000E8D, 0x00000EA5, 0x00000EA7, 0x00000EC6, 0x00000ECD, 0x00000F00, 0x00001038, 0x0000108E, 0x000010C7, 0x000010CD, 0x00001258, 0x000012C0, 0x0000135F, 0x000017D7, 0x000017DC, 0x00001AA7, 0x00001F59, 0x00001F5B, 0x00001F5D, 0x00001FBE, 0x00002071, 0x0000207F, 0x00002102, 0x00002107, 0x00002115, 0x00002124, 0x00002126, 0x00002128, 0x0000214E, 0x00002D27, 0x00002D2D, 0x00002D6F, 0x00002E2F, 0x0000A8C5, 0x0000A8FB, 0x0000A8FD, 0x0000AA7A, 0x0000AAC0, 0x0000AAC2, 0x0000FB3E, 0x00010808, 0x0001083C, 0x00011176, 0x000111DC, 0x00011237, 0x0001123E, 0x00011288, 0x00011350, 0x00011357, 0x000114C7, 0x00011640, 0x00011644, 0x000118FF, 0x00011C40, 0x00011D3A, 0x00011D43, 0x0001BC9E, 0x0001D4A2, 0x0001D4BB, 0x0001D546, 0x0001E947, 0x0001EE24, 0x0001EE27, 0x0001EE39, 0x0001EE3B, 0x0001EE42, 0x0001EE47, 0x0001EE49, 0x0001EE4B, 0x0001EE54, 0x0001EE57, 0x0001EE59, 0x0001EE5B, 0x0001EE5D, 0x0001EE5F, 0x0001EE64, 0x0001EE7E }; /* END::UTF8TABLE */ static inline size_t utf8towc(unsigned *wc, const unsigned char *uc, size_t len) { unsigned char ub = utf8_mblen[*uc]; if (!ub || ub > len || ub > 4) { return 0; } *wc = *uc & utf8_mask[ub]; switch (ub) { case 4: if ((uc[1] & 0xc0) != 0x80) { return 0; } *wc <<= 6; *wc += *++uc & 0x3f; /* no break */ case 3: if ((uc[1] & 0xc0) != 0x80) { return 0; } *wc <<= 6; *wc += *++uc & 0x3f; /* no break */ case 2: if ((uc[1] & 0xc0) != 0x80) { return 0; } *wc <<= 6; *wc += *++uc & 0x3f; /* no break */ case 1: break; default: return 0; } return ub; } static inline zend_bool isualpha(unsigned ch) { unsigned hi = sizeof(utf8_ranges)/sizeof(utf8_ranges[0])-1, cur = hi/2, lo = 0, prev; #undef u #define u (utf8_ranges[cur]) do { #if 0 fprintf(stderr, "=> cur=%u lo=%u hi=%u (%u in %u-%u)\n", cur, lo, hi, ch, u.start, u.end); #endif if (u.start <= ch && u.end >= ch) { return 1; } prev = cur; if (u.start > ch) { hi = cur; cur -= (cur - lo) / 2; } else if ((u.end && u.end < ch) || (!u.end && u.start < ch)) { lo = cur; cur += (hi - cur) / 2; } else { break; } } while (cur != prev); #undef u #define u (utf8_chars[cur]) hi = sizeof(utf8_chars)/sizeof(utf8_chars[0]); cur = hi/2; lo = 0; do { #if 0 fprintf(stderr, "=> cur=%u lo=%u hi=%u (%u is %u)\n", cur, lo, hi, ch, u); #endif if (u == ch) { return 1; } prev = cur; if (u > ch) { hi = cur; cur -= (cur - lo) / 2; } else { lo = cur; cur += (hi - cur) / 2; } } while (cur != prev); #undef u return 0; } static inline zend_bool isualnum(unsigned ch) { /* digits */ if (ch >= 0x30 && ch <= 0x39) { return 1; } return isualpha(ch); } static inline size_t wctoutf16(unsigned short u16[2], unsigned wc) { if (wc > 0x10ffff || (wc >= 0xd800 && wc <= 0xdfff)) { return 0; } if (wc <= 0xffff) { u16[0] = (unsigned short) wc; return 1; } wc -= 0x10000; u16[0] = (unsigned short) ((wc >> 10) + 0xd800); u16[1] = (unsigned short) ((wc & 0x3ff) + 0xdc00); return 2; } static inline size_t utf16towc(unsigned *wc, unsigned short *u16_str, size_t u16_len) { if (u16_len < 1) { return 0; } if (u16_str[0] - 0xd800 >= 0x800) { *wc = u16_str[0]; return 1; } if (u16_len < 2 || (u16_str[0] & 0xfffffc00) != 0xd800 || (u16_str[1] & 0xfffffc00) != 0xdc00) { return 0; } *wc = (u16_str[0] << 10) + u16_str[1] - 0x35fdc00; return 2; } #endif /* PHP_HTTP_UTF8_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 */ pecl_http-4.2.1/src/php_http_version.c0000644000076500000240000000527614117626035016615 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #include "php_http_api.h" php_http_version_t *php_http_version_init(php_http_version_t *v, unsigned major, unsigned minor) { if (!v) { v = emalloc(sizeof(*v)); } v->major = major; v->minor = minor; return v; } php_http_version_t *php_http_version_parse(php_http_version_t *v, const char *str) { long major, minor; char separator = 0; register const char *ptr = str; switch (*ptr) { case 'h': case 'H': ++ptr; if (*ptr != 't' && *ptr != 'T') break; ++ptr; if (*ptr != 't' && *ptr != 'T') break; ++ptr; if (*ptr != 'p' && *ptr != 'P') break; ++ptr; if (*ptr != '/') break; ++ptr; /* no break */ default: /* rfc7230#2.6 The HTTP version number consists of two decimal digits separated by a "." (period or decimal point) */ major = *ptr++ - '0'; if (major >= 0 && major <= 9) { separator = *ptr++; switch (separator) { default: php_error_docref(NULL, E_NOTICE, "Non-standard version separator '%c' in HTTP protocol version '%s'", separator, ptr - 2); /* no break */ case '.': case ',': minor = *ptr - '0'; break; case ' ': if (major > 1) { minor = 0; } else { goto error; } } if (minor >= 0 && minor <= 9) { return php_http_version_init(v, major, minor); } } } error: php_error_docref(NULL, E_WARNING, "Could not parse HTTP protocol version '%s'", str); return NULL; } void php_http_version_to_string(php_http_version_t *v, char **str, size_t *len, const char *pre, const char *post) { /* different semantics for different versions */ if (v->major == 2) { *len = spprintf(str, 0, "%s2%s", STR_PTR(pre), STR_PTR(post)); } else { *len = spprintf(str, 0, "%s%u.%u%s", STR_PTR(pre), v->major, v->minor, STR_PTR(post)); } } void php_http_version_dtor(php_http_version_t *v) { (void) v; } void php_http_version_free(php_http_version_t **v) { if (*v) { php_http_version_dtor(*v); efree(*v); *v = 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 */ pecl_http-4.2.1/src/php_http_version.h0000644000076500000240000000267214117626035016617 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_HTTP_VERSION_H #define PHP_HTTP_VERSION_H typedef struct php_http_version { unsigned major; unsigned minor; } php_http_version_t; PHP_HTTP_API php_http_version_t *php_http_version_init(php_http_version_t *v, unsigned major, unsigned minor); PHP_HTTP_API php_http_version_t *php_http_version_parse(php_http_version_t *v, const char *str); PHP_HTTP_API void php_http_version_to_string(php_http_version_t *v, char **str, size_t *len, const char *pre, const char *post); PHP_HTTP_API void php_http_version_dtor(php_http_version_t *v); PHP_HTTP_API void php_http_version_free(php_http_version_t **v); #endif /* PHP_HTTP_VERSION_H */ /* * 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 */ pecl_http-4.2.1/tests/data/bug71719.bin0000644000076500000240000000040014117626035016202 0ustar Mikestaff€¬Td 5 HTTP/1.1 Aµ_eptA eg²²²²²²²²²²²²²²²²²²²²Õ²²²²²²²²²²²²²²²°°A HTTP/1.1 Aµ_eptABCDEFGHI²²²²²²²²²²²²²²²²²²²²²²²²²TTP//X-Csrf-Token:1.0 HTTP/.0²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²² ÿe: Mg ²²´²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²² eDate: Mg pecl_http-4.2.1/tests/data/message_r_content_range.txt0000644000076500000240000000026514117626035021747 0ustar MikestaffPUT / HTTP/1.1 User-Agent: PECL_HTTP/2.3.0dev PHP/5.6.6-dev libcurl/7.41.0-DEV Host: localhost:8000 Accept: */* Expect: 100-continue Content-Length: 3 Content-Range: bytes 1-2/3 23pecl_http-4.2.1/tests/data/message_r_multipart_put.txt0000644000076500000240000000476614117626035022044 0ustar MikestaffPUT /docs/ HTTP/1.1 User-Agent: curl/7.24.0 (x86_64-unknown-linux-gnu) libcurl/7.24.0 OpenSSL/1.0.0g zlib/1.2.6 libssh2/1.3.0 Host: drop Accept: */* Content-Length: 2273 Expect: 100-continue Content-Type: multipart/form-data; boundary=----------------------------6e182425881c ------------------------------6e182425881c Content-Disposition: form-data; name="LICENSE"; filename="LICENSE" Content-Type: application/octet-stream Copyright (c) 2011-2012, Michael Wallner . 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. ------------------------------6e182425881c Content-Disposition: form-data; name="composer"; filename="composer.json" Content-Type: application/octet-stream { "name": "mike_php_net/autocracy", "type": "library", "description": "http\\Controller preserves your autocracy", "keywords": ["http", "controller", "pecl", "pecl_http"], "homepage": "http://github.com/mike-php-net/autocracy", "license": "BSD-2", "authors": [ { "name": "Michael Wallner", "email": "mike@php.net" } ], "require": { "php": ">=5.4.0", "pecl/pecl_http": "2.*" }, "autoload": { "psr-0": { "http\\Controller": "lib" } } } ------------------------------6e182425881c-- pecl_http-4.2.1/tests/data/message_rr_empty.txt0000644000076500000240000000061014117626035020433 0ustar MikestaffGET /default/empty.txt HTTP/1.1 Host: localhost Connection: close HTTP/1.1 200 OK Date: Wed, 25 Aug 2010 12:11:44 GMT Server: Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6 Last-Modified: Wed, 28 Apr 2010 10:54:37 GMT ETag: "2002a-0-48549d615a35c" Accept-Ranges: bytes Content-Length: 0 Vary: Accept-Encoding Connection: close Content-Type: text/plain pecl_http-4.2.1/tests/data/message_rr_empty_chunked.txt0000644000076500000240000000047314117626035022143 0ustar MikestaffGET /default/empty.php HTTP/1.1 Connection: close Host: localhost HTTP/1.1 200 OK Date: Thu, 26 Aug 2010 11:41:02 GMT Server: Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6 X-Powered-By: PHP/5.3.3 Vary: Accept-Encoding Connection: close Transfer-Encoding: chunked Content-Type: text/html 0 pecl_http-4.2.1/tests/data/message_rr_empty_gzip.txt0000644000076500000240000000067314117626035021475 0ustar MikestaffGET /default/empty.txt HTTP/1.1 Host: localhost Accept-Encoding: gzip Connection: close HTTP/1.1 200 OK Date: Thu, 26 Aug 2010 09:55:09 GMT Server: Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6 Last-Modified: Wed, 28 Apr 2010 10:54:37 GMT ETag: "2002a-0-48549d615a35c" Accept-Ranges: bytes Vary: Accept-Encoding Content-Encoding: gzip Content-Length: 20 Connection: close Content-Type: text/plain ‹0;vL pecl_http-4.2.1/tests/data/message_rr_helloworld_chunked.txt0000644000076500000240000000047414117626035023161 0ustar MikestaffGET /cgi-bin/chunked.sh HTTP/1.1 Host: localhost Connection: close HTTP/1.1 200 OK Date: Thu, 26 Aug 2010 12:51:28 GMT Server: Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6 Vary: Accept-Encoding Connection: close Transfer-Encoding: chunked Content-Type: text/plain 5 Hello 2 , 7 World! 0 pecl_http-4.2.1/tests/data/urls.txt0000644000076500000240000000202314117626035016053 0ustar Mikestaffhttp://www.microsoft.com http://www.opensource.org http://www.google.com http://www.yahoo.com http://www.ibm.com http://www.mysql.com http://www.oracle.com http://www.ripe.net http://www.iana.org http://www.amazon.com http://www.netcraft.com http://www.heise.de http://www.chip.de http://www.ca.com http://www.cnet.com http://www.news.com http://www.cnn.com http://www.wikipedia.org http://www.dell.com http://www.hp.com http://www.cert.org http://www.mit.edu http://www.nist.gov http://www.ebay.com http://www.postgresql.org http://www.uefa.com http://www.ieee.org http://www.apple.com http://www.sony.com http://www.symantec.com http://www.zdnet.com http://www.fujitsu.com http://www.supermicro.com http://www.hotmail.com http://www.ecma.com http://www.bbc.co.uk http://news.google.com http://www.foxnews.com http://www.msn.com http://www.wired.com http://www.sky.com http://www.usatoday.com http://www.cbs.com http://www.nbc.com http://slashdot.org http://www.bloglines.com http://www.freecode.org http://www.newslink.org http://www.un.org pecl_http-4.2.1/tests/helper/html/index.html0000644000076500000240000000021014117626035017630 0ustar Mikestaff HTTP2 Nothing to see here. pecl_http-4.2.1/tests/helper/cookie.inc0000644000076500000240000000047714117626035016652 0ustar MikestaffgetHeader("cookie")); $response = new http\Env\Response; $response->setCookie($cookies->setCookie("counter", $cookies->getCookie("counter")+1)); $response->send($client); }); pecl_http-4.2.1/tests/helper/cookie1.inc0000644000076500000240000000046214117626035016725 0ustar MikestaffsetCookie("foo", "bar"); $cookies->setCookie("bar", "foo"); $response = new http\Env\Response; $response->setCookie($cookies); $response->send($client); }); pecl_http-4.2.1/tests/helper/cookie2.inc0000644000076500000240000000111214117626035016717 0ustar MikestaffgetHeader("Cookie")); $new_cookies = new http\Cookie; $new_cookies->setCookie("temp", $old_cookies->getCookie("temp") ?: microtime(true)); $response->setCookie($new_cookies); $new_cookies = new http\Cookie; $new_cookies->setCookie("perm", $old_cookies->getCookie("perm") ?: microtime(true)); $new_cookies->setExpires(time()+3600); $response->setCookie($new_cookies); $response->send($client); }); pecl_http-4.2.1/tests/helper/dump.inc0000644000076500000240000000176714117626035016351 0ustar Mikestaff $val) { fprintf($stream, "%s: %s\n", $key, $val); } fprintf($stream, "\n"); } function dump_message($stream, http\Message $msg, $parent = false) { if (!is_resource($stream)) { $stream = fopen("php://output", "w"); } fprintf($stream, "%s\n", $msg->getInfo()); dump_headers($stream, $msg->getHeaders()); $msg->getBody()->toStream($stream); if ($parent && ($msg = $msg->getParentMessage())) { dump_message($stream, $msg, true); } } function dump_responses($client, array $expect_cookie = []) { while (($r = $client->getResponse())) { dump_headers(null, $r->getHeaders()); if ($expect_cookie) { $got_cookies = array_merge(...array_map(fn($c) => $c->getCookies(), $r->getCookies())); if ($expect_cookie != $got_cookies) { var_dump($expect_cookie, $got_cookies); echo $r->toString(true); } } } } ?> pecl_http-4.2.1/tests/helper/env.inc0000644000076500000240000000226114117626035016162 0ustar MikestaffsetEnvRequest($request); $response->setContentEncoding(http\Env\Response::CONTENT_ENCODING_GZIP); $response->setHeader("X-Request-Content-Length", $request->getBody()->stat("size")); ob_start($response); if ($request->isMultipart()) { $files = []; foreach ($request->splitMultipartBody() as $part) { $cd = $part->getHeader("Content-Disposition", http\Header::class)->getParams(); foreach ($cd->params as $key => $val) { if ($key === "form-data" && $val["value"] === true) { if (isset($val["arguments"]["filename"])) { $files[$val["arguments"]["name"]] = [ "name" => $val["arguments"]["filename"], "type" => $part->getHeader("Content-Type"), "size" => $part->getBody()->stat("s"), ]; } } } print_r($files); } } else { if (($c = $request->getHeader("Cookie"))) { print_r((new http\Cookie($c))->getCookies()); } if ($request->getBody()->stat("s")) { var_dump($request->getBody()->toString()); } } ob_end_flush(); $response->send($client); }); pecl_http-4.2.1/tests/helper/http2.crt0000644000076500000240000000223014117626035016446 0ustar Mikestaff-----BEGIN CERTIFICATE----- MIIDNzCCAh+gAwIBAgIJAKOw1awbt7aIMA0GCSqGSIb3DQEBCwUAMDIxCzAJBgNV BAYTAkFUMQ8wDQYDVQQKDAZQSFAgUUExEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0x NTAyMTIxMjQ2NTRaFw0xNzExMDcxMjQ2NTRaMDIxCzAJBgNVBAYTAkFUMQ8wDQYD VQQKDAZQSFAgUUExEjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEB BQADggEPADCCAQoCggEBAMxa+A6xEKQOYme55nQyu0qpvvGB4c4wGBNa6X6YAEzE Hc19Nbix02UZWQgHM1dmBhbVDW3stO42CQmcViIKfAy5R1A9UZjUcn9nQpaxL/sp 9LrrCANyljISXS40QcBvhCzmcUvDWBRhVTGjV+QTaYmmaM+8hJJJM6W7ByIP22Zv jHoAnzTx9sjs+OMyWmjYT9pWv6aE+u5iSC8bn3B0GgtfPwoPqDF8ePxIMBpmtbk7 JqXFzHxTVywkypnsF34XK94QjpvRcFGSg/Dc1TopJG2Wfq8hxwtoKerSlL5tyKy0 ZrltxCiLkfVZixwNZEqkg7jPSUvLS299mBrwy+ikmr8CAwEAAaNQME4wHQYDVR0O BBYEFDiHynoXXjMChfYhc1k7TNtU8ey0MB8GA1UdIwQYMBaAFDiHynoXXjMChfYh c1k7TNtU8ey0MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAGD9GERC uJv+oHfMwkNkDV5ZB4F+SQPzXVxDx+rJm1aGJs9PcwPNiV5GweXbvgcnvRAL4h8h uv3MLQPgVOq0iqp1QPFCoUXxbYYjYzi9FVbR/154sg0uWEHElU2e3fSjcinNRfXD 12232k6HNwSeeZUFQqn2fuk+cae5BsYT8GfsyMq5EfPtG2d8IG+Ji4eEOJeKu4gl Y33yQnHhw6QKbx8vWaDpZK8qtpapCtLrTtw/nRhX5YV6kMGK+htQUK1etV2O0VQQ OtDrhOWWaDxQULsHIvCMgTTnZqNQD+Xz4MBm3PGEGi/QUsrEaSQYppb8xxQKZU4X MyTh7rO5TdNSXmo= -----END CERTIFICATE----- pecl_http-4.2.1/tests/helper/http2.key0000644000076500000240000000321714117626035016454 0ustar Mikestaff-----BEGIN RSA PRIVATE KEY----- MIIEpQIBAAKCAQEAzFr4DrEQpA5iZ7nmdDK7Sqm+8YHhzjAYE1rpfpgATMQdzX01 uLHTZRlZCAczV2YGFtUNbey07jYJCZxWIgp8DLlHUD1RmNRyf2dClrEv+yn0uusI A3KWMhJdLjRBwG+ELOZxS8NYFGFVMaNX5BNpiaZoz7yEkkkzpbsHIg/bZm+MegCf NPH2yOz44zJaaNhP2la/poT67mJILxufcHQaC18/Cg+oMXx4/EgwGma1uTsmpcXM fFNXLCTKmewXfhcr3hCOm9FwUZKD8NzVOikkbZZ+ryHHC2gp6tKUvm3IrLRmuW3E KIuR9VmLHA1kSqSDuM9JS8tLb32YGvDL6KSavwIDAQABAoIBAQCzUdAB9FYJ36Vy J6qVpD69EZ7ABZzDdWhq84eY0oDQ2/ba7lhJraE2QbviU481zgzh1CponyFVNo1P paPfUxvvflWZj3Ueiq2+JjpESU81MmfR7ZOmktJBNeQWOzzHRBPT4pLgTJXprE85 s3/YX0BozWGDiIU8aIetkiR8OzXm97+BrJWiPFl733dGnHvfpHAZu/PwKZc2+8ft CnQw4GHRhTBWCVNj29HLwm+CA66zQqiAXItgijWMKzs+9ciPn+aCsCnZDNF+o1zs 4pWt60CtIJQtD3r3rSRy7nBaCKcTrr/JU3FvwqKdunuUBUsuYeSaMBokW67kpVzS dO9L9p6BAoGBAP+pvcAd8qfC1WIrn9vka3aK25ulbYSCae3YaWmABc93INJPBMvO GrcUuaLKiQC1oou+E64vGyJ9MeEFwxh2zbvU75a9ezeKAajgaq92ciMX2QqREh0N IntNOc4w7eB6BK8NpaDXNvTtxNWMvlYyhVN0M7FVQRmYJfCJdnTZAkzvAoGBAMyf 6rvWuc/wmIcAtBVe+jIeQ69EJJ/Idcjk0JUm6lFECAAraPpsCglha+wTHWWRQZ9u pPqBnb7QPjevU+3bZHnMvGoEzd5F4Rw74J+p5EZeMUJpuKmon7Ekzemcb0DV+qX9 NorB781D2Z0MG9SCptKyKpN5TPHTjGz4BB3mLC8xAoGAdq99/ynn9ClmleRameI4 YRelS2RIqzM/qcLFbMyZ5e4PtpIoT9SmYkekxgXwA/xOMUFUMZB8sE4eUbAzGbBN Yd1APGJKSUYv7w3/eOUrp07y2wzts77dOxBmvWnJhGQguINFWJ2QTbPzpI9p7OoX Kt7PAIvrZM5VDo1CCIyVnNECgYEAgLmpZXlzcwicK3GZ2EfjhVvcoIlxsMLetf6b 6PiON4lgrxqf88m7lqMezWhI+fgjHDTyvFSF89/1A/rcBaoazzSo4tka2VWEg8p3 SHoMDOh8fJcdgD2AGGRa1TeAFX2HLJzajvfp72tbnpxbdZircah7eEK60PaQRIzR qi1+ZkECgYEAi7GkO7Ey98DppLnt7567veQoEj0u8ixTlCyJ4V278nHR5+6eAZP5 PfdZVC3MtKGLnxrrPTVUy5wU0hR6Gk9EVDmrAF8TgJdnZFlBK7X23eWZ0q4qO/eO 3xIi+UrNwLag8BjYOr32nP/i+F+TLikgRIFR4oiZjk867+ofkTXmNFA= -----END RSA PRIVATE KEY----- pecl_http-4.2.1/tests/helper/pipeline.inc0000644000076500000240000000167514117626035017207 0ustar MikestaffsetEnvRequest($msg) ->setHeader("X-Req", $msg->getRequestUrl()) ->send($client); } serve(function($client) { $R = array(STDIN); $W = $E = array(); if (!stream_select($R, $W, $E, 10, 0)) { logger("Client %d timed out", (int) $client); return; } $count = trim(fgets(STDIN)); logger("Expecting %d messages from client %d", $count, (int) $client); /* the peek message */ respond($client, new http\Message($client, false)); logger("Handled the peek request of client %d", (int) $client); /* pipelined messages */ $req = array(); for ($i=0; $i < $count; ++ $i) { $req[] = $m = new http\Message($client, false); logger("Read request no. %d from client %d (%s)", $i+1, (int) $client, $m->getRequestUrl()); } foreach ($req as $i => $msg) { respond($client, $msg); logger("Sent response no. %d to client %d", $i+1, (int) $client); } }); pecl_http-4.2.1/tests/helper/proxy.inc0000644000076500000240000000153614117626035016557 0ustar Mikestaff= 7.48 does not send Proxy-Connection anymore */ if ($request->getHeader("Proxy-Connection") || $request->getRequestMethod() === "CONNECT") { $response = new http\Env\Response; $response->setEnvRequest($request); $response->send($client); /* soak up the request following the connect */ new http\Message($client, false); } /* return the initial message as response body */ $response = new http\Env\Response; $response->setHeader("X-Request-Content-Length", $request->getBody()->stat("size")); /* avoid OOM with $response->getBody()->append($request); */ dump_message($response->getBody()->getResource(), $request); $response->send($client); }); pecl_http-4.2.1/tests/helper/server.inc0000644000076500000240000001227514117626035016706 0ustar MikestaffgetMessage()); /* ignore disconnect */ if ($ex->getMessage() !== "Empty message received from stream") { fprintf(STDERR, "%s\n", $ex); } break; } } } while ($select); return; } } } function server($handler, $cb) { $args = []; $argList = preg_split('#\s+#', getenv('TEST_PHP_ARGS'), -1, PREG_SPLIT_NO_EMPTY); for ($i = 0; isset($argList[$i]); $i++) { if ($argList[$i] === '-c') { array_push($args, '-c', $argList[++$i]); continue; } if ($argList[$i] === '-n') { $args[] = '-n'; continue; } if ($argList[$i] === '-d') { $args[] = '-d' . $argList[++$i]; continue; } if (substr($argList[$i], 0, 2) === '-d') { $args[] = $argList[$i]; } } foreach (['raphf', 'http'] as $ext) { if (null !== $arg = get_extension_load_arg(PHP_BIN, $args, $ext)) { $args[] = $arg; } } $args[] = __DIR__ . '/' . $handler; proc(PHP_BIN, $args, $cb); } function nghttpd($cb) { $spec = array(array("pipe","r"), array("pipe","w"), array("pipe","w")); $offset = rand(0,2000); foreach (range(8000+$offset, 9000+$offset) as $port) { $comm = "exec nghttpd -d html $port http2.key http2.crt"; if (($proc = proc_open($comm, $spec, $pipes, __DIR__))) { $stdin = $pipes[0]; $stdout = $pipes[1]; $stderr = $pipes[2]; sleep(1); $status = proc_get_status($proc); logger("nghttpd: %s", new http\Params($status)); if (!$status["running"]) { continue; } try { $cb($port, $stdin, $stdout, $stderr); } catch (Exception $e) { echo $e,"\n"; } proc_terminate($proc); fpassthru($stderr); fpassthru($stdout); return; } } } function proc($bin, $args, $cb) { $spec = array(array("pipe","r"), array("pipe","w"), array("pipe","w")); $comm = escapeshellcmd($bin) . " ". implode(" ", array_map("escapeshellarg", $args)); logger("proc: %s %s", $bin, implode(" ", $args)); if (($proc = proc_open($comm, $spec, $pipes, __DIR__))) { $stdin = $pipes[0]; $stdout = $pipes[1]; $stderr = $pipes[2]; do { $port = trim(fgets($stderr)); $R = array($stderr); $W = array(); $E = array(); } while (is_numeric($port) && stream_select($R, $W, $E, 0, 10000)); if (is_numeric($port)) { try { $cb($port, $stdin, $stdout, $stderr); } catch (Exception $e) { echo $e,"\n"; } } proc_terminate($proc); fpassthru($stderr); fpassthru($stdout); } } pecl_http-4.2.1/tests/helper/upload.inc0000644000076500000240000000106714117626035016661 0ustar MikestaffgetHeader("Expect") === "100-continue") { $response = new http\Env\Response; $response->setEnvRequest($request); $response->setResponseCode(100); $response->send($client); } /* return the initial message as response body */ $response = new http\Env\Response; /* avoid OOM with $response->getBody()->append($request); */ dump_message($response->getBody()->getResource(), $request); $response->send($client); }); pecl_http-4.2.1/tests/skipif.inc0000644000076500000240000000267514117626035015411 0ustar Mikestaff=")) { die("skip need at least libcurl version $version\n"); } } function skip_http2_test($message = "skip need http2 support") { if (!defined("http\\Client\\Curl\\HTTP_VERSION_2_0")) { die("$message (HTTP_VERSION_2_0)\n"); } if (!(http\Client\Curl\FEATURES & http\Client\Curl\Features\HTTP2)) { die("$message (FEATURES & HTTP2)\n"); } foreach (explode(":", getenv("PATH")) as $path) { if (is_executable($path . "/nghttpd")) { return; } } die("$message (nghttpd in PATH)\n"); } pecl_http-4.2.1/tests/bug61444.phpt0000644000076500000240000000217614117626035015502 0ustar Mikestaff--TEST-- Bug #61444 (. become _ in query strings due to php_default_treat_data()) --SKIPIF-- --FILE-- 'utm_source=changed'), http\Url::JOIN_QUERY), PHP_EOL, PHP_EOL; // Replacing the host echo new http\Url($url, array('host' => 'www.google.com')), PHP_EOL, PHP_EOL; // Generating a query string from scratch echo new http\QueryString(array( 'bar.baz' => 'blah', 'utm_source' => 'google', 'utm_campaign' => 'somethingelse', 'blat' => null, )), PHP_EOL, PHP_EOL; ?> DONE --EXPECT-- http://www.example.com/foobar?bar.baz=blah&utm_source=google&utm_campaign=somethingelse&blat http://www.example.com/foobar?bar.baz=blah&utm_source=changed&utm_campaign=somethingelse&blat http://www.google.com/foobar?bar.baz=blah&utm_source=google&utm_campaign=somethingelse&blat bar.baz=blah&utm_source=google&utm_campaign=somethingelse DONE pecl_http-4.2.1/tests/bug66388.phpt0000644000076500000240000000114114117626035015505 0ustar Mikestaff--TEST-- Bug #66388 (Crash on POST with Content-Length:0 and untouched body) --SKIPIF-- --FILE-- 0 ) ); $client->setOptions(["timeout" => 30]); $client->enqueue($request); echo $client->send()->getResponse()->getResponseCode(); }); ?> ===DONE=== --EXPECTF-- Test 200 ===DONE=== pecl_http-4.2.1/tests/bug66891.phpt0000644000076500000240000000045614117626035015514 0ustar Mikestaff--TEST-- Bug #66891 (Unexpected HTTP 401 after NTLM authentication) --SKIPIF-- --GET-- dummy=1 --FILE-- setResponseCode(200); $r->send(); var_dump(http\Env::getResponseCode()); ?> --EXPECT-- int(200)pecl_http-4.2.1/tests/bug67932.phpt0000644000076500000240000000044314117626035015505 0ustar Mikestaff--TEST-- Bug #67932 (php://input always empty) --SKIPIF-- --PUT-- Content-Type: text/xml test --FILE-- --EXPECT-- testpecl_http-4.2.1/tests/bug69000.phpt0000644000076500000240000000241614117626035015473 0ustar Mikestaff--TEST-- Bug #69000 (http\Url breaks down with very long URL query strings) --SKIPIF-- --FILE-- ===DONE=== --EXPECT-- Test http://foo.bar/?aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ===DONE=== pecl_http-4.2.1/tests/bug69076.phpt0000644000076500000240000000036414117626035015510 0ustar Mikestaff--TEST-- Bug #69076 (URL parsing throws exception on empty query string) --SKIPIF-- --FILE-- ===DONE=== --EXPECT-- Test http://foo.bar/ ===DONE=== pecl_http-4.2.1/tests/bug69313.phpt0000644000076500000240000000153514117626035015503 0ustar Mikestaff--TEST-- Bug #69313 (http\Client doesn't send GET body) --SKIPIF-- --FILE-- setHeader("Content-Type", "text/plain"); $request->getBody()->append("foo"); $client = new http\Client(); $client->enqueue($request); $client->send(); dump_message(null, $client->getResponse()); }); ?> Done --EXPECTF-- Test HTTP/1.1 200 OK Accept-Ranges: bytes Content-Length: %d Etag: "%s" X-Original-Transfer-Encoding: chunked X-Request-Content-Length: 3 GET / HTTP/1.1 Accept: */* Content-Length: 3 Content-Type: text/plain Host: localhost:%d User-Agent: %s X-Original-Content-Length: 3 foo Done pecl_http-4.2.1/tests/bug69357.phpt0000644000076500000240000000151114117626035015505 0ustar Mikestaff--TEST-- Bug #69357 (HTTP/1.1 100 Continue overriding subsequent 200 response code with PUT request) --SKIPIF-- --FILE-- append("foo"); $r = new \http\Client\Request("PUT", "http://localhost:$port/", array(), $b); $c = new \http\Client; $c->setOptions(array("expect_100_timeout" => 0)); $c->enqueue($r)->send(); var_dump($c->getResponse($r)->getInfo()); var_dump($c->getResponse($r)->getHeaders()); }); ?> ===DONE=== --EXPECTF-- Test string(15) "HTTP/1.1 200 OK" array(4) { ["Accept-Ranges"]=> string(5) "bytes" ["Etag"]=> string(10) ""%x"" ["X-Original-Transfer-Encoding"]=> string(7) "chunked" ["Content-Length"]=> int(%d) } ===DONE=== pecl_http-4.2.1/tests/bug71719.phpt0000644000076500000240000000120714117626035015502 0ustar Mikestaff--TEST-- Bug #71719 (Buffer overflow in HTTP url parsing functions) --SKIPIF-- --INI-- zend.exception_ignore_args=off --FILE-- ===DONE=== --EXPECTF-- Test %r(exception ')?%rhttp\Exception\BadMessageException%r(' with message '|: )%rhttp\Message::__construct(): Could not parse HTTP protocol version 'HTTP/%s.0'%r'?%r in %sbug71719.php:5 Stack trace: #0 %sbug71719.php(5): http\Message->__construct('%r(\?\?|\\x80\\xAC)%rTd 5 HTTP/1.1...', false) #1 {main} ===DONE=== pecl_http-4.2.1/tests/bug73055.phpt0000644000076500000240000000124214117626035015474 0ustar Mikestaff--TEST-- Bug #73055 (Type confusion vulnerability in merge_param()) --SKIPIF-- --INI-- zend.exception_ignore_args=off --FILE-- ===DONE=== --EXPECTF-- Test %r(exception ')?%rhttp\Exception\BadQueryStringException%r(' with message '|: )%rhttp\QueryString::__construct(): Max input nesting level of %d exceeded%r'?%r in %sbug73055.php:%d Stack trace: #0 %sbug73055.php(%d): http\QueryString->__construct('[[[[[[[[[[[[[[[...') #1 {main} ===DONE=== pecl_http-4.2.1/tests/client001.phpt0000644000076500000240000000046614117626035016021 0ustar Mikestaff--TEST-- client drivers --SKIPIF-- --FILE-- Done --EXPECTREGEX-- Test (?:bool\(true\) )+Done pecl_http-4.2.1/tests/client002.phpt0000644000076500000240000000160414117626035016015 0ustar Mikestaff--TEST-- client observer --SKIPIF-- --FILE-- getProgressInfo($request); if ($progress->info !== "prepare" && $compare && $compare != $progress) { var_dump($progress, $compare); } } } server("proxy.inc", function($port, $stdin, $stdout, $stderr) { foreach (http\Client::getAvailableDrivers() as $driver) { $client = new http\Client($driver); $client->attach(new Observer); $client->enqueue(new http\Client\Request("GET", "http://localhost:$port/")); $client->send(); } }); ?> Done --EXPECTREGEX-- Test P+ Done pecl_http-4.2.1/tests/client003.phpt0000644000076500000240000000106314117626035016015 0ustar Mikestaff--TEST-- client once & wait --SKIPIF-- --FILE-- enqueue($request); while ($client->once()) { $client->wait(.1); } if (!$client->getResponse()) { var_dump($client); } } }); ?> Done --EXPECT-- Test Done pecl_http-4.2.1/tests/client004.phpt0000644000076500000240000000146014117626035016017 0ustar Mikestaff--TEST-- client reset --SKIPIF-- --FILE-- enqueue($request)->send(); if (!($client->getResponse($request) instanceof http\Client\Response)) { var_dump($client); } try { $client->enqueue($request); } catch (Exception $e) { echo $e->getMessage(),"\n"; } $client->reset(); if (($response = $client->getResponse())) { var_dump($response); } $client->enqueue($request); } }); ?> Done --EXPECTREGEX-- Test (?:Failed to enqueue request; request already in queue )+Done pecl_http-4.2.1/tests/client005.phpt0000644000076500000240000000106614117626035016022 0ustar Mikestaff--TEST-- client response callback --SKIPIF-- --FILE-- enqueue(new http\Client\Request("GET", "http://localhost:$port"), function($response) { echo "R\n"; if (!($response instanceof http\Client\Response)) { var_dump($response); } }); $client->send(); } }); ?> Done --EXPECTREGEX-- Test (?:R )+Done pecl_http-4.2.1/tests/client006.phpt0000644000076500000240000000152314117626035016021 0ustar Mikestaff--TEST-- client response callback + dequeue --SKIPIF-- --FILE-- enqueue($request, "response"); $client->send(); try { $client->dequeue($request); } catch (Exception $e) { echo $e->getMessage(),"\n"; } } } }); ?> Done --EXPECTREGEX-- Test (?:(?:R Failed to dequeue request; request not in queue )+)+Done pecl_http-4.2.1/tests/client007.phpt0000644000076500000240000000121114117626035016014 0ustar Mikestaff--TEST-- client response callback + requeue --SKIPIF-- --FILE-- requeue($request, "response"); $client->send(); } } }); ?> Done --EXPECTREGEX-- Test (?:R R )+Done pecl_http-4.2.1/tests/client008.phpt0000644000076500000240000000141014117626035016016 0ustar Mikestaff--TEST-- client pipelining --SKIPIF-- =")) { die("skip CURL_VERSION >= 7.62 -- pipelining disabled\n"); } ?> --FILE-- configure(array("pipelining" => true, "use_eventloop" => true)); $client->enqueue($request); $client->send(); $client->enqueue(clone $request); $client->enqueue(clone $request); $client->send(); while ($client->getResponse()) { echo "R\n"; } }); ?> Done --EXPECTREGEX-- Test (?:R R R )+Done pecl_http-4.2.1/tests/client009.phpt0000644000076500000240000000153014117626035016022 0ustar Mikestaff--TEST-- client static cookies --SKIPIF-- --FILE-- setCookies(array("test" => "bar")); $client->addCookies(array("foo" => "test")); $request = new http\Client\Request("GET", "http://localhost:$port"); $client->enqueue($request); $client->send(); echo $client->getResponse()->getBody()->toString(); $request->setOptions(array("cookies" => x($client->getCookies()))); $client->requeue($request); $client->send(); echo $client->getResponse()->getBody()->toString(); }); ?> Done --EXPECT-- Test Array ( [test] => bar [foo] => test ) Array ( [test] => test [foo] => bar ) Done pecl_http-4.2.1/tests/client010.phpt0000644000076500000240000000146214117626035016016 0ustar Mikestaff--TEST-- client upload --SKIPIF-- --FILE-- Array \( \[name\] \=\> client010\.php \[type\] \=\> text\/plain \[size\] \=\> \d+ \) \) )+/'; server("env.inc", function($port) use($RE) { $request = new http\Client\Request("POST", "http://localhost:$port"); $request->getBody()->addForm(null, array("file"=>__FILE__, "name"=>"upload", "type"=>"text/plain")); foreach (http\Client::getAvailableDrivers() as $driver) { $client = new http\Client($driver); $client->enqueue($request)->send(); if (!preg_match($RE, $s = $client->getResponse()->getBody()->toString())) { echo($s); } } }); ?> Done --EXPECT-- Test Done pecl_http-4.2.1/tests/client011.phpt0000644000076500000240000000236714117626035016024 0ustar Mikestaff--TEST-- client history --SKIPIF-- --FILE-- append("foobar"); $request = new http\Client\Request; $request->setBody($body); $request->setRequestMethod("POST"); $request->setRequestUrl("http://localhost:$port"); $client = new http\Client; $client->recordHistory = true; $client->enqueue($request)->send(); echo $client->getHistory()->toString(true); $client->requeue($request)->send(); echo $client->getHistory()->toString(true); }); ?> Done --EXPECTF-- Test POST http://localhost:%d/ HTTP/1.1 Content-Length: 6 foobar HTTP/1.1 200 OK Accept-Ranges: bytes X-Request-Content-Length: 6 X-Original-Transfer-Encoding: chunked Content-Length: 19 string(6) "foobar" POST http://localhost:%d/ HTTP/1.1 Content-Length: 6 foobar HTTP/1.1 200 OK Accept-Ranges: bytes X-Request-Content-Length: 6 X-Original-Transfer-Encoding: chunked Content-Length: 19 string(6) "foobar" POST http://localhost:%d/ HTTP/1.1 Content-Length: 6 foobar HTTP/1.1 200 OK Accept-Ranges: bytes X-Request-Content-Length: 6 X-Original-Transfer-Encoding: chunked Content-Length: 19 string(6) "foobar" Done pecl_http-4.2.1/tests/client012.phpt0000644000076500000240000000257014117626035016021 0ustar Mikestaff--TEST-- client ssl --SKIPIF-- --FILE-- setSslOptions(array("verifypeer" => true)); $client->addSslOptions(array("verifyhost" => 2)); var_dump( array( "verifypeer" => true, "verifyhost" => 2, ) === $client->getSslOptions() ); $client->attach($observer = new class implements SplObserver { public $data = []; #[ReturnTypeWillChange] function update(SplSubject $client, $req = null, $progress = null) { $ti = $client->getTransferInfo($req); if (isset($ti->tls_session["internals"])) { foreach ((array) $ti->tls_session["internals"] as $key => $val) { if (!isset($this->data[$key]) || $this->data[$key] < $val) { $this->data[$key] = $val; } } } } }); $client->enqueue($req = new http\Client\Request("GET", "https://twitter.com/")); $client->send(); switch ($client->getTransferInfo($req)->tls_session["backend"]) { case "openssl": case "gnutls": if (count($observer->data) < 1) { printf("%s: failed count(ssl.internals) >= 1\n", $client->getTransferInfo($req)->tls_session["backend"]); var_dump($observer); exit; } break; default: break; } ?> Done --EXPECTF-- Test bool(true) Done pecl_http-4.2.1/tests/client013.phpt0000644000076500000240000000361114117626035016017 0ustar Mikestaff--TEST-- client observers --SKIPIF-- --FILE-- getProgressInfo($r)) $c->pi .= "-"; } } class ProgressObserver2 implements SplObserver { #[ReturnTypeWillChange] function update(SplSubject $c, $r = null) { if ($c->getProgressInfo($r)) $c->pi .= "."; } } class CallbackObserver implements SplObserver { public $callback; function __construct($callback) { $this->callback = $callback; } #[ReturnTypeWillChange] function update(SplSubject $c, $r = null) { call_user_func($this->callback, $c, $r); } } server("proxy.inc", function($port) { $client = new Client; $client->attach($o1 = new ProgressObserver1); $client->attach($o2 = new ProgressObserver2); $client->attach( $o3 = new CallbackObserver( function ($c, $r) { $p = (array) $c->getProgressInfo($r); if (!$p) { return; } var_dump(array_key_exists("started", $p)); var_dump(array_key_exists("finished", $p)); var_dump(array_key_exists("dlnow", $p)); var_dump(array_key_exists("ulnow", $p)); var_dump(array_key_exists("dltotal", $p)); var_dump(array_key_exists("ultotal", $p)); var_dump(array_key_exists("info", $p)); } ) ); $client->enqueue(new http\Client\Request("GET", "http://localhost:$port/"))->send(); var_dump(1 === preg_match("/(\.-)+/", $client->pi)); var_dump(3 === count($client->getObservers())); $client->detach($o1); var_dump(2 === count($client->getObservers())); $client->detach($o2); var_dump(1 === count($client->getObservers())); $client->detach($o3); var_dump(0 === count($client->getObservers())); }); ?> Done --EXPECTREGEX-- Test\n(bool\(true\)\n)+Done pecl_http-4.2.1/tests/client014.phpt0000644000076500000240000000104614117626035016020 0ustar Mikestaff--TEST-- reset content length when resetting body --SKIPIF-- --FILE-- setBody(new http\Message\Body(fopen(__FILE__, "r"))); $client->enqueue($request); var_dump($request->getHeader("Content-Length")); $request->setBody(new http\Message\Body); $client->requeue($request); var_dump($request->getHeader("Content-Length")); ?> ===DONE=== --EXPECTF-- Test int(379) bool(false) ===DONE=== pecl_http-4.2.1/tests/client015.phpt0000644000076500000240000000140614117626035016021 0ustar Mikestaff--TEST-- http client event base --SKIPIF-- --FILE-- configure(array("use_eventloop" => true)); $client2->configure(array("use_eventloop" => true)); $client1->enqueue(new http\Client\Request("GET", "http://localhost:$port/")); $client2->enqueue(new http\Client\Request("GET", "http://localhost:$port/")); $client1->send(); if (($r = $client1->getResponse())) { var_dump($r->getTransferInfo("response_code")); } if (($r = $client2->getResponse())) { var_dump($r->getTransferInfo("response_code")); } }); ?> DONE --EXPECT-- Test int(200) DONE pecl_http-4.2.1/tests/client016.phpt0000644000076500000240000000114114117626035016016 0ustar Mikestaff--TEST-- client once & wait with events --SKIPIF-- --FILE-- configure(array("use_eventloop" => true)); $client->enqueue($request); while ($client->once()) { $client->wait(.1); } if (!$client->getResponse()) { var_dump($client); } } }); ?> Done --EXPECT-- Test Done pecl_http-4.2.1/tests/client017.phpt0000644000076500000240000000120014117626035016013 0ustar Mikestaff--TEST-- client request gzip --SKIPIF-- --FILE-- setOptions(array("compress" => true)); $client->enqueue($request); $client->send(); echo $client->getResponse(); }); ?> ===DONE=== --EXPECTF-- Test HTTP/1.1 200 OK Accept-Ranges: bytes X-Request-Content-Length: 0 Vary: Accept-Encoding Etag: "%s" X-Original-Transfer-Encoding: chunked X-Original-Content-Encoding: deflate ===DONE=== pecl_http-4.2.1/tests/client018.phpt0000644000076500000240000000217314117626035016026 0ustar Mikestaff--TEST-- client pipelining --SKIPIF-- =")) { die("skip CURL_VERSION >= 7.62 -- pipelining disabled\n"); } ?> --FILE-- getHeader("X-Req"),"\n"; } server("pipeline.inc", function($port, $stdin, $stdout, $stderr) { /* tell the server we're about to send 3 pipelined messages */ fputs($stdin, "3\n"); $client = new http\Client(null); $client->configure(array("pipelining" => true, "max_host_connections" => 0)); /* this is just to let curl know the server may be capable of pipelining */ $client->enqueue(new http\Client\Request("GET", "http://localhost:$port"), "dump"); $client->send(); $client->enqueue(new http\Client\Request("GET", "http://localhost:$port/1"), "dump"); $client->enqueue(new http\Client\Request("GET", "http://localhost:$port/2"), "dump"); $client->enqueue(new http\Client\Request("GET", "http://localhost:$port/3"), "dump"); $client->send(); }); ?> ===DONE=== --EXPECT-- Test / /1 /2 /3 ===DONE=== pecl_http-4.2.1/tests/client019.phpt0000644000076500000240000000205214117626035016023 0ustar Mikestaff--TEST-- client proxy - send proxy headers for a proxy request --SKIPIF-- getAvailableOptions()) or die("skip need libcurl with CURLOPT_PROXYHEADER support\n"); ?> --FILE-- setOptions(array( "timeout" => 10, "proxytunnel" => true, "proxyheader" => array("Hello" => "there!"), "proxyhost" => "localhost", "proxyport" => $port, )); try { $c->enqueue($r)->send(); } catch (Exception $e) { echo $e; } echo $c->getResponse()->getBody(); }); ?> ===DONE=== --EXPECTF-- Test Server on port %d CONNECT www.example.com:80 HTTP/1.1 Hello: there! Host: www.example.com:80 %r(Proxy-Connection: Keep-Alive )?%rUser-Agent: PECL_HTTP/%s PHP/%s libcurl/%s ===DONE=== pecl_http-4.2.1/tests/client020.phpt0000644000076500000240000000137014117626035016015 0ustar Mikestaff--TEST-- client proxy - don't send proxy headers for a standard request --SKIPIF-- --FILE-- setOptions(array( "timeout" => 3, "proxyheader" => array("Hello" => "there!"), )); try { $c->enqueue($r)->send(); } catch (Exception $e) { echo $e; } echo $c->getResponse()->getBody(); unset($r, $client); }); ?> ===DONE=== --EXPECTF-- Test Server on port %d GET / HTTP/1.1 Accept: */* Host: localhost:%d User-Agent: PECL_HTTP/%s PHP/%s libcurl/%s ===DONE=== pecl_http-4.2.1/tests/client021.phpt0000644000076500000240000001070214117626035016015 0ustar Mikestaff--TEST-- client cookies --SKIPIF-- --FILE-- requeue($request)->send(); foreach ($client->getResponse()->getCookies() as $list) { foreach ($list->getCookies() as $name => $value) { if ($cmp[$name] != $value) { printf("# %s\nExpected %s=%s, got %s\n", $section, $name, $cmp[$name], $value); } } } #dump(); } $tmpfile = tempnam(sys_get_temp_dir(), "cookie."); $request = new http\Client\Request("GET", "http://localhost"); $section = "distinct clients"; server("cookie.inc", function($port) use($request, $tmpfile) { $request->setOptions(array("port" => $port)); $client = new http\Client; send_and_check($client, ["counter" => 1]); }); server("cookie.inc", function($port) use($request, $tmpfile) { $request->setOptions(array("port" => $port)); $client = new http\Client; send_and_check($client, ["counter" => 1]); }); server("cookie.inc", function($port) use($request, $tmpfile) { $request->setOptions(array("port" => $port)); $client = new http\Client; send_and_check($client, ["counter" => 1]); }); $section = "reusing curl handles"; server("cookie.inc", function($port) use($request, $tmpfile) { $request->setOptions(array("port" => $port)); $client = new http\Client("curl", "test"); send_and_check($client, ["counter" => 1]); }); server("cookie.inc", function($port) use($request, $tmpfile) { $request->setOptions(array("port" => $port)); $client = new http\Client("curl", "test"); send_and_check($client, ["counter" => 2]); }); server("cookie.inc", function($port) use($request, $tmpfile) { $request->setOptions(array("port" => $port)); $client = new http\Client("curl", "test"); send_and_check($client, ["counter" => 3]); }); $section = "distict client with persistent cookies"; $request->setOptions(array("cookiestore" => $tmpfile)); server("cookie.inc", function($port) use($request, $tmpfile) { $request->setOptions(array("port" => $port)); $client = new http\Client; send_and_check($client, ["counter" => 1]); send_and_check($client, ["counter" => 2]); send_and_check($client, ["counter" => 3]); }); server("cookie.inc", function($port) use($request, $tmpfile) { $request->setOptions(array("port" => $port)); $client = new http\Client; send_and_check($client, ["counter" => 4]); send_and_check($client, ["counter" => 5]); send_and_check($client, ["counter" => 6]); }); $section = "distinct client with persistent cookies, but session cookies removed"; server("cookie.inc", function($port) use($request, $tmpfile) { $request->setOptions(array("port" => $port, "cookiesession" => true)); $client = new http\Client; send_and_check($client, ["counter" => 1]); send_and_check($client, ["counter" => 1]); send_and_check($client, ["counter" => 1]); }); $section = "distinct client with persistent cookies, and session cookies kept"; server("cookie.inc", function($port) use($request, $tmpfile) { $request->setOptions(array("port" => $port, "cookiesession" => false)); $client = new http\Client; send_and_check($client, ["counter" => 2]); send_and_check($client, ["counter" => 3]); send_and_check($client, ["counter" => 4]); }); $section = "reusing curl handles without persistent cookies and disabling cookie_share"; $c = new http\Client("curl", "test"); $c->configure(array("share_cookies" => false)); $c = null; $request->setOptions(array("cookiestore" => null)); server("cookie.inc", function($port) use($request, $tmpfile) { $request->setOptions(array("port" => $port)); $client = new http\Client("curl", "test"); send_and_check($client, ["counter" => 1]); }); server("cookie.inc", function($port) use($request, $tmpfile) { $request->setOptions(array("port" => $port)); $client = new http\Client("curl", "test"); send_and_check($client, ["counter" => 1]); }); server("cookie.inc", function($port) use($request, $tmpfile) { $request->setOptions(array("port" => $port)); $client = new http\Client("curl", "test"); send_and_check($client, ["counter" => 1]); }); unlink($tmpfile); ?> ===DONE=== --EXPECT-- Test ===DONE=== pecl_http-4.2.1/tests/client022.phpt0000644000076500000240000000137414117626035016023 0ustar Mikestaff--TEST-- client http2 --SKIPIF-- --FILE-- setOptions([ "protocol" => http\Client\Curl\HTTP_VERSION_2_0, "ssl" => [ "cainfo" => __DIR__."/helper/http2.crt", "verifypeer" => false, // needed for NSS without PEM support ] ]); $request = new http\Client\Request("GET", "https://localhost:$port"); $client->enqueue($request); echo $client->send()->getResponse(); }); ?> ===DONE=== --EXPECTF-- Test HTTP/2 200 %a HTTP2 Nothing to see here. ===DONE=== pecl_http-4.2.1/tests/client023.phpt0000644000076500000240000000136614117626035016025 0ustar Mikestaff--TEST-- client available options and configuration --SKIPIF-- --FILE-- getOptions())) { var_dump($options); } $client->setOptions($avail = $client->getAvailableOptions()); $opt = $client->getOptions(); foreach ($avail as $k => $v) { if (is_array($v)) { $oo = $opt[$k]; foreach ($v as $kk => $vv) { if (isset($vv) && $oo[$kk] !== $vv) { var_dump(array($kk => array($vv, $oo[$kk]))); } } } else if (isset($v) && $opt[$k] !== $v) { var_dump(array($k => array($v, $opt[$k]))); } } var_dump($client === $client->configure($client->getAvailableConfiguration())); ?> ===DONE=== --EXPECT-- Test bool(true) ===DONE=== pecl_http-4.2.1/tests/client024.phpt0000644000076500000240000000103614117626035016020 0ustar Mikestaff--TEST-- client deprecated methods --SKIPIF-- --FILE-- enableEvents(false); $client->enablePipelining(false); ?> ===DONE=== --EXPECTF-- Test Deprecated: Method http\Client::enableEvents() is deprecated in %sclient024.php on line %d Deprecated: Method http\Client::enablePipelining() is deprecated in %sclient024.php on line %d ===DONE=== pecl_http-4.2.1/tests/client025.phpt0000644000076500000240000000156414117626035016027 0ustar Mikestaff--TEST-- client seek --SKIPIF-- --FILE-- setOptions(array("resume" => 1, "expect_100_timeout" => 0)); $request->getBody()->append("123"); dump_message(null, $client->enqueue($request)->send()->getResponse()); }); // Content-length is 2 instead of 3 in older libcurls ?> ===DONE=== --EXPECTF-- Test HTTP/1.1 200 OK Accept-Ranges: bytes Content-Length: %d Etag: "%x" X-Original-Transfer-Encoding: chunked X-Request-Content-Length: 2 PUT / HTTP/1.1 Accept: */* Content-Length: %d Content-Range: bytes 1-2/3 Expect: 100-continue Host: localhost:%d User-Agent: %s X-Original-Content-Length: %d 23===DONE=== pecl_http-4.2.1/tests/client026.phpt0000644000076500000240000000152114117626035016021 0ustar Mikestaff--TEST-- client stream 128M --SKIPIF-- --FILE-- setContentType("application/octet-stream"); for ($i = 0, $data = str_repeat("a",1024); $i < 128*1024; ++$i) { $request->getBody()->append($data); } $request->setOptions(array("timeout" => 10, "expect_100_timeout" => 0)); $client->enqueue($request); $client->send(); dump_headers(null, $client->getResponse()->getHeaders()); }); ?> ===DONE=== --EXPECTF-- Test Accept-Ranges: bytes Content-Length: %d Etag: "%x" Last-Modified: %s X-Original-Transfer-Encoding: chunked X-Request-Content-Length: 134217728 ===DONE=== pecl_http-4.2.1/tests/client027.phpt0000644000076500000240000000203314117626035016021 0ustar Mikestaff--TEST-- client cookie woes --SKIPIF-- --FILE-- configure(array("pipelining" => false, "share_cookies" => false)); $request = new http\Client\Request("GET", "http://localhost:$port?r1"); $client->enqueue($request); $client->send(); dump_responses($client, ["counter" => 1]); $client->requeue($request); $client->send(); dump_responses($client, ["counter" => 2]); $client->dequeue($request); $request = new http\Client\Request("GET", "http://localhost:$port?r2"); $client->enqueue($request); $client->send(); dump_responses($client, ["counter" => 1]); }); ?> ===DONE=== --EXPECTF-- Test Etag: "" Set-Cookie: counter=1; X-Original-Transfer-Encoding: chunked Etag: "" Set-Cookie: counter=2; X-Original-Transfer-Encoding: chunked Etag: "" Set-Cookie: counter=1; X-Original-Transfer-Encoding: chunked ===DONE=== pecl_http-4.2.1/tests/client028.phpt0000644000076500000240000000505514117626035016031 0ustar Mikestaff--TEST-- client curl user handler --SKIPIF-- --FILE-- array(), "W" => array() ); private $R = array(); private $W = array(); private $timeout = 1000; function __construct(http\Client $client) { $this->client = $client; } function init($run) { $this->run = $run; } function timer(int $timeout_ms) { echo "T"; $this->timeout = $timeout_ms; } function socket($socket, int $action) { echo "S"; switch ($action) { case self::POLL_NONE: break; case self::POLL_REMOVE: if (false !== ($r = array_search($socket, $this->fds["R"], true))) { echo "U"; unset($this->fds["R"][$r]); } if (false !== ($w = array_search($socket, $this->fds["W"], true))) { echo "U"; unset($this->fds["W"][$w]); } break; default: if ($action & self::POLL_IN) { if (!in_array($socket, $this->fds["R"], true)) { $this->fds["R"][] = $socket; } } if ($action & self::POLL_OUT) { if (!in_array($socket, $this->fds["W"], true)) { $this->fds["W"][] = $socket; } } break; } } function once() { echo "O"; foreach ($this->W as $w) { call_user_func($this->run, $this->client, $w, self::POLL_OUT); } foreach ($this->R as $r) { call_user_func($this->run, $this->client, $r, self::POLL_IN); } return count($this->client); } function wait(int $timeout_ms = null) { echo "W"; if ($timeout_ms === null) { $timeout_ms = $this->timeout; } $ts = floor($timeout_ms / 1000); $tu = ($timeout_ms % 1000) * 1000; extract($this->fds); if (($wfds = count($R) + count($W))) { $nfds = stream_select($R, $W, $E, $ts, $tu); } else { $nfds = 0; } $this->R = (array) $R; $this->W = (array) $W; if ($nfds === false) { return false; } if (!$nfds) { if (!$wfds) { echo "S"; time_nanosleep($ts, $tu*1000); } call_user_func($this->run, $this->client); } return true; } function send() { $this->wait(); $this->once(); } } include "helper/server.inc"; server("proxy.inc", function($port) { $client = new http\Client; $client->configure(array( "use_eventloop" => new UserHandler($client) )); $client->enqueue(new http\Client\Request("GET", "http://localhost:$port/"), function($r) { var_dump($r->getResponseCode()); }); $client->send(); }); ?> ===DONE=== --EXPECTREGEX-- Test [ST][WST]*([OWSTU]*)+U+int\(200\) O*===DONE=== pecl_http-4.2.1/tests/client029.phpt0000644000076500000240000000524514117626035016033 0ustar Mikestaff--TEST-- client curl user handler --SKIPIF-- --FILE-- evbase = $evbase; $this->client = $client; } function init($run) { $this->run = $run; } function timer(int $timeout_ms) { echo "T"; if (isset($this->timeout)) { $this->timeout->add($timeout_ms/1000); } else { $this->timeout = Event::timer($this->evbase, function() { if (!call_user_func($this->run, $this->client)) { if ($this->timeout) { $this->timeout->del(); $this->timeout = null; } } }); $this->timeout->add($timeout_ms/1000); } } function socket($socket, int $action) { echo "S"; switch ($action) { case self::POLL_NONE: break; case self::POLL_REMOVE: if (isset($this->ios[(int) $socket])) { echo "U"; $this->ios[(int) $socket]->del(); unset($this->ios[(int) $socket]); } break; default: $ev = 0; if ($action & self::POLL_IN) { $ev |= Event::READ; } if ($action & self::POLL_OUT) { $ev |= Event::WRITE; } if (isset($this->ios[(int) $socket])) { $this->ios[(int) $socket]->set($this->evbase, $socket, $ev, $this->onEvent($socket)); } else { $this->ios[(int) $socket] = new Event($this->evbase, $socket, $ev, $this->onEvent($socket)); } break; } } function onEvent($socket) { return function($watcher, $events) use($socket) { $action = 0; if ($events & Ev::READ) { $action |= self::POLL_IN; } if ($events & Ev::WRITE) { $action |= self::POLL_OUT; } if (!call_user_func($this->run, $this->client, $socket, $action)) { if ($this->timeout) { $this->timeout->del(); $this->timeout = null; } } }; } function once() { throw new BadMethodCallException("this test uses EventBase::loop()"); } function wait(int $timeout_ms = null) { throw new BadMethodCallException("this test uses EventBase::loop()"); } function send() { throw new BadMethodCallException("this test uses EventBase::loop()"); } } include "helper/server.inc"; server("proxy.inc", function($port) { $evbase = new EventBase; $client = new http\Client; $client->configure([ "use_eventloop" => new UserHandler($client, $evbase) ]); $client->enqueue(new http\Client\Request("GET", "http://localhost:$port/"), function($r) { var_dump($r->getResponseCode()); }); $evbase->loop(); }); ?> ===DONE=== --EXPECTREGEX-- Test T*[ST]+U+T*int\(200\) ===DONE=== pecl_http-4.2.1/tests/client030.phpt0000644000076500000240000000120214117626035016010 0ustar Mikestaff--TEST-- client eventloop recursion --SKIPIF-- --FILE-- once(); } } server("proxy.inc", function($port) { $client = new http\Client; $client->configure(array( "use_eventloop" => true, )); $client->attach(new test); $client->enqueue(new http\Client\Request("GET", "http://localhost:$port/"), function($r) { var_dump($r->getResponseCode()); }); $client->send(); }); ?> ===DONE=== --EXPECTF-- Test int(200) ===DONE===pecl_http-4.2.1/tests/client031.phpt0000644000076500000240000000263714117626035016026 0ustar Mikestaff--TEST-- client cookie sharing disabled --SKIPIF-- --FILE-- configure(array("share_cookies" => false)); $request = new http\Client\Request("GET", "http://localhost:$port"); $client->enqueue($request); $client->send(); dump_responses($client, ["counter" => 1]); /* requeue the previous request */ $client->requeue($request); $client->send(); dump_responses($client, ["counter" => 2]); for($i = 0; $i < 3; ++$i) { /* new requests */ $request = new http\Client\Request("GET", "http://localhost:$port"); $client->enqueue($request); $client->send(); dump_responses($client, ["counter" => 1]); } /* requeue the previous request */ $client->requeue($request); $client->send(); dump_responses($client, ["counter" => 2]); }); ?> ===DONE=== --EXPECTF-- Test Etag: "" Set-Cookie: counter=1; X-Original-Transfer-Encoding: chunked Etag: "" Set-Cookie: counter=2; X-Original-Transfer-Encoding: chunked Etag: "" Set-Cookie: counter=1; X-Original-Transfer-Encoding: chunked Etag: "" Set-Cookie: counter=1; X-Original-Transfer-Encoding: chunked Etag: "" Set-Cookie: counter=1; X-Original-Transfer-Encoding: chunked Etag: "" Set-Cookie: counter=2; X-Original-Transfer-Encoding: chunked ===DONE=== pecl_http-4.2.1/tests/client032.phpt0000644000076500000240000000263714117626035016027 0ustar Mikestaff--TEST-- client cookie sharing enabled --SKIPIF-- --FILE-- configure(array("share_cookies" => true)); $request = new http\Client\Request("GET", "http://localhost:$port"); $client->enqueue($request); $client->send(); dump_responses($client, ["counter" => 1]); /* requeue the previous request */ $client->requeue($request); $client->send(); dump_responses($client, ["counter" => 2]); for($i = 3; $i < 6; ++$i) { /* new requests */ $request = new http\Client\Request("GET", "http://localhost:$port"); $client->enqueue($request); $client->send(); dump_responses($client, ["counter" => $i]); } /* requeue the previous request */ $client->requeue($request); $client->send(); dump_responses($client, ["counter" => $i]); }); ?> ===DONE=== --EXPECTF-- Test Etag: "" Set-Cookie: counter=1; X-Original-Transfer-Encoding: chunked Etag: "" Set-Cookie: counter=2; X-Original-Transfer-Encoding: chunked Etag: "" Set-Cookie: counter=3; X-Original-Transfer-Encoding: chunked Etag: "" Set-Cookie: counter=4; X-Original-Transfer-Encoding: chunked Etag: "" Set-Cookie: counter=5; X-Original-Transfer-Encoding: chunked Etag: "" Set-Cookie: counter=6; X-Original-Transfer-Encoding: chunked ===DONE=== pecl_http-4.2.1/tests/clientrequest001.phpt0000644000076500000240000000074514117626035017432 0ustar Mikestaff--TEST-- client request --SKIPIF-- --FILE-- getBody()); var_dump($h === $r->getHeaders()); var_dump($u === $r->getRequestUrl()); var_dump($m === $r->getRequestMethod()); ?> Done --EXPECT-- Test bool(true) bool(true) bool(true) bool(true) Done pecl_http-4.2.1/tests/clientrequest002.phpt0000644000076500000240000000051614117626035017427 0ustar Mikestaff--TEST-- client request content type --SKIPIF-- --FILE-- setContentType($ct = "text/plain; charset=utf-8")); var_dump($ct === $r->getContentType()); ?> Done --EXPECT-- Test bool(true) bool(true) Done pecl_http-4.2.1/tests/clientrequest003.phpt0000644000076500000240000000102414117626035017423 0ustar Mikestaff--TEST-- client request query --SKIPIF-- --FILE-- getQuery()); var_dump($r === $r->setQuery($q = "foo=bar")); var_dump($q === $r->getQuery()); var_dump($r === $r->addQuery("a[]=1&a[]=2")); var_dump("foo=bar&a%5B0%5D=1&a%5B1%5D=2" === $r->getQuery()); var_dump(null === $r->setQuery(null)->getQuery()); ?> Done --EXPECT-- Test bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) Done pecl_http-4.2.1/tests/clientrequest004.phpt0000644000076500000240000000111214117626035017422 0ustar Mikestaff--TEST-- client request options --SKIPIF-- --FILE-- setOptions($o = array("redirect"=>5, "timeout"=>5))); var_dump($o === $r->getOptions()); var_dump($r === $r->setOptions(array("timeout"=>50))); $o["timeout"] = 50; var_dump($o === $r->getOptions()); var_dump($r === $r->setSslOptions($o = array("verify_peer"=>false))); var_dump($o === $r->getSslOptions()); ?> Done --EXPECT-- Test bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) Done pecl_http-4.2.1/tests/clientresponse001.phpt0000644000076500000240000000163314117626035017575 0ustar Mikestaff--TEST-- client response cookie --SKIPIF-- --FILE-- enqueue($request)->send()->getResponse()->getCookies(0, array("comment")) as $cookies) { var_dump($cookies->toArray()); } } }); ?> Done --EXPECTREGEX-- Test (?:array\(7\) \{\n \["cookies"\]\=\>\n array\(2\) \{\n \["foo"\]\=\>\n string\(3\) "bar"\n \["bar"\]\=\>\n string\(3\) "foo"\n \}\n \["extras"\]\=\>\n array\(0\) \{\n \}\n \["flags"\]\=\>\n int\(0\)\n \["expires"\]\=\>\n int\(\-1\)\n \["max\-age"\]\=\>\n int\(\-1\)\n \["path"\]\=\>\n string\(0\) ""\n \["domain"\]\=\>\n string\(0\) ""\n\}\n)+Done pecl_http-4.2.1/tests/clientresponse002.phpt0000644000076500000240000000230614117626035017574 0ustar Mikestaff--TEST-- client response cookies --SKIPIF-- --FILE-- enqueue($request)->send()->getResponse()->getCookies(0, array("comment")) as $cookies) { var_dump($cookies->toArray()); } } }); ?> Done --EXPECTREGEX-- Test (?:array\(7\) \{\n \["cookies"\]\=\>\n array\(1\) \{\n \["temp"\]\=\>\n string\(1\d\) "\d+\.\d+"\n \}\n \["extras"\]\=\>\n array\(0\) \{\n \}\n \["flags"\]\=\>\n int\(0\)\n \["expires"\]\=\>\n int\(\-1\)\n \["max\-age"\]\=\>\n int\(\-1\)\n \["path"\]\=\>\n string\(0\) ""\n \["domain"\]\=\>\n string\(0\) ""\n\}\narray\(7\) \{\n \["cookies"\]\=\>\n array\(1\) \{\n \["perm"\]\=\>\n string\(1\d\) "\d+\.\d+"\n \}\n \["extras"\]\=\>\n array\(0\) \{\n \}\n \["flags"\]\=\>\n int\(0\)\n \["expires"\]\=\>\n int\(\d+\)\n \["max\-age"\]\=\>\n int\(\-1\)\n \["path"\]\=\>\n string\(0\) ""\n \["domain"\]\=\>\n string\(0\) ""\n\}\n)+Done pecl_http-4.2.1/tests/clientresponse003.phpt0000644000076500000240000000115714117626035017600 0ustar Mikestaff--TEST-- client response transfer info --SKIPIF-- --FILE-- enqueue($request)->send()->getResponse(); var_dump($response->getTransferInfo("response_code")); var_dump(count((array)$response->getTransferInfo())); } }); ?> Done --EXPECTREGEX-- Test (?:int\([1-5]\d\d\) int\(\d\d\) )+Done pecl_http-4.2.1/tests/cookie001.phpt0000644000076500000240000000061414117626035016007 0ustar Mikestaff--TEST-- cookies empty state --SKIPIF-- --FILE-- array(), "extras" => array(), "flags" => 0, "expires" => -1, "path" => "", "domain" => "", "max-age" => -1, ); var_dump($a == $c->toArray()); var_dump($a == $o->toArray()); ?> DONE --EXPECT-- Test bool(true) bool(true) DONE pecl_http-4.2.1/tests/cookie002.phpt0000644000076500000240000000046714117626035016016 0ustar Mikestaff--TEST-- cookies expire as date --SKIPIF-- --INI-- date.timezone=UTC --FILE-- $d->format(DateTime::RFC1123))); var_dump($d->format("U") == $c->getExpires()); ?> DONE --EXPECT-- Test bool(true) DONE pecl_http-4.2.1/tests/cookie003.phpt0000644000076500000240000000037514117626035016015 0ustar Mikestaff--TEST-- cookies numeric keys --SKIPIF-- --FILE-- DONE --EXPECT-- Test bool(true) DONE pecl_http-4.2.1/tests/cookie004.phpt0000644000076500000240000000042114117626035016006 0ustar Mikestaff--TEST-- cookies raw --SKIPIF-- --FILE-- DONE --EXPECT-- Test bool(true) DONE pecl_http-4.2.1/tests/cookie005.phpt0000644000076500000240000000207414117626035016015 0ustar Mikestaff--TEST-- cookies simple data --SKIPIF-- --FILE-- toArray()); foreach (array($orig, $copy) as $c) { var_dump($c->getCookie("key")); var_dump($c->getExpires()); var_dump($c->getMaxAge()); var_dump($c->getFlags()); var_dump($c->getPath()); var_dump($c->getDomain()); var_dump($c->getExtras()); var_dump($c->getCookies()); var_dump($c->toString()); var_dump( array ( "cookies" => array ( "key" => "value", ), "extras" => array ( ), "flags" => 0, "expires" => -1, "path" => "", "domain" => "", "max-age" => -1, ) == $c->toArray() ); } ?> DONE --EXPECT-- Test string(5) "value" int(-1) int(-1) int(0) NULL NULL array(0) { } array(1) { ["key"]=> string(5) "value" } string(11) "key=value; " bool(true) string(5) "value" int(-1) int(-1) int(0) NULL NULL array(0) { } array(1) { ["key"]=> string(5) "value" } string(11) "key=value; " bool(true) DONE pecl_http-4.2.1/tests/cookie006.phpt0000644000076500000240000000140414117626035016012 0ustar Mikestaff--TEST-- cookies expire --SKIPIF-- --INI-- date.timezone=UTC --FILE-- getCookie("this")); var_dump($c->getExpires()); $o = clone $c; $t = time(); $o->setExpires(); var_dump(-1 === $o->getExpires()); var_dump(-1 != $c->getExpires()); $o->setExpires($t); var_dump($t === $o->getExpires()); var_dump($t != $c->getExpires()); var_dump( sprintf( "this=expires; expires=%s; ", date_create("@$t") ->setTimezone(new DateTimezone("UTC")) ->format("D, d M Y H:i:s \\G\\M\\T") ) === $o->toString() ); ?> DONE --EXPECT-- Test string(7) "expires" int(1327397732) bool(true) bool(true) bool(true) bool(true) bool(true) DONE pecl_http-4.2.1/tests/cookie007.phpt0000644000076500000240000000111714117626035016014 0ustar Mikestaff--TEST-- cookies max-age --SKIPIF-- --INI-- date.timezone=UTC --FILE-- getCookie("this")); var_dump($c->getMaxAge()); $o = clone $c; $t = 54321; $o->setMaxAge(); var_dump($o->getMaxAge()); var_dump(-1 != $c->getMaxAge()); $o->setMaxAge($t); var_dump($o->getMaxAge()); var_dump($t != $c->getMaxAge()); var_dump($o->toString()); ?> DONE --EXPECT-- Test string(7) "max-age" int(12345) int(-1) bool(true) int(54321) bool(true) string(29) "this=max-age; max-age=54321; " DONE pecl_http-4.2.1/tests/cookie008.phpt0000644000076500000240000000117414117626035016020 0ustar Mikestaff--TEST-- cookies path --SKIPIF-- --FILE-- getCookie("this")); var_dump((string)$c); var_dump($c->getPath()); $o = clone $c; $p = "/up"; $o->setPath(); var_dump($o->getPath()); var_dump($c->getPath()); $o->setPath($p); var_dump($o->getPath()); var_dump($c->getPath()); var_dump($o->toString()); ?> DONE --EXPECT-- Test string(10) "has a path" string(33) "this=has%20a%20path; path=/down; " string(5) "/down" NULL string(5) "/down" string(3) "/up" string(5) "/down" string(31) "this=has%20a%20path; path=/up; " DONE pecl_http-4.2.1/tests/cookie009.phpt0000644000076500000240000000134514117626035016021 0ustar Mikestaff--TEST-- cookies domain --SKIPIF-- --FILE-- getCookie("this")); var_dump((string)$c); var_dump($c->getDomain()); $o = clone $c; $d = "sub.example.com"; $o->setDomain(); var_dump($o->getDomain()); var_dump($c->getDomain()); $o->setDomain($d); var_dump($o->getDomain()); var_dump($c->getDomain()); var_dump($o->toString()); ?> DONE --EXPECT-- Test string(12) "has a domain" string(44) "this=has%20a%20domain; domain=.example.com; " string(12) ".example.com" NULL string(12) ".example.com" string(15) "sub.example.com" string(12) ".example.com" string(47) "this=has%20a%20domain; domain=sub.example.com; " DONE pecl_http-4.2.1/tests/cookie010.phpt0000644000076500000240000000164414117626035016013 0ustar Mikestaff--TEST-- cookies flags --SKIPIF-- --FILE-- getFlags() & http\Cookie::SECURE)); var_dump(http\Cookie::HTTPONLY === ($c->getFlags() & http\Cookie::HTTPONLY)); $c->setFlags($c->getFlags() ^ http\Cookie::SECURE); var_dump(!($c->getFlags() & http\Cookie::SECURE)); var_dump(http\Cookie::HTTPONLY === ($c->getFlags() & http\Cookie::HTTPONLY)); $c->setFlags($c->getFlags() ^ http\Cookie::HTTPONLY); var_dump(!($c->getFlags() & http\Cookie::SECURE)); var_dump(!($c->getFlags() & http\Cookie::HTTPONLY)); var_dump("icanhas=flags; " === $c->toString()); $c->setFlags(http\Cookie::SECURE|http\Cookie::HTTPONLY); var_dump("icanhas=flags; secure; httpOnly; " === $c->toString()); ?> DONE --EXPECT-- Test bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) DONE pecl_http-4.2.1/tests/cookie011.phpt0000644000076500000240000000213614117626035016011 0ustar Mikestaff--TEST-- cookies extras --SKIPIF-- --FILE-- "v1", "c2"=>"v2") === $c->getCookies()); var_dump(array("e0"=>"1", "e2"=>"2") === $c->getExtras()); $c->addExtra("e1", 1); $c->setExtra("e0"); $c->setExtra("e3", 123); var_dump("123" === $c->getExtra("e3")); $c->setExtra("e3"); var_dump(array("e2"=>"2", "e1"=>"1") === $c->getExtras()); var_dump("c1=v1; c2=v2; e2=2; e1=1; " === $c->toString()); $c->addExtras(array("e3"=>3, "e4"=>4)); var_dump(array("e2"=>"2", "e1"=>"1", "e3"=>"3", "e4"=>"4") === $c->getExtras()); var_dump("c1=v1; c2=v2; e2=2; e1=1; e3=3; e4=4; " === $c->toString()); $c->setExtras(array("e"=>"x")); var_dump(array("e"=>"x") === $c->getExtras()); var_dump("c1=v1; c2=v2; e=x; " === $c->toString()); $c->setExtras(); var_dump(array() === $c->getExtras()); var_dump("c1=v1; c2=v2; " === $c->toString()); ?> DONE --EXPECT-- Test bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) DONE pecl_http-4.2.1/tests/cookie012.phpt0000644000076500000240000000215314117626035016011 0ustar Mikestaff--TEST-- cookies cookies --SKIPIF-- --FILE-- "v1", "c2"=>"v2") === $c->getExtras()); var_dump(array("e0"=>"1", "e2"=>"2") === $c->getCookies()); $c->addCookie("e1", 1); $c->setCookie("e0"); $c->setCookie("e3", 123); var_dump("123" === $c->getCookie("e3")); $c->setCookie("e3"); var_dump(array("e2"=>"2", "e1"=>"1") === $c->getCookies()); var_dump("e2=2; e1=1; c1=v1; c2=v2; " === $c->toString()); $c->addCookies(array("e3"=>3, "e4"=>4)); var_dump(array("e2"=>"2", "e1"=>"1", "e3"=>"3", "e4"=>"4") === $c->getCookies()); var_dump("e2=2; e1=1; e3=3; e4=4; c1=v1; c2=v2; " === $c->toString()); $c->setCookies(array("e"=>"x")); var_dump(array("e"=>"x") === $c->getCookies()); var_dump("e=x; c1=v1; c2=v2; " === $c->toString()); $c->setCookies(); var_dump(array() === $c->getCookies()); var_dump("c1=v1; c2=v2; " === $c->toString()); ?> DONE --EXPECT-- Test bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) DONE pecl_http-4.2.1/tests/encstream001.phpt0000644000076500000240000000061314117626035016516 0ustar Mikestaff--TEST-- encoding stream chunked static --SKIPIF-- --FILE-- DONE --EXPECT-- Test bool(true) DONE pecl_http-4.2.1/tests/encstream002.phpt0000644000076500000240000000056014117626035016520 0ustar Mikestaff--TEST-- encoding stream chunked not encoded --SKIPIF-- --FILE-- DONE --EXPECTF-- Test Notice: http\Encoding\Stream\Dechunk::decode(): Data does not seem to be chunked encoded in %s on line %d bool(true) DONE pecl_http-4.2.1/tests/encstream003.phpt0000644000076500000240000000213014117626035016514 0ustar Mikestaff--TEST-- encoding stream chunked error --SKIPIF-- --FILE-- DONE --EXPECTF-- Test Warning: http\Encoding\Stream\Dechunk::decode(): Expected LF at pos 8 of 20 but got 0x74 in %s on line %d Warning: http\Encoding\Stream\Dechunk::decode(): Truncated message: chunk size 190 exceeds remaining data size 11 at pos 9 of 20 in %s on line %d string(14) "is ter than 1 " Warning: http\Encoding\Stream\Dechunk::decode(): Expected CRLF at pos 10 of 24 but got 0x74 0x74 in %s on line %d Warning: http\Encoding\Stream\Dechunk::decode(): Truncated message: chunk size 190 exceeds remaining data size 12 at pos 12 of 24 in %s on line %d string(15) "is er than 1 " Warning: http\Encoding\Stream\Dechunk::decode(): Expected chunk size at pos 6 of 27 but got trash in %s on line %d bool(false) DONE pecl_http-4.2.1/tests/encstream004.phpt0000644000076500000240000000146114117626035016523 0ustar Mikestaff--TEST-- encoding stream chunked flush --SKIPIF-- --FILE-- $line) { $dech = clone $dech; if ($i % 2) { $data .= $dech->update(sprintf("%lx\r\n%s\r\n", strlen($line), $line)); } else { $data .= $dech->update(sprintf("%lx\r\n", strlen($line))); $data .= $dech->flush(); $data .= $dech->update($line); $data .= $dech->flush(); $data .= $dech->update("\r\n"); } $dech->flush(); $dech->done() and printf("uh-oh done() reported true!\n"); } $data .= $dech->update("0\r\n"); var_dump($dech->done()); $data .= $dech->finish(); var_dump(implode("", $file) === $data); ?> DONE --EXPECT-- Test bool(true) bool(true) DONE pecl_http-4.2.1/tests/encstream005.phpt0000644000076500000240000000125314117626035016523 0ustar Mikestaff--TEST-- encoding stream zlib static --SKIPIF-- --FILE-- DONE --EXPECT-- Test bool(true) bool(true) bool(true) DONE pecl_http-4.2.1/tests/encstream006.phpt0000644000076500000240000000110014117626035016513 0ustar Mikestaff--TEST-- encoding stream zlib auto flush --SKIPIF-- --FILE-- update($defl->update($data))) { printf("uh-oh »%s« != »%s«\n", $data, $d); } } } echo $infl->update($defl->finish()); echo $infl->finish(); ?> DONE --EXPECT-- Test DONE pecl_http-4.2.1/tests/encstream007.phpt0000644000076500000240000000114614117626035016526 0ustar Mikestaff--TEST-- encoding stream zlib without flush --SKIPIF-- --FILE-- update($line))) { foreach(str_split($temp) as $byte) { $data .= $infl->update($byte); } } } if (strlen($temp = $defl->finish())) { $data .= $infl->update($temp); } $data .= $infl->finish(); var_dump(implode("", $file) === $data); ?> DONE --EXPECT-- Test bool(true) DONE pecl_http-4.2.1/tests/encstream008.phpt0000644000076500000240000000146414117626035016532 0ustar Mikestaff--TEST-- encoding stream zlib with explicit flush --SKIPIF-- --FILE-- flush(); if (strlen($temp = $defl->update($line))) { $data .= $infl->update($temp); $data .= $infl->flush(); } if (strlen($temp = $defl->flush())) { $data .= $infl->update($temp); $data .= $infl->flush(); } $defl->done() or printf("uh-oh stream's not done yet!\n"); } if (strlen($temp = $defl->finish())) { $data .= $infl->update($temp); } var_dump($defl->done()); $data .= $infl->finish(); var_dump($infl->done()); var_dump(implode("", $file) === $data); ?> DONE --EXPECT-- Test bool(true) bool(true) bool(true) DONE pecl_http-4.2.1/tests/encstream009.phpt0000644000076500000240000000054014117626035016525 0ustar Mikestaff--TEST-- encoding stream zlib error --SKIPIF-- --FILE-- DONE --EXPECTF-- Test Warning: http\Encoding\Stream\Inflate::decode(): Could not inflate data: data error in %s on line %d bool(false) DONE pecl_http-4.2.1/tests/encstream015.phpt0000644000076500000240000000142614117626035016526 0ustar Mikestaff--TEST-- encoding stream brotli static --SKIPIF-- --FILE-- DONE --EXPECT-- Test bool(true) bool(true) bool(true) DONE pecl_http-4.2.1/tests/encstream016.phpt0000644000076500000240000000125514117626035016527 0ustar Mikestaff--TEST-- encoding stream brotli auto flush --SKIPIF-- --FILE-- update($defl->update($data))) { printf("uh-oh »%s« != »%s«\n", $data, $d); } } } echo $infl->update($defl->finish()); echo $infl->finish(); var_dump($infl->done(), $defl->done()); ?> DONE --EXPECT-- Test bool(true) bool(true) DONE pecl_http-4.2.1/tests/encstream017.phpt0000644000076500000240000000122314117626035016523 0ustar Mikestaff--TEST-- encoding stream brotli without flush --SKIPIF-- --FILE-- update($line))) { foreach(str_split($temp) as $byte) { $data .= $infl->update($byte); } } } if (strlen($temp = $defl->finish())) { $data .= $infl->update($temp); } $data .= $infl->finish(); var_dump(implode("", $file) === $data); ?> DONE --EXPECT-- Test bool(true) DONE pecl_http-4.2.1/tests/encstream018.phpt0000644000076500000240000000150314117626035016525 0ustar Mikestaff--TEST-- encoding stream brotli with explicit flush --SKIPIF-- --FILE-- flush(); if (strlen($temp = $enc->update($line))) { $data .= $dec->update($temp); $data .= $dec->flush(); } if (strlen($temp = $enc->flush())) { $data .= $dec->update($temp); $data .= $dec->flush(); } } if (strlen($temp = $enc->finish())) { $data .= $dec->update($temp); } var_dump($enc->done()); $data .= $dec->finish(); var_dump($dec->done()); var_dump(implode("", $file) === $data); ?> DONE --EXPECT-- Test bool(true) bool(true) bool(true) DONE pecl_http-4.2.1/tests/encstream019.phpt0000644000076500000240000000066714117626035016540 0ustar Mikestaff--TEST-- encoding stream brotli error --SKIPIF-- --FILE-- DONE --EXPECTF-- Test Warning: http\Encoding\Stream\Debrotli::decode(): Could not brotli decode data: %s in %s on line %d bool(false) DONE pecl_http-4.2.1/tests/envrequestbody001.phpt0000644000076500000240000000031514117626035017613 0ustar Mikestaff--TEST-- env request body --SKIPIF-- --PUT-- Content-Type: skip/me foo --FILE-- DONE --EXPECT-- string(3) "foo" DONE pecl_http-4.2.1/tests/envrequestcookie001.phpt0000644000076500000240000000070314117626035020130 0ustar Mikestaff--TEST-- env request cookie --SKIPIF-- --COOKIE-- foo=bar;bar=123 --FILE-- getCookie()->toArray()); var_dump($r->getCookie("foo", "s")); var_dump($r->getCookie("bar", "i")); var_dump($r->getCookie("baz", "b", true)); ?> DONE --EXPECT-- Test array(2) { ["foo"]=> string(3) "bar" ["bar"]=> string(3) "123" } string(3) "bar" int(123) bool(true) DONE pecl_http-4.2.1/tests/envrequestfiles001.phpt0000644000076500000240000000125214117626035017761 0ustar Mikestaff--TEST-- env request grabbing $_FILES --SKIPIF-- --POST_RAW-- Content-Type: multipart/form-data;boundary=--123 ----123 Content-Disposition: form-data;filename="foo.bar" foo bar ----123 Content-Disposition: form-data;filename="bar.foo" bar foo ----123-- --FILE-- getFiles(); foreach ($_FILES as $i => $file) { foreach (array("name","type","size","error","file") as $key) { if ($file[$key == "file" ? "tmp_name" : $key] != $f[$i][$key]) { printf("%d.%s differs: '%s' != '%s'\n", $i, $key, $f[$i][$key], $file[$key]); } } } ?> DONE --EXPECT-- TEST DONE pecl_http-4.2.1/tests/envrequestfiles002.phpt0000644000076500000240000000153514117626035017766 0ustar Mikestaff--TEST-- env request grabbing $_FILES from array --SKIPIF-- --POST_RAW-- Content-Type: multipart/form-data;boundary=--123 ----123 Content-Disposition: form-data;filename=file1;name=file[] first ----123 Content-Disposition: form-data;filename=file2;name=file[] second ----123 Content-Disposition: form-data;filename=file3;name=file[] third ----123-- --FILE-- $data) { foreach ($data["tmp_name"] as $i => $file) { $f[$name][$i] = array( "file" => $file, "name" => $data["name"][$i], "size" => $data["size"][$i], "type" => $data["type"][$i], "error"=> $data["error"][$i] ); } } var_dump($f == $r->getFiles()); ?> DONE --EXPECT-- TEST bool(true) DONE pecl_http-4.2.1/tests/envrequestform.phpt0000644000076500000240000000062714117626035017406 0ustar Mikestaff--TEST-- env request form --SKIPIF-- --POST-- a=b&b=c&r[]=1&r[]=2 --FILE-- getForm()); printf("%s\n", $r->getForm("b", "s", null, true)); printf("%s\n", $r->getForm("x", "s", "nooo")); printf("%s\n", $r->getForm()); ?> DONE --EXPECT-- TEST a=b&b=c&r%5B0%5D=1&r%5B1%5D=2 c nooo a=b&r%5B0%5D=1&r%5B1%5D=2 DONE pecl_http-4.2.1/tests/envrequestheader001.phpt0000644000076500000240000000116714117626035020114 0ustar Mikestaff--TEST-- env request header --SKIPIF-- --POST-- a=b --ENV-- HTTP_HOST=foo.bar HTTP_ACCEPT=*/* --FILE-- --EXPECTF-- NULL string(%d) "foo.bar" string(%d) "application/x-www-form-urlencoded" array(4) { ["Accept"]=> string(3) "*/*" ["Content-Length"]=> string(1) "3" ["Content-Type"]=> string(33) "application/x-www-form-urlencoded" ["Host"]=> string(7) "foo.bar" } pecl_http-4.2.1/tests/envrequestquery.phpt0000644000076500000240000000063314117626035017605 0ustar Mikestaff--TEST-- env request query --SKIPIF-- --GET-- a=b&b=c&r[]=1&r[]=2 --FILE-- getQuery()); printf("%s\n", $r->getQuery("b", "s", null, true)); printf("%s\n", $r->getQuery("x", "s", "nooo")); printf("%s\n", $r->getQuery()); ?> DONE --EXPECT-- TEST a=b&b=c&r%5B0%5D=1&r%5B1%5D=2 c nooo a=b&r%5B0%5D=1&r%5B1%5D=2 DONE pecl_http-4.2.1/tests/envreset001.phpt0000644000076500000240000000244614117626035016376 0ustar Mikestaff--TEST-- env reset --SKIPIF-- --POST-- a=b --ENV-- HTTP_HOST=foo.bar HTTP_ACCEPT=*/* --FILE-- ==DONE== --EXPECTF-- NULL string(%d) "foo.bar" string(%d) "application/x-www-form-urlencoded" array(4) { ["Accept"]=> string(3) "*/*" ["Content-Length"]=> string(1) "3" ["Content-Type"]=> string(33) "application/x-www-form-urlencoded" ["Host"]=> string(7) "foo.bar" } NULL string(%d) "foo.bar" string(%d) "yesyes" NULL string(%d) "application/x-www-form-urlencoded" array(4) { ["Accept"]=> string(3) "*/*" ["Content-Length"]=> string(1) "3" ["Content-Type"]=> string(33) "application/x-www-form-urlencoded" ["Nono"]=> string(6) "yesyes" } ==DONE== pecl_http-4.2.1/tests/envresponse001.phpt0000644000076500000240000000065714117626035017114 0ustar Mikestaff--TEST-- env response message --SKIPIF-- --POST-- a=b --ENV-- HTTP_ACCEPT_ENCODING=gzip --FILE-- setHeader("foo","bar"); $r->setContentEncoding(http\env\Response::CONTENT_ENCODING_GZIP); $r->setBody(new http\message\Body(fopen(__FILE__,"r"))); $r->send(); --EXPECTHEADERS-- Foo: bar Content-Encoding: gzip Vary: Accept-Encoding --EXPECTREGEX-- ^\x1f\x8b\x08.+ pecl_http-4.2.1/tests/envresponse002.phpt0000644000076500000240000000112714117626035017106 0ustar Mikestaff--TEST-- env response cache negative --SKIPIF-- --GET-- a=b --ENV-- HTTP_IF_MODIFIED_SINCE=Fri, 13 Feb 2009 23:31:30 GMT HTTP_IF_NONE_MATCH=0000-00-0000 --FILE-- setBody(new http\Message\Body(fopen(__FILE__,"rb"))); $r->setEtag("abc"); $r->setLastModified(1234567891); $r->send(); ?> --EXPECTHEADERS-- ETag: "abc" Last-Modified: Fri, 13 Feb 2009 23:31:31 GMT --EXPECT-- setBody(new http\Message\Body(fopen(__FILE__,"rb"))); $r->setEtag("abc"); $r->setLastModified(1234567891); $r->send(); ?> pecl_http-4.2.1/tests/envresponse003.phpt0000644000076500000240000000066014117626035017110 0ustar Mikestaff--TEST-- env response ranges --SKIPIF-- --ENV-- HTTP_RANGE=bytes=2-4 --GET-- a=b --FILE-- setContentType("text/plain"); $r->setContentDisposition( array("attachment" => array(array("filename" => basename(__FILE__)))) ); $r->setBody(new http\Message\Body(fopen(__FILE__, "rb"))); $r->send(); ?> --EXPECTHEADERS-- Content-Range: bytes 2-4/248 --EXPECTF-- php pecl_http-4.2.1/tests/envresponse004.phpt0000644000076500000240000000075314117626035017114 0ustar Mikestaff--TEST-- env response callback --SKIPIF-- --GET-- dummy=1 --FILE-- setCacheControl("public,must-revalidate,max-age=0"); $r->setThrottleRate(1, 0.1); ob_start($r); echo "foo"; echo "bar"; ob_end_flush(); $r->send(); ?> --EXPECTHEADERS-- Accept-Ranges: bytes Cache-Control: public,must-revalidate,max-age=0 ETag: "9ef61f95" --EXPECTF-- foobar pecl_http-4.2.1/tests/envresponse005.phpt0000644000076500000240000000111114117626035017102 0ustar Mikestaff--TEST-- env response cache positive --SKIPIF-- --GET-- a=b --ENV-- HTTP_IF_MODIFIED_SINCE=Fri, 13 Feb 2009 23:31:32 GMT --FILE-- setBody(new http\Message\Body(fopen(__FILE__,"rb"))); $r->setEtag("abc"); $r->setLastModified(1234567891); $r->isCachedByEtag("If-None-Match") and die("Huh? etag? really?\n"); $r->isCachedByLastModified("If-Modified-Since") or die("yep, I should be cached"); $r->send(); ?> --EXPECTHEADERS-- HTTP/1.1 304 Not Modified ETag: "abc" Last-Modified: Fri, 13 Feb 2009 23:31:31 GMT --EXPECT-- pecl_http-4.2.1/tests/envresponse006.phpt0000644000076500000240000000065714117626035017121 0ustar Mikestaff--TEST-- env response stream --SKIPIF-- --FILE-- addHeader("foo", array("bar","baz")); $r->getBody()->append("foo"); $r->send($f); rewind($f); var_dump(stream_get_contents($f)); ?> Done --EXPECT-- Test string(115) "HTTP/1.1 200 OK Accept-Ranges: bytes Foo: bar, baz ETag: "8c736521" Transfer-Encoding: chunked 3 foo 0 " Done pecl_http-4.2.1/tests/envresponse007.phpt0000644000076500000240000000121614117626035017112 0ustar Mikestaff--TEST-- env response env request --SKIPIF-- --GET-- dummy=1 --FILE-- setHeader("Range", "bytes=2-4"); $res = new http\Env\Response; $res->setEnvRequest($req); $res->setContentType("text/plain"); $res->getBody()->append("012345679"); $res->send($tmp); rewind($tmp); var_dump(stream_get_contents($tmp)); ?> Done --EXPECTF-- Test string(%d) "HTTP/1.1 206 Partial Content%c Accept-Ranges: bytes%c X-Powered-By: %s%c Content-Type: text/plain%c Content-Range: bytes 2-4/9%c Transfer-Encoding: chunked%c %c 3%c 234%c 0%c %c " Done pecl_http-4.2.1/tests/envresponse008.phpt0000644000076500000240000000117714117626035017121 0ustar Mikestaff--TEST-- env response stream message --SKIPIF-- --ENV-- HTTP_ACCEPT_ENCODING=gzip --FILE-- setHeader("foo","bar"); $r->setContentEncoding(http\env\Response::CONTENT_ENCODING_GZIP); $r->setBody(new http\message\Body(fopen(__FILE__,"r"))); $r->send($f); rewind($f); var_dump(stream_get_contents($f)); ?> --EXPECTREGEX-- string\(\d+\) "HTTP\/1\.1 200 OK Accept-Ranges: bytes Foo: bar Content-Encoding: gzip Vary: Accept-Encoding ETag: "\w+-\w+-\w+" Last-Modified: \w+, \d+ \w+ \d{4} \d\d:\d\d:\d\d GMT Transfer-Encoding: chunked d0 \x1f\x8b\x08.+ 0 " pecl_http-4.2.1/tests/envresponse009.phpt0000644000076500000240000000146214117626035017117 0ustar Mikestaff--TEST-- env response stream cache negative --SKIPIF-- --GET-- a=b --ENV-- HTTP_IF_MODIFIED_SINCE=Fri, 13 Feb 2009 23:31:30 GMT HTTP_IF_NONE_MATCH=0000-00-0000 --FILE-- setBody(new http\Message\Body(fopen(__FILE__,"rb"))); $r->setEtag("abc"); $r->setLastModified(1234567891); $r->send($f); rewind($f); var_dump(stream_get_contents($f)); ?> --EXPECTF-- string(%d) "HTTP/1.1 200 OK%c Accept-Ranges: bytes%c X-Powered-By: %s%c ETag: "abc"%c Last-Modified: %s%c Transfer-Encoding: chunked%c %c e1%c setBody(new http\Message\Body(fopen(__FILE__,"rb"))); $r->setEtag("abc"); $r->setLastModified(1234567891); $r->send($f); rewind($f); var_dump(stream_get_contents($f)); ?> %c 0%c %c " pecl_http-4.2.1/tests/envresponse010.phpt0000644000076500000240000000121114117626035017077 0ustar Mikestaff--TEST-- env response stream ranges --SKIPIF-- --ENV-- HTTP_RANGE=bytes=2-4 --GET-- a=b --FILE-- setContentType("text/plain"); $r->setContentDisposition( array("attachment" => array(array("filename" => basename(__FILE__)))) ); $r->setBody(new http\Message\Body(fopen(__FILE__, "rb"))); $r->send($f); rewind($f); var_dump(stream_get_contents($f)); ?> --EXPECTF-- string(%i) "HTTP/1.1 206 Partial Content%c Accept-Ranges: bytes%c X-Powered-By: PHP/%s%c Content-Type: text/plain%c Content-Range: bytes 2-4/311%c Transfer-Encoding: chunked%c %c 3%c php%c 0%c %c " pecl_http-4.2.1/tests/envresponse011.phpt0000644000076500000240000000123014117626035017101 0ustar Mikestaff--TEST-- env response cache positive with env message --SKIPIF-- --GET-- dummy=1 --FILE-- setHeader("If-Modified-Since", "Fri, 13 Feb 2009 23:31:32 GMT"); $r = new http\Env\Response; $r->setEnvRequest($e); $r->setBody(new http\Message\Body(fopen(__FILE__,"rb"))); $r->setEtag("abc"); $r->setLastModified(1234567891); $r->isCachedByEtag("If-None-Match") and die("Huh? etag? really?\n"); $r->isCachedByLastModified("If-Modified-Since") or die("yep, I should be cached"); $r->send(); ?> --EXPECTHEADERS-- HTTP/1.1 304 Not Modified ETag: "abc" Last-Modified: Fri, 13 Feb 2009 23:31:31 GMT --EXPECT-- pecl_http-4.2.1/tests/envresponse012.phpt0000644000076500000240000000111514117626035017104 0ustar Mikestaff--TEST-- env response content disposition --SKIPIF-- --GET-- dummy=1 --FILE-- setContentDisposition(array("attachment"=>array("filename"=>basename(__FILE__)))); $r->setBody(new http\Message\Body(fopen(__FILE__,"r"))); $r->send(); ?> --EXPECTHEADERS-- Content-Disposition: attachment;filename=envresponse012.php --EXPECT-- setContentDisposition(array("attachment"=>array("filename"=>basename(__FILE__)))); $r->setBody(new http\Message\Body(fopen(__FILE__,"r"))); $r->send(); ?> pecl_http-4.2.1/tests/envresponse013.phpt0000644000076500000240000000103114117626035017102 0ustar Mikestaff--TEST-- env response deflate --SKIPIF-- --GET-- dummy=1 --FILE-- setHeader("Accept-Encoding", "deflate"); $res = new http\Env\Response; $res->setCacheControl("public, max-age=3600"); $res->setContentEncoding(http\Env\Response::CONTENT_ENCODING_GZIP); $res->getBody()->append("foobar"); $res->setEnvRequest($req); $res->send(); ?> --EXPECTHEADERS-- Content-Encoding: deflate Vary: Accept-Encoding Cache-Control: public, max-age=3600 --EXPECTREGEX-- ^\x78\x9c.+ pecl_http-4.2.1/tests/envresponse014.phpt0000644000076500000240000000075514117626035017117 0ustar Mikestaff--TEST-- env response invalid ranges --SKIPIF-- --FILE-- setHeader("Range", "bytes=321-123,123-0"); $res = new http\Env\Response; $res->getBody()->append("foobar"); $res->setEnvRequest($req); $res->send($f); rewind($f); var_dump(stream_get_contents($f)); --EXPECTF-- string(129) "HTTP/1.1 416 Requested Range Not Satisfiable Accept-Ranges: bytes Content-Range: bytes */6 Transfer-Encoding: chunked 0 " pecl_http-4.2.1/tests/envresponse015.phpt0000644000076500000240000000100514117626035017105 0ustar Mikestaff--TEST-- env response send replaced body using multiple ob_start --SKIPIF-- --FILE-- getBody(); $r->setBody(new http\Message\Body); ob_start($r); echo "foo: $b\n"; ob_end_flush(); $f = fopen("php://memory", "r+"); $r->send($f); fseek($f, 0, SEEK_SET); echo stream_get_contents($f); ?> --EXPECT-- HTTP/1.1 200 OK Accept-Ranges: bytes ETag: "fc8305a1" Transfer-Encoding: chunked 9 foo: bar 0 pecl_http-4.2.1/tests/envresponse016.phpt0000644000076500000240000000124614117626035017115 0ustar Mikestaff--TEST-- env response send failure --SKIPIF-- --FILE-- getBody()->append(str_repeat("a", 16*1024*4)); $s = fopen("php://temp", "w"); stream_filter_append($s, "closer"); var_dump($r->send($s)); ?> DONE --EXPECTF-- Test Warning: http\Env\Response::send(): Failed to send response body in %s on line %d bool(false) DONE pecl_http-4.2.1/tests/envresponse017.phpt0000644000076500000240000000072014117626035017112 0ustar Mikestaff--TEST-- env response stream: no chunked transfer encoding for CONNECTs --SKIPIF-- --FILE-- setRequestMethod("CONNECT"); $req->setRequestUrl(array("host"=>"www.example.com", "port"=>80)); echo $req; $res = new http\Env\Response; $res->setEnvRequest($req); $res->send(STDOUT); ?> ===DONE=== --EXPECTF-- Test CONNECT www.example.com:80 HTTP/1.1 HTTP/1.1 200 OK ===DONE=== pecl_http-4.2.1/tests/envresponse018.phpt0000644000076500000240000000071114117626035017113 0ustar Mikestaff--TEST-- env response don't generate stat based etag for temp stream --SKIPIF-- --FILE-- append("1234567890\n"); $r = new http\Env\Response; $r->setBody($b); $r->send(STDOUT); ?> ===DONE=== --EXPECTF-- Test HTTP/1.1 200 OK Accept-Ranges: bytes ETag: "%x" Last-Modified: %s Transfer-Encoding: chunked b 1234567890 0 ===DONE=== pecl_http-4.2.1/tests/envresponsebody001.phpt0000644000076500000240000000035414117626035017764 0ustar Mikestaff--TEST-- env response body --SKIPIF-- --INI-- output_buffering=1 --FILE-- getBody()); ?> Done --EXPECTF-- Test string(5) "Test " Done pecl_http-4.2.1/tests/envresponsebody002.phpt0000644000076500000240000000065514117626035017771 0ustar Mikestaff--TEST-- env response body error --SKIPIF-- --INI-- output_buffering=1 --FILE-- getBody()); } catch (http\Exception $e) { echo $e->getMessage(),"\n"; } ?> Done --EXPECTF-- Test http\Env\Response::__construct(): Could not fetch response body, output has already been sent at %senvresponsebody002.php:3 Done pecl_http-4.2.1/tests/envresponsecodes.phpt0000644000076500000240000000051314117626035017700 0ustar Mikestaff--TEST-- env response codes --SKIPIF-- --FILE-- Done --EXPECT-- Test array(0) { } Done pecl_http-4.2.1/tests/envresponsecookie001.phpt0000644000076500000240000000063214117626035020277 0ustar Mikestaff--TEST-- env response cookie --SKIPIF-- --FILE-- addCookie("foo","bar"); $c->setMaxAge(60); $r->setCookie($c); $r->setCookie("baz"); $r->setCookie(123); $r->send(STDOUT); ?> --EXPECT-- HTTP/1.1 200 OK Set-Cookie: foo=bar; max-age=60; Set-Cookie: baz=1; Set-Cookie: 123=1; ETag: "" Transfer-Encoding: chunked 0 pecl_http-4.2.1/tests/envresponseheader001.phpt0000644000076500000240000000137114117626035020257 0ustar Mikestaff--TEST-- env response header --SKIPIF-- --FILE-- %s [Foo] => bar [More] => Array ( [0] => than [1] => what's [2] => good ) [Content-Type] => %s ) Created pecl_http-4.2.1/tests/envresponseranges001.phpt0000644000076500000240000000130214117626035020300 0ustar Mikestaff--TEST-- ranges --SKIPIF-- --GET-- a=b --ENV-- HTTP_RANGE=bytes=-3,000-001,1-1,0-0,100- --FILE-- setBody(new http\Message\Body(fopen(__FILE__, "rb"))); $r->send(); ?> --EXPECTF-- --%s%c Content-Type: application/octet-stream%c Content-Range: bytes 107-109/110%c %c ?> %c --%s%c Content-Type: application/octet-stream%c Content-Range: bytes 0-1/110%c %c %c --%s--pecl_http-4.2.1/tests/etag001.phpt0000644000076500000240000000120514117626035015453 0ustar Mikestaff--TEST-- etags with hash --SKIPIF-- --FILE-- append("Hello, my old fellow."); foreach (["md5", "sha1", "sha256"] as $algo) { if (strncmp($algo, "sha3-", 5) && strncmp($algo, "sha512/", 7) && strcmp($algo, "crc32c")) { ini_set("http.etag.mode", $algo); printf("%10s: %s\n", $algo, $body->etag() ); } } ?> DONE --EXPECT-- md5: 6ce3cc8f3861fb7fd0d77739f11cd29c sha1: ad84012eabe27a61762a97138d9d2623f4f1a7a9 sha256: ed9ecfe5c76d51179c3c1065916fdb8d94aee05577f187bd763cdc962bba1f42 DONE pecl_http-4.2.1/tests/filterbrotli.phpt0000644000076500000240000000130714117626035017016 0ustar Mikestaff--TEST-- brotli filter --SKIPIF-- --FILE-- DONE --EXPECT-- DONE pecl_http-4.2.1/tests/filterchunked.phpt0000644000076500000240000000111314117626035017137 0ustar Mikestaff--TEST-- chunked filter --SKIPIF-- --FILE-- DONE --EXPECT-- DONE pecl_http-4.2.1/tests/filterzlib.phpt0000644000076500000240000000113314117626035016460 0ustar Mikestaff--TEST-- zlib filter --SKIPIF-- --FILE-- DONE --EXPECT-- DONE pecl_http-4.2.1/tests/gh-issue6.phpt0000644000076500000240000000140714117626035016130 0ustar Mikestaff--TEST-- url - unsafe characters --SKIPIF-- --FILE-- query; echo "\n"; $url = new http\Url("?id={\$id}"); echo $url->query; echo "\n"; ?> ===DONE=== --EXPECT-- Test __utma=1152894289.1017686999.9107388726.1439222726.1494721726.1&__utmb=115739289.1.10.1437388726&__utmc=115883619&__utmx=-&__utmz=115111289.14310476.1.1.utmcsr=google|utmccn=(organic)|utmcmd=organic|utmctr=(not%20provided)&__utmv=-&__utmk=112678937 id={$id} ===DONE=== pecl_http-4.2.1/tests/gh-issue11.phpt0000644000076500000240000000052514117626035016204 0ustar Mikestaff--TEST-- crash when query string has nested array keys --SKIPIF-- --FILE-- ===DONE=== --EXPECT-- Test a%5B0%5D%5B0%5D=x&a%5B1%5D%5B0%5D=x ===DONE=== pecl_http-4.2.1/tests/gh-issue12.phpt0000644000076500000240000000121714117626035016204 0ustar Mikestaff--TEST-- crash with bad url passed to http\Message::setRequestUrl() --SKIPIF-- --FILE-- setRequestUrl($url); printf("OK: %s\n", $url); } catch (Exception $e) { printf("%s\n", $e->getMessage()); } } ?> ===DONE=== --EXPECT-- Test http\Message::setRequestUrl(): Failed to parse host; unexpected '.' at pos 0 in '.foo.bar' http\Message::setRequestUrl(): Failed to parse host; unexpected '.' at pos 4 in 'foo..bar' OK: http://foo.bar. ===DONE=== pecl_http-4.2.1/tests/gh-issue42.phpt0000644000076500000240000000034114117626035016204 0ustar Mikestaff--TEST-- URL barfs on punycode --SKIPIF-- --FILE-- ===DONE=== --EXPECT-- Test http://www.xn--kln-sna.de/ ===DONE=== pecl_http-4.2.1/tests/gh-issue47.phpt0000644000076500000240000000046614117626035016221 0ustar Mikestaff--TEST-- Null pointer deref in sanitize_value --SKIPIF-- --FILE-- mod($urls[1]); echo $url1; ?> ===DONE=== --EXPECTF-- Test http://%s/ ===DONE=== pecl_http-4.2.1/tests/gh-issue48.phpt0000644000076500000240000001153014117626035016214 0ustar Mikestaff--TEST-- url errors --SKIPIF-- --FILE-- getMessage(), "\n"; } echo "# IGNORE\n"; echo new http\Url($url, null, $flags|http\Url::IGNORE_ERRORS), "\n"; echo "# SILENT\n"; echo new http\Url($url, null, $flags|http\Url::SILENT_ERRORS), "\n"; echo "# IGNORE|SILENT\n"; echo new http\Url($url, null, $flags|http\Url::IGNORE_ERRORS|http\Url::SILENT_ERRORS), "\n"; echo "==========\n"; } test("http://.foo.bar/?q=1"); test("http://..foo.bar/i.x"); test("http://foo..bar/i..x"); test("http://-foo.bar"); test("http://--foo.bar"); test("http://f--oo.bar"); test("htto://foo.bar/?q=%"); test("htto://foo.bar/?q=%", http\Url::PARSE_TOPCT); test("http://a\xc3\xc3b"); test("http://[foobar]:123"); test("#/?foo=&#", http\Url::PARSE_MBUTF8); ?> ===DONE=== --EXPECTF-- Test # DEFAULT http\Url::__construct(): Failed to parse host; unexpected '.' at pos 0 in '.foo.bar/?q=1' # IGNORE Warning: http\Url::__construct(): Failed to parse host; unexpected '.' at pos 0 in '.foo.bar/?q=1' in %sgh-issue48.php on line %d http://foo.bar/?q=1 # SILENT # IGNORE|SILENT http://foo.bar/?q=1 ========== # DEFAULT http\Url::__construct(): Failed to parse host; unexpected '.' at pos 0 in '..foo.bar/i.x' # IGNORE Warning: http\Url::__construct(): Failed to parse host; unexpected '.' at pos 0 in '..foo.bar/i.x' in %sgh-issue48.php on line %d Warning: http\Url::__construct(): Failed to parse host; unexpected '.' at pos 1 in '..foo.bar/i.x' in %sgh-issue48.php on line %d http://foo.bar/i.x # SILENT # IGNORE|SILENT http://foo.bar/i.x ========== # DEFAULT http\Url::__construct(): Failed to parse host; unexpected '.' at pos 4 in 'foo..bar/i..x' # IGNORE Warning: http\Url::__construct(): Failed to parse host; unexpected '.' at pos 4 in 'foo..bar/i..x' in %sgh-issue48.php on line %d http://foo.bar/i..x # SILENT # IGNORE|SILENT http://foo.bar/i..x ========== # DEFAULT http\Url::__construct(): Failed to parse host; unexpected '-' at pos 0 in '-foo.bar' # IGNORE Warning: http\Url::__construct(): Failed to parse host; unexpected '-' at pos 0 in '-foo.bar' in %sgh-issue48.php on line %d http://foo.bar/ # SILENT # IGNORE|SILENT http://foo.bar/ ========== # DEFAULT http\Url::__construct(): Failed to parse host; unexpected '-' at pos 0 in '--foo.bar' # IGNORE Warning: http\Url::__construct(): Failed to parse host; unexpected '-' at pos 0 in '--foo.bar' in %sgh-issue48.php on line %d Warning: http\Url::__construct(): Failed to parse host; unexpected '-' at pos 1 in '--foo.bar' in %sgh-issue48.php on line %d http://foo.bar/ # SILENT # IGNORE|SILENT http://foo.bar/ ========== # DEFAULT http://f--oo.bar/ # IGNORE http://f--oo.bar/ # SILENT http://f--oo.bar/ # IGNORE|SILENT http://f--oo.bar/ ========== # DEFAULT http\Url::__construct(): Failed to parse query; invalid percent encoding at pos 2 in 'q=%' # IGNORE Warning: http\Url::__construct(): Failed to parse query; invalid percent encoding at pos 2 in 'q=%' in %sgh-issue48.php on line %d htto://foo.bar/?q=% # SILENT # IGNORE|SILENT htto://foo.bar/?q=% ========== # DEFAULT http\Url::__construct(): Failed to parse query; invalid percent encoding at pos 2 in 'q=%' # IGNORE Warning: http\Url::__construct(): Failed to parse query; invalid percent encoding at pos 2 in 'q=%' in %sgh-issue48.php on line %d htto://foo.bar/?q=%25 # SILENT # IGNORE|SILENT htto://foo.bar/?q=%25 ========== # DEFAULT http\Url::__construct(): Failed to parse hostinfo; unexpected byte 0xc3 at pos 1 in 'a%c%cb' # IGNORE Warning: http\Url::__construct(): Failed to parse hostinfo; unexpected byte 0xc3 at pos 1 in 'a%c%cb' in %sgh-issue48.php on line %d Warning: http\Url::__construct(): Failed to parse hostinfo; unexpected byte 0xc3 at pos 2 in 'a%c%cb' in %sgh-issue48.php on line %d http://a%r\xc3\xc3%rb/ # SILENT # IGNORE|SILENT http://a%r\xc3\xc3%rb/ ========== # DEFAULT http\Url::__construct(): Failed to parse hostinfo; unexpected '[' at pos 0 in '[foobar]:123' # IGNORE Warning: http\Url::__construct(): Failed to parse hostinfo; unexpected '[' at pos 0 in '[foobar]:123' in %sgh-issue48.php on line %d Warning: http\Url::__construct(): Failed to parse hostinfo; unexpected byte 0x5b at pos 0 in '[foobar]:123' in %sgh-issue48.php on line %d Warning: http\Url::__construct(): Failed to parse hostinfo; unexpected byte 0x5d at pos 7 in '[foobar]:123' in %sgh-issue48.php on line %d http://[foobar]:123/ # SILENT # IGNORE|SILENT http://[foobar]:123/ ========== # DEFAULT http\Url::__construct(): Failed to parse fragment; invalid fragment identifier at pos 7 in '/?foo=&#' # IGNORE Warning: http\Url::__construct(): Failed to parse fragment; invalid fragment identifier at pos 7 in '/?foo=&#' in %sgh-issue48.php on line %d #/?foo=&# # SILENT # IGNORE|SILENT #/?foo=&# ========== ===DONE=== pecl_http-4.2.1/tests/gh-issue50.phpt0000644000076500000240000000166314117626035016213 0ustar Mikestaff--TEST-- segfault with Client::setDebug and Client::dequeue() --SKIPIF-- --INI-- zend.exception_ignore_args=off --FILE-- enqueue(new http\Client\Request("GET", "http://example.com")); $c->setDebug(function(http\Client $c, http\Client\Request $r, $type, $data) { if ($type & http\Client::DEBUG_HEADER) { $c->dequeue($r); } }); try { $c->send(); } catch (Exception $e) { echo $e; } ?> ===DONE=== --EXPECTF-- Test http\Exception\RuntimeException: http\Client::dequeue(): Could not dequeue request while executing callbacks in %sgh-issue50.php:9 Stack trace: #0 %sgh-issue50.php(9): http\Client->dequeue(Object(http\Client\Request)) #1 [internal function]: {closure}(Object(http\Client), Object(http\Client\Request), 18, 'GET / HTTP/1.1%s...') #2 %sgh-issue50.php(14): http\Client->send() #3 {main} ===DONE=== pecl_http-4.2.1/tests/gh-issue63.phpt0000644000076500000240000000075214117626035016215 0ustar Mikestaff--TEST-- gh issue #63: Url::mod() breaks query strings containing plus-notation spaces in the input URL --SKIPIF-- --FILE-- 'bar']; $parts['query'] = new QueryString($query); echo (new Url($url, null, Url::STDFLAGS))->mod($parts)->toString(); ?> ===DONE=== --EXPECTF-- Test http://example.com/?param=has%20spaces&foo=bar ===DONE=== pecl_http-4.2.1/tests/gh-issue92.phpt0000644000076500000240000000453414117626035016221 0ustar Mikestaff--TEST-- gh-issue #93: message body add form ignores numeric indices --SKIPIF-- --FILE-- addForm( array("foo", "bar", "baz"), array( array( "file" => __FILE__, "name" => "upload", "type" => "text/plain", ), "dir" => array( array( "file" => __FILE__, "name" => 1, "type" => "text/plain", ), array( "file" => __FILE__, "name" => 2, "type" => "text/plain", ), ), ) ); echo $temp; ?> DONE --EXPECTF-- Test --%x.%x Content-Disposition: form-data; name="0" foo --%x.%x Content-Disposition: form-data; name="1" bar --%x.%x Content-Disposition: form-data; name="2" baz --%x.%x Content-Disposition: form-data; name="upload"; filename="gh-issue92.php" Content-Transfer-Encoding: binary Content-Type: text/plain addForm( array("foo", "bar", "baz"), array( array( "file" => __FILE__, "name" => "upload", "type" => "text/plain", ), "dir" => array( array( "file" => __FILE__, "name" => 1, "type" => "text/plain", ), array( "file" => __FILE__, "name" => 2, "type" => "text/plain", ), ), ) ); echo $temp; ?> DONE --%x.%x Content-Disposition: form-data; name="dir[1]"; filename="gh-issue92.php" Content-Transfer-Encoding: binary Content-Type: text/plain addForm( array("foo", "bar", "baz"), array( array( "file" => __FILE__, "name" => "upload", "type" => "text/plain", ), "dir" => array( array( "file" => __FILE__, "name" => 1, "type" => "text/plain", ), array( "file" => __FILE__, "name" => 2, "type" => "text/plain", ), ), ) ); echo $temp; ?> DONE --%x.%x Content-Disposition: form-data; name="dir[2]"; filename="gh-issue92.php" Content-Transfer-Encoding: binary Content-Type: text/plain addForm( array("foo", "bar", "baz"), array( array( "file" => __FILE__, "name" => "upload", "type" => "text/plain", ), "dir" => array( array( "file" => __FILE__, "name" => 1, "type" => "text/plain", ), array( "file" => __FILE__, "name" => 2, "type" => "text/plain", ), ), ) ); echo $temp; ?> DONE --%x.%x-- DONE pecl_http-4.2.1/tests/header001.phpt0000644000076500000240000000032514117626035015765 0ustar Mikestaff--TEST-- header string --SKIPIF-- --FILE-- Done --EXPECT-- Test bool(true) Done pecl_http-4.2.1/tests/header002.phpt0000644000076500000240000000032214117626035015763 0ustar Mikestaff--TEST-- header numeric --SKIPIF-- --FILE-- Done --EXPECT-- Test bool(true) Done pecl_http-4.2.1/tests/header003.phpt0000644000076500000240000000053114117626035015766 0ustar Mikestaff--TEST-- header serialize --SKIPIF-- --FILE-- Done --EXPECT-- Test bool(true) bool(true) Done pecl_http-4.2.1/tests/header004.phpt0000644000076500000240000000141214117626035015766 0ustar Mikestaff--TEST-- header match --SKIPIF-- --FILE-- match("gzip", http\Header::MATCH_WORD)); var_dump($ae->match("gzip", http\Header::MATCH_WORD|http\Header::MATCH_CASE)); var_dump($ae->match("gzip", http\Header::MATCH_STRICT)); var_dump($ae->match("deflate", http\Header::MATCH_WORD)); var_dump($ae->match("deflate", http\Header::MATCH_WORD|http\Header::MATCH_CASE)); var_dump($ae->match("deflate", http\Header::MATCH_STRICT)); var_dump($ae->match("zip", http\Header::MATCH_WORD)); var_dump($ae->match("gzip", http\Header::MATCH_FULL)); ?> Done --EXPECT-- Test bool(true) bool(true) bool(false) bool(true) bool(true) bool(false) bool(false) bool(false) Done pecl_http-4.2.1/tests/header005.phpt0000644000076500000240000000141714117626035015774 0ustar Mikestaff--TEST-- header negotiation --SKIPIF-- --FILE-- negotiate(array("text/plain","text/html"))); var_dump("text/html" === $a->negotiate(array("text/plain","text/html"), $rs)); var_dump(array("text/html"=>0.99, "text/plain"=>0.5) === array_map("r", $rs)); var_dump("text/plain" === $a->negotiate(array("foo/bar", "text/plain"), $rs)); var_dump(array("text/plain"=>0.5) === array_map("r", $rs)); var_dump("foo/bar" === $a->negotiate(array("foo/bar"), $rs)); var_dump(array() === $rs); ?> Done --EXPECT-- Test bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) Done pecl_http-4.2.1/tests/header006.phpt0000644000076500000240000000074714117626035016002 0ustar Mikestaff--TEST-- header parsing --SKIPIF-- --FILE-- "bar","Bar"=>"foo") === http\Header::parse($header)); $headers = http\Header::parse($header, "http\\Header"); var_dump(2 === count($headers)); var_dump(2 === array_reduce($headers, function($count, $header) { return $count + ($header instanceof http\Header); }, 0)); ?> Done --EXPECT-- Test bool(true) bool(true) bool(true) Done pecl_http-4.2.1/tests/header007.phpt0000644000076500000240000000046114117626035015774 0ustar Mikestaff--TEST-- header parse error --SKIPIF-- --FILE-- Done --EXPECTF-- Test Warning: http\Header::parse(): Failed to parse headers: unexpected end of line at pos 4 of 'wass\nup' in %s on line %d Done pecl_http-4.2.1/tests/header008.phpt0000644000076500000240000000073114117626035015775 0ustar Mikestaff--TEST-- header params --SKIPIF-- --FILE-- array("value" => true, "arguments" => array()), "must-revalidate" => array("value" => true, "arguments" => array()), "max-age" => array("value" => "0", "arguments" => array()), ) === $header->getParams()->params ); ?> Done --EXPECT-- Test bool(true) Done pecl_http-4.2.1/tests/header009.phpt0000644000076500000240000000071214117626035015775 0ustar Mikestaff--TEST-- header params w/ args --SKIPIF-- --FILE-- array("value" => "bar", "arguments" => array()), "bar" => array("value" => "bis", "arguments" => array("bis" => "where")) ) === $header->getParams(".", "where", "is")->params ); ?> Done --EXPECT-- Test bool(true) Done pecl_http-4.2.1/tests/headerparser001.phpt0000644000076500000240000000265114117626035017206 0ustar Mikestaff--TEST-- header parser --SKIPIF-- --FILE-- "FAILURE",0=>"START","KEY","VALUE","VALUE_EX","HEADER_DONE","DONE"); $parser = new http\Header\Parser; do { $state = $parser->parse($part = array_shift($headers), $headers ? 0 : http\Header\Parser::CLEANUP, $result); printf("%2\$-32s | %1\$s\n", $states[$state], addcslashes($part, "\r\n\t\0")); } while ($headers && $state !== http\Header\Parser::STATE_FAILURE); var_dump($result); ?> ===DONE=== --EXPECT-- Test One: | VALUE header\n | VALUE_EX Two: header\n\tlines\n | VALUE_EX Three | KEY : header\n lines\n here\n | VALUE_EX More: than one header\n | VALUE_EX More: | VALUE than: | VALUE you: | VALUE expect\n | VALUE_EX \n | DONE array(4) { ["One"]=> string(6) "header" ["Two"]=> string(12) "header lines" ["Three"]=> string(17) "header lines here" ["More"]=> array(2) { [0]=> string(15) "than one header" [1]=> string(17) "than: you: expect" } } ===DONE=== pecl_http-4.2.1/tests/headerparser002.phpt0000644000076500000240000000267714117626035017217 0ustar Mikestaff--TEST-- header parser errors --SKIPIF-- --FILE-- parse($header, http\Header\Parser::CLEANUP, $parsed), $parsed); } ?> ===DONE=== --EXPECTF-- Test Warning: http\Header\Parser::parse(): Failed to parse headers: unexpected character '\000' at pos 2 of 'Na\000me' in %sheaderparser002.php on line %d int(-1) array(0) { } Warning: http\Header\Parser::parse(): Failed to parse headers: unexpected end of line at pos 2 of 'Na\nme: value' in %sheaderparser002.php on line %d int(-1) array(0) { } Warning: http\Header\Parser::parse(): Failed to parse headers: unexpected character '\000' at pos 0 of '\000value' in %sheaderparser002.php on line %d int(-1) array(0) { } Warning: http\Header\Parser::parse(): Failed to parse headers: unexpected end of input at pos 5 of 'value' in %sheaderparser002.php on line %d int(-1) array(0) { } Warning: http\Header\Parser::parse(): Failed to parse headers: unexpected character '\000' at pos 3 of 'val\000ue' in %sheaderparser002.php on line %d int(-1) array(0) { } Warning: http\Header\Parser::parse(): Failed to parse headers: unexpected character '\000' at pos 5 of 'value\000' in %sheaderparser002.php on line %d int(-1) array(0) { } ===DONE===pecl_http-4.2.1/tests/headerparser003.phpt0000644000076500000240000000143714117626035017211 0ustar Mikestaff--TEST-- header parser with nonblocking stream --SKIPIF-- --FILE-- stream($socket[0], 0, $hdrs); fwrite($socket[1], $line); var_dump($parser->getState()); var_dump($parser->stream($socket[0], 0, $hdrs)); } var_dump($hdrs); ?> DONE --EXPECT-- Test int(0) int(1) int(1) int(2) int(2) int(3) int(3) int(1) int(1) int(3) int(3) int(5) array(2) { ["Host"]=> string(9) "localhost" ["Content-Length"]=> string(1) "3" } DONE pecl_http-4.2.1/tests/info001.phpt0000644000076500000240000000304614117626035015473 0ustar Mikestaff--TEST-- invalid HTTP info --SKIPIF-- --INI-- zend.exception_ignore_args=off --FILE-- DONE --EXPECTF-- http\Exception\BadMessageException: http\Message::__construct(): Failed to parse headers: unexpected character '\040' at pos 3 of 'GET HTTP/1.1' in %s Stack trace: #0 %s: http\Message->__construct('GET HTTP/1.1') #1 {main} http\Exception\BadMessageException: http\Message::__construct(): Failed to parse headers: unexpected character '\040' at pos 3 of 'GET HTTP/1.123' in %s Stack trace: #0 %s: http\Message->__construct('GET HTTP/1.123') #1 {main} http\Exception\BadMessageException: http\Message::__construct(): Failed to parse headers: unexpected character '\057' at pos 7 of 'GETHTTP/1.1' %s Stack trace: #0 %s: http\Message->__construct('GETHTTP/1.1') #1 {main} object(http\Message)#%d (9) { ["type":protected]=> int(1) ["body":protected]=> NULL ["requestMethod":protected]=> string(3) "GET" ["requestUrl":protected]=> string(1) "/" ["responseStatus":protected]=> string(0) "" ["responseCode":protected]=> int(0) ["httpVersion":protected]=> string(3) "1.1" ["headers":protected]=> array(0) { } ["parentMessage":protected]=> NULL } DONE pecl_http-4.2.1/tests/info002.phpt0000644000076500000240000000235614117626035015477 0ustar Mikestaff--TEST-- invalid HTTP info --SKIPIF-- --INI-- zend.exception_ignore_args=off --FILE-- ===DONE=== --EXPECTF-- Test http\Exception\BadMessageException: http\Message::__construct(): Failed to parse headers: unexpected character '\057' at pos 4 of 'HTTP/1.1 99 Apples in my Basket' in %sinfo002.php:%d Stack trace: #0 %sinfo002.php(%d): http\Message->__construct('HTTP/1.1 99 App...') #1 %sinfo002.php(%d): {closure}() #2 %sinfo002.php(%d): trap(Object(Closure)) #3 {main} http\Exception\BadMessageException: http\Message::__construct(): Failed to parse headers: unexpected character '\040' at pos 7 of 'CONNECT HTTP/1.1' in %sinfo002.php:%d Stack trace: #0 %sinfo002.php(%d): http\Message->__construct('CONNECT HTTP/1....') #1 %sinfo002.php(%d): {closure}() #2 %sinfo002.php(%d): trap(Object(Closure)) #3 {main} HTTP/1.1 200 CONNECT www.example.org:80 HTTP/1.1 ===DONE=== pecl_http-4.2.1/tests/message001.phpt0000644000076500000240000002443414117626035016170 0ustar Mikestaff--TEST-- message --SKIPIF-- --FILE-- getHttpVersion(), $m->getType()==HttpMessage::TYPE_NONE, $m->getHeaders() ); $m = new HttpMessage("GET / HTTP/1.1\r\n"); echo $m; var_dump( $m->getHttpVersion(), $m->getType()==HttpMessage::TYPE_REQUEST, $m->getRequestMethod(), $m->getRequestUrl(), $m->getHeaders() ); $m = new HttpMessage("HTTP/1.1 200 Okidoki\r\n"); echo $m; var_dump( $m->getHttpVersion(), $m->getType()==HttpMessage::TYPE_RESPONSE, $m->getResponseCode(), $m->getResponseStatus(), $m->getHeaders() ); echo "---\n"; $m = new HttpMessage(file_get_contents(__DIR__."/data/message_rr_empty.txt")); echo $m; var_dump( $m->getHttpVersion(), $m->getType()==HttpMessage::TYPE_RESPONSE, $m->getResponseCode(), $m->getResponseStatus(), $m->getHeaders() ); echo $m->getParentMessage(); $m = new HttpMessage(file_get_contents(__DIR__."/data/message_rr_empty_gzip.txt")); echo $m; var_dump( $m->getHttpVersion(), $m->getType()==HttpMessage::TYPE_RESPONSE, $m->getResponseCode(), $m->getResponseStatus(), $m->getHeaders() ); echo $m->getParentMessage(); $m = new HttpMessage(file_get_contents(__DIR__."/data/message_rr_empty_chunked.txt")); echo $m; var_dump( $m->getHttpVersion(), $m->getType()==HttpMessage::TYPE_RESPONSE, $m->getResponseCode(), $m->getResponseStatus(), $m->getHeaders() ); echo $m->getParentMessage(); $m = new HttpMessage(file_get_contents(__DIR__."/data/message_rr_helloworld_chunked.txt")); echo $m; var_dump( $m->getHttpVersion(), $m->getType()==HttpMessage::TYPE_RESPONSE, $m->getResponseCode(), $m->getResponseStatus(), $m->getHeaders() ); echo $m->getParentMessage(); echo "---\n"; $m = new HttpMessage(fopen(__DIR__."/data/message_rr_empty.txt", "r+b")); echo $m; var_dump( $m->getHttpVersion(), $m->getType()==HttpMessage::TYPE_RESPONSE, $m->getResponseCode(), $m->getResponseStatus(), $m->getHeaders() ); echo $m->getParentMessage(); $m = new HttpMessage(fopen(__DIR__."/data/message_rr_empty_gzip.txt", "r+b")); echo $m; var_dump( $m->getHttpVersion(), $m->getType()==HttpMessage::TYPE_RESPONSE, $m->getResponseCode(), $m->getResponseStatus(), $m->getHeaders() ); echo $m->getParentMessage(); $m = new HttpMessage(fopen(__DIR__."/data/message_rr_empty_chunked.txt", "r+b")); echo $m; var_dump( $m->getHttpVersion(), $m->getType()==HttpMessage::TYPE_RESPONSE, $m->getResponseCode(), $m->getResponseStatus(), $m->getHeaders() ); echo $m->getParentMessage(); $m = new HttpMessage(fopen(__DIR__."/data/message_rr_helloworld_chunked.txt", "r+b")); echo $m; var_dump( $m->getHttpVersion(), $m->getType()==HttpMessage::TYPE_RESPONSE, $m->getResponseCode(), $m->getResponseStatus(), $m->getHeaders() ); echo $m->getParentMessage(); echo "Done\n"; --EXPECTF-- Test string(3) "1.1" bool(true) array(0) { } GET / HTTP/1.1 string(3) "1.1" bool(true) string(3) "GET" string(1) "/" array(0) { } HTTP/1.1 200 Okidoki string(3) "1.1" bool(true) int(200) string(7) "Okidoki" array(0) { } --- HTTP/1.1 200 OK Date: Wed, 25 Aug 2010 12:11:44 GMT Server: Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6 Last-Modified: Wed, 28 Apr 2010 10:54:37 GMT Etag: "2002a-0-48549d615a35c" Accept-Ranges: bytes Content-Length: 0 Vary: Accept-Encoding Connection: close Content-Type: text/plain X-Original-Content-Length: 0 string(3) "1.1" bool(true) int(200) string(2) "OK" array(10) { ["Date"]=> string(29) "Wed, 25 Aug 2010 12:11:44 GMT" ["Server"]=> string(68) "Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6" ["Last-Modified"]=> string(29) "Wed, 28 Apr 2010 10:54:37 GMT" ["Etag"]=> string(23) ""2002a-0-48549d615a35c"" ["Accept-Ranges"]=> string(5) "bytes" ["Content-Length"]=> string(1) "0" ["Vary"]=> string(15) "Accept-Encoding" ["Connection"]=> string(5) "close" ["Content-Type"]=> string(10) "text/plain" ["X-Original-Content-Length"]=> string(1) "0" } GET /default/empty.txt HTTP/1.1 Host: localhost Connection: close HTTP/1.1 200 OK Date: Thu, 26 Aug 2010 09:55:09 GMT Server: Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6 Last-Modified: Wed, 28 Apr 2010 10:54:37 GMT Etag: "2002a-0-48549d615a35c" Accept-Ranges: bytes Vary: Accept-Encoding Connection: close Content-Type: text/plain X-Original-Content-Length: 20 X-Original-Content-Encoding: gzip string(3) "1.1" bool(true) int(200) string(2) "OK" array(10) { ["Date"]=> string(29) "Thu, 26 Aug 2010 09:55:09 GMT" ["Server"]=> string(68) "Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6" ["Last-Modified"]=> string(29) "Wed, 28 Apr 2010 10:54:37 GMT" ["Etag"]=> string(23) ""2002a-0-48549d615a35c"" ["Accept-Ranges"]=> string(5) "bytes" ["Vary"]=> string(15) "Accept-Encoding" ["Connection"]=> string(5) "close" ["Content-Type"]=> string(10) "text/plain" ["X-Original-Content-Length"]=> string(2) "20" ["X-Original-Content-Encoding"]=> string(4) "gzip" } GET /default/empty.txt HTTP/1.1 Host: localhost Accept-Encoding: gzip Connection: close HTTP/1.1 200 OK Date: Thu, 26 Aug 2010 11:41:02 GMT Server: Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6 X-Powered-By: PHP/5.3.3 Vary: Accept-Encoding Connection: close Content-Type: text/html X-Original-Transfer-Encoding: chunked Content-Length: 0 string(3) "1.1" bool(true) int(200) string(2) "OK" array(8) { ["Date"]=> string(29) "Thu, 26 Aug 2010 11:41:02 GMT" ["Server"]=> string(68) "Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6" ["X-Powered-By"]=> string(9) "PHP/5.3.3" ["Vary"]=> string(15) "Accept-Encoding" ["Connection"]=> string(5) "close" ["Content-Type"]=> string(9) "text/html" ["X-Original-Transfer-Encoding"]=> string(7) "chunked" ["Content-Length"]=> int(0) } GET /default/empty.php HTTP/1.1 Connection: close Host: localhost HTTP/1.1 200 OK Date: Thu, 26 Aug 2010 12:51:28 GMT Server: Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6 Vary: Accept-Encoding Connection: close Content-Type: text/plain X-Original-Transfer-Encoding: chunked Content-Length: 14 Hello, World! string(3) "1.1" bool(true) int(200) string(2) "OK" array(7) { ["Date"]=> string(29) "Thu, 26 Aug 2010 12:51:28 GMT" ["Server"]=> string(68) "Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6" ["Vary"]=> string(15) "Accept-Encoding" ["Connection"]=> string(5) "close" ["Content-Type"]=> string(10) "text/plain" ["X-Original-Transfer-Encoding"]=> string(7) "chunked" ["Content-Length"]=> int(14) } GET /cgi-bin/chunked.sh HTTP/1.1 Host: localhost Connection: close --- HTTP/1.1 200 OK Date: Wed, 25 Aug 2010 12:11:44 GMT Server: Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6 Last-Modified: Wed, 28 Apr 2010 10:54:37 GMT Etag: "2002a-0-48549d615a35c" Accept-Ranges: bytes Content-Length: 0 Vary: Accept-Encoding Connection: close Content-Type: text/plain X-Original-Content-Length: 0 string(3) "1.1" bool(true) int(200) string(2) "OK" array(10) { ["Date"]=> string(29) "Wed, 25 Aug 2010 12:11:44 GMT" ["Server"]=> string(68) "Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6" ["Last-Modified"]=> string(29) "Wed, 28 Apr 2010 10:54:37 GMT" ["Etag"]=> string(23) ""2002a-0-48549d615a35c"" ["Accept-Ranges"]=> string(5) "bytes" ["Content-Length"]=> string(1) "0" ["Vary"]=> string(15) "Accept-Encoding" ["Connection"]=> string(5) "close" ["Content-Type"]=> string(10) "text/plain" ["X-Original-Content-Length"]=> string(1) "0" } GET /default/empty.txt HTTP/1.1 Host: localhost Connection: close HTTP/1.1 200 OK Date: Thu, 26 Aug 2010 09:55:09 GMT Server: Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6 Last-Modified: Wed, 28 Apr 2010 10:54:37 GMT Etag: "2002a-0-48549d615a35c" Accept-Ranges: bytes Vary: Accept-Encoding Connection: close Content-Type: text/plain X-Original-Content-Length: 20 X-Original-Content-Encoding: gzip string(3) "1.1" bool(true) int(200) string(2) "OK" array(10) { ["Date"]=> string(29) "Thu, 26 Aug 2010 09:55:09 GMT" ["Server"]=> string(68) "Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6" ["Last-Modified"]=> string(29) "Wed, 28 Apr 2010 10:54:37 GMT" ["Etag"]=> string(23) ""2002a-0-48549d615a35c"" ["Accept-Ranges"]=> string(5) "bytes" ["Vary"]=> string(15) "Accept-Encoding" ["Connection"]=> string(5) "close" ["Content-Type"]=> string(10) "text/plain" ["X-Original-Content-Length"]=> string(2) "20" ["X-Original-Content-Encoding"]=> string(4) "gzip" } GET /default/empty.txt HTTP/1.1 Host: localhost Accept-Encoding: gzip Connection: close HTTP/1.1 200 OK Date: Thu, 26 Aug 2010 11:41:02 GMT Server: Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6 X-Powered-By: PHP/5.3.3 Vary: Accept-Encoding Connection: close Content-Type: text/html X-Original-Transfer-Encoding: chunked Content-Length: 0 string(3) "1.1" bool(true) int(200) string(2) "OK" array(8) { ["Date"]=> string(29) "Thu, 26 Aug 2010 11:41:02 GMT" ["Server"]=> string(68) "Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6" ["X-Powered-By"]=> string(9) "PHP/5.3.3" ["Vary"]=> string(15) "Accept-Encoding" ["Connection"]=> string(5) "close" ["Content-Type"]=> string(9) "text/html" ["X-Original-Transfer-Encoding"]=> string(7) "chunked" ["Content-Length"]=> int(0) } GET /default/empty.php HTTP/1.1 Connection: close Host: localhost HTTP/1.1 200 OK Date: Thu, 26 Aug 2010 12:51:28 GMT Server: Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6 Vary: Accept-Encoding Connection: close Content-Type: text/plain X-Original-Transfer-Encoding: chunked Content-Length: 14 Hello, World! string(3) "1.1" bool(true) int(200) string(2) "OK" array(7) { ["Date"]=> string(29) "Thu, 26 Aug 2010 12:51:28 GMT" ["Server"]=> string(68) "Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6" ["Vary"]=> string(15) "Accept-Encoding" ["Connection"]=> string(5) "close" ["Content-Type"]=> string(10) "text/plain" ["X-Original-Transfer-Encoding"]=> string(7) "chunked" ["Content-Length"]=> int(14) } GET /cgi-bin/chunked.sh HTTP/1.1 Host: localhost Connection: close Done pecl_http-4.2.1/tests/message002.phpt0000644000076500000240000000353014117626035016163 0ustar Mikestaff--TEST-- env request message --SKIPIF-- --POST_RAW-- Content-Type: test/something b=c --ENV-- HTTP_X_TEST=test --COOKIE-- foo=bar --INI-- always_populate_raw_post_data=-1 --FILE-- getHeaders(); ksort($h); $m->setHeaders($h); var_dump($m); echo "Message->toString\n"; echo $m,"\n"; echo "Body->toString\n"; var_dump((string)$m->getBody()); echo "stream\n"; var_dump(file_get_contents("php://input")); ?> Done --EXPECTF-- Test object(%s)#%d (13) { ["type":protected]=> int(1) ["body":protected]=> object(http\Message\Body)#3 (0) { } ["requestMethod":protected]=> string(4) "POST" ["requestUrl":protected]=> string(0) "" ["responseStatus":protected]=> string(0) "" ["responseCode":protected]=> int(0) ["httpVersion":protected]=> string(3) "1.1" ["headers":protected]=> array(4) { ["Content-Length"]=> string(1) "3" ["Content-Type"]=> string(14) "test/something" ["Cookie"]=> string(7) "foo=bar" ["X-Test"]=> string(4) "test" } ["parentMessage":protected]=> NULL ["query":protected]=> object(http\QueryString)#%d (1) { ["queryArray":"http\QueryString":private]=> array(0) { } } ["form":protected]=> object(http\QueryString)#%d (1) { ["queryArray":"http\QueryString":private]=> array(0) { } } ["cookie":protected]=> object(http\QueryString)#%d (1) { ["queryArray":"http\QueryString":private]=> array(1) { ["foo"]=> string(3) "bar" } } ["files":protected]=> array(0) { } } Message->toString POST / HTTP/1.1%a Content-Length: 3%a Content-Type: test/something%a Cookie: foo=bar%a X-Test: test%a %a b=c Body->toString string(3) "b=c" stream string(3) "b=c" Done pecl_http-4.2.1/tests/message003.phpt0000644000076500000240000000505714117626035016172 0ustar Mikestaff--TEST-- multipart message --SKIPIF-- --FILE-- isMultipart($boundary)) { var_dump($boundary); foreach ($m->splitMultipartBody() as $i => $mm) { echo "==$i==\n",$mm,"===\n"; } } ?> DONE --EXPECTF-- string(40) "----------------------------6e182425881c" ==%d== Content-Disposition: form-data; name="composer"; filename="composer.json" Content-Type: application/octet-stream Content-Length: 567 { "name": "mike_php_net/autocracy", "type": "library", "description": "http\\Controller preserves your autocracy", "keywords": ["http", "controller", "pecl", "pecl_http"], "homepage": "http://github.com/mike-php-net/autocracy", "license": "BSD-2", "authors": [ { "name": "Michael Wallner", "email": "mike@php.net" } ], "require": { "php": ">=5.4.0", "pecl/pecl_http": "2.*" }, "autoload": { "psr-0": { "http\\Controller": "lib" } } } === ==%d== Content-Disposition: form-data; name="LICENSE"; filename="LICENSE" Content-Type: application/octet-stream Content-Length: 1354 Copyright (c) 2011-2012, Michael Wallner . 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. === DONE pecl_http-4.2.1/tests/message004.phpt0000644000076500000240000000172014117626035016164 0ustar Mikestaff--TEST-- message reversal --SKIPIF-- --FILE-- toString(true); echo "===\n"; echo newHttpMessage($s)->reverse()->toString(true); $m = newHttpMessage($s); $r = $m->reverse(); unset($m); var_dump($r->count()); echo $r->toString(true); ?> DONE --EXPECTF-- GET /first HTTP/1.1 HTTP/1.1 200 Ok-first GET /second HTTP/1.1 HTTP/1.1 200 Ok-second GET /third HTTP/1.1 HTTP/1.1 200 Ok-third === HTTP/1.1 200 Ok-third GET /third HTTP/1.1 HTTP/1.1 200 Ok-second GET /second HTTP/1.1 HTTP/1.1 200 Ok-first GET /first HTTP/1.1 int(6) HTTP/1.1 200 Ok-third GET /third HTTP/1.1 HTTP/1.1 200 Ok-second GET /second HTTP/1.1 HTTP/1.1 200 Ok-first GET /first HTTP/1.1 DONE pecl_http-4.2.1/tests/message005.phpt0000644000076500000240000000070014117626035016162 0ustar Mikestaff--TEST-- message cloning --SKIPIF-- setType(http\Message::TYPE_REQUEST); $cpy->setHeaders(array("Numbers" => array(1,2,3,4.5))); echo $msg; echo "\n===\n"; echo $cpy; ?> DONE --EXPECTF-- HTTP/1.1 200 Ok String: foobar === UNKNOWN / HTTP/1.1 Numbers: 1 Numbers: 2 Numbers: 3 Numbers: 4.5 DONE pecl_http-4.2.1/tests/message007.phpt0000644000076500000240000000060114117626035016164 0ustar Mikestaff--TEST-- message to stream --SKIPIF-- --FILE-- addHeader("Content-Type", "text/plain"); $m->getBody()->append("this\nis\nthe\ntext"); $f = tmpfile(); $m->toStream($f); rewind($f); var_dump((string) $m === stream_get_contents($f)); fclose($f); ?> Done --EXPECT-- Test bool(true) Done pecl_http-4.2.1/tests/message008.phpt0000644000076500000240000000075714117626035016201 0ustar Mikestaff--TEST-- message to callback --SKIPIF-- --FILE-- addHeader("Content-Type", "text/plain"); $m->getBody()->append("this\nis\nthe\ntext"); $d = new http\Encoding\Stream\Deflate; $s = ""; $m->toCallback(function ($m, $data) use ($d, &$s) { $s.=$d->update($data); }); $s.=$d->finish(); var_dump($m->toString() === http\Encoding\Stream\Inflate::decode($s)); ?> Done --EXPECT-- Test bool(true) Done pecl_http-4.2.1/tests/message009.phpt0000644000076500000240000000772514117626035016204 0ustar Mikestaff--TEST-- message properties --SKIPIF-- --FILE-- $prop; case "set": $this->$prop = current($args); break; } } } } $test = new message; var_dump(0 === $test->testGetType()); var_dump(null === $test->testGetBody()); var_dump(null === $test->testGetRequestMethod()); var_dump(null === $test->testGetRequestUrl()); var_dump(null === $test->testGetResponseStatus()); var_dump(null === $test->testGetResponseCode()); var_dump("1.1" === $test->testGetHttpVersion()); var_dump(array() === $test->testGetHeaders()); var_dump(null === $test->testGetParentMessage()); $test->testSetType(http\Message::TYPE_REQUEST); var_dump(http\Message::TYPE_REQUEST === $test->testGetType()); var_dump(http\Message::TYPE_REQUEST === $test->getType()); $body = new http\Message\Body; $test->testSetBody($body); var_dump($body === $test->testGetBody()); var_dump($body === $test->getBody()); $file = fopen(__FILE__,"r"); $test->testSetBody($file); var_dump($file === $test->testGetBody()->getResource()); var_dump($file === $test->getBody()->getResource()); $test->testSetBody("data"); var_dump("data" === (string) $test->testGetBody()); var_dump("data" === (string) $test->getBody()); $test->testSetRequestMethod("HEAD"); var_dump("HEAD" === $test->testGetRequestMethod()); var_dump("HEAD" === $test->getRequestMethod()); $test->testSetRequestUrl("/"); var_dump("/" === $test->testGetRequestUrl()); var_dump("/" === $test->getRequestUrl()); var_dump("HEAD / HTTP/1.1" === $test->getInfo()); $test->testSetType(http\Message::TYPE_RESPONSE); $test->setResponseStatus("Created"); var_dump("Created" === $test->testGetResponseStatus()); var_dump("Created" === $test->getResponseStatus()); $test->setResponseCode(201); var_dump(201 === $test->testGetResponseCode()); var_dump(201 === $test->getResponseCode()); $test->testSetResponseStatus("Ok"); var_dump("Ok" === $test->testGetResponseStatus()); var_dump("Ok" === $test->getResponseStatus()); $test->testSetResponseCode(200); var_dump(200 === $test->testGetResponseCode()); var_dump(200 === $test->getResponseCode()); $test->testSetHttpVersion("1.0"); var_dump("1.0" === $test->testGetHttpVersion()); var_dump("1.0" === $test->getHttpVersion()); var_dump("HTTP/1.0 200 OK" === $test->getInfo()); $test->setHttpVersion("1.1"); var_dump("1.1" === $test->testGetHttpVersion()); var_dump("1.1" === $test->getHttpVersion()); var_dump("HTTP/1.1 200 OK" === $test->getInfo()); $test->setInfo("HTTP/1.1 201 Created"); var_dump("Created" === $test->testGetResponseStatus()); var_dump("Created" === $test->getResponseStatus()); var_dump(201 === $test->testGetResponseCode()); var_dump(201 === $test->getResponseCode()); var_dump("1.1" === $test->testGetHttpVersion()); var_dump("1.1" === $test->getHttpVersion()); $test->testSetHeaders(array("Foo" => "bar")); var_dump(array("Foo" => "bar") === $test->testGetHeaders()); var_dump(array("Foo" => "bar") === $test->getHeaders()); var_dump("bar" === $test->getHeader("foo")); var_dump(false === $test->getHeader("bar")); $parent = new message; $test->testSetParentMessage($parent); var_dump($parent === $test->testGetParentMessage()); var_dump($parent === $test->getParentMessage()); ?> Done --EXPECT-- Test bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) Done pecl_http-4.2.1/tests/message010.phpt0000644000076500000240000000054114117626035016161 0ustar Mikestaff--TEST-- message body --SKIPIF-- --FILE-- append("foo"); $m->addBody($body); $body = new http\Message\Body; $body->append("bar"); $m->addBody($body); var_dump("foobar" === (string) $m->getBody()); ?> Done --EXPECT-- Test bool(true) Done pecl_http-4.2.1/tests/message011.phpt0000644000076500000240000000331514117626035016164 0ustar Mikestaff--TEST-- message headers --SKIPIF-- --INI-- date.timezone=UTC --FILE-- str = $str; } function __toString() { return (string) $this->str; } } $m = new http\Message; $m->addHeaders(array("foo"=>"bar","bar"=>"foo")); if (array("Foo"=>"bar", "Bar"=>"foo") !== $m->getHeaders()) { var_dump($m->getHeaders()); } $m->addHeaders(array("key"=>"val","more"=>"Stuff")); if (array("Foo"=>"bar", "Bar"=>"foo","Key"=>"val","More"=>"Stuff") !== $m->getHeaders()) { var_dump($m->getHeaders()); } $m = new http\Message("GET / HTTP/1.1"); $m->addHeader("Accept", "text/html"); $m->addHeader("Accept", "text/xml;q=0"); $m->addHeader("Accept", "text/plain;q=0.5"); if ( "GET / HTTP/1.1\r\n". "Accept: text/html, text/xml;q=0, text/plain;q=0.5\r\n" !== $m->toString()) { var_dump($m->toString()); } $m = new http\Message("HTTP/1.1 200 Ok"); $m->addHeader("Bool", true); $m->addHeader("Int", 123); $m->addHeader("Float", 1.23); $m->addHeader("Array", array(1,2,3)); $m->addHeader("Object", new strval("test")); $m->addHeader("Set-Cookie", new http\Cookie( array( "cookies" => array("foo" => "bar"), "expires" => date_create("2012-12-31 22:59:59 GMT")->format( DateTime::COOKIE ), "path" => "/somewhere" ) ) ); $m->addHeader("Set-Cookie", "val=0"); if ( "HTTP/1.1 200 Ok\r\n". "Bool: true\r\n". "Int: 123\r\n". "Float: 1.23\r\n". "Array: 1, 2, 3\r\n". "Object: test\r\n". "Set-Cookie: foo=bar; path=/somewhere; expires=Mon, 31 Dec 2012 22:59:59 GMT; \r\n". "Set-Cookie: val=0\r\n" !== $m->toString()) { var_dump($m->toString()); } ?> Done --EXPECT-- Test Done pecl_http-4.2.1/tests/message012.phpt0000644000076500000240000000071014117626035016161 0ustar Mikestaff--TEST-- message part --SKIPIF-- --FILE-- addHeader("Content-Type", "text/plain"); $p->getBody()->append("data"); $m = new http\Message("HTTP/1.1 200"); $m->getBody()->addPart($p); echo $m; ?> Done --EXPECTF-- Test HTTP/1.1 200 Content-Length: %d Content-Type: multipart/form-data; boundary="%x.%x" --%x.%x Content-Type: text/plain Content-Length: 4 data --%x.%x-- Done pecl_http-4.2.1/tests/message013.phpt0000644000076500000240000000067114117626035016170 0ustar Mikestaff--TEST-- message detach --SKIPIF-- --FILE-- detach(); var_dump(3 === count($m)); var_dump(1 === count($d)); var_dump("HTTP/1.1 302 Found\r\n\r\n" === $d->toString(true)); ?> Done --EXPECTF-- Test bool(true) bool(true) bool(true) bool(true) Done pecl_http-4.2.1/tests/message014.phpt0000644000076500000240000000104114117626035016161 0ustar Mikestaff--TEST-- message prepend --SKIPIF-- --FILE-- prepend($p); $p = $m; } var_dump( "HTTP/1.1 200\r\n\r\n". "HTTP/1.1 201\r\n\r\n". "HTTP/1.1 202\r\n\r\n". "HTTP/1.1 203\r\n\r\n". "HTTP/1.1 204\r\n\r\n". "HTTP/1.1 205\r\n\r\n". "HTTP/1.1 206\r\n\r\n". "HTTP/1.1 207\r\n\r\n". "HTTP/1.1 208\r\n\r\n" === $m->toString(true) ); ?> Done --EXPECTF-- Test bool(true) Done pecl_http-4.2.1/tests/message015.phpt0000644000076500000240000000156514117626035016175 0ustar Mikestaff--TEST-- message errors --SKIPIF-- --FILE-- setRequestUrl("/foo"); } catch (http\Exception $e) { echo $e->getMessage(),"\n"; } $m->setType(http\Message::TYPE_REQUEST); try { $m->setRequestUrl(""); } catch (http\Exception $e) { echo $e->getMessage(),"\n"; } $m = new http\Message; try { $m->getParentMessage(); die("unreached"); } catch (http\Exception $e) { echo $e->getMessage(),"\n"; } $m = new http\Message("HTTP/1.1 200\r\nHTTP/1.1 201"); try { $m->prepend($m->getParentMessage()); die("unreached"); } catch (http\Exception $e) { echo $e->getMessage(),"\n"; } ?> Done --EXPECTF-- Test http\Message is not of type request Cannot set http\Message's request url to an empty string http\Message has no parent message Cannot prepend a message located within the same message chain Done pecl_http-4.2.1/tests/message016.phpt0000644000076500000240000000066414117626035016175 0ustar Mikestaff--TEST-- message content range --SKIPIF-- --FILE-- ===DONE=== --EXPECT-- Test PUT / HTTP/1.1 User-Agent: PECL_HTTP/2.3.0dev PHP/5.6.6-dev libcurl/7.41.0-DEV Host: localhost:8000 Accept: */* Expect: 100-continue Content-Length: 3 Content-Range: bytes 1-2/3 X-Original-Content-Length: 3 23===DONE=== pecl_http-4.2.1/tests/messagebody001.phpt0000644000076500000240000000113514117626035017037 0ustar Mikestaff--TEST-- message body stat --SKIPIF-- --FILE-- stat("size")); var_dump(filemtime(__FILE__) === $file->stat("mtime")); var_dump(fileatime(__FILE__) === $file->stat("atime")); var_dump(filectime(__FILE__) === $file->stat("ctime")); var_dump( (object) array( "size" => 0, "mtime" => 0, "atime" => 0, "ctime" => 0, ) == $temp->stat() ); ?> DONE --EXPECT-- Test bool(true) bool(true) bool(true) bool(true) bool(true) DONE pecl_http-4.2.1/tests/messagebody002.phpt0000644000076500000240000000034614117626035017043 0ustar Mikestaff--TEST-- message body append --SKIPIF-- --FILE-- append("yes"); var_dump((string) $temp); ?> DONE --EXPECT-- Test string(3) "yes" DONE pecl_http-4.2.1/tests/messagebody003.phpt0000644000076500000240000000074614117626035017050 0ustar Mikestaff--TEST-- message body append error --SKIPIF-- --INI-- zend.exception_ignore_args=off --FILE-- append("nope"); } catch (Exception $e) { echo $e, "\n"; } ?> DONE --EXPECTF-- Test http\Exception\RuntimeException: http\Message\Body::append(): Failed to append 4 bytes to body; wrote 0 in %s:%d Stack trace: #0 %s(%d): http\Message\Body->append('nope') #1 {main} DONE pecl_http-4.2.1/tests/messagebody004.phpt0000644000076500000240000000177014117626035017047 0ustar Mikestaff--TEST-- message body add form --SKIPIF-- --FILE-- addForm( array( "foo" => "bar", "more" => array( "bah", "baz", "fuz" ), ), array( array( "file" => __FILE__, "name" => "upload", "type" => "text/plain", ) ) ); echo $temp; ?> DONE --EXPECTF-- Test --%x.%x Content-Disposition: form-data; name="foo" bar --%x.%x Content-Disposition: form-data; name="more[0]" bah --%x.%x Content-Disposition: form-data; name="more[1]" baz --%x.%x Content-Disposition: form-data; name="more[2]" fuz --%x.%x Content-Disposition: form-data; name="upload"; filename="%s" Content-Transfer-Encoding: binary Content-Type: text/plain addForm( array( "foo" => "bar", "more" => array( "bah", "baz", "fuz" ), ), array( array( "file" => __FILE__, "name" => "upload", "type" => "text/plain", ) ) ); echo $temp; ?> DONE --%x.%x-- DONE pecl_http-4.2.1/tests/messagebody005.phpt0000644000076500000240000000065114117626035017045 0ustar Mikestaff--TEST-- message body add part --SKIPIF-- --FILE-- getBoundary()); $temp->addPart(new http\Message("This: is a header\n\nand this is the data\n")); var_dump($temp->getBoundary()); echo $temp; ?> DONE --EXPECTF-- Test NULL string(%d) "%x.%x" --%x.%x This: is a header Content-Length: 21 and this is the data --%x.%x-- DONE pecl_http-4.2.1/tests/messagebody006.phpt0000644000076500000240000000064514117626035017051 0ustar Mikestaff--TEST-- message body etag --SKIPIF-- --INI-- http.etag.mode = crc32b --FILE-- etag() ); var_dump($temp->etag()); ?> DONE --EXPECT-- Test bool(true) string(8) "00000000" DONE pecl_http-4.2.1/tests/messagebody007.phpt0000644000076500000240000000052214117626035017044 0ustar Mikestaff--TEST-- message body to stream --SKIPIF-- --FILE-- toStream($f = fopen("php://temp", "w")); fseek($f, 0, SEEK_SET); var_dump(file_get_contents(__FILE__) === stream_get_contents($f)); ?> DONE --EXPECT-- Test bool(true) DONE pecl_http-4.2.1/tests/messagebody008.phpt0000644000076500000240000000047514117626035017054 0ustar Mikestaff--TEST-- message body to callback --SKIPIF-- --FILE-- toCallback( function($body, $string) use (&$s) { $s.=$string; } ); var_dump($s === (string) $file); ?> DONE --EXPECT-- Test bool(true) DONE pecl_http-4.2.1/tests/messagebody009.phpt0000644000076500000240000000036514117626035017053 0ustar Mikestaff--TEST-- message body clone --SKIPIF-- --FILE-- DONE --EXPECT-- Test bool(true) DONE pecl_http-4.2.1/tests/messagebody010.phpt0000644000076500000240000000055514117626035017044 0ustar Mikestaff--TEST-- message body resource --SKIPIF-- --FILE-- getResource(); var_dump(is_resource($stream)); $stat = fstat($stream); var_dump(filesize(__FILE__) === $stat["size"]); ?> DONE --EXPECT-- Test bool(true) bool(true) DONE pecl_http-4.2.1/tests/messageparser001.phpt0000644000076500000240000000252414117626035017401 0ustar Mikestaff--TEST-- message parser --SKIPIF-- --FILE-- parse(fgets($fd), 0, $message)) { case Parser::STATE_DONE: $string = (string) $message; break 2; case Parser::STATE_FAILURE: throw new Exception(($e = error_get_last()) ? $e["message"] : "Could not parse $file"); } } if (!$string) { $s = array("START", "HEADER", "HEADER_DONE", "BODY", "BODY_DUMB", "BODY_LENGTH", "BODY_CHUNK", "BODY_DONE", "UPDATE_CL", "DONE"); printf("Unexpected state: %s (%s)\n", $s[$parser->getState()], $file); } $parser = new Parser; rewind($fd); unset($message); switch ($parser->stream($fd, 0, $message)) { case Parser::STATE_DONE: case Parser::STATE_START: break; default: printf("Expected parser state 0 or 8, got %d", $parser->getState()); } if ($string !== (string) $message) { $a = explode("\n", $string); $b = explode("\n", (string) $message); do { $aa = array_shift($a); $bb = array_shift($b); if ($aa !== $bb) { isset($aa) and printf("-- %s\n", $aa); isset($bb) and printf("++ %s\n", $bb); } } while ($a || $b); } } ?> DONE --EXPECT-- Test DONE pecl_http-4.2.1/tests/messageparser002.phpt0000644000076500000240000000226714117626035017406 0ustar Mikestaff--TEST-- message parser with nonblocking stream --SKIPIF-- --FILE-- stream($socket[0], 0, $msg); fwrite($socket[1], $line); $parser->stream($socket[0], 0, $msg); } var_dump($msg, (string) $msg->getBody()); ?> DONE --EXPECTF-- Test object(http\Message)#%d (9) { ["type":protected]=> int(1) ["body":protected]=> object(http\Message\Body)#%d (0) { } ["requestMethod":protected]=> string(3) "GET" ["requestUrl":protected]=> string(1) "/" ["responseStatus":protected]=> string(0) "" ["responseCode":protected]=> int(0) ["httpVersion":protected]=> string(3) "1.1" ["headers":protected]=> array(3) { ["Host"]=> string(9) "localhost" ["Content-Length"]=> string(1) "3" ["X-Original-Content-Length"]=> string(1) "3" } ["parentMessage":protected]=> NULL } string(3) "OK " DONE pecl_http-4.2.1/tests/negotiate001.phpt0000644000076500000240000000442214117626035016516 0ustar Mikestaff--TEST-- negotiate --SKIPIF-- --ENV-- HTTP_ACCEPT=text/html,text/plain,text/xml;q=0.1,image/*;q=0.1,*/*;q=0 HTTP_ACCEPT_CHARSET=utf-8,iso-8859-1;q=0.8,iso-8859-15;q=0 HTTP_ACCEPT_ENCODING=gzip,deflate;q=0 HTTP_ACCEPT_LANGUAGE=de-DE,de-AT;q=0.9,en;q=0.8,fr;q=0 --FILE-- CONTENT TYPE CHARSET ENCODING LANGUAGE CUSTOM DONE --EXPECT-- CONTENT TYPE text/html: Array ( [text/html] => 0.99 [text/xml] => 0.1 ) text/xml: Array ( [text/xml] => 0.1 ) text/json: Array ( ) CHARSET utf-8: Array ( [utf-8] => 0.99 [iso-8859-1] => 0.8 ) iso-8859-1: Array ( [iso-8859-1] => 0.8 ) utf-16: Array ( ) ENCODING gzip: Array ( [gzip] => 0.99 ) : Array ( ) LANGUAGE de: Array ( [de] => 0.97 [en] => 0.8 ) de-DE: Array ( [de-DE] => 0.99 [de-AT] => 0.9 [en] => 0.8 ) en: Array ( [en] => 0.8 ) CUSTOM a.b: Array ( [a.b] => 0.9 [a.x] => 0.08 [c.e] => 0.08 ) DONE pecl_http-4.2.1/tests/params001.phpt0000644000076500000240000000203614117626035016021 0ustar Mikestaff--TEST-- header params --SKIPIF-- --FILE-- array("charset" => "iso-8859-1")); var_dump( isset($ct["text/html"]), isset($ct["text/json"]), $ct["text/json"]["arguments"]["charset"] ); var_dump((string) $ct,$ct); ?> DONE --EXPECTF-- Test bool(true) bool(false) string(5) "utf-8" bool(false) bool(true) string(10) "iso-8859-1" string(%d) "text/json;charset=iso-8859-1" object(http\Params)#%d (5) { ["params"]=> array(1) { ["text/json"]=> array(2) { ["value"]=> bool(true) ["arguments"]=> array(1) { ["charset"]=> string(10) "iso-8859-1" } } } ["param_sep"]=> string(1) "," ["arg_sep"]=> string(1) ";" ["val_sep"]=> string(1) "=" ["flags"]=> int(0) } DONE pecl_http-4.2.1/tests/params002.phpt0000644000076500000240000000147714117626035016032 0ustar Mikestaff--TEST-- query parser --SKIPIF-- --FILE-- DONE --EXPECTF-- object(http\Params)#%d (5) { ["params"]=> array(2) { ["foo"]=> array(2) { ["value"]=> string(3) "bar" ["arguments"]=> array(0) { } } ["arr"]=> array(2) { ["value"]=> array(2) { [0]=> string(1) "1" [1]=> string(1) "2" } ["arguments"]=> array(0) { } } } ["param_sep"]=> array(2) { [0]=> string(1) "&" [1]=> string(1) ";" } ["arg_sep"]=> string(0) "" ["val_sep"]=> string(1) "=" ["flags"]=> int(12) } foo=bar&arr%5B0%5D=1&arr%5B1%5D=2 DONE pecl_http-4.2.1/tests/params003.phpt0000644000076500000240000000246314117626035016027 0ustar Mikestaff--TEST-- default params --SKIPIF-- --FILE-- "arg", "bar"=>"bla", "gotit"=>"now"); $r = array ( 'foo' => array ( 'value' => true, 'arguments' => array ( ), ), 'bar' => array ( 'value' => true, 'arguments' => array ( 'arg' => '0', 'bla' => true, ), ), 'gotit' => array ( 'value' => '0', 'arguments' => array ( 'now' => true, ), ), ); # --- var_dump(count($p->params)); echo "key exists\n"; foreach ($k as $key) { var_dump(array_key_exists($key, $p->params)); } echo "values\n"; foreach ($k as $key) { var_dump($p[$key]["value"]); } echo "args\n"; foreach ($k as $key) { var_dump(count($p[$key]["arguments"])); } echo "arg values\n"; foreach ($k as $key) { var_dump(@$p[$key]["arguments"][$a[$key]]); } echo "equals\n"; var_dump($c === (string) $p); var_dump($r === $p->params); $x = new http\Params($p->params); var_dump($r === $x->toArray()); ?> DONE --EXPECT-- Test int(3) key exists bool(true) bool(true) bool(true) values bool(true) bool(true) string(1) "0" args int(0) int(2) int(1) arg values NULL bool(true) bool(true) equals bool(true) bool(true) bool(true) DONE pecl_http-4.2.1/tests/params004.phpt0000644000076500000240000000245114117626035016025 0ustar Mikestaff--TEST-- custom params --SKIPIF-- --FILE-- "arg", "bar"=>"bla", "gotit"=>"now"); $r = array ( 'foo' => array ( 'value' => true, 'arguments' => array ( ), ), 'bar' => array ( 'value' => true, 'arguments' => array ( 'arg' => '0', 'bla' => true, ), ), 'gotit' => array ( 'value' => '0', 'arguments' => array ( 'now' => true, ), ), ); # --- var_dump(count($p->params)); echo "key exists\n"; foreach ($k as $key) { var_dump(array_key_exists($key, $p->params)); } echo "values\n"; foreach ($k as $key) { var_dump($p[$key]["value"]); } echo "args\n"; foreach ($k as $key) { var_dump(count($p[$key]["arguments"])); } echo "arg values\n"; foreach ($k as $key) { var_dump(@$p[$key]["arguments"][$a[$key]]); } echo "equals\n"; var_dump($c === (string) $p); var_dump($r === $p->params); $x = new http\Params($p->params); var_dump($r === $x->toArray()); ?> DONE --EXPECT-- Test int(3) key exists bool(true) bool(true) bool(true) values bool(true) bool(true) string(1) "0" args int(0) int(2) int(1) arg values NULL bool(true) bool(true) equals bool(true) bool(true) bool(true) DONE pecl_http-4.2.1/tests/params005.phpt0000644000076500000240000000065414117626035016031 0ustar Mikestaff--TEST-- quoted params --SKIPIF-- --FILE-- array( "value" => true, "arguments" => array( "boundary" => "--123" ) ) ); var_dump($c === $p->params); var_dump("multipart/form-data;boundary=--123" === (string) $p); ?> DONE --EXPECT-- Test bool(true) bool(true) DONE pecl_http-4.2.1/tests/params006.phpt0000644000076500000240000000075214117626035016031 0ustar Mikestaff--TEST-- escaped params --SKIPIF-- --FILE-- array( "value" => true, "arguments" => array( "name" => "upload", "filename" => "trick\"\0\"ed" ) ) ); var_dump($c === $p->params); var_dump("form-data;name=upload;filename=\"trick\\\"\\000\\\"ed\"" === (string) $p); ?> DONE --EXPECT-- Test bool(true) bool(true) DONE pecl_http-4.2.1/tests/params007.phpt0000644000076500000240000000110214117626035016020 0ustar Mikestaff--TEST-- urlencoded params --SKIPIF-- --FILE-- array( "value" => "b\"r", "arguments" => array(), ), "bar" => array( "value" => "b\"z", "arguments" => array(), ), "a[][]" => array( "value" => "1", "arguments" => array(), ), ); var_dump($c === $p->params); var_dump("foo=b%22r&bar=b%22z&a%5B%5D%5B%5D=1" === (string) $p); ?> DONE --EXPECT-- Test bool(true) bool(true) DONE pecl_http-4.2.1/tests/params008.phpt0000644000076500000240000000112114117626035016022 0ustar Mikestaff--TEST-- querystring params --SKIPIF-- --FILE-- array( "value" => "b\"r", "arguments" => array(), ), "bar" => array( "value" => "b\"z", "arguments" => array(), ), "a" => array( "value" => array( array("1") ), "arguments" => array(), ), ); var_dump($c === $p->params); var_dump("foo=b%22r&bar=b%22z&a%5B0%5D%5B0%5D=1" === (string) $p); ?> DONE --EXPECT-- Test bool(true) bool(true) DONE pecl_http-4.2.1/tests/params009.phpt0000644000076500000240000000030414117626035016025 0ustar Mikestaff--TEST-- empty params --SKIPIF-- --FILE-- params); ?> DONE --EXPECT-- Test bool(true) DONE pecl_http-4.2.1/tests/params010.phpt0000644000076500000240000000052214117626035016017 0ustar Mikestaff--TEST-- int key params --SKIPIF-- --FILE-- array("value" => "nothing", "arguments" => array(1=>"yes"))) === $p->params); var_dump("0=nothing;1=yes" === $p->toString()); ?> DONE --EXPECT-- Test bool(true) bool(true) DONE pecl_http-4.2.1/tests/params011.phpt0000644000076500000240000000064614117626035016027 0ustar Mikestaff--TEST-- bool args params --SKIPIF-- --FILE-- false, "arguments" => array("wrong" => false, "correct" => true)); $p["container"] = $container; var_dump("container=0;wrong=0;correct" === $p->toString()); var_dump(array("container" => $container) === $p->toArray()); ?> DONE --EXPECT-- Test bool(true) bool(true) DONE pecl_http-4.2.1/tests/params012.phpt0000644000076500000240000000044114117626035016021 0ustar Mikestaff--TEST-- no args params --SKIPIF-- --FILE-- toString()); $p["param"] = false; var_dump("param=0" === $p->toString()); ?> DONE --EXPECT-- Test bool(true) bool(true) DONE pecl_http-4.2.1/tests/params013.phpt0000644000076500000240000000262414117626035016027 0ustar Mikestaff--TEST-- header params rfc5987 --SKIPIF-- --FILE-- params, (string) $p); $p = new http\Params("bar; title*=iso-8859-1'en'%A3%20rates"); var_dump($p->params, (string) $p); $p = new http\Params("bar; title*=UTF-8''%c2%a3%20and%20%e2%82%ac%20rates"); var_dump($p->params, (string) $p); ?> ===DONE=== --EXPECT-- Test array(1) { ["attachment"]=> array(2) { ["value"]=> bool(true) ["arguments"]=> array(1) { ["*rfc5987*"]=> array(1) { ["filename"]=> array(1) { [""]=> string(10) "döner.pdf" } } } } } string(42) "attachment;filename*=utf-8''d%C3%B6ner.pdf" array(1) { ["bar"]=> array(2) { ["value"]=> bool(true) ["arguments"]=> array(1) { ["*rfc5987*"]=> array(1) { ["title"]=> array(1) { ["en"]=> string(8) "£ rates" } } } } } string(34) "bar;title*=utf-8'en'%C2%A3%20rates" array(1) { ["bar"]=> array(2) { ["value"]=> bool(true) ["arguments"]=> array(1) { ["*rfc5987*"]=> array(1) { ["title"]=> array(1) { [""]=> string(16) "£ and € rates" } } } } } string(50) "bar;title*=utf-8''%C2%A3%20and%20%E2%82%AC%20rates" ===DONE=== pecl_http-4.2.1/tests/params014.phpt0000644000076500000240000000236614117626035016033 0ustar Mikestaff--TEST-- header params rfc5987 --SKIPIF-- --FILE-- params); var_dump((string)$p === $t, (string)$p, $t); ?> ===DONE=== --EXPECT-- Test array(3) { ["p1"]=> array(2) { ["*rfc5987*"]=> array(1) { [""]=> string(5) "süß" } ["arguments"]=> array(0) { } } ["p2"]=> array(2) { ["*rfc5987*"]=> array(1) { [""]=> string(5) "heiß" } ["arguments"]=> array(2) { ["*rfc5987*"]=> array(2) { ["a1"]=> array(1) { [""]=> string(3) "aß" } ["a2"]=> array(1) { [""]=> string(3) "eß" } } ["a3"]=> string(2) "no" } } ["p3"]=> array(2) { ["value"]=> string(3) "not" ["arguments"]=> array(0) { } } } bool(true) string(96) "p1*=utf-8''s%C3%BC%C3%9F,p2*=utf-8''hei%C3%9F;a1*=utf-8''a%C3%9F;a2*=utf-8''e%C3%9F;a3=no,p3=not" string(96) "p1*=utf-8''s%C3%BC%C3%9F,p2*=utf-8''hei%C3%9F;a1*=utf-8''a%C3%9F;a2*=utf-8''e%C3%9F;a3=no,p3=not" ===DONE=== pecl_http-4.2.1/tests/params015.phpt0000644000076500000240000000062514117626035016030 0ustar Mikestaff--TEST-- header params rfc5987 regression --SKIPIF-- --FILE-- array("filename"=>"foo.bar"))); var_dump($p->params); var_dump((string)$p); ?> ===DONE=== --EXPECT-- Test array(1) { ["attachment"]=> array(1) { ["filename"]=> string(7) "foo.bar" } } string(27) "attachment;filename=foo.bar" ===DONE=== pecl_http-4.2.1/tests/params016.phpt0000644000076500000240000000206514117626035016031 0ustar Mikestaff--TEST-- header params rfc5988 --SKIPIF-- --FILE-- ; rel="next", ; rel="last" EOF; $p = new http\Params($link, ",", ";", "=", http\Params::PARSE_RFC5988 | http\Params::PARSE_ESCAPED); var_dump($p->params); var_dump((string)$p); ?> ===DONE=== --EXPECT-- Test array(2) { ["https://api.github.com/search/code?q=addClass+user%3Amozilla&page=2"]=> array(2) { ["value"]=> bool(true) ["arguments"]=> array(1) { ["rel"]=> string(4) "next" } } ["https://api.github.com/search/code?q=addClass+user%3Amozilla&page=34"]=> array(2) { ["value"]=> bool(true) ["arguments"]=> array(1) { ["rel"]=> string(4) "last" } } } string(162) ";rel="next",;rel="last"" ===DONE=== pecl_http-4.2.1/tests/params017.phpt0000644000076500000240000000261214117626035016030 0ustar Mikestaff--TEST-- header params rfc5988 --SKIPIF-- --FILE-- ; rel="previous"; title*=UTF-8'de'letztes%20Kapitel, ; rel="next"; title*=UTF-8'de'n%c3%a4chstes%20Kapitel EOF; $p = current(http\Header::parse($link, "http\\Header"))->getParams( http\Params::DEF_PARAM_SEP, http\Params::DEF_ARG_SEP, http\Params::DEF_VAL_SEP, http\Params::PARSE_RFC5987 | http\Params::PARSE_RFC5988 | http\Params::PARSE_ESCAPED ); var_dump($p->params); var_dump((string)$p); ?> ===DONE=== --EXPECTF-- Test array(2) { ["/TheBook/chapter2"]=> array(2) { ["value"]=> bool(true) ["arguments"]=> array(2) { ["rel"]=> string(8) "previous" ["*rfc5987*"]=> array(1) { ["title"]=> array(1) { ["de"]=> string(15) "letztes Kapitel" } } } } ["/TheBook/chapter4"]=> array(2) { ["value"]=> bool(true) ["arguments"]=> array(2) { ["rel"]=> string(4) "next" ["*rfc5987*"]=> array(1) { ["title"]=> array(1) { ["de"]=> string(17) "nächstes Kapitel" } } } } } string(139) ";rel="previous";title*=utf-8'de'letztes%20Kapitel,;rel="next";title*=utf-8'de'n%C3%A4chstes%20Kapitel" ===DONE=== pecl_http-4.2.1/tests/phpinfo.phpt0000644000076500000240000000030614117626035015756 0ustar Mikestaff--TEST-- phpinfo --SKIPIF-- --FILE-- Done --EXPECTF-- Test %a HTTP Support => enabled Extension Version => 4.%s %a Done pecl_http-4.2.1/tests/querystring001_a.phpt0000644000076500000240000000720014117626035017430 0ustar Mikestaff--TEST-- query string --SKIPIF-- =") or die("skip only for PHP >= 7.2.0"); ?> --GET-- str=abc&num=-123&dec=123.123&bool=1&arr[]=1&arr[]=2&ma[l1][l2]=2&ma[l2][l3][l4]=3 --FILE-- getString("str")); var_dump($q->getInt("num")); var_dump($q->getFloat("dec")); var_dump($q->getInt("dec")); var_dump($q->getFloat("dec")); var_dump($q->getBool("bool")); var_dump($q->getInt("bool")); var_dump($q->getBool("num")); var_dump($q->getInt("num")); var_dump($q->getArray("arr")); var_dump($q->getArray("ma")); var_dump($q->getObject("arr")); var_dump($q->getObject("ma")); $s = $q->toString(); printf("\nClone modifications do not alter global instance:\n"); $q->mod(array("arr" => array(3 => 3))); printf("%s\n", $q); printf("\nClone modifications do not alter standard instance:\n"); $q2 = new http\QueryString($s); $q3 = $q2->mod(array("arr" => array(3 => 3))); printf("%s\n%s\n", $q2, $q3); #var_dump($q2, $q3); printf("\nIterator:\n"); $it = new RecursiveIteratorIterator($q2, RecursiveIteratorIterator::SELF_FIRST); foreach ($it as $k => $v) { $i = $it->getDepth()*8; @printf("%{$i}s: %s\n", $k, $v); } printf("\nReplace a multi dimensional key:\n"); printf("%s\n", $q2->mod(array("ma" => null))->set(array("ma" => array("l1" => false)))); printf("\nXlate:\n"); $qu = new http\QueryString("ü=ö"); printf("utf8: %s\n", $qu); printf("latin1: %s\n", method_exists($qu, "xlate") ? $qu->xlate("utf-8", "latin1") : "%FC=%F6"); printf("\nOffsets:\n"); var_dump($q2["ma"]); $q2["ma"] = array("bye"); var_dump($q2["ma"]); var_dump(isset($q2["ma"])); unset($q2["ma"]); var_dump(isset($q2["ma"])); echo "Done\n"; ?> --EXPECTF-- Test Global instance: str=abc&num=-123&dec=123.123&bool=1&arr%5B0%5D=1&arr%5B1%5D=2&ma%5Bl1%5D%5Bl2%5D=2&ma%5Bl2%5D%5Bl3%5D%5Bl4%5D=3 Standard getters: string(3) "abc" int(-123) float(123.123) int(123) float(123.123) bool(true) int(1) bool(true) int(-123) array(2) { [0]=> string(1) "1" [1]=> string(1) "2" } array(2) { ["l1"]=> array(1) { ["l2"]=> string(1) "2" } ["l2"]=> array(1) { ["l3"]=> array(1) { ["l4"]=> string(1) "3" } } } object(stdClass)#%d (2) { ["0"]=> string(1) "1" ["1"]=> string(1) "2" } object(stdClass)#%d (2) { ["l1"]=> array(1) { ["l2"]=> string(1) "2" } ["l2"]=> array(1) { ["l3"]=> array(1) { ["l4"]=> string(1) "3" } } } Clone modifications do not alter global instance: str=abc&num=-123&dec=123.123&bool=1&arr%5B0%5D=1&arr%5B1%5D=2&ma%5Bl1%5D%5Bl2%5D=2&ma%5Bl2%5D%5Bl3%5D%5Bl4%5D=3 Clone modifications do not alter standard instance: str=abc&num=-123&dec=123.123&bool=1&arr%5B0%5D=1&arr%5B1%5D=2&ma%5Bl1%5D%5Bl2%5D=2&ma%5Bl2%5D%5Bl3%5D%5Bl4%5D=3 str=abc&num=-123&dec=123.123&bool=1&arr%5B0%5D=1&arr%5B1%5D=2&arr%5B3%5D=3&ma%5Bl1%5D%5Bl2%5D=2&ma%5Bl2%5D%5Bl3%5D%5Bl4%5D=3 Iterator: str: abc num: -123 dec: 123.123 bool: 1 arr: Array 0: 1 1: 2 ma: Array l1: Array l2: 2 l2: Array l3: Array l4: 3 Replace a multi dimensional key: str=abc&num=-123&dec=123.123&bool=1&arr%5B0%5D=1&arr%5B1%5D=2&ma%5Bl1%5D= Xlate: utf8: %C3%BC=%C3%B6 latin1: %FC=%F6 Offsets: array(2) { ["l1"]=> array(1) { ["l2"]=> string(1) "2" } ["l2"]=> array(1) { ["l3"]=> array(1) { ["l4"]=> string(1) "3" } } } array(1) { [0]=> string(3) "bye" } bool(true) bool(false) Done pecl_http-4.2.1/tests/querystring002.phpt0000644000076500000240000000355414117626035017141 0ustar Mikestaff--TEST-- query string --SKIPIF-- --FILE-- get()); printf("Get defval\n"); var_dump("nonexistant" === $q->get("unknown", "s", "nonexistant")); var_dump(null === $q->get("unknown")); printf("Get 'a'\n"); var_dump("b" === $q->get("a")); var_dump(0 === $q->get("a", "i")); var_dump(array("b") === $q->get("a", "a")); var_dump((object)array("scalar" => "b") == $q->get("a", "o")); printf("Get 'r'\n"); var_dump(array("0","1","2") === $q->get("r")); printf("Get 'rr'\n"); var_dump(array(array("00","01")) === $q->get("rr")); printf("Get 1\n"); var_dump(2 == $q->get(1)); var_dump("2" === $q->get(1, "s")); var_dump(2.0 === $q->get(1, "f")); var_dump($q->get(1, "b")); printf("Del 'a'\n"); var_dump("b" === $q->get("a", http\QueryString::TYPE_STRING, null, true)); var_dump(null === $q->get("a")); printf("Del all\n"); $q->set(array("a" => null, "r" => null, "rr" => null, 1 => null)); var_dump("" === $q->toString()); $q = new http\QueryString($s); printf("QSO\n"); var_dump($e === (string) new http\QueryString($q)); var_dump(http_build_query(array("e"=>$q->toArray())) === (string) new http\QueryString(array("e" => $q))); printf("Iterator\n"); var_dump($q->toArray() === iterator_to_array($q)); printf("Serialize\n"); var_dump($e === (string) unserialize(serialize($q))); ?> DONE --EXPECT-- Test bool(true) bool(true) Get defval bool(true) bool(true) Get 'a' bool(true) bool(true) bool(true) bool(true) Get 'r' bool(true) Get 'rr' bool(true) Get 1 bool(true) bool(true) bool(true) bool(true) Del 'a' bool(true) bool(true) Del all bool(true) QSO bool(true) bool(true) Iterator bool(true) Serialize bool(true) DONE pecl_http-4.2.1/tests/querystring003.phpt0000644000076500000240000000042414117626035017133 0ustar Mikestaff--TEST-- querystring offset set --SKIPIF-- --FILE-- ===DONE=== --EXPECT-- Test foo=bar&bar=baz bar=baz&foo=baz ===DONE=== pecl_http-4.2.1/tests/serialize001.phpt0000644000076500000240000000106714117626035016530 0ustar Mikestaff--TEST-- serialization --SKIPIF-- --FILE-- getClasses() as $class) { if ($class->isInstantiable()) { #printf("%s\n", $class->getName()); $instance = $class->newInstance(); $serialized = serialize($instance); $unserialized = unserialize($serialized); foreach (array("toString", "toArray") as $m) { if ($class->hasMethod($m)) { #printf("%s#%s\n", $class->getName(), $m); $unserialized->$m(); } } } } ?> DONE --EXPECTF-- DONE pecl_http-4.2.1/tests/url001.phpt0000644000076500000240000000157614117626035015350 0ustar Mikestaff--TEST-- url from env --SKIPIF-- --ENV-- SERVER_PORT=55555 HTTP_HOST=example.com --GET-- s=b&i=0&e=&a[]=1&a[]=2 --FILE-- "https", "port" => 443))); printf("%s\n", new http\Env\Url(array("path" => "/./up/../down/../././//index.php/.", "query" => null), null, http\Url::SANITIZE_PATH|http\Url::FROM_ENV)); printf("%s\n", new http\Env\Url(null, null, 0)); printf("%s\n", new http\Url(null, null, http\Url::FROM_ENV)); ?> DONE --EXPECTF-- http://example.com:55555/?s=b&i=0&e=&a[]=1&a[]=2 http://example.com:55555/index?s=b&i=0&e=&a[]=1&a[]=2 https://example.com/?s=b&i=0&e=&a[]=1&a[]=2 http://example.com:55555/index.php/ http://example.com:55555/?s=b&i=0&e=&a[]=1&a[]=2 http://example.com:55555/?s=b&i=0&e=&a[]=1&a[]=2 DONE pecl_http-4.2.1/tests/url002.phpt0000644000076500000240000000145514117626035015345 0ustar Mikestaff--TEST-- url properties --SKIPIF-- --FILE-- "changed", "query" => "bar&foo=&added=this"), http\Url::JOIN_PATH | http\Url::JOIN_QUERY | http\Url::STRIP_AUTH | http\Url::STRIP_FRAGMENT ); var_dump($url->scheme); var_dump($url->user); var_dump($url->pass); var_dump($url->host); var_dump($url->port); var_dump($url->path); var_dump($url->query); var_dump($url->fragment); ?> DONE --EXPECT-- Test bool(true) string(4) "http" NULL NULL string(15) "www.example.com" int(8080) string(13) "/path/changed" string(47) "foo=&more%5B0%5D=1&more%5B1%5D=2&bar&added=this" NULL DONE pecl_http-4.2.1/tests/url003.phpt0000644000076500000240000000076214117626035015346 0ustar Mikestaff--TEST-- url modification --SKIPIF-- --FILE-- mod(array("query" => "set=1"), http\Url::REPLACE); var_dump($tmp->toArray() != $mod->toArray()); var_dump("set=1" === $mod->query); var_dump("new_fragment" === $tmp->mod("#new_fragment")->fragment); ?> DONE --EXPECT-- Test bool(true) bool(true) bool(true) DONE pecl_http-4.2.1/tests/url004.phpt0000644000076500000240000000050614117626035015343 0ustar Mikestaff--TEST-- url as string --SKIPIF-- --FILE-- DONE --EXPECT-- Test bool(true) DONE pecl_http-4.2.1/tests/url005.phpt0000644000076500000240000000053214117626035015343 0ustar Mikestaff--TEST-- url as array --SKIPIF-- --FILE-- toArray()); var_dump($url->toArray() === $url2->toArray()); ?> DONE --EXPECT-- Test bool(true) DONE pecl_http-4.2.1/tests/urlparser001.phpt0000644000076500000240000000376214117626035016564 0ustar Mikestaff--TEST-- url parser --SKIPIF-- --FILE-- DONE --EXPECTF-- Test s: object(http\Url)#%d (8) { ["scheme"]=> string(1) "s" ["user"]=> NULL ["pass"]=> NULL ["host"]=> NULL ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } ss: object(http\Url)#%d (8) { ["scheme"]=> string(2) "ss" ["user"]=> NULL ["pass"]=> NULL ["host"]=> NULL ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } s:a object(http\Url)#%d (8) { ["scheme"]=> string(1) "s" ["user"]=> NULL ["pass"]=> NULL ["host"]=> NULL ["port"]=> NULL ["path"]=> string(1) "a" ["query"]=> NULL ["fragment"]=> NULL } ss:aa object(http\Url)#%d (8) { ["scheme"]=> string(2) "ss" ["user"]=> NULL ["pass"]=> NULL ["host"]=> NULL ["port"]=> NULL ["path"]=> string(2) "aa" ["query"]=> NULL ["fragment"]=> NULL } s:// object(http\Url)#%d (8) { ["scheme"]=> string(1) "s" ["user"]=> NULL ["pass"]=> NULL ["host"]=> NULL ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } ss:// object(http\Url)#%d (8) { ["scheme"]=> string(2) "ss" ["user"]=> NULL ["pass"]=> NULL ["host"]=> NULL ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } s://a object(http\Url)#%d (8) { ["scheme"]=> string(1) "s" ["user"]=> NULL ["pass"]=> NULL ["host"]=> string(1) "a" ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } ss://aa object(http\Url)#%d (8) { ["scheme"]=> string(2) "ss" ["user"]=> NULL ["pass"]=> NULL ["host"]=> string(2) "aa" ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } DONE pecl_http-4.2.1/tests/urlparser002.phpt0000644000076500000240000000454514117626035016565 0ustar Mikestaff--TEST-- url parser with paths --SKIPIF-- --FILE-- DONE --EXPECTF-- Test s:a/ object(http\Url)#%d (8) { ["scheme"]=> string(1) "s" ["user"]=> NULL ["pass"]=> NULL ["host"]=> NULL ["port"]=> NULL ["path"]=> string(2) "a/" ["query"]=> NULL ["fragment"]=> NULL } ss:aa/ object(http\Url)#%d (8) { ["scheme"]=> string(2) "ss" ["user"]=> NULL ["pass"]=> NULL ["host"]=> NULL ["port"]=> NULL ["path"]=> string(3) "aa/" ["query"]=> NULL ["fragment"]=> NULL } s:/a/ object(http\Url)#%d (8) { ["scheme"]=> string(1) "s" ["user"]=> NULL ["pass"]=> NULL ["host"]=> NULL ["port"]=> NULL ["path"]=> string(3) "/a/" ["query"]=> NULL ["fragment"]=> NULL } ss:/aa/ object(http\Url)#%d (8) { ["scheme"]=> string(2) "ss" ["user"]=> NULL ["pass"]=> NULL ["host"]=> NULL ["port"]=> NULL ["path"]=> string(4) "/aa/" ["query"]=> NULL ["fragment"]=> NULL } s://a/ object(http\Url)#%d (8) { ["scheme"]=> string(1) "s" ["user"]=> NULL ["pass"]=> NULL ["host"]=> string(1) "a" ["port"]=> NULL ["path"]=> string(1) "/" ["query"]=> NULL ["fragment"]=> NULL } s://h/a object(http\Url)#%d (8) { ["scheme"]=> string(1) "s" ["user"]=> NULL ["pass"]=> NULL ["host"]=> string(1) "h" ["port"]=> NULL ["path"]=> string(2) "/a" ["query"]=> NULL ["fragment"]=> NULL } ss://hh/aa object(http\Url)#%d (8) { ["scheme"]=> string(2) "ss" ["user"]=> NULL ["pass"]=> NULL ["host"]=> string(2) "hh" ["port"]=> NULL ["path"]=> string(3) "/aa" ["query"]=> NULL ["fragment"]=> NULL } s:///a/b object(http\Url)#%d (8) { ["scheme"]=> string(1) "s" ["user"]=> NULL ["pass"]=> NULL ["host"]=> NULL ["port"]=> NULL ["path"]=> string(4) "/a/b" ["query"]=> NULL ["fragment"]=> NULL } ss:///aa/bb object(http\Url)#%d (8) { ["scheme"]=> string(2) "ss" ["user"]=> NULL ["pass"]=> NULL ["host"]=> NULL ["port"]=> NULL ["path"]=> string(6) "/aa/bb" ["query"]=> NULL ["fragment"]=> NULL } DONE pecl_http-4.2.1/tests/urlparser003.phpt0000644000076500000240000000624714117626035016567 0ustar Mikestaff--TEST-- url parser with query --SKIPIF-- --FILE-- DONE --EXPECTF-- Test s:?q object(http\Url)#%d (8) { ["scheme"]=> string(1) "s" ["user"]=> NULL ["pass"]=> NULL ["host"]=> NULL ["port"]=> NULL ["path"]=> NULL ["query"]=> string(1) "q" ["fragment"]=> NULL } ss:?qq object(http\Url)#%d (8) { ["scheme"]=> string(2) "ss" ["user"]=> NULL ["pass"]=> NULL ["host"]=> NULL ["port"]=> NULL ["path"]=> NULL ["query"]=> string(2) "qq" ["fragment"]=> NULL } s:/?q object(http\Url)#%d (8) { ["scheme"]=> string(1) "s" ["user"]=> NULL ["pass"]=> NULL ["host"]=> NULL ["port"]=> NULL ["path"]=> string(1) "/" ["query"]=> string(1) "q" ["fragment"]=> NULL } ss:/?qq object(http\Url)#%d (8) { ["scheme"]=> string(2) "ss" ["user"]=> NULL ["pass"]=> NULL ["host"]=> NULL ["port"]=> NULL ["path"]=> string(1) "/" ["query"]=> string(2) "qq" ["fragment"]=> NULL } s://?q object(http\Url)#%d (8) { ["scheme"]=> string(1) "s" ["user"]=> NULL ["pass"]=> NULL ["host"]=> NULL ["port"]=> NULL ["path"]=> NULL ["query"]=> string(1) "q" ["fragment"]=> NULL } ss://?qq object(http\Url)#%d (8) { ["scheme"]=> string(2) "ss" ["user"]=> NULL ["pass"]=> NULL ["host"]=> NULL ["port"]=> NULL ["path"]=> NULL ["query"]=> string(2) "qq" ["fragment"]=> NULL } s://h?q object(http\Url)#%d (8) { ["scheme"]=> string(1) "s" ["user"]=> NULL ["pass"]=> NULL ["host"]=> string(1) "h" ["port"]=> NULL ["path"]=> NULL ["query"]=> string(1) "q" ["fragment"]=> NULL } ss://hh?qq object(http\Url)#%d (8) { ["scheme"]=> string(2) "ss" ["user"]=> NULL ["pass"]=> NULL ["host"]=> string(2) "hh" ["port"]=> NULL ["path"]=> NULL ["query"]=> string(2) "qq" ["fragment"]=> NULL } s://h/p?q object(http\Url)#%d (8) { ["scheme"]=> string(1) "s" ["user"]=> NULL ["pass"]=> NULL ["host"]=> string(1) "h" ["port"]=> NULL ["path"]=> string(2) "/p" ["query"]=> string(1) "q" ["fragment"]=> NULL } ss://hh/pp?qq object(http\Url)#%d (8) { ["scheme"]=> string(2) "ss" ["user"]=> NULL ["pass"]=> NULL ["host"]=> string(2) "hh" ["port"]=> NULL ["path"]=> string(3) "/pp" ["query"]=> string(2) "qq" ["fragment"]=> NULL } s://h:123/p/?q object(http\Url)#%d (8) { ["scheme"]=> string(1) "s" ["user"]=> NULL ["pass"]=> NULL ["host"]=> string(1) "h" ["port"]=> int(123) ["path"]=> string(3) "/p/" ["query"]=> string(1) "q" ["fragment"]=> NULL } ss://hh:123/pp/?qq object(http\Url)#%d (8) { ["scheme"]=> string(2) "ss" ["user"]=> NULL ["pass"]=> NULL ["host"]=> string(2) "hh" ["port"]=> int(123) ["path"]=> string(4) "/pp/" ["query"]=> string(2) "qq" ["fragment"]=> NULL } DONE pecl_http-4.2.1/tests/urlparser004.phpt0000644000076500000240000000241114117626035016555 0ustar Mikestaff--TEST-- url parser multibyte/locale --SKIPIF-- --FILE-- DONE --EXPECTF-- Test sçheme: object(http\Url)#%d (8) { ["scheme"]=> string(7) "sçheme" ["user"]=> NULL ["pass"]=> NULL ["host"]=> NULL ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } sçheme://hÆŸst object(http\Url)#%d (8) { ["scheme"]=> string(7) "sçheme" ["user"]=> NULL ["pass"]=> NULL ["host"]=> string(5) "hÆŸst" ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } sçheme://hÆŸst:23/päth/öf/fıle object(http\Url)#%d (8) { ["scheme"]=> string(7) "sçheme" ["user"]=> NULL ["pass"]=> NULL ["host"]=> string(5) "hÆŸst" ["port"]=> int(23) ["path"]=> string(16) "/päth/öf/fıle" ["query"]=> NULL ["fragment"]=> NULL } DONE pecl_http-4.2.1/tests/urlparser005.phpt0000644000076500000240000000214014117626035016555 0ustar Mikestaff--TEST-- url parser multibyte/utf-8 --SKIPIF-- --FILE-- DONE --EXPECTF-- Test sçheme: object(http\Url)#%d (8) { ["scheme"]=> string(7) "sçheme" ["user"]=> NULL ["pass"]=> NULL ["host"]=> NULL ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } sçheme://hÆŸst object(http\Url)#%d (8) { ["scheme"]=> string(7) "sçheme" ["user"]=> NULL ["pass"]=> NULL ["host"]=> string(5) "hÆŸst" ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } sçheme://hÆŸst:23/päth/öf/fıle object(http\Url)#%d (8) { ["scheme"]=> string(7) "sçheme" ["user"]=> NULL ["pass"]=> NULL ["host"]=> string(5) "hÆŸst" ["port"]=> int(23) ["path"]=> string(16) "/päth/öf/fıle" ["query"]=> NULL ["fragment"]=> NULL } DONE pecl_http-4.2.1/tests/urlparser006.phpt0000644000076500000240000000257714117626035016574 0ustar Mikestaff--TEST-- url parser multibyte/locale/idna --SKIPIF-- --FILE-- DONE --EXPECTF-- Test sçheme: object(http\Url)#%d (8) { ["scheme"]=> string(7) "sçheme" ["user"]=> NULL ["pass"]=> NULL ["host"]=> NULL ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } sçheme://hÆŸst object(http\Url)#%d (8) { ["scheme"]=> string(7) "sçheme" ["user"]=> NULL ["pass"]=> NULL ["host"]=> string(11) "xn--hst-kwb" ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } sçheme://hÆŸst:23/päth/öf/fıle object(http\Url)#%d (8) { ["scheme"]=> string(7) "sçheme" ["user"]=> NULL ["pass"]=> NULL ["host"]=> string(11) "xn--hst-kwb" ["port"]=> int(23) ["path"]=> string(16) "/päth/öf/fıle" ["query"]=> NULL ["fragment"]=> NULL } DONE pecl_http-4.2.1/tests/urlparser007.phpt0000644000076500000240000000236614117626035016571 0ustar Mikestaff--TEST-- url parser multibyte/utf-8/idna --SKIPIF-- --FILE-- DONE --EXPECTF-- Test sçheme: object(http\Url)#%d (8) { ["scheme"]=> string(7) "sçheme" ["user"]=> NULL ["pass"]=> NULL ["host"]=> NULL ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } sçheme://hÆŸst object(http\Url)#%d (8) { ["scheme"]=> string(7) "sçheme" ["user"]=> NULL ["pass"]=> NULL ["host"]=> string(11) "xn--hst-kwb" ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } sçheme://hÆŸst:23/päth/öf/fıle object(http\Url)#%d (8) { ["scheme"]=> string(7) "sçheme" ["user"]=> NULL ["pass"]=> NULL ["host"]=> string(11) "xn--hst-kwb" ["port"]=> int(23) ["path"]=> string(16) "/päth/öf/fıle" ["query"]=> NULL ["fragment"]=> NULL } DONE pecl_http-4.2.1/tests/urlparser008.phpt0000644000076500000240000000215314117626035016564 0ustar Mikestaff--TEST-- url parser ipv6 --SKIPIF-- --FILE-- getMessage(),"\n"; } } ?> DONE --EXPECTF-- Test s://[a:80 http\Url::__construct(): Failed to parse hostinfo; expected ']' at pos 5 in '[a:80' s://[0] http\Url::__construct(): Failed to parse hostinfo; unexpected '[' at pos 0 in '[0]' s://[::1]:80 object(http\Url)#%d (8) { ["scheme"]=> string(1) "s" ["user"]=> NULL ["pass"]=> NULL ["host"]=> string(5) "[::1]" ["port"]=> int(80) ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } s://mike@[0:0:0:0:0:FFFF:204.152.189.116]/foo object(http\Url)#%d (8) { ["scheme"]=> string(1) "s" ["user"]=> string(4) "mike" ["pass"]=> NULL ["host"]=> string(24) "[::ffff:204.152.189.116]" ["port"]=> NULL ["path"]=> string(4) "/foo" ["query"]=> NULL ["fragment"]=> NULL } DONE pecl_http-4.2.1/tests/urlparser009.phpt0000644000076500000240000000645514117626035016576 0ustar Mikestaff--TEST-- url parser userinfo --SKIPIF-- --FILE-- getMessage(),"\n"; } } ?> DONE --EXPECTF-- Test s://:@ object(http\Url)#1 (8) { ["scheme"]=> string(1) "s" ["user"]=> string(0) "" ["pass"]=> string(0) "" ["host"]=> NULL ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } s://u@ object(http\Url)#1 (8) { ["scheme"]=> string(1) "s" ["user"]=> string(1) "u" ["pass"]=> NULL ["host"]=> NULL ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } s://u:@ object(http\Url)#1 (8) { ["scheme"]=> string(1) "s" ["user"]=> string(1) "u" ["pass"]=> string(0) "" ["host"]=> NULL ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } s://u:p@ object(http\Url)#1 (8) { ["scheme"]=> string(1) "s" ["user"]=> string(1) "u" ["pass"]=> string(1) "p" ["host"]=> NULL ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } s://user:pass@ object(http\Url)#1 (8) { ["scheme"]=> string(1) "s" ["user"]=> string(4) "user" ["pass"]=> string(4) "pass" ["host"]=> NULL ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } s://user:pass@host object(http\Url)#1 (8) { ["scheme"]=> string(1) "s" ["user"]=> string(4) "user" ["pass"]=> string(4) "pass" ["host"]=> string(4) "host" ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } s://u@h object(http\Url)#1 (8) { ["scheme"]=> string(1) "s" ["user"]=> string(1) "u" ["pass"]=> NULL ["host"]=> string(1) "h" ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } s://user@h object(http\Url)#1 (8) { ["scheme"]=> string(1) "s" ["user"]=> string(4) "user" ["pass"]=> NULL ["host"]=> string(1) "h" ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } s://u@host object(http\Url)#1 (8) { ["scheme"]=> string(1) "s" ["user"]=> string(1) "u" ["pass"]=> NULL ["host"]=> string(4) "host" ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } s://user:p@h object(http\Url)#1 (8) { ["scheme"]=> string(1) "s" ["user"]=> string(4) "user" ["pass"]=> string(1) "p" ["host"]=> string(1) "h" ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } s://user:pass@h object(http\Url)#1 (8) { ["scheme"]=> string(1) "s" ["user"]=> string(4) "user" ["pass"]=> string(4) "pass" ["host"]=> string(1) "h" ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } s://user:pass@host object(http\Url)#1 (8) { ["scheme"]=> string(1) "s" ["user"]=> string(4) "user" ["pass"]=> string(4) "pass" ["host"]=> string(4) "host" ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } DONE pecl_http-4.2.1/tests/urlparser010.phpt0000644000076500000240000000155114117626035016556 0ustar Mikestaff--TEST-- url parser multibyte/locale/topct --SKIPIF-- --FILE-- DONE --EXPECTF-- Test object(http\Url)#%d (8) { ["scheme"]=> string(4) "http" ["user"]=> string(4) "mike" ["pass"]=> string(12) "pa%C3%9Fwort" ["host"]=> string(15) "ðŒ€ðŒðŒ‚.it" ["port"]=> NULL ["path"]=> string(15) "/for/%E2%82%AC/" ["query"]=> string(9) "by=%C2%A2" ["fragment"]=> string(6) "%C3%B8" } DONE pecl_http-4.2.1/tests/urlparser011.phpt0000644000076500000240000000121414117626035016553 0ustar Mikestaff--TEST-- url parser multibyte/utf-8/topct --SKIPIF-- --FILE-- DONE --EXPECTF-- Test object(http\Url)#%d (8) { ["scheme"]=> string(4) "http" ["user"]=> string(4) "mike" ["pass"]=> string(12) "pa%C3%9Fwort" ["host"]=> string(15) "ðŒ€ðŒðŒ‚.it" ["port"]=> NULL ["path"]=> string(15) "/for/%E2%82%AC/" ["query"]=> string(9) "by=%C2%A2" ["fragment"]=> string(6) "%C3%B8" } DONE pecl_http-4.2.1/tests/urlparser012.phpt0000644000076500000240000000160714117626035016562 0ustar Mikestaff--TEST-- url parser multibyte/locale/topct --SKIPIF-- --FILE-- DONE --EXPECTF-- Test object(http\Url)#%d (8) { ["scheme"]=> string(4) "http" ["user"]=> string(4) "mike" ["pass"]=> string(12) "pa%C3%9Fwort" ["host"]=> string(13) "xn--097ccd.it" ["port"]=> NULL ["path"]=> string(15) "/for/%E2%82%AC/" ["query"]=> string(9) "by=%C2%A2" ["fragment"]=> string(6) "%C3%B8" } DONE pecl_http-4.2.1/tests/urlparser013.phpt0000644000076500000240000000136714117626035016566 0ustar Mikestaff--TEST-- url parser multibyte/utf-8/topct --SKIPIF-- --FILE-- DONE --EXPECTF-- Test object(http\Url)#%d (8) { ["scheme"]=> string(4) "http" ["user"]=> string(4) "mike" ["pass"]=> string(12) "pa%C3%9Fwort" ["host"]=> string(13) "xn--097ccd.it" ["port"]=> NULL ["path"]=> string(15) "/for/%E2%82%AC/" ["query"]=> string(9) "by=%C2%A2" ["fragment"]=> string(6) "%C3%B8" } DONE pecl_http-4.2.1/tests/version001.phpt0000644000076500000240000000072414117626035016225 0ustar Mikestaff--TEST-- version parse error --SKIPIF-- --FILE-- setHttpVersion("1-1"); $m->setHttpVersion("one.one"); } catch (http\Exception $e) { echo $e->getMessage(),"\n"; } ?> --EXPECTF-- Notice: http\Message::setHttpVersion(): Non-standard version separator '-' in HTTP protocol version '1-1' in %s http\Message::setHttpVersion(): Could not parse HTTP protocol version 'one.one' pecl_http-4.2.1/scripts/bench_select_vs_event.php0000644000076500000240000000253114117626035021005 0ustar Mikestaff -n -c [-p (enable pipelining)] [-e (use libevent)]\n", $argv[0]); fprintf(STDERR, "\nDefaults: -u http://localhost/ -n 1000 -c 10\n\n"); exit(-1); } function push($client, $url, &$n) { if ($n-- > 0) { $req = new http\Client\Request("GET", $url); $client->enqueue($req, function($response) use ($client, $req, $url, &$n) { global $count; ++$count; push($client, $url, $n); return true; // dequeue }); } } isset($argv) or $argv = $_SERVER['argv']; defined('STDERR') or define('STDERR', fopen('php://stderr', 'w')); $opts = getopt("u:c:n:e"); isset($opts["u"]) or $opts["u"] = "http://localhost/"; isset($opts["c"]) or $opts["c"] = 10; isset($opts["n"]) or $opts["n"] = 1000; $argc > 1 or usage(); $time = microtime(true); $count = 0; $client = new http\Client; $client->enablePipelining($opts["p"]===false); $client->enableEvents($opts["e"]===false); for ($i = 0, $x = $opts["n"]; $i < $opts["c"]; ++$i) { push($client, $opts["u"], $x); } try { $client->send(); } catch (Exception $e) { echo $e; } printf("\n> %10.6fs (%3.2fM)\n", microtime(true)-$time, memory_get_peak_usage(true)/1024/1024); $count == $opts["n"] or printf("\nOnly %d finished\n", $count); pecl_http-4.2.1/scripts/check_package-xml.php0000755000076500000240000000513714117626035020014 0ustar Mikestaff#!/usr/bin/env php 1) { if ($argv[1] === "-") { $file = "php://stdin"; } else { $file = $argv[1]; } } elseif (stdin_is_readable()) { $file = "php://stdin"; } else { $file = "./package.xml"; } if (($xml = simplexml_load_file($file))) { $xml_files = xmllist($xml->contents[0]); $dirs = ["."]; while ($dir = array_shift($dirs)) { foreach (dirlist($dir) as $file) { if (is_gitignored($file)) { continue; } if (is_commonly_ignored($file)) { continue; } if (!is_dir($file)) { if (!in_array($file, $xml_files)) { echo "Missing file $file\n"; } } else { $base = basename($file); if ($base[0] !== ".") { array_push($dirs, $file); } } } } foreach ($xml_files as $file) { if (!file_exists($file)) { echo "Extraneous file $file\n"; } } } ### function error($fmt) { trigger_error(call_user_func_array("sprintf", func_get_args())); } function stdin_is_readable() { $r = [STDIN]; $w = $e = []; return stream_select($r, $w, $e, 0); } function is_gitignored($file) { static $gitignore, $gitmodules; if (!isset($gitmodules)) { if (is_readable("./.gitmodules")) { $gitmodules = explode("\n", `git submodule status | awk '{printf$2}'`); } else { $gitmodules = false; } } if (!isset($gitignore)) { if (is_readable("./.gitignore")) { $ignore_submodules = $gitmodules ? " ! -path './".implode("/*' ! -path './", $gitmodules)."/*'" : ""; $gitignore = explode("\n", `find . $ignore_submodules | git check-ignore --stdin`); } else { $gitignore = false; } } if ($gitignore) { if (in_array($file, $gitignore)) { return true; } } if ($gitmodules) { foreach ($gitmodules as $module) { if (fnmatch("./$module/*", $file)) { return true; } } } return false; } function is_commonly_ignored($file) { return fnmatch("./.git*", $file) || in_array($file, ["./package.xml", "./package2.xml", "./.travis.yml", "./.editorconfig"], true); } function xmllist(SimpleXmlElement $dir, $p = ".", &$a = null) { settype($a, "array"); $p = trim($p, "/") . "/" . trim($dir["name"], "/") . "/"; foreach ($dir as $file) { switch ($file->getName()) { case "dir": xmllist($file, $p, $a); break; case "file": $a[] = sprintf("%s/%s", trim($p, "/"), trim($file["name"])); break; default: error("Unknown content type: %s", $file->getName()); break; } } return $a; } function dirlist($dir, $p = null) { $p = implode("/", array_filter([trim($p, "/"), trim($dir, "/")])); foreach (scandir($p) as $file) { yield $p."/".$file; } } pecl_http-4.2.1/scripts/curlver.dist0000644000076500000240000000070614117626035016316 0ustar Mikestaff# current is 7.78.0 ATM # 7.21.5-7.29.0 fail to configure on gh actions alpine: 7.78.0 7.67.0 centos: 7.61.1 # 7.29.0 debian: 7.74.0 7.64.0 7.52.1 fedora: 7.78.0 7.76.1 7.71.1 other: 7.49.1 7.31.0 ubuntu: 7.74.0 7.68.0 7.58.0 # always test against a few recent latest: master 7.78.0 7.77.0 7.76.1 oldest: 7.18.2 7.19.7 7.20.1 # 7.64.1 fails client tests because of superfluous infof() calls # 7.64.0 fails client cookie test because of curl/curl#3613 pecl_http-4.2.1/scripts/gen_curlinfo.php0000755000076500000240000000632014117626035017133 0ustar Mikestaff#!/usr/bin/env php 'PHP_HTTP_CURL_VERSION(7,19,0)', 'APPCONNECT_TIME' => 'PHP_HTTP_CURL_VERSION(7,19,0)', 'CONDITION_UNMET' => 'PHP_HTTP_CURL_VERSION(7,19,4)', 'PRIMARY_PORT' => 'PHP_HTTP_CURL_VERSION(7,21,0)', 'LOCAL_PORT' => 'PHP_HTTP_CURL_VERSION(7,21,0)', 'LOCAL_IP' => 'PHP_HTTP_CURL_VERSION(7,21,0)', 'HTTP_VERSION' => 'PHP_HTTP_CURL_VERSION(7,50,0)', 'PROXY_SSL_VERIFYRESULT' => 'PHP_HTTP_CURL_VERSION(7,52,0)', 'PROTOCOL' => 'PHP_HTTP_CURL_VERSION(7,52,0)', 'SCHEME' => 'PHP_HTTP_CURL_VERSION(7,52,0)', 'RETRY_AFTER' => 'PHP_HTTP_CURL_VERSION(7,66,0)', 'EFFECTIVE_METHOD' => 'PHP_HTTP_CURL_VERSION(7,72,0)', 'PROXY_ERROR' => 'PHP_HTTP_CURL_VERSION(7,73,0)', ); $exclude = array( 'ACTIVESOCKET', 'CERTINFO', 'COOKIELIST', 'FTP_ENTRY_PATH', 'LASTSOCKET', 'PRIVATE', 'RTSP_CLIENT_CSEQ', 'RTSP_CSEQ_RECV', 'RTSP_SERVER_CSEQ', 'RTSP_SESSION_ID', 'TLS_SESSION', 'TLS_SSL_PTR', ); $translate = array( 'HTTP_CONNECTCODE' => "connect_code", 'COOKIELIST' => 'cookies', ); $templates = array( 'STRING' => ' if (CURLE_OK == curl_easy_getinfo(ch, %s, &c)) { ZVAL_STRING(&tmp, STR_PTR(c)); zend_hash_str_update(info, "%s", lenof("%2$s"), &tmp); } ', 'DOUBLE' => ' if (CURLE_OK == curl_easy_getinfo(ch, %s, &d)) { ZVAL_DOUBLE(&tmp, d); zend_hash_str_update(info, "%s", lenof("%2$s"), &tmp); } ', 'LONG' => ' if (CURLE_OK == curl_easy_getinfo(ch, %s, &l)) { ZVAL_LONG(&tmp, l); zend_hash_str_update(info, "%s", lenof("%2$s"), &tmp); } ', 'OFF_T' => ' if (CURLE_OK == curl_easy_getinfo(ch, %s, &o)) { ZVAL_LONG(&tmp, o); zend_hash_str_update(info, "%s", lenof("%2$s"), &tmp); } ', 'SLIST' => ' if (CURLE_OK == curl_easy_getinfo(ch, %s, &s)) { array_init(&tmp); for (p = s; p; p = p->next) { if (p->data) { add_next_index_string(&tmp, p->data); } } zend_hash_str_update(info, "%s", lenof("%2$s"), &tmp); curl_slist_free_all(s); } ', ); $infos = file_re('curl.h', '/^\s*(CURLINFO_(\w+))\s*=\s*CURLINFO_(STRING|LONG|DOUBLE|SLIST|OFF_T)\s*\+\s*\d+\s*,?\s*$/m'); ob_start(); foreach ($infos as $info) { list(, $full, $short, $type) = $info; if (in_array($short, $exclude) || substr($short, -2) === "_T") continue; if (isset($ifdefs[$short])) printf("#if %s\n", $ifdefs[$short]); printf($templates[$type], $full, strtolower((isset($translate[$short])) ? $translate[$short] : $short)); if (isset($ifdefs[$short])) printf("#endif\n"); } file_put_contents("src/php_http_client_curl.c", preg_replace('/(\/\* BEGIN::CURLINFO \*\/\n).*(\n\s*\/\* END::CURLINFO \*\/)/s', '$1'. ob_get_contents() .'$2', file_get_contents("src/php_http_client_curl.c"))); ?> pecl_http-4.2.1/scripts/gen_stubs.php0000755000076500000240000001757014117626035016463 0ustar Mikestaff#!/usr/bin/env php isInterface()) { $m ^= ReflectionMethod::IS_ABSTRACT; } foreach (Reflection::getModifierNames($m) as $mn) { $n .= $mn . " "; } return $n; } function t(ReflectionParameter $p) { if ($c = $p->getClass()) return ($p->allowsNull()?"?":"") . "\\" . $c->getName() . " "; if ($p->isArray()) return ($p->allowsNull() ? "?":"") . "array "; if ($p->hasType()) { return ($p->allowsNull() ? "?" : "") . ($p->getType()->isBuiltin() ? "" : "\\") . $p->getType()->getName() . " "; } } function c($n, $c) { $_=$c; while ($c = $c->getParentClass()) { if (array_key_exists($n, $c->getConstants())) { return false; } } $c=$_; foreach ((array) $c->getInterfaces() as $i) { if (array_key_exists($n, $i->getConstants()) || !c($n, $i)) { return false; } } return true; } ob_start(function($s) { // redirect any output to stderr fwrite(STDERR, $s); return true; }); $out = STDOUT; switch ($argc) { default: case 3: $out = fopen($argv[2], "w") or die; case 2: $ext = $argv[1]; break; case 1: die(sprintf($out, "Usage: %s \n", $argv[0])); } fprintf($out, "getConstants() as $constant => $value) { $ns = ($nsend = strrpos($constant, "\\")) ? substr($constant, 0, $nsend++) : ""; $cn = substr($constant, $nsend); $constants[$ns][$cn] = $value; } foreach ($ext->getFunctions() as $f) { /* @var $f ReflectionFunction */ $ns = $f->inNamespace() ? $f->getNamespaceName() : ""; $functions[$ns][$f->getShortName()] = $f; } foreach ($ext->getClasses() as $c) { /* @var $c ReflectionClass */ $ns = $c->inNamespace() ? $c->getNamespaceName() : ""; $structures[$ns][$c->getShortName()] = $c; } $namespaces = array_unique(array_merge( array_keys($constants), array_keys($functions), array_keys($structures) )); // simple sort natsort($namespaces); foreach ($namespaces as $ns) { fprintf($out, "namespace %s%s\n{\n", $ns, strlen($ns) ? " " : ""); // if (isset($constants[$ns])) { ksort($constants[$ns], SORT_NATURAL); foreach ($constants[$ns] as $cn => $value) { fprintf($out, "\tconst %s = %s;\n", $cn, var_export($value, true)); } } // if (isset($functions[$ns])) { ksort($functions[$ns], SORT_NATURAL); foreach ($functions[$ns] as $fn => $f) { /* @var $f ReflectionFunction */ fprintf($out, "\n\tfunction %s(", $fn); $ps = array(); foreach ($f->getParameters() as $p) { $p1 = sprintf("%s%s\$%s", t($p), $p->isPassedByReference()?"&":"", trim($p->getName(), "\"")); if ($p->isOptional()) { if ($p->isDefaultValueAvailable()) { $p1 .= sprintf(" = %s", var_export($p->getDefaultValue(), true)); } elseif (!($p->isArray() || $p->getClass()) || $p->allowsNull()) { $p1 .= " = NULL"; } elseif ($p->isArray()) { $p1 .= " = array()"; } } $ps[] = $p1; } fprintf($out, "%s)", implode(", ", $ps)); if ($f->hasReturnType()) { fprintf($out, " : %s%s", $f->getReturnType()->allowsNull() ? "?":"", $f->getReturnType()->getName()); } fprintf($out, " {\n\t}\n"); } } // if (isset($structures[$ns])) { uasort($structures[$ns], function ($a, $b) { /* @var $a ReflectionClass */ /* @var $b ReflectionClass */ $score = array_sum([ -!$a->isInterface()+ -!$a->isAbstract()+ -!$a->isTrait()+ -!substr_compare($a->getShortName(), "Exception", -strlen("Exception")), +!$b->isInterface()+ +!$b->isAbstract()+ +!$b->isTrait()+ -!substr_compare($b->getShortName(), "Exception", -strlen("Exception")), ]); if ($score) { return -$score; } return strnatcmp($a->getShortName(), $b->getShortName()); }); foreach ($structures[$ns] as $cn => $c) { fprintf($out, "\n\t%s%s %s ", m($c->getModifiers()), $c->isInterface() ? "interface":"class", $c->getShortName()); if ($p = $c->getParentClass()) { fprintf($out, "extends \\%s ", $p->getName()); } if ($i = $c->getInterfaceNames()) { fprintf($out, "%s \\%s ", $c->isInterface() ? "extends" : "implements", implode(", \\", array_filter($i, function($v) use($c, $i) { foreach ($i as $ii) { if ($v != $ii && (new ReflectionClass($ii))->implementsInterface("\\".$v)) { return false; } } return $v != "Traversable"; })) ); } fprintf($out, "\n\t{\n"); $_=0; foreach ($c->getConstants() as $n => $v) { c($n, $c) and $_+=fprintf($out, "\t\tconst %s = %s;\n", $n, var_export($v, true)); } $_ and fprintf($out, "\n"); $_=0; foreach ($c->getProperties() as $p) { if ($p->getDeclaringClass()->getName() == $c->getName()) { $_+=fprintf($out, "\t\t%s\$%s;\n", m($p->getModifiers()), $p->getName()); } } $_ and fprintf($out, "\n"); foreach ($c->getMethods() as $m) { if ($m->getDeclaringClass()->getName() == $c->getName()) { fprintf($out, "\t\t%sfunction %s(", m($m->getModifiers(), $c), $m->getName()); $ps = array(); foreach ($m->getParameters() as $p) { $p1 = sprintf("%s%s\$%s", t($p), $p->isPassedByReference()?"&":"", $p->getName()); if ($p->isOptional()) { if ($p->isDefaultValueAvailable()) { $p1 .= sprintf(" = %s", var_export($p->getDefaultValue(), true)); } elseif (!($p->isArray() || $p->getClass()) || $p->allowsNull()) { $p1 .= sprintf(" = NULL"); } elseif ($p->isArray()) { $p1 .= " = array()"; } } $ps[] = $p1; } fprintf($out, "%s)", implode(", ", $ps)); if ($m->hasReturnType()) { fprintf($out, " : %s%s%s", $m->getReturnType()->allowsNull() ? "?":"", $m->getReturnType()->isBuiltin() ? "" : "\\", //0 === strpos($m->getReturnType()->getName(), $c->getNamespaceName()) ? "\\":"", $m->getReturnType()->getName()); } if ($m->isAbstract()) { fprintf($out, ";\n\n"); } else { fprintf($out, " {\n\t\t}\n\n"); } } } fprintf($out, "\t}\n"); } } // fprintf($out, "}\n\n"); } pecl_http-4.2.1/scripts/gen_github_workflow_ci.php0000755000076500000240000000511714117626035021204 0ustar Mikestaff#!/usr/bin/env php name: ci on: workflow_dispatch: push: pull_request: jobs: github([ "master" => [ // most useful for all additional versions except current "PHP" => ["master"], "enable_debug" => "yes", "enable_zts" => "yes", "enable_iconv" => "yes", "TEST_PHP_ARGS" => "-d error_reporting=24575" // ignore E_DEPRECATED ], "cur-none" => [ // everything disabled for current "PHP" => $cur, "with_http_libicu_dir" => "no", "with_http_libidn_dir" => "no", "with_http_libidn2_dir" => "no", "with_http_libcurl_dir" => "no", "with_http_libevent_dir" => "no", "with_http_libbrotli_dir" => "no", ], "cur-dbg-zts" => [ // everything enabled for current, switching debug/zts "PHP" => $cur, "enable_debug", "enable_zts", "enable_iconv" => "yes", ], "cur-cov" => [ // once everything enabled for current, with coverage "CFLAGS" => "-O0 -g --coverage", "CXXFLAGS" => "-O0 -g --coverage", "PHP" => $cur, "enable_iconv" => "yes", [ // mutually exclusive "with_http_libicu_dir", "with_http_libidn_dir", "with_http_libidn2_dir", ], ]]); foreach ($job as $id => $env) { printf(" %s:\n", $id); printf(" name: %s\n", $id); if ($env["PHP"] == "master") { printf(" continue-on-error: true\n"); } printf(" env:\n"); foreach ($env as $key => $val) { printf(" %s: \"%s\"\n", $key, $val); } ?> runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 with: submodules: true - name: Install run: | sudo apt-get install -y \ php-cli \ php-pear \ libcurl4-openssl-dev \ libidn11-dev \ libidn2-0-dev \ libicu-dev \ libevent-dev \ libbrotli-dev \ re2c - name: Prepare run: | make -f scripts/ci/Makefile php || make -f scripts/ci/Makefile clean php make -f scripts/ci/Makefile pecl PECL=m6w6/ext-raphf.git:raphf:master - name: Build run: | make -f scripts/ci/Makefile ext PECL=http - name: Test run: | make -f scripts/ci/Makefile test - name: Coverage if: success() run: | cd src/.libs bash <(curl -s https://codecov.io/bash) -X xcode -X coveragepy name: curl-matrix on: workflow_dispatch: push: jobs: 1) { $curlver = array_map(fn($v) => strtr($v, ".", "_"), array_unique(array_slice($argv, 1))); } else { $curlver = array_unique( iterator_to_array( (function() { $split = function($sep, $subject, $def = [""]) { return array_filter(array_map("trim", explode($sep, $subject))) + $def; }; foreach (file(__DIR__."/curlver.dist") as $line) { $rec = $split(":", $split("#", $line)[0]); if (!empty($rec[1])) foreach ($split(" ", $rec[1], []) as $dist_ver) { yield strtr($dist_ver, ".", "_"); } } })() ) ); } rsort($curlver, SORT_NATURAL); $gen = include __DIR__ . "/ci/gen-matrix.php"; $job = $gen->github([ "curl" => [ "PHP" => "8.0", "CURL" => $curlver, "enable_debug" => "yes", "enable_iconv" => "yes", "with_http_libcurl_dir" => "/opt", ]]); foreach ($job as $id => $env) { printf(" curl-%s:\n", $env["CURL"]); printf(" name: curl-%s\n", $env["CURL"]); printf(" continue-on-error: true\n"); printf(" env:\n"); foreach ($env as $key => $val) { printf(" %s: \"%s\"\n", $key, $val); } ?> runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v2 with: submodules: true path: http - uses: actions/checkout@v2 with: repository: curl/curl path: curl ref: curl- # - name: Install run: | echo 'deb-src http://azure.archive.ubuntu.com/ubuntu bionic main' | sudo tee -a /etc/apt/sources.list && \ echo 'deb-src http://azure.archive.ubuntu.com/ubuntu bionic-updates main' | sudo tee -a /etc/apt/sources.list && \ sudo apt-get update -y && \ sudo apt-get build-dep -y libcurl4-openssl-dev && \ sudo apt-get install -y \ php-cli \ php-pear \ libidn11-dev \ libidn2-0-dev \ libicu-dev \ libevent-dev \ libbrotli-dev \ re2c - name: Curl run: | sudo chmod +x /usr/share/libtool/build-aux/ltmain.sh sudo ln -s /usr/share/libtool/build-aux/ltmain.sh /usr/bin/libtool cd curl ./buildconf ./configure --prefix=/opt --disable-dependency-tracking --with-ssl --with-openssl --without-libssh2 make -j2 make install - name: Prepare run: | cd http make -f scripts/ci/Makefile php || make -f scripts/ci/Makefile clean php make -f scripts/ci/Makefile pecl PECL=m6w6/ext-raphf.git:raphf:master - name: Build run: | cd http make -f scripts/ci/Makefile ext PECL=http - name: Test run: | cd http make -f scripts/ci/Makefile test = 2 ? $argv[1] : "/usr/share/i18n/locales/i18n"; $f = fopen($i18n, "r"); $c = false; $a = false; $r = []; $n = []; ob_start(null, 0xffff); while (!feof($f)) { $line = fgets($f); if (!$c && $line !== "LC_CTYPE\n") { continue; } $c = true; if ($line === "END LC_CTYPE\n") { break; } switch($line{0}) { case "%": break; case "\n": if ($a) { break 2; } break; case " ": if ($a) { foreach (explode(";", trim($line, "\n/ ;")) as $ranges) { $range = explode("..", $ranges); $step = 0; $end = 0; switch (count($range)) { case 3: list($sstart, $sstep, $send) = $range; sscanf($sstart, "", $start); sscanf($sstep, "(%d)", $step); sscanf($send, "", $end); break; case 2: list($sstart, $send) = $range; $step = 1; sscanf($sstart, "", $start); sscanf($send, "", $end); break; case 1: list($sstart) = $range; sscanf($sstart, "", $start); break; } if ($end) { if ($step != 1) { die("UNEXPECTED step=$step\n"); } $r[] = [$start, $end]; } else { $n[] = $start; } } } break; default: if ($a) { break 2; } elseif ($line === "alpha /\n") { $a = true; } break; } } $maxstep = 0; printf("static const utf8_range_t utf8_ranges[] = {\n\t{"); foreach ($r as $i => list($start, $end)) { if ($i) if ($i%3) { printf(", {"); } else { printf(",\n\t{"); } printf("0x%08X, 0x%08X}", $start, $end); } printf("\n};\n\n"); printf("static const unsigned utf8_chars[] = {\n\t"); foreach ($n as $i => $u) { if ($i) if (($i%6)) { printf(", "); } else { printf(",\n\t"); } printf("0x%08X", $u); } printf("\n};\n"); file_put_contents("php_http_utf8.h", preg_replace('/(\/\* BEGIN::UTF8TABLE \*\/\n).*(\n\s*\/\* END::UTF8TABLE \*\/)/s', '$1'. ob_get_contents() .'$2', file_get_contents("php_http_utf8.h"))); pecl_http-4.2.1/AUTHORS0000644000076500000240000000003714117626035013325 0ustar MikestaffMichael Wallner pecl_http-4.2.1/BUGS0000644000076500000240000000223114117626035012736 0ustar MikestaffKnown Issues ============ 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 raphf.persistent_handles.limit = 0 * call raphf\persistent_handles_clean() every request * call $client->flushCookies(), which is available since libcurl v7.17.1 and does not work with the procedural API 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. pecl_http-4.2.1/CHANGELOG.md0000644000076500000240000000454214117626035014073 0ustar Mikestaff# ChangeLog v4 ## 4.2.1, 2021-09-13 * Fixed failing tests with PHP-8.1 (see gh issue #120) * Fixed configure reliably finding the right libcurl features available * Fixed cookie handling with libcurl 7.77+ and consistently across all supported libcurl versions (follow-up to gh issue #116) ## 4.2.0, 2021-08-30 * Fixed PHP-8.1 compatibility (see gh issues #114, #115 and #118) * Fixed cookies failing with libcurl >= 7.77 (see gh issue #116) * Fixed tests using $_ENV instead of getenv() to find executables in PATH (see gh issue #113) * Added http\Env::reset(): resets internal HTTP request cache (see gh issue #90) ## 4.1.0, 2021-04-21 * Added request options: * http\Client\Curl::$abstract_unix_socket * http\Client\Curl::$altsvc * http\Client\Curl::$altsvc_ctrl * http\Client\Curl::$aws_sigv4 * http\Client\Curl::$doh_url * http\Client\Curl::$dns_shuffle_addresses * http\Client\Curl::$haproxy_protocol * http\Client\Curl::$hsts * http\Client\Curl::$hsts_ctrl * http\Client\Curl::$http09_allowed * http\Client\Curl::$maxage_conn * http\Client\Curl::$pinned_publickey * http\Client\Curl::$proxy_ssl * http\Client\Curl::$socks5_auth * http\Client\Curl::$tcp_fastopen * http\Client\Curl::$tls13_ciphers * http\Client\Curl::$xoauth2_bearer * Added request option constants: * http\Client\Curl\AUTH_AWS_SIGV4 * http\Client\Curl\AUTH_BEARER * http\Client\Curl\AUTH_NONE * http\Client\Curl\HTTP_VERSION_2_PRIOR_KNOWLEDGE * http\Client\Curl\HTTP_VERSION_3 * http\Client\Curl\SSL_VERSION_MAX_* * http\Client\Curl\SSL_VERSION_TLSv1_3 * Added library version constants: * http\Client\Curl\Versions\BROTLI * http\Client\Curl\Versions\CAINFO * http\Client\Curl\Versions\CAPATH * http\Client\Curl\Versions\HYPER * http\Client\Curl\Versions\ICONV * http\Client\Curl\Versions\NGHTTP2 * http\Client\Curl\Versions\QUIC * http\Client\Curl\Versions\ZSTD ## 4.0.0, 2021-01-13 Changes from beta1: * Fixed configure on systems which do not provide icu-config * Fixed gh-issue #89: Cookie handling cannot be disabled since v3.2.1 ## 4.0.0beta1, 2020-09-23 * PHP 8 compatibility - Drop ext-propro support: PHP 8 removes the object get/set API from the ZendEngine, which renders that extension dysfunctional. As a consequence, the header property of http\Message and derived classes cannot be modified in place, and thus by reference. pecl_http-4.2.1/CONTRIBUTING.md0000644000076500000240000000361614117626035014514 0ustar Mikestaff# Contributor Code of Conduct As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality. Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery * Personal attacks * Trolling or insulting/derogatory comments * Public or private harassment * Publishing other's private information, such as physical or electronic addresses, without explicit permission * Other unethical or unprofessional conduct. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team. This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers. This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0, available at http://contributor-covenant.org/version/1/2/0/. pecl_http-4.2.1/CVE.md0000644000076500000240000000175714117626035013226 0ustar Mikestaff# CVE List of [CVE](http://cve.mitre.org/)s regarding pecl/http. ID | GH-Issue/PHP-Bug | Summary | Fixed in | Commit --------------|----------------------------------------------------|-----------------------------------------------|--------------------|------- CVE-2016-5873 | [PHP-71719](https://bugs.php.net/bug.php?id=71719) | Buffer overflow in HTTP url parsing functions | 2.5.6, 3.0.1 | https://github.com/m6w6/ext-http/commit/3724cd76a28be1d6049b5537232e97ac567ae1f5 CVE-2016-7398 | [PHP-73055](https://bugs.php.net/bug.php?id=73055) | Type confusion vulnerability in merge_param() | 2.6.0RC1, 3.1.0RC1 | https://github.com/m6w6/ext-http/commit/17137d4ab1ce81a2cee0fae842340a344ef3da83 CVE-2016-7961 | [PHP-73185](https://bugs.php.net/bug.php?id=73185) | Buffer overflow in HTTP parse_hostinfo() | 2.6.0RC1, 3.1.0RC1 | https://github.com/m6w6/ext-http/commit/ec043079e9915d7d1f4cb06eeadb2c7fca195658pecl_http-4.2.1/CREDITS0000644000076500000240000000004714117626035013276 0ustar MikestaffHTTP extension for PHP Michael Wallner pecl_http-4.2.1/LICENSE0000644000076500000240000000250714117626035013266 0ustar MikestaffCopyright (c) 2004-2015, Michael Wallner . 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. pecl_http-4.2.1/README.md0000644000076500000240000000322214117626035013533 0ustar Mikestaff# ext-http [![Build Status](https://github.com/m6w6/ext-http/workflows/ci/badge.svg?branch=master)](https://github.com/m6w6/ext-http/actions?query=workflow%3Aci+branch%3Amaster) [![Coverity Scan Build Status](https://scan.coverity.com/projects/8711/badge.svg)](https://scan.coverity.com/projects/m6w6-ext-http) [![codecov](https://codecov.io/gh/m6w6/ext-http/branch/master/graph/badge.svg)](https://codecov.io/gh/m6w6/ext-http) Extended HTTP support for PHP. ## Branches and Versions: > **NOTE:** Use `v3.x` branch, and resp. v3 releases, for PHP-7. `master` and v4 releases are only for PHP-8. ## Documentation See the [online markdown reference](https://mdref.m6w6.name/http). Known issues are listed in [BUGS](./BUGS) and future ideas can be found in [TODO](./TODO). ## Install ### PECL pecl install pecl_http ### PHARext Watch out for [PECL replicates](https://replicator.pharext.org?pecl_http) and pharext packages attached to [releases](https://github.com/m6w6/ext-http/releases). ### Checkout git clone https://github.com/m6w6/ext-http.git cd ext-http /path/to/phpize ./configure --with-php-config=/path/to/php-config make sudo make install ## ChangeLog A comprehensive list of changes can be obtained from the [ChangeLog](./CHANGELOG.md) and the list of [fixed CVEs](./CVE.md). ## License ext-http is licensed under the 2-Clause-BSD license, which can be found in the accompanying [LICENSE](./LICENSE) file. ## Contributing All forms of contribution are welcome! Please see the bundled [CONTRIBUTING](./CONTRIBUTING.md) note for the general principles followed. The list of past and current contributors is maintained in [THANKS](./THANKS). pecl_http-4.2.1/THANKS0000644000076500000240000000117614117626035013175 0ustar MikestaffThanks go to the following people, who have contributed to this project: Ilia Alshanetsky (ilia at php dot net) Anatol Belski (ab at php dot net) Petr Czaderna (petr at hroch dot info) Remi Collet (remi at php dot net) Benjamin Eberlei (kontakt at beberlei dot de) David James (james82 at gmail dot com) Thomas Landro Johnsen (thomas dot l dot johnsen at gmail dot com) 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) pecl_http-4.2.1/TODO0000644000076500000240000000034114117626035012743 0ustar Mikestaff* let the message body be a simple query string unless files are added * php_http_message_serialize reverses the chain twice; remove that * CURLOPT_PROXY_HEADER and CURLOPT_HEADEROPT * CURLMOPT_PIPELINING changed to a bitmaskpecl_http-4.2.1/config.m40000644000076500000240000000022014117626035013756 0ustar Mikestaffdnl 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) pecl_http-4.2.1/config9.m40000644000076500000240000001723314117626035014063 0ustar Mikestaff m4_foreach(dir, [., ext/http], [ sinclude(dir/autoconf/pecl/pecl.m4) sinclude(dir/autoconf/pecl/zlib.m4) sinclude(dir/autoconf/pecl/libbrotli.m4) sinclude(dir/autoconf/pecl/libcurl.m4) sinclude(dir/autoconf/pecl/libevent.m4) ]) PECL_INIT([http]) PHP_ARG_WITH([http], [whether to enable extended HTTP support], [ --with-http Enable extended HTTP support]) if test "$PHP_HTTP" != "no"; then dnl STDC AC_TYPE_OFF_T AC_TYPE_MBSTATE_T dnl getdomainname() is declared in netdb.h on some platforms: AIX, OSF AC_CHECK_HEADERS([netdb.h unistd.h wchar.h wctype.h arpa/inet.h]) AC_CHECK_FUNC(gethostname,,[ AC_CHECK_LIB(nsl, gethostname) ]) AC_CHECK_FUNC(getdomainname,,[ AC_CHECK_LIB(nsl, getdomainname) ]) AC_CHECK_FUNCS(mbrtowc mbtowc iswalnum inet_pton) CFLAGS="$CFLAGS -Wno-strict-prototypes" dnl ZLIB PHP_ARG_WITH([http-zlib-dir], [whether/where to check for zlib], [ --with-http-zlib-dir[=DIR] HTTP: where to find zlib], $PHP_HTTP) PECL_CHECK_ZLIB([$PHP_HTTP_ZLIB_DIR], [1.2.0.4]) PECL_CHECK_DONE(zlib, $PECL_VAR([HAVE_ZLIB])) dnl BROTLI PHP_ARG_WITH([http-libbrotli-dir], [whether/where to check for libbrotli], [ --with-http-libbrotli-dir[=DIR] HTTP: where to find libbrotli], $PHP_HTTP) PECL_CHECK_LIBBROTLI([$PHP_HTTP_LIBBROTLI_DIR], [1.0]) PECL_CHECK_DONE(libbrotli, $PECL_VAR([HAVE_LIBBROTLI])) dnl CURL PHP_ARG_WITH([http-libcurl-dir], [whether/where to check for libcurl], [ --with-http-libcurl-dir[=DIR] HTTP: where to find libcurl], $PHP_HTTP) if test "$PHP_HTTP_LIBCURL_DIR" != "no"; then PECL_CHECK_LIBCURL([$PHP_HTTP_LIBCURL_DIR], [7.18.2]) PECL_HAVE_LIBCURL_PROTOCOL([HTTP], [ PECL_HAVE_LIBCURL_FEATURE([HTTP2]) PECL_HAVE_LIBCURL_FEATURE([ALT-SVC]) PECL_HAVE_LIBCURL_FEATURE([HSTS]) PECL_HAVE_LIBCURL_ARES PECL_HAVE_LIBCURL_SSL PECL_HAVE_LIBCURL_CA PECL_DEFINE([HAVE_CLIENT]) ]) PECL_CHECK_DONE(libcurl, [$PECL_VAR([HAVE_LIBCURL_PROTOCOL_HTTP])]) fi dnl EVENT PHP_ARG_WITH([http-libevent-dir], [whether/where to check for libevent], [ --with-http-libevent-dir[=DIR] HTTP: where to find libevent], $PHP_HTTP_LIBCURL_DIR, no) if test "$PHP_HTTP_LIBEVENT_DIR" != "no"; then PECL_CHECK_LIBEVENT([$PHP_HTTP_LIBEVENT_DIR]) PECL_CHECK_DONE(libevent, [$PECL_VAR([HAVE_LIBEVENT])]) fi dnl GNU IDNA PHP_ARG_WITH([http-libidn2-dir], [whether/where to check for libidn2], [ --with-http-libidn2-dir[=DIR] HTTP: where to find libidn2], $PHP_HTTP_LIBCURL_DIR, no) if test "$PHP_HTTP_LIBIDN2_DIR" != "no"; then PECL_CHECK_CUSTOM(libidn2, "$PHP_HTTP_LIBIDN2_DIR", idn2.h, idn2, [$($EGREP "define IDN2_VERSION " "include/idn2.h" | $SED -e's/^.*VERSION //g' -e 's/@<:@^0-9\.@:>@//g')]) if $PECL_VAR([HAVE_LIBIDN2]); then PECL_DEFINE([HAVE_IDNA2008]) fi PECL_CHECK_DONE(libidn2, $PECL_VAR([HAVE_LIBIDN2])) fi PHP_ARG_WITH([http-libidn-dir], [whether/where to check for libidn], [ --with-http-libidn-dir[=DIR] HTTP: where to find libidn], $PHP_HTTP_LIBCURL_DIR, no) if test "$PHP_HTTP_LIBIDN_DIR" != "no"; then PECL_CHECK_PKGCONFIG(libidn, [$PHP_HTTP_LIBIDN_DIR]) if $PECL_VAR([HAVE_LIBIDN]); then PECL_DEFINE([HAVE_IDNA2003]) fi PECL_CHECK_DONE(libidn, $PECL_VAR([HAVE_LIBIDN])) fi dnl ICU IDNA PHP_ARG_WITH([http-libicu-dir], [whether/where to check for libicu], [ --with-http-libicu-dir[=DIR] HTTP: where to find libicu], $PHP_HTTP_LIBCURL_DIR, no) if test "$PHP_HTTP_LIBICU_DIR" != "no"; then AC_PATH_PROG(ICU_CONFIG, icu-config, false, [$PHP_HTTP_LIBICU_DIR/bin:$PATH:/usr/local/bin]) if $ICU_CONFIG --exists >/dev/null 2>/dev/null; then PECL_CHECK_CONFIG(libicu, [$ICU_CONFIG], [--version], [--cppflags], [--ldflags-searchpath], [--ldflags-libsonly]) else PECL_CHECK_PKGCONFIG(icu-i18n, [$PHP_HTTP_LIBICU_DIR]) fi AC_CACHE_CHECK([for uidna_IDNToASCII], PECL_CACHE_VAR([HAVE_UIDNA_IDNToASCII]), [ if printf "%s" "$CFLAGS" | $EGREP -q "(^|\s)-Werror\b"; then if ! printf "%s" "$CFLAGS" | $EGREP -q "(^|\s)-Wno-error=deprecated-declarations\b"; then CFLAGS="$CFLAGS -Wno-error=deprecated-declarations" fi fi AC_TRY_LINK([ #include ], [ uidna_IDNToASCII(0, 0, 0, 0, 0, 0, 0); ], [ PECL_CACHE_VAR([HAVE_UIDNA_IDNToASCII])=yes ], [ PECL_CACHE_VAR([HAVE_UIDNA_IDNToASCII])=no ]) ]) if $PECL_CACHE_VAR([HAVE_UIDNA_IDNTOASCII]); then PECL_DEFINE([HAVE_IDNA2003]) PECL_DEFINE_FN([UIDNA_IDNTOASCII]) fi AC_CACHE_CHECK([for uidna_nameToASCII_UTF8], PECL_CACHE_VAR([HAVE_UIDNA_NAMETOASCII_UTF8]), [ AC_TRY_LINK([ #include ], [ uidna_nameToASCII_UTF8(0, 0, 0, 0, 0, 0, 0); ], [ PECL_CACHE_VAR([HAVE_UIDNA_NAMETOASCII_UTF8])=yes ], [ PECL_CACHE_VAR([HAVE_UIDNA_NAMETOASCII_UTF8])=no ]) ]) if $PECL_CACHE_VAR([HAVE_UIDNA_NAMETOASCII_UTF8]); then PECL_DEFINE([HAVE_IDNA2008]) PECL_DEFINE_FN([uidna_nameToASCII_UTF8]) fi PECL_CHECK_DONE(libicu, [$PECL_VAR([HAVE_LIBICU])]) fi dnl IDNKIT2 PHP_ARG_WITH([http-libidnkit2-dir], [whether/where to check for libidnkit2], [ --with-http-libidnkit2-dir[=DIR] HTTP: where to find libidnkit2], $PHP_HTTP_LIBCURL_DIR, no) if test "$PHP_HTTP_LIBIDNKIT2_DIR" != "no"; then PECL_CHECK_CUSTOM(libidnkit2, "$PHP_HTTP_LIBIDNKIT2_DIR", idn/api.h, idnkit, [$($EGREP "define IDNKIT_VERSION_LIBIDN\b" "include/idn/version.h" | $SED -e's/^.*VERSION_LIBIDN//g' -e 's/@<:@^0-9\.@:>@//g')]) if $PECL_VAR([HAVE_LIBIDNKIT2]); then PECL_DEFINE([HAVE_IDNA2008]) fi PECL_CHECK_DONE(libidnkit2, [$PECL_VAR([HAVE_LIBIDNKIT2])]) fi dnl IDNKIT1 PHP_ARG_WITH([http-libidnkit-dir], [whether/where to check for libidnkit], [ --with-http-libidnkit-dir[=DIR] HTTP: where to find libidnkit], $PHP_HTTP_LIBCURL_DIR, no) if test "$PHP_HTTP_LIBIDNKIT_DIR" != "no"; then # libidnkit1 and libidnkit2 have the same API if test "$PHP_HTTP_LIBIDNKIT2_DIR" != no && $PECL_VAR([HAVE_LIBIDNKIT2]); then AC_MSG_WARN([libidnkit-$PECL_VAR([LIBIDNKIT2_VERSION]) already enabled, skipping libidnkit1]) else PECL_CHECK_CUSTOM(libidnkit, "$PHP_HTTP_LIBIDNKIT_DIR", idn/api.h, idnkit, [$($EGREP "define IDNKIT_VERSION\b" "include/idn/version.h" | $SED -e's/^.*VERSION//g' -e 's/@<:@^0-9\.@:>@//g')]) if $PECL_VAR([HAVE_LIBIDNKIT]); then PECL_DEFINE([HAVE_IDNA2003]) fi PECL_CHECK_DONE(libidnkit, [$PECL_VAR([HAVE_LIBIDNKIT])]) fi fi dnl EXTENSIONS PECL_HAVE_PHP_EXT([raphf], [ PECL_HAVE_PHP_EXT_HEADER([raphf]) ], [ AC_MSG_ERROR([please install and enable pecl/raphf]) ]) PECL_HAVE_PHP_EXT([iconv]) dnl DONE PHP_SUBST([HTTP_SHARED_LIBADD]) PECL_VAR([SRCDIR])=PHP_EXT_SRCDIR(http) PECL_VAR([BUILDDIR])=PHP_EXT_BUILDDIR(http) PHP_ADD_INCLUDE([$PECL_VAR([SRCDIR])/src]) PHP_ADD_BUILD_DIR([$PECL_VAR([BUILDDIR])/src]) PECL_VAR([HEADERS])=$(cd $PECL_VAR([SRCDIR])/src && echo *.h) PECL_VAR([SOURCES])=$(cd $PECL_VAR([SRCDIR]) && echo src/*.c) PHP_NEW_EXTENSION(http, [$PECL_VAR([SOURCES])], [$ext_shared]) PHP_INSTALL_HEADERS(ext/http, [php_http.h $PECL_VAR([HEADERS])]) 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 are built shared)], yes, no) if test "$PHP_HTTP_SHARED_DEPS" != "no"; then if $PECL_VAR([HAVE_EXT_HASH]); then PHP_ADD_EXTENSION_DEP([http], [hash], true) fi if $PECL_VAR([HAVE_EXT_ICONV]); then PHP_ADD_EXTENSION_DEP([http], [iconv], true) fi fi PHP_ADD_EXTENSION_DEP([http], [raphf], true) PHP_SUBST(PECL_VAR([HEADERS])) PHP_SUBST(PECL_VAR([SOURCES])) PHP_SUBST(PECL_VAR([SRCDIR])) PHP_SUBST(PECL_VAR([BUILDDIR])) PHP_ADD_MAKEFILE_FRAGMENT AC_DEFINE([HAVE_HTTP], [1], [Have extended HTTP support]) fi pecl_http-4.2.1/config.w320000644000076500000240000001245714117626035014070 0ustar Mikestaff// config.w32 for pecl/http // $Id$ ARG_ENABLE("http", "whether to enable extended HTTP support", "no"); function check_for_main_ext(ext, header) { if (!header) { header = "php_"+ ext +".h"; } /* When in configure, we're always in the root of PHP source */ var ext_path = "ext\\" + ext; STDOUT.Write("Checking for ext/"+ ext +" ... "); if (FSO.FileExists(ext_path + "\\" + header)) { STDOUT.WriteLine(ext_path); return ext_path; } STDOUT.WriteLine(""); return false; } function check_for_pecl_ext(ext, header) { if (!header) { header = "php_"+ ext +".h"; } var g; var s = ext +"\\"+ header; STDOUT.Write("Checking for pecl/"+ ext +" ... "); if ( (g = glob(configure_module_dirname +"\\..\\"+ s)) || (g = glob(configure_module_dirname +"\\..\\..\\..\\pecl\\"+ s))) { var f = g[0].substr(0, g[0].length - header.length - 1); STDOUT.WriteLine(f); return f; } STDOUT.WriteLine(""); return false; } if (PHP_HTTP != "no") { var PHP_HTTP_SRC_ARRAY = glob(configure_module_dirname + "/src/*.c"); var PHP_HTTP_SOURCES=""; for (var i=0; i$@ <$< $(all_targets): http-build-headers clean: http-clean-headers .PHONY: http-build-headers http-build-headers: $(PHP_HTTP_HEADERS) .PHONY: http-clean-headers http-clean-headers: -rm -f $(PHP_HTTP_HEADERS) pecl_http-4.2.1/php_http.h0000644000076500000240000000203514117626035014254 0ustar Mikestaff/* +--------------------------------------------------------------------+ | PECL :: http | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_EXT_HTTP_H #define PHP_EXT_HTTP_H #define PHP_PECL_HTTP_VERSION "4.2.1" extern zend_module_entry http_module_entry; #define phpext_http_ptr &http_module_entry extern int http_module_number; #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 */