package.xml 0000644 0000765 0000024 00000102037 14117626035 011753 0 ustar Mike staff
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.m4 0000644 0000765 0000024 00000025775 14117626035 016223 0 ustar Mike staff
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.m4 0000644 0000765 0000024 00000002654 14117626035 017251 0 ustar Mike staff
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.m4 0000644 0000765 0000024 00000020604 14117626035 016716 0 ustar Mike staff dnl
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.m4 0000644 0000765 0000024 00000001124 14117626035 017066 0 ustar Mike staff
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.m4 0000644 0000765 0000024 00000000666 14117626035 016230 0 ustar Mike staff dnl
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.h 0000644 0000765 0000024 00000010040 14117626035 015667 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.c 0000644 0000765 0000024 00000027746 14117626035 016407 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.h 0000644 0000765 0000024 00000024421 14117626035 016377 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.c 0000644 0000765 0000024 00000016400 14117626035 015037 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.c 0000644 0000765 0000024 00000133265 14117626035 016406 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.h 0000644 0000765 0000024 00000016266 14117626035 016414 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.c 0000644 0000765 0000024 00000320030 14117626035 017417 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.h 0000644 0000765 0000024 00000004737 14117626035 017441 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.c 0000644 0000765 0000024 00000020317 14117626035 020625 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.h 0000644 0000765 0000024 00000002015 14117626035 020625 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.c 0000644 0000765 0000024 00000023507 14117626035 020466 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.h 0000644 0000765 0000024 00000005347 14117626035 020475 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.h 0000644 0000765 0000024 00000002027 14117626035 020152 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.c 0000644 0000765 0000024 00000011232 14117626035 020311 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.h 0000644 0000765 0000024 00000002035 14117626035 020317 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.c 0000644 0000765 0000024 00000070341 14117626035 016374 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.h 0000644 0000765 0000024 00000007416 14117626035 016404 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.c 0000644 0000765 0000024 00000007010 14117626035 016061 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.h 0000644 0000765 0000024 00000002452 14117626035 016073 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.c 0000644 0000765 0000024 00000050330 14117626035 016705 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.h 0000644 0000765 0000024 00000011202 14117626035 016705 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.c 0000644 0000765 0000024 00000047605 14117626035 017740 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.h 0000644 0000765 0000024 00000004461 14117626035 017736 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.c 0000644 0000765 0000024 00000031066 14117626035 020265 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.h 0000644 0000765 0000024 00000004076 14117626035 020273 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.c 0000644 0000765 0000024 00000054700 14117626035 015714 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.h 0000644 0000765 0000024 00000007414 14117626035 015721 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.c 0000644 0000765 0000024 00000023323 14117626035 017461 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.h 0000644 0000765 0000024 00000001753 14117626035 017471 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.c 0000644 0000765 0000024 00000131132 14117626035 017625 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.h 0000644 0000765 0000024 00000006340 14117626035 017634 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.c 0000644 0000765 0000024 00000003544 14117626035 016044 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.h 0000644 0000765 0000024 00000003066 14117626035 016050 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.c 0000644 0000765 0000024 00000014455 14117626035 017125 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.h 0000644 0000765 0000024 00000004414 14117626035 017124 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.c 0000644 0000765 0000024 00000032007 14117626035 016405 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.h 0000644 0000765 0000024 00000001722 14117626035 016412 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.c 0000644 0000765 0000024 00000042250 14117626035 017725 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.h 0000644 0000765 0000024 00000005625 14117626035 017737 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.c 0000644 0000765 0000024 00000035720 14117626035 016355 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.h 0000644 0000765 0000024 00000003415 14117626035 016356 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.c 0000644 0000765 0000024 00000015540 14117626035 016056 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.h 0000644 0000765 0000024 00000004064 14117626035 016062 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.c 0000644 0000765 0000024 00000070001 14117626035 017555 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.h 0000644 0000765 0000024 00000010133 14117626035 017562 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.c 0000644 0000765 0000024 00000207551 14117626035 016554 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.h 0000644 0000765 0000024 00000011327 14117626035 016553 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.c 0000644 0000765 0000024 00000060274 14117626035 020127 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.h 0000644 0000765 0000024 00000006362 14117626035 020132 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.c 0000644 0000765 0000024 00000015052 14117626035 016054 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.h 0000644 0000765 0000024 00000017574 14117626035 016074 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.c 0000644 0000765 0000024 00000012574 14117626035 017106 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.h 0000644 0000765 0000024 00000007656 14117626035 017120 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.c 0000644 0000765 0000024 00000007200 14117626035 016363 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.h 0000644 0000765 0000024 00000003477 14117626035 016404 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.c 0000644 0000765 0000024 00000006475 14117626035 016625 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.h 0000644 0000765 0000024 00000004304 14117626035 016617 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.c 0000644 0000765 0000024 00000112436 14117626035 016410 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.h 0000644 0000765 0000024 00000004621 14117626035 016411 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.c 0000644 0000765 0000024 00000057003 14117626035 017517 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.h 0000644 0000765 0000024 00000003525 14117626035 017524 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.h 0000644 0000765 0000024 00000007041 14117626035 020140 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.c 0000644 0000765 0000024 00000166043 14117626035 015732 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.h 0000644 0000765 0000024 00000011070 14117626035 015724 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.h 0000644 0000765 0000024 00000051057 14117626035 016021 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.c 0000644 0000765 0000024 00000005276 14117626035 016615 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.h 0000644 0000765 0000024 00000002672 14117626035 016617 0 ustar Mike staff /*
+--------------------------------------------------------------------+
| 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.bin 0000644 0000765 0000024 00000000400 14117626035 016202 0 ustar Mike staff €¬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.txt 0000644 0000765 0000024 00000000265 14117626035 021747 0 ustar Mike staff 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
23 pecl_http-4.2.1/tests/data/message_r_multipart_put.txt 0000644 0000765 0000024 00000004766 14117626035 022044 0 ustar Mike staff PUT /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.txt 0000644 0000765 0000024 00000000610 14117626035 020433 0 ustar Mike staff GET /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.txt 0000644 0000765 0000024 00000000473 14117626035 022143 0 ustar Mike staff GET /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.txt 0000644 0000765 0000024 00000000673 14117626035 021475 0 ustar Mike staff GET /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.txt 0000644 0000765 0000024 00000000474 14117626035 023161 0 ustar Mike staff GET /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.txt 0000644 0000765 0000024 00000002023 14117626035 016053 0 ustar Mike staff http://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.html 0000644 0000765 0000024 00000000210 14117626035 017630 0 ustar Mike staff
HTTP2
Nothing to see here.
pecl_http-4.2.1/tests/helper/cookie.inc 0000644 0000765 0000024 00000000477 14117626035 016652 0 ustar Mike staff getHeader("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.inc 0000644 0000765 0000024 00000000462 14117626035 016725 0 ustar Mike staff setCookie("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.inc 0000644 0000765 0000024 00000001112 14117626035 016717 0 ustar Mike staff getHeader("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.inc 0000644 0000765 0000024 00000001767 14117626035 016351 0 ustar Mike staff $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.inc 0000644 0000765 0000024 00000002261 14117626035 016162 0 ustar Mike staff setEnvRequest($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.crt 0000644 0000765 0000024 00000002230 14117626035 016446 0 ustar Mike staff -----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.key 0000644 0000765 0000024 00000003217 14117626035 016454 0 ustar Mike staff -----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.inc 0000644 0000765 0000024 00000001675 14117626035 017207 0 ustar Mike staff setEnvRequest($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.inc 0000644 0000765 0000024 00000001536 14117626035 016557 0 ustar Mike staff = 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.inc 0000644 0000765 0000024 00000012275 14117626035 016706 0 ustar Mike staff getMessage());
/* 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.inc 0000644 0000765 0000024 00000001067 14117626035 016661 0 ustar Mike staff getHeader("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.inc 0000644 0000765 0000024 00000002675 14117626035 015411 0 ustar Mike staff =")) {
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.phpt 0000644 0000765 0000024 00000002176 14117626035 015502 0 ustar Mike staff --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.phpt 0000644 0000765 0000024 00000001141 14117626035 015505 0 ustar Mike staff --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.phpt 0000644 0000765 0000024 00000000456 14117626035 015514 0 ustar Mike staff --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.phpt 0000644 0000765 0000024 00000000443 14117626035 015505 0 ustar Mike staff --TEST--
Bug #67932 (php://input always empty)
--SKIPIF--
--PUT--
Content-Type: text/xml
test
--FILE--
--EXPECT--
test