AC_DEFINE("HTTP_SHARED_DEPS", 1, "Depend on shared extensions");\r
\r
AC_DEFINE("HAVE_GETHOSTNAME", 1);\r
- AC_DEFINE("HAVE_GETSERVBYPORT", 1);\r
- AC_DEFINE("HAVE_GETSERVBYNAME", 1);\r
\r
if (PHP_DEBUG != "no") {\r
ADD_FLAG("CFLAGS_HTTP", "/W3");\r
AC_DEFUN([HTTP_HAVE_PHP_EXT], [
extname=$1
haveext=$[PHP_]translit($1,a-z_-,A-Z__)
-
AC_MSG_CHECKING([for ext/$extname support])
if test -x "$PHP_EXECUTABLE"; then
grepext=`$PHP_EXECUTABLE -m | $EGREP ^$extname\$`
dnl ----
dnl STDC
dnl ----
+ AC_TYPE_OFF_T
+ dnl getdomainname() is declared in netdb.h on some platforms: AIX, OSF
AC_CHECK_HEADERS([netdb.h unistd.h])
PHP_CHECK_FUNC(gethostname, nsl)
PHP_CHECK_FUNC(getdomainname, nsl)
- PHP_CHECK_FUNC(getservbyport, nsl)
- PHP_CHECK_FUNC(getservbyport_r, nsl)
- PHP_CHECK_FUNC(getservbyname, nsl)
- PHP_CHECK_FUNC(getservbyname_r, nsl)
dnl ----
dnl ZLIB
PHP_ADD_INCLUDE([$HTTP_EXT_RAPHF_INCDIR])
fi
], [
- AC_MSG_ERROR([Please install pecl/raphf])
+ AC_MSG_ERROR([Please install pecl/raphf and activate extension=raphf.$SHLIB_DL_SUFFIX_NAME in your php.ini])
])
dnl ----
PHP_ADD_INCLUDE([$HTTP_EXT_PROPRO_INCDIR])
fi
], [
- AC_MSG_ERROR([Please install pecl/propro])
+ AC_MSG_ERROR([Please install pecl/propro and activate extension=propro.$SHLIB_DL_SUFFIX_NAME in your php.ini])
])
PHP_ARG_WITH([http-shared-deps], [whether to depend on extensions which have been built shared],
<email>mike@php.net</email>
<active>yes</active>
</lead>
- <date>2014-08-01</date>
+ <date>2014-08-19</date>
<version>
- <release>2.1.0RC1</release>
- <api>2.1.0</api>
+ <release>2.2.0dev</release>
+ <api>2.2.0</api>
</version>
<stability>
<release>beta</release>
</stability>
<license>BSD, revised</license>
<notes><![CDATA[
-* Fixed bug #67733 (Compile error with libevent 2.x)
-+ Added RFC5987 support in http\Params
-+ Improved synthetic HTTP message parsing performace for ~20%
-+ Added request options if libcurl has builtin c-ares support:
- dns_interface, dns_local_ip4, dns_local_ip6 (all libcurl >= 7.33.0)
-+ Added request options:
- expect_100_timeout (libcurl >= 7.36.0)
- tcp_nodelay
-+ Added transfer info:
- tls_session (libcurl >= 7.34.0), only available during transfer
+- var_dump(http\Message) no longer automatically creates an empty body
++ Added http\Message\Parser class
]]></notes>
<contents>
<dir name="/">
<file role="test" name="messagebody008.phpt"/>
<file role="test" name="messagebody009.phpt"/>
<file role="test" name="messagebody010.phpt"/>
+ <file role="test" name="messageparser001.phpt"/>
<file role="test" name="negotiate001.phpt"/>
<file role="test" name="params001.phpt"/>
<file role="test" name="params002.phpt"/>
|| SUCCESS != PHP_MINIT_CALL(http_filter)
|| SUCCESS != PHP_MINIT_CALL(http_header)
|| 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)
{
if (0
|| SUCCESS != PHP_RINIT_CALL(http_env)
-#if PHP_HTTP_HAVE_CURL && PHP_HTTP_HAVE_EVENT
- || SUCCESS != PHP_RINIT_CALL(http_client_curl)
-#endif
) {
return FAILURE;
}
PHP_RSHUTDOWN_FUNCTION(http)
{
if (0
-#if PHP_HTTP_HAVE_CURL && PHP_HTTP_HAVE_EVENT
- || SUCCESS != PHP_RSHUTDOWN_CALL(http_client_curl)
-#endif
|| SUCCESS != PHP_RSHUTDOWN_CALL(http_env)
) {
return FAILURE;
#ifndef PHP_EXT_HTTP_H
#define PHP_EXT_HTTP_H
-#define PHP_PECL_HTTP_VERSION "2.1.0RC1"
+#define PHP_PECL_HTTP_VERSION "2.2.0dev"
extern zend_module_entry http_module_entry;
#define phpext_http_ptr &http_module_entry
#ifdef PHP_WIN32
# define CURL_STATICLIB
-# define PHP_HTTP_HAVE_NETDB
# include <winsock2.h>
-#elif defined(HAVE_NETDB_H)
-# define PHP_HTTP_HAVE_NETDB
-# include <netdb.h>
+#else
+# ifdef HAVE_NETDB_H
+# include <netdb.h>
+# endif
# ifdef HAVE_UNISTD_H
# include <unistd.h>
# endif
-# ifdef HAVE_ERRNO_H
-# include <errno.h>
-# endif
#endif
#include <ctype.h>
ZEND_BEGIN_MODULE_GLOBALS(php_http)
struct php_http_env_globals env;
-#if PHP_HTTP_HAVE_CURL && PHP_HTTP_HAVE_EVENT
- struct php_http_curl_globals curl;
-#endif
ZEND_END_MODULE_GLOBALS(php_http)
ZEND_EXTERN_MODULE_GLOBALS(php_http);
int unfinished; /* int because of curl_multi_perform() */
#if PHP_HTTP_HAVE_EVENT
+ struct event_base *evbase;
struct event *timeout;
unsigned useevents:1;
#endif
typedef struct php_http_curle_storage {
char *url;
char *cookiestore;
+ CURLcode errorcode;
char errorbuffer[0x100];
} php_http_curle_storage_t;
#if PHP_HTTP_CURL_VERSION(7,34,0)
{
- int i;
zval *ti_array;
struct curl_tlssessioninfo *ti;
}
}
#endif
- add_assoc_string_ex(&array, "error", sizeof("error"), php_http_curle_get_storage(ch)->errorbuffer, 1);
+ {
+ php_http_curle_storage_t *st = php_http_curle_get_storage(ch);
+
+ add_assoc_long_ex(&array, "curlcode", sizeof("curlcode"), st->errorcode);
+ add_assoc_string_ex(&array, "error", sizeof("error"), st->errorbuffer, 1);
+ }
return SUCCESS;
}
if (msg && CURLMSG_DONE == msg->msg) {
if (CURLE_OK != msg->data.result) {
php_http_curle_storage_t *st = php_http_curle_get_storage(msg->easy_handle);
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s; %s (%s)", curl_easy_strerror(msg->data.result), STR_PTR(st->errorbuffer), STR_PTR(st->url));
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s; %s (%s)", curl_easy_strerror(st->errorcode = msg->data.result), STR_PTR(st->errorbuffer), STR_PTR(st->url));
}
if ((enqueue = php_http_client_enqueued(context, msg->easy_handle, compare_queue))) {
return -1;
}
- event_assign(&ev->evnt, PHP_HTTP_G->curl.event_base, sock, events, php_http_curlm_event_callback, context);
+ event_assign(&ev->evnt, curl->evbase, sock, events, php_http_curlm_event_callback, context);
event_add(&ev->evnt, NULL);
}
php_http_curlm_timeout_callback(CURL_SOCKET_TIMEOUT, /*EV_READ|EV_WRITE*/0, context);
} else if (timeout_ms > 0 || !event_initialized(curl->timeout) || !event_pending(curl->timeout, EV_TIMEOUT, NULL)) {
struct timeval timeout;
- TSRMLS_FETCH_FROM_CTX(context->ts);
if (!event_initialized(curl->timeout)) {
- event_assign(curl->timeout, PHP_HTTP_G->curl.event_base, CURL_SOCKET_TIMEOUT, 0, php_http_curlm_timeout_callback, context);
+ event_assign(curl->timeout, curl->evbase, CURL_SOCKET_TIMEOUT, 0, php_http_curlm_timeout_callback, context);
} else if (event_pending(curl->timeout, EV_TIMEOUT, NULL)) {
event_del(curl->timeout);
}
}
if ((opt = php_http_option_register(registry, ZEND_STRL("certtype"), CURLOPT_SSLCERTTYPE, IS_STRING))) {
opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
- ZVAL_STRING(&opt->defval, "PEM", 1);
+ ZVAL_STRING(&opt->defval, "PEM", 0);
}
if ((opt = php_http_option_register(registry, ZEND_STRL("key"), CURLOPT_SSLKEY, IS_STRING))) {
opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
}
if ((opt = php_http_option_register(registry, ZEND_STRL("keytype"), CURLOPT_SSLKEYTYPE, IS_STRING))) {
opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
- ZVAL_STRING(&opt->defval, "PEM", 1);
+ ZVAL_STRING(&opt->defval, "PEM", 0);
}
if ((opt = php_http_option_register(registry, ZEND_STRL("keypasswd"), CURLOPT_SSLKEYPASSWD, IS_STRING))) {
opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
#if PHP_HTTP_HAVE_EVENT
if (curl->timeout) {
+ if (event_initialized(curl->timeout) && event_pending(curl->timeout, EV_TIMEOUT, NULL)) {
+ event_del(curl->timeout);
+ }
efree(curl->timeout);
curl->timeout = NULL;
}
+ if (curl->evbase) {
+ event_base_free(curl->evbase);
+ curl->evbase = NULL;
+ }
#endif
curl->unfinished = 0;
if (curl->useevents) {
php_http_curlm_timeout_callback(CURL_SOCKET_TIMEOUT, /*EV_READ|EV_WRITE*/0, h);
do {
- int ev_rc = event_base_dispatch(PHP_HTTP_G->curl.event_base);
+ int ev_rc = event_base_dispatch(curl->evbase);
#if DBG_EVENTS
fprintf(stderr, "%c", "X.0"[ev_rc+1]);
case PHP_HTTP_CLIENT_OPT_USE_EVENTS:
#if PHP_HTTP_HAVE_EVENT
if ((curl->useevents = *((zend_bool *) arg))) {
+ if (!curl->evbase) {
+ curl->evbase = event_base_new();
+ }
if (!curl->timeout) {
curl->timeout = ecalloc(1, sizeof(struct event));
}
return SUCCESS;
}
-#if PHP_HTTP_HAVE_EVENT
-PHP_RINIT_FUNCTION(http_client_curl)
-{
- if (!PHP_HTTP_G->curl.event_base && !(PHP_HTTP_G->curl.event_base = event_base_new())) {
- return FAILURE;
- }
- return SUCCESS;
-}
-PHP_RSHUTDOWN_FUNCTION(http_client_curl)
-{
- if (PHP_HTTP_G->curl.event_base) {
- event_base_free(PHP_HTTP_G->curl.event_base);
- PHP_HTTP_G->curl.event_base = NULL;
- }
- return SUCCESS;
-}
-#endif /* PHP_HTTP_HAVE_EVENT */
-
#endif /* PHP_HTTP_HAVE_CURL */
/*
#if PHP_HTTP_HAVE_CURL
-#if PHP_HTTP_HAVE_EVENT
-struct php_http_curl_globals {
- void *event_base;
-};
-
-PHP_RINIT_FUNCTION(http_client_curl);
-PHP_RSHUTDOWN_FUNCTION(http_client_curl);
-#endif /* PHP_HTTP_HAVE_EVENT */
-
PHP_MINIT_FUNCTION(http_client_curl);
PHP_MSHUTDOWN_FUNCTION(http_client_curl);
#endif /* PHP_HTTP_HAVE_CURL */
# elif defined(PHP_HTTP_HAVE_GNUTLS)
# define PHP_HTTP_NEED_GNUTLS_TSL
# include <gcrypt.h>
-# else
-# warning \
- "libcurl was compiled with SSL support, but configure could not determine which" \
- "library was used; thus no SSL crypto locking callbacks will be set, which may " \
- "cause random crashes on SSL requests"
# endif /* PHP_HTTP_HAVE_OPENSSL || PHP_HTTP_HAVE_GNUTLS */
# endif /* PHP_WIN32 */
#endif /* ZTS && PHP_HTTP_HAVE_SSL */
php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Data does not seem to be chunked encoded");
memcpy(*decoded, encoded, encoded_len);
*decoded_len = encoded_len;
- decoded[*decoded_len] = '\0';
return encoded + encoded_len;
} else {
efree(*decoded);
php_http_message_object_init_body_object(obj);
php_http_message_body_append(obj->message->body, ob_str, ob_len);
+#if PHP_VERSION_ID >= 50400
RETURN_TRUE;
+#else
+ RETURN_EMPTY_STRING();
+#endif
}
}
php_http_header_parser_state_t state;
if (parser->stack.top) {
- return (php_http_header_parser_state_t) zend_ptr_stack_top(&parser->stack);
+ return (php_http_header_parser_state_t) parser->stack.elements[parser->stack.top - 1];
}
return PHP_HTTP_HEADER_PARSER_STATE_START;
zval_dtor(&tval);
}
}
+#else
+ if (OG(ob_nesting_level)) {
+ if (php_get_output_start_filename(TSRMLS_C)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not fetch response body, output has already been sent at %s:%d", php_get_output_start_filename(TSRMLS_C), php_get_output_start_lineno(TSRMLS_C));
+ goto error;
+ } else if (SUCCESS != php_ob_get_buffer(&tval TSRMLS_CC)) {
+ php_error_docref(NULL TSRMLS_CC, 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);
+ }
+ }
#endif
break;
{
zval *headers;
php_http_message_object_t *obj = zend_object_store_get_object(object TSRMLS_CC);
- php_http_message_t *msg = obj->message;
HashTable *props = zend_get_std_object_handlers()->get_properties(object TSRMLS_CC);
zval array, *parent, *body;
char *version;
PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
-
INIT_PZVAL_ARRAY(&array, props);
#define ASSOC_PROP(ptype, n, val) \
} \
} while(0)
- ASSOC_PROP(long, "type", msg->type);
- ASSOC_STRINGL_EX("httpVersion", version, spprintf(&version, 0, "%u.%u", msg->http.version.major, msg->http.version.minor), 0);
+ ASSOC_PROP(long, "type", obj->message->type);
+ ASSOC_STRINGL_EX("httpVersion", version, spprintf(&version, 0, "%u.%u", obj->message->http.version.major, obj->message->http.version.minor), 0);
- switch (msg->type) {
+ switch (obj->message->type) {
case PHP_HTTP_REQUEST:
ASSOC_PROP(long, "responseCode", 0);
ASSOC_STRINGL("responseStatus", "", 0);
- ASSOC_STRING("requestMethod", STR_PTR(msg->http.info.request.method));
- ASSOC_STRING("requestUrl", STR_PTR(msg->http.info.request.url));
+ ASSOC_STRING("requestMethod", STR_PTR(obj->message->http.info.request.method));
+ ASSOC_STRING("requestUrl", STR_PTR(obj->message->http.info.request.url));
break;
case PHP_HTTP_RESPONSE:
- ASSOC_PROP(long, "responseCode", msg->http.info.response.code);
- ASSOC_STRING("responseStatus", STR_PTR(msg->http.info.response.status));
+ ASSOC_PROP(long, "responseCode", obj->message->http.info.response.code);
+ ASSOC_STRING("responseStatus", STR_PTR(obj->message->http.info.response.status));
ASSOC_STRINGL("requestMethod", "", 0);
ASSOC_STRINGL("requestUrl", "", 0);
break;
MAKE_STD_ZVAL(headers);
array_init(headers);
- zend_hash_copy(Z_ARRVAL_P(headers), &msg->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
+ zend_hash_copy(Z_ARRVAL_P(headers), &obj->message->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
ASSOC_PROP(zval, "headers", headers);
MAKE_STD_ZVAL(body);
- if (!obj->body) {
- php_http_new(NULL, php_http_message_body_class_entry, (php_http_new_t) php_http_message_body_object_new_ex, NULL, (void *) php_http_message_body_init(&obj->message->body, NULL TSRMLS_CC), (void *) &obj->body TSRMLS_CC);
+ if (obj->body) {
+ ZVAL_OBJVAL(body, obj->body->zv, 1);
+ } else {
+ ZVAL_NULL(body);
}
- ZVAL_OBJVAL(body, obj->body->zv, 1);
ASSOC_PROP(zval, "body", body);
MAKE_STD_ZVAL(parent);
- if (msg->parent) {
+ if (obj->message->parent) {
ZVAL_OBJVAL(parent, obj->parent->zv, 1);
} else {
ZVAL_NULL(parent);
php_http_message_parser_state_t php_http_message_parser_state_is(php_http_message_parser_t *parser)
{
if (parser->stack.top) {
- return (php_http_message_parser_state_t) zend_ptr_stack_top(&parser->stack);
+ return (php_http_message_parser_state_t) parser->stack.elements[parser->stack.top - 1];
}
return PHP_HTTP_MESSAGE_PARSER_STATE_START;
}
{
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);
}
return php_http_message_parser_state_is(parser);
}
+zend_class_entry *php_http_message_parser_class_entry;
+static zend_object_handlers php_http_message_parser_object_handlers;
+
+zend_object_value php_http_message_parser_object_new(zend_class_entry *ce TSRMLS_DC)
+{
+ return php_http_message_parser_object_new_ex(ce, NULL, NULL TSRMLS_CC);
+}
+
+zend_object_value php_http_message_parser_object_new_ex(zend_class_entry *ce, php_http_message_parser_t *parser, php_http_message_parser_object_t **ptr TSRMLS_DC)
+{
+ php_http_message_parser_object_t *o;
+
+ o = ecalloc(1, sizeof(php_http_message_parser_object_t));
+ zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
+ object_properties_init((zend_object *) o, ce);
+
+ if (ptr) {
+ *ptr = o;
+ }
+
+ if (parser) {
+ o->parser = parser;
+ } else {
+ o->parser = php_http_message_parser_init(NULL TSRMLS_CC);
+ }
+ o->buffer = php_http_buffer_new();
+
+ o->zv.handle = zend_objects_store_put((zend_object *) o, NULL, php_http_message_parser_object_free, NULL TSRMLS_CC);
+ o->zv.handlers = &php_http_message_parser_object_handlers;
+
+ return o->zv;
+}
+
+void php_http_message_parser_object_free(void *object TSRMLS_DC)
+{
+ php_http_message_parser_object_t *o = (php_http_message_parser_object_t *) object;
+
+ if (o->parser) {
+ php_http_message_parser_free(&o->parser);
+ }
+ if (o->buffer) {
+ php_http_buffer_free(&o->buffer);
+ }
+ zend_object_std_dtor((zend_object *) o TSRMLS_CC);
+ efree(o);
+}
+
+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 = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ zend_parse_parameters_none();
+ /* always return the real state */
+ RETVAL_LONG(php_http_message_parser_state_is(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;
+ int data_len;
+ long flags;
+
+ php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "slz", &data_str, &data_len, &flags, &zmsg), invalid_arg, return);
+
+ parser_obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+ 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_dtor(zmsg);
+ if (parser_obj->parser->message) {
+ ZVAL_OBJVAL(zmsg, php_http_message_object_new_ex(php_http_message_class_entry, php_http_message_copy(parser_obj->parser->message, NULL), NULL TSRMLS_CC), 0);
+ }
+}
+
+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;
+ long flags;
+
+ php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rlz", &zstream, &flags, &zmsg), invalid_arg, return);
+
+ zend_replace_error_handling(EH_THROW, php_http_exception_unexpected_val_class_entry, &zeh TSRMLS_CC);
+ php_stream_from_zval(s, &zstream);
+ zend_restore_error_handling(&zeh TSRMLS_CC);
+
+ parser_obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+ RETVAL_LONG(php_http_message_parser_parse_stream(parser_obj->parser, s, flags, &parser_obj->parser->message));
+
+ zval_dtor(zmsg);
+ if (parser_obj->parser->message) {
+ ZVAL_OBJVAL(zmsg, php_http_message_object_new_ex(php_http_message_class_entry, php_http_message_copy(parser_obj->parser->message, NULL), NULL TSRMLS_CC), 0);
+ }
+}
+
+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)
+ {NULL, NULL, NULL}
+};
+
+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 TSRMLS_CC);
+ 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;
+
+ zend_declare_class_constant_long(php_http_message_parser_class_entry, ZEND_STRL("CLEANUP"), PHP_HTTP_MESSAGE_PARSER_CLEANUP TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_message_parser_class_entry, ZEND_STRL("DUMB_BODIES"), PHP_HTTP_MESSAGE_PARSER_DUMB_BODIES TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_message_parser_class_entry, ZEND_STRL("EMPTY_REDIRECTS"), PHP_HTTP_MESSAGE_PARSER_EMPTY_REDIRECTS TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_message_parser_class_entry, ZEND_STRL("GREEDY"), PHP_HTTP_MESSAGE_PARSER_GREEDY TSRMLS_CC);
+
+ zend_declare_class_constant_long(php_http_message_parser_class_entry, ZEND_STRL("STATE_FAILURE"), PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_message_parser_class_entry, ZEND_STRL("STATE_START"), PHP_HTTP_MESSAGE_PARSER_STATE_START TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_message_parser_class_entry, ZEND_STRL("STATE_HEADER"), PHP_HTTP_MESSAGE_PARSER_STATE_HEADER TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_message_parser_class_entry, ZEND_STRL("STATE_HEADER_DONE"), PHP_HTTP_MESSAGE_PARSER_STATE_HEADER_DONE TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_message_parser_class_entry, ZEND_STRL("STATE_BODY"), PHP_HTTP_MESSAGE_PARSER_STATE_BODY TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_message_parser_class_entry, ZEND_STRL("STATE_BODY_DUMB"), PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DUMB TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_message_parser_class_entry, ZEND_STRL("STATE_BODY_LENGTH"), PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_message_parser_class_entry, ZEND_STRL("STATE_BODY_CHUNKED"), PHP_HTTP_MESSAGE_PARSER_STATE_BODY_CHUNKED TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_message_parser_class_entry, ZEND_STRL("STATE_BODY_DONE"), PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE TSRMLS_CC);
+ zend_declare_class_constant_long(php_http_message_parser_class_entry, ZEND_STRL("STATE_DONE"), PHP_HTTP_MESSAGE_PARSER_STATE_DONE TSRMLS_CC);
+
+ return SUCCESS;
+}
+
/*
* Local variables:
* tab-width: 4
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_stream *s, unsigned flags, php_http_message_t **message);
+typedef struct php_http_message_parser_object {
+ zend_object zo;
+ zend_object_value zv;
+ php_http_buffer_t *buffer;
+ php_http_message_parser_t *parser;
+} php_http_message_parser_object_t;
+
+PHP_HTTP_API zend_class_entry *php_http_message_parser_class_entry;
+
+PHP_MINIT_FUNCTION(http_message_parser);
+
+zend_object_value php_http_message_parser_object_new(zend_class_entry *ce TSRMLS_DC);
+zend_object_value php_http_message_parser_object_new_ex(zend_class_entry *ce, php_http_message_parser_t *parser, php_http_message_parser_object_t **ptr TSRMLS_DC);
+void php_http_message_parser_object_free(void *object TSRMLS_DC);
+
#endif
/*
if ((wasalpha = PHP_HTTP_IS_CTYPE(alpha, key[0]))) {
key[0] = (char) (uctitle ? PHP_HTTP_TO_CTYPE(upper, key[0]) : PHP_HTTP_TO_CTYPE(lower, key[0]));
}
- PHP_HTTP_DUFF(1, key_len,
+ PHP_HTTP_DUFF(key_len,
if (PHP_HTTP_IS_CTYPE(alpha, key[i])) {
key[i] = (char) (((!wasalpha) && uctitle) ? PHP_HTTP_TO_CTYPE(upper, key[i]) : PHP_HTTP_TO_CTYPE(lower, key[i]));
wasalpha = 1;
int php_http_select_str(const char *cmp, int argc, ...);
/* See "A Reusable Duff Device" By Ralf Holly, August 01, 2005 */
-#define PHP_HTTP_DUFF_BREAK(i) do { \
- times_##i = 1; \
-} while (0)
-
-#define PHP_HTTP_DUFF(i, c, a) do { \
- size_t count_##i = (c); \
- size_t times_##i = (count_##i + 7) >> 3; \
- switch (count_##i & 7){ \
- case 0: do { a; \
- case 7: a; \
- case 6: a; \
- case 5: a; \
- case 4: a; \
- case 3: a; \
- case 2: a; \
- case 1: a; \
- } while (--times_##i > 0); \
+#define PHP_HTTP_DUFF_BREAK() times_=1
+#define PHP_HTTP_DUFF(c, a) do { \
+ size_t count_ = (c); \
+ size_t times_ = (count_ + 7) >> 3; \
+ switch (count_ & 7){ \
+ case 0: do { \
+ a; \
+ case 7: \
+ a; \
+ case 6: \
+ a; \
+ case 5: \
+ a; \
+ case 4: \
+ a; \
+ case 3: \
+ a; \
+ case 2: \
+ a; \
+ case 1: \
+ a; \
+ } while (--times_ > 0); \
} \
} while (0)
-
static inline const char *php_http_locate_str(register const char *h, size_t h_len, const char *n, size_t n_len)
{
- register const char *p1, *p2;
-
- if (n_len && h_len && h_len >= n_len) {
- PHP_HTTP_DUFF(1, h_len - n_len + 1,
- if (*h == *n) {
- p1 = h;
- p2 = n;
- PHP_HTTP_DUFF(2, n_len,
- if (*p1++ != *p2++) {
- PHP_HTTP_DUFF_BREAK(2);
- } else if (p2 == n + n_len - 1) {
- return h;
- }
- );
- }
- ++h;
- );
+ if (!n_len || !h_len || h_len < n_len) {
+ return NULL;
}
+ PHP_HTTP_DUFF(h_len - n_len + 1,
+ if (*h == *n && !strncmp(h + 1, n + 1, n_len - 1)) {
+ return h;
+ }
+ ++h;
+ );
+
return NULL;
}
register const char *eol = bin;
if (len > 0) {
- PHP_HTTP_DUFF(1, len,
+ PHP_HTTP_DUFF(len,
if (*eol == '\r' || *eol == '\n') {
if (eol_len) {
*eol_len = ((eol[0] == '\r' && eol[1] == '\n') ? 2 : 1);
if (flags & PHP_HTTP_PARAMS_ESCAPED) {
sanitize_escaped(zv TSRMLS_CC);
}
+
+ if (!Z_STRLEN_P(zv)) {
+ return;
+ }
eos = &Z_STRVAL_P(zv)[Z_STRLEN_P(zv)-1];
if (*eos == '*') {
switch (Z_STRVAL_P(zv)[0]) {
case 'I':
case 'i':
- if (!strncasecmp(Z_STRVAL_P(zv), ZEND_STRL("iso-8859-1"))) {
+ 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), ZEND_STRL("utf-8"))) {
+ if (!strncasecmp(Z_STRVAL_P(zv), "utf-8", lenof("utf-8"))) {
*latin1 = 0;
ptr = Z_STRVAL_P(zv) + lenof("utf-8");
break;
return estrndup("localhost", lenof("localhost"));
}
-static inline unsigned port(const char *scheme)
-{
- unsigned port = 80;
-
-#if defined(ZTS) && defined(HAVE_GETSERVBYPORT_R)
- int rc;
- size_t len = 0xff;
- char *buf = NULL;
- struct servent *se_res = NULL, se_buf = {0};
-
- do {
- buf = erealloc(buf, len);
- rc = getservbyname_r(scheme, "tcp", &se_buf, buf, len, &se_res);
- len *= 2;
- } while (rc == ERANGE && len <= 0xfff);
-
- if (!rc) {
- port = ntohs(se_res->s_port);
- }
-
- efree(buf);
-#elif !defined(ZTS) && defined(HAVE_GETSERVBYPORT)
- struct servent *se;
-
- if ((se = getservbyname(scheme, "tcp")) && se->s_port) {
- port = ntohs(se->s_port);
- }
-#endif
-
- return port;
-}
-static inline char *scheme(unsigned port)
-{
- char *scheme;
-#if defined(ZTS) && defined(HAVE_GETSERVBYPORT_R)
- int rc;
- size_t len = 0xff;
- char *buf = NULL;
- struct servent *se_res = NULL, se_buf = {0};
-#elif !defined(ZTS) && defined(HAVE_GETSERVBYPORT)
- struct servent *se;
-#endif
-
- switch (port) {
- case 443:
- scheme = estrndup("https", lenof("https"));
- break;
-
-#if defined(ZTS) && !defined(HAVE_GETSERVBYPORT_R)
- default:
-#elif !defined(ZTS) && !defined(HAVE_GETSERVBYPORT)
- default:
-#endif
- case 80:
- case 0:
- scheme = estrndup("http", lenof("http"));
- break;
-
-#if defined(ZTS) && defined(HAVE_GETSERVBYPORT_R)
- default:
- do {
- buf = erealloc(buf, len);
- rc = getservbyport_r(htons(port), "tcp", &se_buf, buf, len, &se_res);
- len *= 2;
- } while (rc == ERANGE && len <= 0xfff);
-
- if (!rc && se_res) {
- scheme = estrdup(se_res->s_name);
- } else {
- scheme = estrndup("http", lenof("http"));
- }
-
- efree(buf);
- break;
-
-#elif !defined(ZTS) && defined(HAVE_GETSERVBYPORT)
- default:
- if ((se = getservbyport(htons(port), "tcp")) && se->s_name) {
- scheme = estrdup(se->s_name);
- } else {
- scheme = estrndup("http", lenof("http"));
- }
- break;
-#endif
- }
- return scheme;
-}
-
static php_url *php_http_url_from_env(php_url *url TSRMLS_DC)
{
zval *https, *zhost, *zport;
if (https && !strcasecmp(Z_STRVAL_P(https), "ON")) {
url->scheme = estrndup("https", lenof("https"));
} else {
- url->scheme = scheme(url->port);
+ url->scheme = estrndup("http", lenof("http"));
}
/* host */
if (url->port) {
if ( ((url->port == 80) && !strcmp(url->scheme, "http"))
|| ((url->port ==443) && !strcmp(url->scheme, "https"))
- || ( url->port == port(url->scheme))
) {
url->port = 0;
}
--- /dev/null
+--TEST--
+http client event base
+--SKIPIF--
+<?php
+include "skipif.inc";
+try {
+ $client = new http\Client;
+ if (!$client->enableEvents())
+ throw new Exception("need events support");
+} catch (Exception $e) {
+ die("skip ".$e->getMessage());
+}
+?>
+--FILE--
+<?php
+echo "Test\n";
+
+$client1 = new http\Client;
+$client2 = new http\Client;
+
+$client1->enableEvents();
+$client2->enableEvents();
+
+$client1->enqueue(new http\Client\Request("GET", "http://www.google.ca/"));
+$client2->enqueue(new http\Client\Request("GET", "http://www.google.co.uk/"));
+
+$client1->send();
+
+if (($r = $client1->getResponse())) {
+ var_dump($r->getTransferInfo("response_code"));
+}
+if (($r = $client2->getResponse())) {
+ var_dump($r->getTransferInfo("response_code"));
+}
+
+?>
+DONE
+--EXPECT--
+Test
+int(200)
+DONE
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: 2284
+Content-Length: 2273
Expect: 100-continue
Content-Type: multipart/form-data; boundary=----------------------------6e182425881c
["type":protected]=>
int(1)
["body":protected]=>
- object(http\Message\Body)#%d (0) {
- }
+ NULL
["requestMethod":protected]=>
string(3) "GET"
["requestUrl":protected]=>
["type":protected]=>
int(1)
["body":protected]=>
- object(http\Message\Body)#%d (0) {
- }
+ NULL
["requestMethod":protected]=>
string(4) "POST"
["requestUrl":protected]=>
["type":protected]=>
int(0)
["body":protected]=>
- object(http\Message\Body)#%d (0) {
- }
+ NULL
["requestMethod":protected]=>
string(0) ""
["requestUrl":protected]=>
--- /dev/null
+--TEST--
+message parser
+--SKIPIF--
+<?php
+include "skipif.inc";
+?>
+--FILE--
+<?php
+
+echo "Test\n";
+
+use http\Message\Parser;
+
+foreach (glob(__DIR__."/data/message_*.txt") as $file) {
+ $parser = new Parser;
+ $fd = fopen($file, "r") or die("Could not open $file");
+ while (!feof($fd)) {
+ switch ($parser->parse(fgets($fd), 0, $message)) {
+ case Parser::STATE_DONE:
+ $string = (string) $message;
+ break 2;
+ case Parser::STATE_FAILURE:
+ throw new Exception(($e = error_get_last()) ? $e["message"] : "Could not parse $file");
+ }
+ }
+
+ $parser = new Parser;
+ rewind($fd);
+ unset($message);
+
+ switch ($parser->stream($fd, 0, $message)) {
+ case Parser::STATE_DONE:
+ case Parser::STATE_START:
+ break;
+ default:
+ printf("Expected parser state 0 or 8, got %d", $parser->getState());
+ }
+ if ($string !== (string) $message) {
+ $a = explode("\n", $string);
+ $b = explode("\n", (string) $message);
+ while ((null !== ($aa = array_shift($a))) || (null !== ($bb = array_shift($b)))) {
+ if ($aa !== $bb) {
+ isset($aa) and printf("-- %s\n", $aa);
+ isset($bb) and printf("++ %s\n", $bb);
+ }
+ }
+ }
+}
+?>
+DONE
+--EXPECT--
+Test
+DONE
--FILE--
<?php
echo "Test\n";
-$p = new http\Params(["attachment"=>["filename"=>"foo.bar"]]);
+$p = new http\Params(array("attachment"=>array("filename"=>"foo.bar")));
var_dump($p->params);
var_dump((string)$p);
?>