</lead>
<date>2014-08-19</date>
<version>
- <release>2.1.0RC3</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[
-Changes from RC2:
-* Fixed PHP-5.3 compatibility
-* Fixed possible bus error on shutdown when using events
-+ Added curlcode transfer info
-- Removed port and scheme guessing of http\Url for portability
+- 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)
#ifndef PHP_EXT_HTTP_H
#define PHP_EXT_HTTP_H
-#define PHP_PECL_HTTP_VERSION "2.1.0RC3"
+#define PHP_PECL_HTTP_VERSION "2.2.0dev"
extern zend_module_entry http_module_entry;
#define phpext_http_ptr &http_module_entry
{
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_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
/*
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