From 112e0617d9aa6f3043dfeb94a945b17e31b85430 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Mon, 30 Jul 2012 18:30:22 +0000 Subject: [PATCH 01/16] foward querystring API --- php_http_env_request.c | 47 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git a/php_http_env_request.c b/php_http_env_request.c index 701e9fd..e4e8eaf 100644 --- a/php_http_env_request.c +++ b/php_http_env_request.c @@ -20,8 +20,21 @@ #define PHP_HTTP_ENV_REQUEST_ME(method, visibility) PHP_ME(HttpEnvRequest, method, PHP_HTTP_ARGS(HttpEnvRequest, method), visibility) PHP_HTTP_EMPTY_ARGS(__construct); -PHP_HTTP_EMPTY_ARGS(getForm); -PHP_HTTP_EMPTY_ARGS(getQuery); + +PHP_HTTP_BEGIN_ARGS(getQuery, 0) + PHP_HTTP_ARG_VAL(name, 0) + PHP_HTTP_ARG_VAL(type, 0) + PHP_HTTP_ARG_VAL(defval, 0) + PHP_HTTP_ARG_VAL(delete, 0) +PHP_HTTP_END_ARGS; + +PHP_HTTP_BEGIN_ARGS(getForm, 0) + PHP_HTTP_ARG_VAL(name, 0) + PHP_HTTP_ARG_VAL(type, 0) + PHP_HTTP_ARG_VAL(defval, 0) + PHP_HTTP_ARG_VAL(delete, 0) +PHP_HTTP_END_ARGS; + PHP_HTTP_EMPTY_ARGS(getFiles); static zend_class_entry *php_http_env_request_class_entry; @@ -160,16 +173,42 @@ PHP_METHOD(HttpEnvRequest, __construct) } end_error_handling(); } +#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 *qs = zend_read_property(Z_OBJCE_P(getThis()), getThis(), ZEND_STRL(prop), 0 TSRMLS_CC); \ + \ + INIT_PZVAL(&mn); \ + array_init(&mn); \ + Z_ADDREF_P(qs); \ + add_next_index_zval(&mn, qs); \ + add_next_index_stringl(&mn, ZEND_STRL("get"), 1); \ + zend_fcall_info_init(&mn, 0, &fci, &fcc, NULL, NULL TSRMLS_CC); \ + zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args); \ + zend_fcall_info_argp(&fci TSRMLS_CC, ZEND_NUM_ARGS(), args); \ + zend_fcall_info_call(&fci, &fcc, &rv, NULL TSRMLS_CC); \ + zend_fcall_info_args_clear(&fci, 1); \ + efree(args); \ + zval_dtor(&mn); \ + RETVAL_ZVAL(rv, 0, 1); \ + } while(0); + PHP_METHOD(HttpEnvRequest, getForm) { - if (SUCCESS == zend_parse_parameters_none()) { + if (ZEND_NUM_ARGS()) { + call_querystring_get("form"); + } else { RETURN_PROP(php_http_env_request_class_entry, "form"); } } PHP_METHOD(HttpEnvRequest, getQuery) { - if (SUCCESS == zend_parse_parameters_none()) { + if (ZEND_NUM_ARGS()) { + call_querystring_get("query"); + } else { RETURN_PROP(php_http_env_request_class_entry, "query"); } } -- 2.30.2 From 22f2117f08acf0fcf84d70a54ef168ff1627fc69 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Mon, 30 Jul 2012 18:31:03 +0000 Subject: [PATCH 02/16] fix parsing of folded headers --- php_http_header_parser.c | 84 +++++++++++++++++++++++++++------------- php_http_header_parser.h | 1 + 2 files changed, 58 insertions(+), 27 deletions(-) diff --git a/php_http_header_parser.c b/php_http_header_parser.c index 1dcd97b..e0dea5b 100644 --- a/php_http_header_parser.c +++ b/php_http_header_parser.c @@ -21,6 +21,7 @@ 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, 1}, {PHP_HTTP_HEADER_PARSER_STATE_HEADER_DONE, 0}, {PHP_HTTP_HEADER_PARSER_STATE_DONE, 0} }; @@ -100,7 +101,7 @@ PHP_HTTP_API STATUS php_http_header_parser_parse(php_http_header_parser_t *parse while (buffer->used || !php_http_header_parser_states[php_http_header_parser_state_is(parser)].need_data) { #if 0 const char *state[] = {"START", "KEY", "VALUE", "HEADER_DONE", "DONE"}; - fprintf(stderr, "#HP: %s (%d)\n", php_http_header_parser_state_is(parser) < 0 ? "FAILURE" : state[php_http_header_parser_state_is(parser)], zend_hash_num_elements(headers)); + fprintf(stderr, "#HP: %s (avail:%zu, num:%d)\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); _dpf(0, buffer->data, buffer->used); #endif switch (php_http_header_parser_state_pop(parser)) { @@ -138,7 +139,7 @@ PHP_HTTP_API STATUS php_http_header_parser_parse(php_http_header_parser_t *parse } else if ((colon = memchr(buffer->data, ':', buffer->used)) && (!eol_str || eol_str > colon)) { /* header: string */ parser->_key.str = estrndup(buffer->data, parser->_key.len = colon - buffer->data); - while (PHP_HTTP_IS_CTYPE(space, *++colon)); + 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, 1, PHP_HTTP_HEADER_PARSER_STATE_VALUE); } else { @@ -152,38 +153,67 @@ PHP_HTTP_API STATUS php_http_header_parser_parse(php_http_header_parser_t *parse const char *eol_str; int eol_len; - line_split: { - - if ((eol_str = php_http_locate_bin_eol(buffer->data, buffer->used, &eol_len))) { - if (eol_str + eol_len - buffer->data < buffer->used) { - const char *nextline = eol_str + eol_len; - - if (*nextline == '\t' || *nextline == ' ') { - while (nextline < buffer->data + buffer->used && (*nextline == '\t' || *nextline == ' ')) { - ++nextline; - } - php_http_buffer_cut(buffer, eol_str - buffer->data, nextline - eol_str); - goto line_split; - } +#define SET_ADD_VAL(slen, eol_len) \ + do { \ + 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); + + if (buffer->used) { + if (*buffer->data != '\t' && *buffer->data != ' ') { + php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_HEADER_DONE); + break; + } else { + php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_VALUE); + break; } - - parser->_val.str = estrndup(buffer->data, parser->_val.len = eol_str - buffer->data); - php_http_buffer_cut(buffer, 0, eol_str + eol_len - buffer->data); - php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_HEADER_DONE); - } else if (flags & PHP_HTTP_HEADER_PARSER_CLEANUP) { - if (buffer->used) { - parser->_val.str = estrndup(buffer->data, parser->_val.len = buffer->used); - php_http_buffer_reset(buffer); - } - php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_HEADER_DONE); - } else { - return php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_VALUE); } } + if (flags & PHP_HTTP_HEADER_PARSER_CLEANUP) { + if (buffer->used) { + SET_ADD_VAL(buffer->used, 0); + } + php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_HEADER_DONE); + } else { + return php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_VALUE_EX); + } break; } + case PHP_HTTP_HEADER_PARSER_STATE_VALUE_EX: + if (*buffer->data == ' ' || *buffer->data == '\t') { + php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_VALUE); + } else { + php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_HEADER_DONE); + } + break; + case PHP_HTTP_HEADER_PARSER_STATE_HEADER_DONE: if (parser->_key.str && parser->_val.str) { zval array, **exist; diff --git a/php_http_header_parser.h b/php_http_header_parser.h index 78ca43f..0c26db3 100644 --- a/php_http_header_parser.h +++ b/php_http_header_parser.h @@ -20,6 +20,7 @@ typedef enum php_http_header_parser_state { 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; -- 2.30.2 From b340a8fa0aacc9727d54bb3957eb6902bc350004 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Mon, 30 Jul 2012 18:31:46 +0000 Subject: [PATCH 03/16] add php_http_message_zip(): merge request/response messages for history --- php_http_message.c | 18 ++++++++++++++++++ php_http_message.h | 1 + 2 files changed, 19 insertions(+) diff --git a/php_http_message.c b/php_http_message.c index 34d9ed8..04e8706 100644 --- a/php_http_message.c +++ b/php_http_message.c @@ -462,6 +462,24 @@ PHP_HTTP_API php_http_message_t *php_http_message_reverse(php_http_message_t *ms return msg; } +PHP_HTTP_API php_http_message_t *php_http_message_zip(php_http_message_t *one, php_http_message_t *two) +{ + php_http_message_t *dst = php_http_message_copy(one, NULL), *src = php_http_message_copy(two, NULL), *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_API 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; diff --git a/php_http_message.h b/php_http_message.h index fb991f5..766c0b4 100644 --- a/php_http_message.h +++ b/php_http_message.h @@ -61,6 +61,7 @@ PHP_HTTP_API void php_http_message_to_callback(php_http_message_t *msg, php_http 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); #define php_http_message_count(c, m) \ { \ -- 2.30.2 From 3d6119e310337b4453b30312ea65613208493cd3 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Mon, 30 Jul 2012 18:32:30 +0000 Subject: [PATCH 04/16] implement Serializable --- php_http_message_body.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/php_http_message_body.c b/php_http_message_body.c index 9d0f226..40a1688 100644 --- a/php_http_message_body.c +++ b/php_http_message_body.c @@ -537,6 +537,9 @@ PHP_HTTP_BEGIN_ARGS(__construct, 0) PHP_HTTP_END_ARGS; PHP_HTTP_EMPTY_ARGS(__toString); +PHP_HTTP_BEGIN_ARGS(unserialize, 1) + PHP_HTTP_ARG_VAL(serialized, 0) +PHP_HTTP_END_ARGS; PHP_HTTP_BEGIN_ARGS(toStream, 1) PHP_HTTP_ARG_VAL(stream, 0) @@ -578,6 +581,8 @@ static zend_function_entry php_http_message_body_method_entry[] = { PHP_HTTP_MESSAGE_BODY_ME(__construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) PHP_HTTP_MESSAGE_BODY_ME(__toString, ZEND_ACC_PUBLIC) PHP_MALIAS(HttpMessageBody, toString, __toString, args_for_HttpMessageBody___toString, ZEND_ACC_PUBLIC) + PHP_MALIAS(HttpMessageBody, serialize, __toString, args_for_HttpMessageBody___toString, ZEND_ACC_PUBLIC) + PHP_HTTP_MESSAGE_BODY_ME(unserialize, ZEND_ACC_PUBLIC) PHP_HTTP_MESSAGE_BODY_ME(toStream, ZEND_ACC_PUBLIC) PHP_HTTP_MESSAGE_BODY_ME(toCallback, ZEND_ACC_PUBLIC) PHP_HTTP_MESSAGE_BODY_ME(getResource, ZEND_ACC_PUBLIC) @@ -596,7 +601,7 @@ PHP_MINIT_FUNCTION(http_message_body) 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.clone_obj = php_http_message_body_object_clone; - + zend_class_implements(php_http_message_body_class_entry TSRMLS_CC, 1, zend_ce_serializable); return SUCCESS; } @@ -694,6 +699,19 @@ PHP_METHOD(HttpMessageBody, __toString) RETURN_EMPTY_STRING(); } +PHP_METHOD(HttpMessageBody, unserialize) +{ + char *us_str; + int us_len; + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &us_str, &us_len)) { + php_http_message_body_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + php_stream *s = php_stream_memory_open(0, us_str, us_len); + + obj->body = php_http_message_body_init(NULL, s TSRMLS_CC); + } +} + PHP_METHOD(HttpMessageBody, toStream) { zval *zstream; -- 2.30.2 From 86c77c2966b90f63ad5b6991733ab036d33a976d Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Mon, 30 Jul 2012 18:32:46 +0000 Subject: [PATCH 05/16] implement Serializable --- php_http_message_body.h | 1 + 1 file changed, 1 insertion(+) diff --git a/php_http_message_body.h b/php_http_message_body.h index 7fc6e56..165dc3f 100644 --- a/php_http_message_body.h +++ b/php_http_message_body.h @@ -67,6 +67,7 @@ void php_http_message_body_object_free(void *object TSRMLS_DC); PHP_METHOD(HttpMessageBody, __construct); PHP_METHOD(HttpMessageBody, __toString); +PHP_METHOD(HttpMessageBody, unserialize); PHP_METHOD(HttpMessageBody, getResource); PHP_METHOD(HttpMessageBody, toStream); PHP_METHOD(HttpMessageBody, toCallback); -- 2.30.2 From 42167829591c8ddf24386c65cf0d5caf00f6f9cc Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Mon, 30 Jul 2012 18:33:20 +0000 Subject: [PATCH 06/16] fix parsing messages from stream --- php_http_message_parser.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/php_http_message_parser.c b/php_http_message_parser.c index ecdfe37..fae3df3 100644 --- a/php_http_message_parser.c +++ b/php_http_message_parser.c @@ -140,10 +140,11 @@ PHP_HTTP_API php_http_message_parser_state_t php_http_message_parser_parse_strea len -= read; } else { + php_http_buffer_resize(&buf, 24); php_stream_get_line(s, buf.data, buf.free, &len); php_http_buffer_account(&buf, len); - len = strtoul(buf.data - len, NULL, 16); + len = strtoul(buf.data + buf.used - len, NULL, 16); } break; @@ -298,10 +299,16 @@ PHP_HTTP_API php_http_message_parser_state_t php_http_message_parser_parse(php_h if (h_cl) { char *stop; - parser->body_length = strtoul(Z_STRVAL_PP(h_cl), &stop, 10); + if (Z_TYPE_PP(h_cl) == IS_STRING) { + parser->body_length = strtoul(Z_STRVAL_PP(h_cl), &stop, 10); - if (stop != Z_STRVAL_PP(h_cl)) { - php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH); + if (stop != Z_STRVAL_PP(h_cl)) { + php_http_message_parser_state_push(parser, 1, !parser->body_length?PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE:PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH); + break; + } + } else if (Z_TYPE_PP(h_cl) == IS_LONG) { + parser->body_length = Z_LVAL_PP(h_cl); + php_http_message_parser_state_push(parser, 1, !parser->body_length?PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE:PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH); break; } } @@ -327,7 +334,7 @@ PHP_HTTP_API php_http_message_parser_state_t php_http_message_parser_parse(php_h if (end >= start && (!total || end < total)) { parser->body_length = end + 1 - start; - php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH); + php_http_message_parser_state_push(parser, 1, !parser->body_length?PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE:PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH); break; } } -- 2.30.2 From 302149963f42c5e839f34dfa79195d6fc441e279 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Mon, 30 Jul 2012 18:33:55 +0000 Subject: [PATCH 07/16] fix php_http_locate_bin_eol(() --- php_http_misc.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php_http_misc.h b/php_http_misc.h index 70dc090..972ba92 100644 --- a/php_http_misc.h +++ b/php_http_misc.h @@ -137,10 +137,10 @@ static inline const char *php_http_locate_bin_eol(const char *bin, size_t len, i { const char *eol; - for (eol = bin; eol - bin < len; ++eol) { + for (eol = bin; eol - bin <= len; ++eol) { if (*eol == '\r' || *eol == '\n') { if (eol_len) { - *eol_len = eol ? ((eol[0] == '\r' && eol[1] == '\n') ? 2 : 1) : 0; + *eol_len = ((eol[0] == '\r' && eol[1] == '\n') ? 2 : 1); } return eol; } -- 2.30.2 From 868dafaf33431cd79f5f28c6f9b8fc166631b243 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Mon, 30 Jul 2012 18:34:35 +0000 Subject: [PATCH 08/16] fix leak in persisten handles cleanup routine --- php_http_persistent_handle.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/php_http_persistent_handle.c b/php_http_persistent_handle.c index 4210437..d27663c 100644 --- a/php_http_persistent_handle.c +++ b/php_http_persistent_handle.c @@ -78,7 +78,16 @@ static int php_http_persistent_handle_apply_cleanup(void *pp, void *arg TSRMLS_D php_http_persistent_handle_list_t **listp = pp; zend_hash_apply_with_argument(&(*listp)->free, php_http_persistent_handle_apply_cleanup_ex, rf TSRMLS_CC); - return (*listp)->used ? ZEND_HASH_APPLY_KEEP : ZEND_HASH_APPLY_REMOVE; + if ((*listp)->used) { + return ZEND_HASH_APPLY_KEEP; + } + zend_hash_destroy(&(*listp)->free); +#if PHP_HTTP_DEBUG_PHANDLES + fprintf(stderr, "LSTFREE: %p\n", *listp); +#endif + pefree(*listp, 1); + *listp = NULL; + return ZEND_HASH_APPLY_REMOVE; } static inline void php_http_persistent_handle_list_dtor(php_http_persistent_handle_list_t *list, php_http_persistent_handle_provider_t *provider TSRMLS_DC) @@ -144,7 +153,9 @@ static inline STATUS php_http_persistent_handle_do_acquire(php_http_persistent_h } else { *handle = php_http_resource_factory_handle_ctor(&provider->rf TSRMLS_CC); } - +#if PHP_HTTP_DEBUG_PHANDLES + fprintf(stderr, "CREATED: %p\n", *handle); +#endif if (*handle) { ++provider->list.used; ++list->used; @@ -163,6 +174,9 @@ static inline STATUS php_http_persistent_handle_do_release(php_http_persistent_h if ((list = php_http_persistent_handle_list_find(provider, ident_str, ident_len TSRMLS_CC))) { if (provider->list.used >= PHP_HTTP_G->persistent_handle.limit) { +#if PHP_HTTP_DEBUG_PHANDLES + fprintf(stderr, "DESTROY: %p\n", *handle); +#endif php_http_resource_factory_handle_dtor(&provider->rf, *handle TSRMLS_CC); } else { if (SUCCESS != zend_hash_next_index_insert(&list->free, (void *) handle, sizeof(void *), NULL)) { @@ -282,6 +296,10 @@ PHP_HTTP_API void php_http_persistent_handle_abandon(php_http_persistent_handle_ { zend_bool f = a->free_on_abandon; +#if PHP_HTTP_DEBUG_PHANDLES + fprintf(stderr, "ABANDON: %p\n", a->provider); +#endif + STR_FREE(a->ident.str); memset(a, 0, sizeof(*a)); if (f) { @@ -331,7 +349,7 @@ PHP_HTTP_API void php_http_persistent_handle_cleanup(const char *name_str, size_ zend_hash_apply_with_argument(&list->free, php_http_persistent_handle_apply_cleanup_ex, &provider->rf TSRMLS_CC); } } else { - zend_hash_apply_with_argument(&provider->list.free, php_http_persistent_handle_apply_cleanup, &provider->list.free TSRMLS_CC); + zend_hash_apply_with_argument(&provider->list.free, php_http_persistent_handle_apply_cleanup, &provider->rf TSRMLS_CC); } } } else { @@ -343,7 +361,7 @@ PHP_HTTP_API void php_http_persistent_handle_cleanup(const char *name_str, size_ zend_hash_apply_with_argument(&list->free, php_http_persistent_handle_apply_cleanup_ex, &provider->rf TSRMLS_CC); } } else { - zend_hash_apply_with_argument(&provider->list.free, php_http_persistent_handle_apply_cleanup, &provider->list.free TSRMLS_CC); + zend_hash_apply_with_argument(&provider->list.free, php_http_persistent_handle_apply_cleanup, &provider->rf TSRMLS_CC); } } } -- 2.30.2 From 773a621472c013138f57ccb3951ca310b084f330 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Mon, 30 Jul 2012 18:35:08 +0000 Subject: [PATCH 09/16] test parsing messages from stream --- tests/message001.phpt | 205 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 205 insertions(+) diff --git a/tests/message001.phpt b/tests/message001.phpt index e0eeddd..9060ee4 100644 --- a/tests/message001.phpt +++ b/tests/message001.phpt @@ -43,6 +43,8 @@ var_dump( $m->getHeaders() ); +echo "---\n"; + $m = new HttpMessage(file_get_contents(__DIR__."/data/message_rr_empty.txt")); echo $m; var_dump( @@ -87,6 +89,52 @@ var_dump( ); echo $m->getParentMessage(); +echo "---\n"; + +$m = new HttpMessage(fopen(__DIR__."/data/message_rr_empty.txt", "r+b")); +echo $m; +var_dump( + $m->getHttpVersion(), + $m->getType()==HttpMessage::TYPE_RESPONSE, + $m->getResponseCode(), + $m->getResponseStatus(), + $m->getHeaders() +); +echo $m->getParentMessage(); + +$m = new HttpMessage(fopen(__DIR__."/data/message_rr_empty_gzip.txt", "r+b")); +echo $m; +var_dump( + $m->getHttpVersion(), + $m->getType()==HttpMessage::TYPE_RESPONSE, + $m->getResponseCode(), + $m->getResponseStatus(), + $m->getHeaders() +); +echo $m->getParentMessage(); + +$m = new HttpMessage(fopen(__DIR__."/data/message_rr_empty_chunked.txt", "r+b")); +echo $m; +var_dump( + $m->getHttpVersion(), + $m->getType()==HttpMessage::TYPE_RESPONSE, + $m->getResponseCode(), + $m->getResponseStatus(), + $m->getHeaders() +); +echo $m->getParentMessage(); + +$m = new HttpMessage(fopen(__DIR__."/data/message_rr_helloworld_chunked.txt", "r+b")); +echo $m; +var_dump( + $m->getHttpVersion(), + $m->getType()==HttpMessage::TYPE_RESPONSE, + $m->getResponseCode(), + $m->getResponseStatus(), + $m->getHeaders() +); +echo $m->getParentMessage(); + echo "Done\n"; --EXPECTF-- Test @@ -108,6 +156,163 @@ int(200) string(7) "Okidoki" array(0) { } +--- +HTTP/1.1 200 OK +Date: Wed, 25 Aug 2010 12:11:44 GMT +Server: Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6 +Last-Modified: Wed, 28 Apr 2010 10:54:37 GMT +Etag: "2002a-0-48549d615a35c" +Accept-Ranges: bytes +Content-Length: 0 +Vary: Accept-Encoding +Connection: close +Content-Type: text/plain +X-Original-Content-Length: 0 +string(3) "1.1" +bool(true) +int(200) +string(2) "OK" +array(10) { + ["Date"]=> + string(29) "Wed, 25 Aug 2010 12:11:44 GMT" + ["Server"]=> + string(68) "Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6" + ["Last-Modified"]=> + string(29) "Wed, 28 Apr 2010 10:54:37 GMT" + ["Etag"]=> + string(23) ""2002a-0-48549d615a35c"" + ["Accept-Ranges"]=> + string(5) "bytes" + ["Content-Length"]=> + int(0) + ["Vary"]=> + string(15) "Accept-Encoding" + ["Connection"]=> + string(5) "close" + ["Content-Type"]=> + string(10) "text/plain" + ["X-Original-Content-Length"]=> + string(1) "0" +} +GET /default/empty.txt HTTP/1.1 +Host: localhost +Connection: close +Content-Length: 0 +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-Length: 0 +Connection: close +Content-Type: text/plain +X-Original-Content-Length: 20 +X-Original-Content-Encoding: gzip +string(3) "1.1" +bool(true) +int(200) +string(2) "OK" +array(11) { + ["Date"]=> + string(29) "Thu, 26 Aug 2010 09:55:09 GMT" + ["Server"]=> + string(68) "Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6" + ["Last-Modified"]=> + string(29) "Wed, 28 Apr 2010 10:54:37 GMT" + ["Etag"]=> + string(23) ""2002a-0-48549d615a35c"" + ["Accept-Ranges"]=> + string(5) "bytes" + ["Vary"]=> + string(15) "Accept-Encoding" + ["Content-Length"]=> + int(0) + ["Connection"]=> + string(5) "close" + ["Content-Type"]=> + string(10) "text/plain" + ["X-Original-Content-Length"]=> + string(2) "20" + ["X-Original-Content-Encoding"]=> + string(4) "gzip" +} +GET /default/empty.txt HTTP/1.1 +Host: localhost +Accept-Encoding: gzip +Connection: close +Content-Length: 0 +HTTP/1.1 200 OK +Date: Thu, 26 Aug 2010 11:41:02 GMT +Server: Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6 +X-Powered-By: PHP/5.3.3 +Vary: Accept-Encoding +Connection: close +Content-Type: text/html +X-Original-Transfer-Encoding: chunked +Content-Length: 0 +string(3) "1.1" +bool(true) +int(200) +string(2) "OK" +array(8) { + ["Date"]=> + string(29) "Thu, 26 Aug 2010 11:41:02 GMT" + ["Server"]=> + string(68) "Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6" + ["X-Powered-By"]=> + string(9) "PHP/5.3.3" + ["Vary"]=> + string(15) "Accept-Encoding" + ["Connection"]=> + string(5) "close" + ["Content-Type"]=> + string(9) "text/html" + ["X-Original-Transfer-Encoding"]=> + string(7) "chunked" + ["Content-Length"]=> + int(0) +} +GET /default/empty.php HTTP/1.1 +Connection: close +Host: localhost +Content-Length: 0 +HTTP/1.1 200 OK +Date: Thu, 26 Aug 2010 12:51:28 GMT +Server: Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6 +Vary: Accept-Encoding +Connection: close +Content-Type: text/plain +X-Original-Transfer-Encoding: chunked +Content-Length: 14 + +Hello, World! +string(3) "1.1" +bool(true) +int(200) +string(2) "OK" +array(7) { + ["Date"]=> + string(29) "Thu, 26 Aug 2010 12:51:28 GMT" + ["Server"]=> + string(68) "Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6" + ["Vary"]=> + string(15) "Accept-Encoding" + ["Connection"]=> + string(5) "close" + ["Content-Type"]=> + string(10) "text/plain" + ["X-Original-Transfer-Encoding"]=> + string(7) "chunked" + ["Content-Length"]=> + int(14) +} +GET /cgi-bin/chunked.sh HTTP/1.1 +Host: localhost +Connection: close +Content-Length: 0 +--- HTTP/1.1 200 OK Date: Wed, 25 Aug 2010 12:11:44 GMT Server: Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6 -- 2.30.2 From 5211ee30b8fe45d429dbf7c37b83ab99a763f33b Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Mon, 30 Jul 2012 18:35:49 +0000 Subject: [PATCH 10/16] test http\Url::SANITIZE_PATH --- tests/url001.phpt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/url001.phpt b/tests/url001.phpt index 6519ddf..cd792f2 100644 --- a/tests/url001.phpt +++ b/tests/url001.phpt @@ -12,7 +12,7 @@ s=b&i=0&e=&a[]=1&a[]=2 printf("%s\n", new http\Url); printf("%s\n", new http\Url("other", "index")); printf("%s\n", new http\Url(array("scheme" => "https", "port" => 443))); -printf("%s\n", new http\Url(array("path" => "/./up/../down/../././//index.php/.", "query" => null))); +printf("%s\n", new http\Url(array("path" => "/./up/../down/../././//index.php/.", "query" => null), null, http\Url::SANITIZE_PATH|http\Url::FROM_ENV)); printf("%s\n", new http\Url(null, null, 0)); ?> DONE -- 2.30.2 From c3200376cd66459d40a1a520074119713c9c8dff Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Thu, 11 Oct 2012 10:10:18 +0000 Subject: [PATCH 11/16] 2.0.0beta1 --- ThanksTo.txt | 1 + config9.m4 | 2 +- package.xml | 27 ++++++++++++++++++--------- php_http.h | 2 +- php_http_header_parser.c | 2 +- 5 files changed, 22 insertions(+), 12 deletions(-) diff --git a/ThanksTo.txt b/ThanksTo.txt index 8dbd1d8..b65cc4d 100644 --- a/ThanksTo.txt +++ b/ThanksTo.txt @@ -7,6 +7,7 @@ so they could be fixed in a reasonable way, or suggested useful features to implement, in alphabetical order: Ilia Alshanetsky (ilia at php dot net) + Anatoly Belsky (ab at php dot net) Petr Czaderna (petr at hroch dot info) David James (james82 at gmail dot com) Thomas Landro Johnsen (thomas dot l dot johnsen at gmail dot com) diff --git a/config9.m4 b/config9.m4 index 63062de..2351eb5 100644 --- a/config9.m4 +++ b/config9.m4 @@ -356,7 +356,7 @@ dnl ---- PHP_ARG_WITH([http-shared-deps], [whether to depend on extensions which have been built shared], [ --without-http-shared-deps HTTP: do not depend on extensions like hash - and iconv (when they're built shared)], $PHP_HTTP, $PHP_HTTP) + and iconv (when they are built shared)], $PHP_HTTP, $PHP_HTTP) dnl ---- dnl HASH dnl ---- diff --git a/package.xml b/package.xml index 8f5d7aa..57a64d2 100644 --- a/package.xml +++ b/package.xml @@ -26,21 +26,29 @@ Extended HTTP support. Again. Keep in mind that it's got the major version 2, be mike@php.net yes - 2012-04-13 + 2012-10-11 - 2.0.0alpha1 + 2.0.0beta1 2.0.0 - alpha - alpha + beta + beta BSD, revised @@ -140,6 +148,7 @@ Extended HTTP support. Again. Keep in mind that it's got the major version 2, be + @@ -184,7 +193,7 @@ Extended HTTP support. Again. Keep in mind that it's got the major version 2, be - 5.3.99 + 5.3.0 1.4.1 diff --git a/php_http.h b/php_http.h index bbea3e7..df63d83 100644 --- a/php_http.h +++ b/php_http.h @@ -13,7 +13,7 @@ #ifndef PHP_EXT_HTTP_H #define PHP_EXT_HTTP_H -#define PHP_HTTP_EXT_VERSION "2.0.0dev" +#define PHP_HTTP_EXT_VERSION "2.0.0beta1" zend_module_entry http_module_entry; #define phpext_http_ptr &http_module_entry diff --git a/php_http_header_parser.c b/php_http_header_parser.c index e0dea5b..866a84e 100644 --- a/php_http_header_parser.c +++ b/php_http_header_parser.c @@ -155,7 +155,7 @@ PHP_HTTP_API STATUS php_http_header_parser_parse(php_http_header_parser_t *parse #define SET_ADD_VAL(slen, eol_len) \ do { \ - char *ptr = buffer->data; \ + const char *ptr = buffer->data; \ size_t len = slen; \ \ while (len > 0 && PHP_HTTP_IS_CTYPE(space, *ptr)) { \ -- 2.30.2 From 287edcbfb698ff402588f7057dae0bc994d6e8e4 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Sun, 28 Oct 2012 20:19:12 +0000 Subject: [PATCH 12/16] fix curl_multi with libevent2 --- config9.m4 | 20 ++++++++++++++------ php_http.c | 8 +++++++- php_http_curl_client_pool.c | 37 ++++++++++++++++++++++--------------- 3 files changed, 43 insertions(+), 22 deletions(-) diff --git a/config9.m4 b/config9.m4 index 2351eb5..d4e211e 100644 --- a/config9.m4 +++ b/config9.m4 @@ -320,7 +320,7 @@ dnl ---- AC_MSG_WARN([event support is incompatible with pecl/event; continuing without libevent support]) AC_DEFINE([PHP_HTTP_HAVE_EVENT], [0], [ ]) ], [ - AC_MSG_CHECKING([for event.h]) + AC_MSG_CHECKING([for event2/event.h]) EVENT_DIR= for i in "$PHP_HTTP_LIBEVENT_DIR" /usr/local /usr /opt; do if test -f "$i/include/event.h"; then @@ -336,12 +336,20 @@ dnl ---- AC_MSG_RESULT([found in $EVENT_DIR]) AC_MSG_CHECKING([for libevent version, roughly]) - EVENT_VER="1.1b or lower" - if test -f "$EVENT_DIR/include/evhttp.h" && test -f "$EVENT_DIR/include/evdns.h"; then - if test -f "$EVENT_DIR/include/evrpc.h"; then - EVENT_VER="1.4 or greater" + + if test -f "$EVENT_DIR/include/event2/event.h"; then + EVENT_VER="`$EGREP _EVENT_VERSION $EVENT_DIR/include/event2/event.h | $AWK '{print $3}'`" + AC_DEFINE([PHP_HTTP_HAVE_EVENT2], [1], [ ]) + else + AC_DEFFINE([PHP_HTTP_HAVE_EVENT2], [0], [ ]) + if test -f "$EVENT_DIR/include/evhttp.h" && test -f "$EVENT_DIR/include/evdns.h"; then + if test -f "$EVENT_DIR/include/evrpc.h"; then + EVENT_VER="1.4 or greater" + else + EVENT_VER="1.2 or greater" + fi else - EVENT_VER="1.2 or greater" + EVENT_VER="1.1b or lower" fi fi AC_DEFINE_UNQUOTED([PHP_HTTP_EVENT_VERSION], ["$EVENT_VER"], [ ]) diff --git a/php_http.c b/php_http.c index 128937d..4eb0f5e 100644 --- a/php_http.c +++ b/php_http.c @@ -233,7 +233,13 @@ PHP_MINFO_FUNCTION(http) #endif #if PHP_HTTP_HAVE_EVENT - php_info_print_table_row(3, "libevent", PHP_HTTP_EVENT_VERSION, event_get_version()); + php_info_print_table_row(3, "libevent", +# ifdef LIBEVENT_VERSION + LIBEVENT_VERSION, +# else + PHP_HTTP_EVENT_VERSION, +# endif + event_get_version()); #else php_info_print_table_row(3, "libevent", "disabled", "disabled"); #endif diff --git a/php_http_curl_client_pool.c b/php_http_curl_client_pool.c index d1873fb..ddac5c1 100644 --- a/php_http_curl_client_pool.c +++ b/php_http_curl_client_pool.c @@ -16,6 +16,13 @@ #if PHP_HTTP_HAVE_EVENT # include +# if !PHP_HTTP_HAVE_EVENT2 && /* just be really sure */ !(LIBEVENT_VERSION_NUMBER >= 0x02000000) +# define event_base_new event_init +# define event_assign(e, b, s, a, cb, d) do {\ + event_set(e, s, a, cb, d); \ + event_base_set(b, e); \ + } while(0) +# endif #endif typedef struct php_http_curl_client_pool { @@ -166,7 +173,6 @@ static int php_http_curl_client_pool_socket_callback(CURL *easy, curl_socket_t s ev = ecalloc(1, sizeof(php_http_client_pool_event_t)); ev->pool = pool; curl_multi_assign(curl->handle, sock, ev); - event_base_set(PHP_HTTP_G->curl.event_base, &ev->evnt); } else { event_del(&ev->evnt); } @@ -193,7 +199,7 @@ static int php_http_curl_client_pool_socket_callback(CURL *easy, curl_socket_t s return -1; } - event_set(&ev->evnt, sock, events, php_http_curl_client_pool_event_callback, pool); + event_assign(&ev->evnt, PHP_HTTP_G->curl.event_base, sock, events, php_http_curl_client_pool_event_callback, pool); event_add(&ev->evnt, NULL); } @@ -206,19 +212,18 @@ static void php_http_curl_client_pool_timer_callback(CURLM *multi, long timeout_ php_http_curl_client_pool_t *curl = pool->ctx; #if DBG_EVENTS - fprintf(stderr, "%ld", timeout_ms); + fprintf(stderr, "\ntimer <- timeout_ms: %ld\n", timeout_ms); #endif if (curl->useevents) { if (timeout_ms < 0) { - php_http_curl_client_pool_timeout_callback(CURL_SOCKET_TIMEOUT, CURL_CSELECT_IN|CURL_CSELECT_OUT, pool); + php_http_curl_client_pool_timeout_callback(CURL_SOCKET_TIMEOUT, EV_READ|EV_WRITE, pool); } else if (timeout_ms > 0 || !event_initialized(curl->timeout) || !event_pending(curl->timeout, EV_TIMEOUT, NULL)) { struct timeval timeout; TSRMLS_FETCH_FROM_CTX(pool->ts); if (!event_initialized(curl->timeout)) { - event_set(curl->timeout, -1, 0, php_http_curl_client_pool_timeout_callback, pool); - event_base_set(PHP_HTTP_G->curl.event_base, curl->timeout); + event_assign(curl->timeout, PHP_HTTP_G->curl.event_base, CURL_SOCKET_TIMEOUT, 0, php_http_curl_client_pool_timeout_callback, pool); } else if (event_pending(curl->timeout, EV_TIMEOUT, NULL)) { event_del(curl->timeout); } @@ -389,11 +394,7 @@ static int php_http_curl_client_pool_once(php_http_client_pool_t *h) return curl->unfinished; } -#if PHP_HTTP_HAVE_EVENT -static void dolog(int i, const char *m) { - fprintf(stderr, "%d: %s\n", i, m); -} -#endif + static STATUS php_http_curl_client_pool_exec(php_http_client_pool_t *h) { TSRMLS_FETCH_FROM_CTX(h->ts); @@ -402,12 +403,18 @@ static STATUS php_http_curl_client_pool_exec(php_http_client_pool_t *h) php_http_curl_client_pool_t *curl = h->ctx; if (curl->useevents) { - event_set_log_callback(dolog); + php_http_curl_client_pool_timeout_callback(CURL_SOCKET_TIMEOUT, EV_READ|EV_WRITE, h); do { + int ev_rc = event_base_dispatch(PHP_HTTP_G->curl.event_base); + #if DBG_EVENTS - fprintf(stderr, "X"); + fprintf(stderr, "%c", "X.0"[ev_rc+1]); #endif - event_base_dispatch(PHP_HTTP_G->curl.event_base); + + if (ev_rc < 0) { + php_http_error(HE_ERROR, PHP_HTTP_E_RUNTIME, "Error in event_base_dispatch()"); + return FAILURE; + } } while (curl->unfinished); } else #endif @@ -556,7 +563,7 @@ PHP_MINIT_FUNCTION(http_curl_client_pool) PHP_RINIT_FUNCTION(http_curl_client_pool) { #if PHP_HTTP_HAVE_EVENT - if (!PHP_HTTP_G->curl.event_base && !(PHP_HTTP_G->curl.event_base = event_init())) { + if (!PHP_HTTP_G->curl.event_base && !(PHP_HTTP_G->curl.event_base = event_base_new())) { return FAILURE; } #endif -- 2.30.2 From d3cd2c4fb0abc0400276e46a8452e7d9297129ce Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Sun, 28 Oct 2012 20:19:44 +0000 Subject: [PATCH 13/16] fix typo --- php_http_client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php_http_client.c b/php_http_client.c index 8a63acd..8f51a03 100644 --- a/php_http_client.c +++ b/php_http_client.c @@ -774,7 +774,7 @@ PHP_METHOD(HttpClient, addCookies) zval *opts = NULL; if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!/", &opts)) { - php_http_client_options_set_subr(getThis(), ZEND_STRS("ssl"), opts, 0 TSRMLS_CC); + php_http_client_options_set_subr(getThis(), ZEND_STRS("cookies"), opts, 0 TSRMLS_CC); RETVAL_ZVAL(getThis(), 1, 0); } -- 2.30.2 From 0ba01182029d13dfd02e90875f3b0da16eb3331c Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Sun, 28 Oct 2012 20:20:08 +0000 Subject: [PATCH 14/16] fix grabbing files from array --- php_http_env_request.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/php_http_env_request.c b/php_http_env_request.c index e4e8eaf..4da183e 100644 --- a/php_http_env_request.c +++ b/php_http_env_request.c @@ -70,7 +70,7 @@ static int grab_file(void *zpp TSRMLS_DC, int argc, va_list argv, zend_hash_key && SUCCESS == zend_hash_index_find(Z_ARRVAL_PP(type), key->h, (void *) &ztype) && SUCCESS == zend_hash_index_find(Z_ARRVAL_PP(error), key->h, (void *) &zerror) ) { - zval *entry; + zval *entry, **array; MAKE_STD_ZVAL(entry); array_init(entry); @@ -86,7 +86,16 @@ static int grab_file(void *zpp TSRMLS_DC, int argc, va_list argv, zend_hash_key Z_ADDREF_PP(zerror); add_assoc_zval_ex(entry, ZEND_STRS("error"), *zerror); - zend_hash_quick_update(Z_ARRVAL_P(zfiles), file_key->arKey, file_key->nKeyLength, file_key->h, (void *) &entry, sizeof(zval *), NULL); + if (SUCCESS == zend_hash_quick_find(Z_ARRVAL_P(zfiles), file_key->arKey, file_key->nKeyLength, file_key->h, (void *) &array)) { + add_next_index_zval(*array, entry); + } else { + zval *tmp; + + MAKE_STD_ZVAL(tmp); + array_init(tmp); + add_next_index_zval(tmp, entry); + zend_hash_quick_update(Z_ARRVAL_P(zfiles), file_key->arKey, file_key->nKeyLength, file_key->h, (void *) &tmp, sizeof(zval *), NULL); + } } return ZEND_HASH_APPLY_KEEP; -- 2.30.2 From 575f4ce7a82c2c2bf4fb597f6a3a3de077403910 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Sun, 28 Oct 2012 20:21:24 +0000 Subject: [PATCH 15/16] 80%+ test coverage --- phpunit/ClientRequestTest.php | 43 +++++++++++++++++++ phpunit/DataShareTest.php | 58 +++++++++++++++++++++++++ phpunit/PoolTest.php | 79 +++++++++++++++++++++++++++++++++++ phpunit/RequestTest.php | 41 ++++++++++++++++-- tests/envrequestfiles001.phpt | 40 ++++++++++++++++++ tests/envrequestfiles002.phpt | 47 +++++++++++++++++++++ tests/envrequestform.phpt | 24 +++++++++++ tests/envrequestquery.phpt | 24 +++++++++++ tests/params002.phpt | 60 ++++++++++++++++++++++++++ tests/serialize001.phpt | 41 ++++++++++++++++++ 10 files changed, 454 insertions(+), 3 deletions(-) create mode 100644 phpunit/ClientRequestTest.php create mode 100644 phpunit/DataShareTest.php create mode 100644 phpunit/PoolTest.php create mode 100644 tests/envrequestfiles001.phpt create mode 100644 tests/envrequestfiles002.phpt create mode 100644 tests/envrequestform.phpt create mode 100644 tests/envrequestquery.phpt create mode 100644 tests/params002.phpt create mode 100644 tests/serialize001.phpt diff --git a/phpunit/ClientRequestTest.php b/phpunit/ClientRequestTest.php new file mode 100644 index 0000000..f14f49e --- /dev/null +++ b/phpunit/ClientRequestTest.php @@ -0,0 +1,43 @@ +assertEquals($b, $r->getBody()); + $this->assertEquals($h, $r->getHeaders()); + $this->assertEquals($u, $r->getRequestUrl()); + $this->assertEquals($m, $r->getRequestMethod()); + } + + function testContentType() { + $r = new Request("POST", "http://localhost/"); + $this->assertEquals($r, $r->setContentType($ct = "text/plain; charset=utf-8")); + $this->assertEquals($ct, $r->getContentType()); + } + + function testQuery() { + $r = new Request("GET", "http://localhost/"); + $this->assertEquals(null, $r->getQuery()); + $this->assertEquals($r, $r->setQuery($q = "foo=bar")); + $this->assertEquals($q, $r->getQuery()); + $this->assertEquals($r, $r->addQuery("a[]=1&a[]=2")); + $this->assertEquals("foo=bar&a%5B0%5D=1&a%5B1%5D=2", $r->getQuery()); + $this->assertEquals(null, $r->setQuery(null)->getQuery()); + } + + function testOptions() { + $r = new Request("GET", "http://localhost"); + $this->assertEquals($r, $r->setOptions($o = array("redirect"=>5, "timeout"=>5))); + $this->assertEquals($o, $r->getOptions()); + $this->assertEquals($r, $r->setSslOptions($o = array("verify_peer"=>false))); + $this->assertEquals($o, $r->getSslOptions()); + } +} + diff --git a/phpunit/DataShareTest.php b/phpunit/DataShareTest.php new file mode 100644 index 0000000..0a50727 --- /dev/null +++ b/phpunit/DataShareTest.php @@ -0,0 +1,58 @@ +createDataShare(); + + $this->assertFalse($s->dns, "dns"); + $this->assertFalse($s->cookie, "cookie"); + $this->assertFalse($s->ssl, "ssl"); + + $s->dns = true; + $s->cookie = true; + $s->ssl = true; + + $this->assertTrue($s->dns, "dns"); + $this->assertTrue($s->cookie, "cookie"); + $this->assertTrue($s->ssl, "ssl"); + } + } + + function testAttach() { + foreach (http\Client\Factory::getAvailableDrivers() as $driver) { + $f = new http\Client\Factory(compact("driver")); + $s = $f->createDataShare(); + $s->dns = $s->ssl = $s->cookie = true; + $c = $f->createClient(); + $s->attach($c); + $c->setRequest(new http\Client\Request("GET", "https://twitter.com/")); + $s->attach($c); + $cc = clone $c; + $s->attach($cc); + + $this->assertEquals(3, count($s)); + } + } + + function testCurl() { + $client = new http\Curl\Client; + $client->setRequest(new http\Client\Request("GET", "https://twitter.com/")); + $share = new http\Curl\Client\DataShare; + $share->ssl = $share->dns = $share->cookie = true; + $share->attach($client); + $share->attach($client2 = clone $client); + $share->attach($client3 = clone $client); + + $this->assertEquals(3, count($share)); + $client->send(); + $client2->send(); + $client3->send(); + + $share->detach($client); + $share->reset(); + } +} + diff --git a/phpunit/PoolTest.php b/phpunit/PoolTest.php new file mode 100644 index 0000000..33dbf9b --- /dev/null +++ b/phpunit/PoolTest.php @@ -0,0 +1,79 @@ +createPool(); + + $this->assertFalse($p->dns, "dns"); + $this->assertFalse($p->cookie, "cookie"); + $this->assertFalse($p->ssl, "ssl"); + + $p->dns = true; + $p->cookie = true; + $p->ssl = true; + + $this->assertTrue($p->dns, "dns"); + $this->assertTrue($p->cookie, "cookie"); + $this->assertTrue($p->ssl, "ssl"); + } + }*/ + + function testAttach() { + foreach (http\Client\Factory::getAvailableDrivers() as $driver) { + $f = new http\Client\Factory(compact("driver")); + + $p = $f->createPool(); + $c = $f->createClient(); + + $c->setRequest(new http\Client\Request("GET", "https://twitter.com/")); + $p->attach($c); + + try { + $p->attach($c); + } catch (http\Exception $e) { + $this->assertEquals("Could not attach request to pool: Invalid easy handle", $e->getMessage()); + } + + $cc = clone $c; + $p->attach($cc); + + $this->assertEquals(2, count($p)); + } + } + + function testCurl() { + $client = new http\Curl\Client; + $client->setRequest(new http\Client\Request("GET", "https://twitter.com/")); + $pool = new http\Curl\Client\Pool; + $pool->attach($client); + $pool->attach($client2 = clone $client); + $pool->attach($client3 = clone $client); + + $this->assertEquals(3, count($pool)); + $pool->send(); + + $pool->detach($client); + $this->assertEquals(2, count($pool)); + + $pool->reset(); + $this->assertEquals(0, count($pool)); + } + + function testCurlEvents() { + $client = new http\Curl\Client; + $pool = new http\Curl\Client\Pool; + + $client->setRequest(new http\Client\Request("GET", "https://twitter.com/")); + + $pool->attach($client); + $pool->attach(clone $client); + $pool->attach(clone $client); + + $pool->enableEvents(); + $pool->send(); + } +} + diff --git a/phpunit/RequestTest.php b/phpunit/RequestTest.php index 56053ee..a327f6d 100644 --- a/phpunit/RequestTest.php +++ b/phpunit/RequestTest.php @@ -35,6 +35,18 @@ class RequestTest extends PHPUnit_Framework_TestCase "timeout" => 300, ) ); + $this->r->setOptions( + array( + "timeout" => 600 + ) + ); + $this->assertEquals( + array( + "connecttimeout" => 30, + "timeout" => 600, + ), + $this->r->getOptions() + ); } function testClone() { @@ -43,10 +55,10 @@ class RequestTest extends PHPUnit_Framework_TestCase } function testObserver() { - $this->r->attach(new ProgressObserver1); - $this->r->attach(new ProgressObserver2); + $this->r->attach($o1 = new ProgressObserver1); + $this->r->attach($o2 = new ProgressObserver2); $this->r->attach( - new CallbackObserver( + $o3 = new CallbackObserver( function ($r) { $p = (array) $r->getProgress(); $this->assertArrayHasKey("started", $p); @@ -62,6 +74,12 @@ class RequestTest extends PHPUnit_Framework_TestCase $this->r->setRequest(new http\Client\Request("GET", "http://dev.iworks.at/ext-http/"))->send(null); $this->assertRegexp("/(\.-)+/", $this->r->pi); $this->assertCount(3, $this->r->getObservers()); + $this->r->detach($o1); + $this->assertCount(2, $this->r->getObservers()); + $this->r->detach($o2); + $this->assertCount(1, $this->r->getObservers()); + $this->r->detach($o3); + $this->assertCount(0, $this->r->getObservers()); } function testCookies() { @@ -92,6 +110,23 @@ class RequestTest extends PHPUnit_Framework_TestCase $this->r->send(null); $this->assertNotEquals($c, array_map($f, $this->r->getResponseMessage()->getCookies())); } + + function testSsl() { + $this->r->setRequest(new http\Client\Request("GET", "https://twitter.com/")); + $this->r->setSslOptions(array("verify_peer" => true)); + $this->r->addSslOptions(array("verify_host" => 2)); + $this->assertEquals( + array( + "verify_peer" => true, + "verify_host" => 2, + ), + $this->r->getSslOptions() + ); + $this->r->send(); + $ti = $this->r->getTransferInfo(); + $this->assertArrayHasKey("ssl_engines", $ti); + $this->assertGreaterThan(0, count($ti["ssl_engines"])); + } function testHistory() { $body = new http\Message\Body; diff --git a/tests/envrequestfiles001.phpt b/tests/envrequestfiles001.phpt new file mode 100644 index 0000000..5b1cd2e --- /dev/null +++ b/tests/envrequestfiles001.phpt @@ -0,0 +1,40 @@ +--TEST-- +http\Env\Request grabbing $_FILES +--SKIPIF-- + +--POST_RAW-- +Content-Type: multipart/form-data;boundary=--123 + +----123 +Content-Disposition: form-data;filename="foo.bar" + +foo +bar + +----123 +Content-Disposition: form-data;filename="bar.foo" + +bar +foo + +----123-- +--FILE-- +getFiles(); + +foreach ($_FILES as $i => $file) { + foreach (array("name","type","size","error","file") as $key) { + if ($file[$key == "file" ? "tmp_name" : $key] != $f[$i][$key]) { + printf("%d.%s differs: '%s' != '%s'\n", $i, $key, $f[$i][$key], $file[$key]); + } + } +} + +?> +DONE +--EXPECT-- +TEST +DONE diff --git a/tests/envrequestfiles002.phpt b/tests/envrequestfiles002.phpt new file mode 100644 index 0000000..85b44db --- /dev/null +++ b/tests/envrequestfiles002.phpt @@ -0,0 +1,47 @@ +--TEST-- +http\Env\Request grabbing $_FILES from array +--SKIPIF-- + +--POST_RAW-- +Content-Type: multipart/form-data;boundary=--123 + +----123 +Content-Disposition: form-data;filename=file1;name=file[] + +first +----123 +Content-Disposition: form-data;filename=file2;name=file[] + +second +----123 +Content-Disposition: form-data;filename=file3;name=file[] + +third +----123-- +--FILE-- + $data) { + foreach ($data["tmp_name"] as $i => $file) { + $f[$name][$i] = array( + "file" => $file, + "name" => $data["name"][$i], + "size" => $data["size"][$i], + "type" => $data["type"][$i], + "error"=> $data["error"][$i] + ); + } +} + +var_dump($f == $r->getFiles()); + +?> +DONE +--EXPECT-- +TEST +bool(true) +DONE diff --git a/tests/envrequestform.phpt b/tests/envrequestform.phpt new file mode 100644 index 0000000..c2086bb --- /dev/null +++ b/tests/envrequestform.phpt @@ -0,0 +1,24 @@ +--TEST-- +http\Env\Request getForm +--SKIPIF-- + +--POST-- +a=b&b=c&r[]=1&r[]=2 +--FILE-- +getForm()); +printf("%s\n", $r->getForm("b", "s", null, true)); +printf("%s\n", $r->getForm("x", "s", "nooo")); +printf("%s\n", $r->getForm()); +?> +DONE +--EXPECT-- +TEST +a=b&b=c&r%5B0%5D=1&r%5B1%5D=2 +c +nooo +a=b&r%5B0%5D=1&r%5B1%5D=2 +DONE diff --git a/tests/envrequestquery.phpt b/tests/envrequestquery.phpt new file mode 100644 index 0000000..87f168d --- /dev/null +++ b/tests/envrequestquery.phpt @@ -0,0 +1,24 @@ +--TEST-- +http\Env\Request getQuery +--SKIPIF-- + +--GET-- +a=b&b=c&r[]=1&r[]=2 +--FILE-- +getQuery()); +printf("%s\n", $r->getQuery("b", "s", null, true)); +printf("%s\n", $r->getQuery("x", "s", "nooo")); +printf("%s\n", $r->getQuery()); +?> +DONE +--EXPECT-- +TEST +a=b&b=c&r%5B0%5D=1&r%5B1%5D=2 +c +nooo +a=b&r%5B0%5D=1&r%5B1%5D=2 +DONE diff --git a/tests/params002.phpt b/tests/params002.phpt new file mode 100644 index 0000000..66e514c --- /dev/null +++ b/tests/params002.phpt @@ -0,0 +1,60 @@ +--TEST-- +query parser +--SKIPIF-- + +--FILE-- + +DONE +--EXPECTF-- +object(http\Params)#%d (6) { + ["errorHandling":protected]=> + NULL + ["params"]=> + array(2) { + ["foo"]=> + array(2) { + ["value"]=> + string(3) "bar" + ["arguments"]=> + array(0) { + } + } + ["arr"]=> + array(2) { + ["value"]=> + array(2) { + [0]=> + string(1) "1" + [1]=> + string(1) "2" + } + ["arguments"]=> + array(0) { + } + } + } + ["param_sep"]=> + array(2) { + [0]=> + string(1) "&" + [1]=> + string(1) ";" + } + ["arg_sep"]=> + string(0) "" + ["val_sep"]=> + string(1) "=" + ["flags"]=> + int(12) +} +foo=bar&arr%5B0%5D=1&arr%5B1%5D=2 +DONE + diff --git a/tests/serialize001.phpt b/tests/serialize001.phpt new file mode 100644 index 0000000..2e06afe --- /dev/null +++ b/tests/serialize001.phpt @@ -0,0 +1,41 @@ +--TEST-- +serialization +--SKIPIF-- + +--FILE-- +request = new \http\Client\Request("GET", "http://localhost"); + } + function send($request) { + } +} + +$ext = new ReflectionExtension("http"); +foreach ($ext->getClasses() as $class) { + if ($class->isInstantiable()) { + #printf("%s\n", $class->getName()); + $instance = $class->newInstance(); + $serialized = serialize($instance); + $unserialized = unserialize($serialized); + + foreach (["toString", "toArray"] as $m) { + if ($class->hasMethod($m)) { + #printf("%s#%s\n", $class->getName(), $m); + $unserialized->$m(); + } + } + if ($class->hasMethod("attach") && !$class->implementsInterface("\\SplSubject")) { + #printf("%s#%s\n", $class->getName(), "attach"); + $unserialized->attach((new http\Curl\Client)->setRequest(new http\Client\Request("GET", "http://localhost"))); + } + } +} +?> +DONE +--EXPECTF-- +DONE -- 2.30.2 From 64722314d70dc547e477d87927c22b598aa463d0 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Wed, 7 Nov 2012 08:52:35 +0000 Subject: [PATCH 16/16] - add http\Env::getResponseStatusForAllCodes() - merge message headers --- config9.m4 | 2 +- php_http_env.c | 22 +++++++ php_http_env.h | 1 + php_http_message.c | 116 +++++++++++++++++++----------------- php_http_strlist.c | 3 +- tests/envresponsecodes.phpt | 26 ++++++++ tests/message005.phpt | 5 +- tests/propertyproxy001.phpt | 4 +- 8 files changed, 116 insertions(+), 63 deletions(-) create mode 100644 tests/envresponsecodes.phpt diff --git a/config9.m4 b/config9.m4 index d4e211e..f9f92c6 100644 --- a/config9.m4 +++ b/config9.m4 @@ -341,7 +341,7 @@ dnl ---- EVENT_VER="`$EGREP _EVENT_VERSION $EVENT_DIR/include/event2/event.h | $AWK '{print $3}'`" AC_DEFINE([PHP_HTTP_HAVE_EVENT2], [1], [ ]) else - AC_DEFFINE([PHP_HTTP_HAVE_EVENT2], [0], [ ]) + AC_DEFINE([PHP_HTTP_HAVE_EVENT2], [0], [ ]) if test -f "$EVENT_DIR/include/evhttp.h" && test -f "$EVENT_DIR/include/evdns.h"; then if test -f "$EVENT_DIR/include/evrpc.h"; then EVENT_VER="1.4 or greater" diff --git a/php_http_env.c b/php_http_env.c index f73be20..3ca996f 100644 --- a/php_http_env.c +++ b/php_http_env.c @@ -663,6 +663,8 @@ PHP_HTTP_BEGIN_ARGS(getResponseStatusForCode, 1) PHP_HTTP_ARG_VAL(code, 0) PHP_HTTP_END_ARGS; +PHP_HTTP_EMPTY_ARGS(getResponseStatusForAllCodes); + PHP_HTTP_BEGIN_ARGS(getResponseHeader, 0) PHP_HTTP_ARG_VAL(header_name, 0) PHP_HTTP_END_ARGS; @@ -726,6 +728,7 @@ static zend_function_entry php_http_env_method_entry[] = { PHP_HTTP_ENV_ME(getRequestBody) PHP_HTTP_ENV_ME(getResponseStatusForCode) + PHP_HTTP_ENV_ME(getResponseStatusForAllCodes) PHP_HTTP_ENV_ME(getResponseHeader) PHP_HTTP_ENV_ME(getResponseCode) @@ -793,6 +796,25 @@ PHP_METHOD(HttpEnv, getResponseStatusForCode) RETURN_FALSE; } +PHP_METHOD(HttpEnv, getResponseStatusForAllCodes) +{ + const char *s; + unsigned c; + php_http_strlist_iterator_t i; + + if (SUCCESS != zend_parse_parameters_none()) { + RETURN_FALSE; + } + + array_init(return_value); + for ( php_http_strlist_iterator_init(&i, php_http_env_response_status, 100); + *(s = php_http_strlist_iterator_this(&i, &c)); + php_http_strlist_iterator_next(&i) + ) { + add_index_string(return_value, c, s, 1); + } +} + PHP_METHOD(HttpEnv, getResponseHeader) { char *header_name_str = NULL; diff --git a/php_http_env.h b/php_http_env.h index 4326054..5bd3fb9 100644 --- a/php_http_env.h +++ b/php_http_env.h @@ -75,6 +75,7 @@ zend_class_entry *php_http_env_get_class_entry(void); PHP_METHOD(HttpEnv, getRequestHeader); PHP_METHOD(HttpEnv, getRequestBody); PHP_METHOD(HttpEnv, getResponseStatusForCode); +PHP_METHOD(HttpEnv, getResponseStatusForAllCodes); PHP_METHOD(HttpEnv, getResponseHeader); PHP_METHOD(HttpEnv, getResponseCode); PHP_METHOD(HttpEnv, setResponseHeader); diff --git a/php_http_message.c b/php_http_message.c index 04e8706..a93d9f5 100644 --- a/php_http_message.c +++ b/php_http_message.c @@ -12,6 +12,9 @@ #include "php_http_api.h" +static zval *message_header_strval(zval **header TSRMLS_DC); +static void message_headers(php_http_message_t *msg, php_http_buffer_t *str); + PHP_HTTP_API zend_bool php_http_message_info_callback(php_http_message_t **message, HashTable **headers, php_http_info_t *info TSRMLS_DC) { php_http_message_t *old = *message; @@ -147,21 +150,9 @@ PHP_HTTP_API zval *php_http_message_header(php_http_message_t *msg, char *key_st if (SUCCESS == zend_symtable_find(&msg->hdrs, key, key_len + 1, (void *) &header)) { if (join && Z_TYPE_PP(header) == IS_ARRAY) { - zval *header_str, **val; - HashPosition pos; - php_http_buffer_t str; TSRMLS_FETCH_FROM_CTX(msg->ts); - php_http_buffer_init(&str); - MAKE_STD_ZVAL(header_str); - FOREACH_VAL(pos, *header, val) { - zval *strval = php_http_ztyp(IS_STRING, *val); - php_http_buffer_appendf(&str, PHP_HTTP_BUFFER_LEN(&str) ? ", %s":"%s", Z_STRVAL_P(strval)); - zval_ptr_dtor(&strval); - } - php_http_buffer_fix(&str); - ZVAL_STRINGL(header_str, PHP_HTTP_BUFFER_VAL(&str), PHP_HTTP_BUFFER_LEN(&str), 0); - ret = header_str; + ret = message_header_strval(header TSRMLS_CC); } else { Z_ADDREF_PP(header); ret = *header; @@ -307,7 +298,37 @@ PHP_HTTP_API void php_http_message_update_headers(php_http_message_t *msg) } } } -static inline void message_headers(php_http_message_t *msg, php_http_buffer_t *str) + +static zval *message_header_strval(zval **header TSRMLS_DC) +{ + zval *ret; + + if (Z_TYPE_PP(header) == IS_BOOL) { + MAKE_STD_ZVAL(ret); + ZVAL_STRING(ret, Z_BVAL_PP(header) ? "true" : "false", 1); + } else if (Z_TYPE_PP(header) == IS_ARRAY) { + zval **val; + HashPosition pos; + php_http_buffer_t str; + + php_http_buffer_init(&str); + MAKE_STD_ZVAL(ret); + FOREACH_VAL(pos, *header, val) { + zval *strval = message_header_strval(val TSRMLS_CC); + + php_http_buffer_appendf(&str, PHP_HTTP_BUFFER_LEN(&str) ? ", %s":"%s", Z_STRVAL_P(strval)); + zval_ptr_dtor(&strval); + } + php_http_buffer_fix(&str); + ZVAL_STRINGL(ret, PHP_HTTP_BUFFER_VAL(&str), PHP_HTTP_BUFFER_LEN(&str), 0); + } else { + ret = php_http_zsep(1, IS_STRING, *header); + } + + return ret; +} + +static void message_headers(php_http_message_t *msg, php_http_buffer_t *str) { php_http_array_hashkey_t key = php_http_array_hashkey_init(0); HashPosition pos1; @@ -331,48 +352,35 @@ static inline void message_headers(php_http_message_t *msg, php_http_buffer_t *s FOREACH_HASH_KEYVAL(pos1, &msg->hdrs, key, header) { if (key.type == HASH_KEY_IS_STRING) { - HashPosition pos2; - zval **single_header; - - switch (Z_TYPE_PP(header)) { - case IS_BOOL: - php_http_buffer_appendf(str, "%s: %s" PHP_HTTP_CRLF, key.str, Z_BVAL_PP(header)?"true":"false"); - break; - - case IS_LONG: - php_http_buffer_appendf(str, "%s: %ld" PHP_HTTP_CRLF, key.str, Z_LVAL_PP(header)); - break; - - case IS_DOUBLE: - php_http_buffer_appendf(str, "%s: %F" PHP_HTTP_CRLF, key.str, Z_DVAL_PP(header)); - break; - - case IS_STRING: - if (Z_STRVAL_PP(header)[Z_STRLEN_PP(header)-1] == '\r') fprintf(stderr, "DOH!\n"); - php_http_buffer_appendf(str, "%s: %s" PHP_HTTP_CRLF, key.str, Z_STRVAL_PP(header)); - break; - - case IS_ARRAY: - FOREACH_VAL(pos2, *header, single_header) { - switch (Z_TYPE_PP(single_header)) { - case IS_BOOL: - php_http_buffer_appendf(str, "%s: %s" PHP_HTTP_CRLF, key.str, Z_BVAL_PP(single_header)?"true":"false"); - break; - - case IS_LONG: - php_http_buffer_appendf(str, "%s: %ld" PHP_HTTP_CRLF, key.str, Z_LVAL_PP(single_header)); - break; - - case IS_DOUBLE: - php_http_buffer_appendf(str, "%s: %F" PHP_HTTP_CRLF, key.str, Z_DVAL_PP(single_header)); - break; - - case IS_STRING: - php_http_buffer_appendf(str, "%s: %s" PHP_HTTP_CRLF, key.str, Z_STRVAL_PP(single_header)); - break; + if (key.len == sizeof("Set-Cookie") && !strcasecmp(key.str, "Set-Cookie") && Z_TYPE_PP(header) == IS_ARRAY) { + HashPosition pos2; + zval **single_header; + + FOREACH_VAL(pos2, *header, single_header) { + if (Z_TYPE_PP(single_header) == IS_ARRAY) { + php_http_cookie_list_t *cookie = php_http_cookie_list_from_struct(NULL, *single_header TSRMLS_CC); + + if (cookie) { + char *buf; + size_t len; + + php_http_cookie_list_to_string(cookie, &buf, &len); + php_http_buffer_appendf(str, "Set-Cookie: %s" PHP_HTTP_CRLF, buf); + php_http_cookie_list_free(&cookie); + efree(buf); } + } else { + zval *strval = message_header_strval(single_header TSRMLS_CC); + + php_http_buffer_appendf(str, "Set-Cookie: %s" PHP_HTTP_CRLF, Z_STRVAL_P(strval)); + zval_ptr_dtor(&strval); } - break; + } + } else { + zval *strval = message_header_strval(header TSRMLS_CC); + + php_http_buffer_appendf(str, "%s: %s" PHP_HTTP_CRLF, key.str, Z_STRVAL_P(strval)); + zval_ptr_dtor(&strval); } } } diff --git a/php_http_strlist.c b/php_http_strlist.c index 35acf40..3a52f3b 100644 --- a/php_http_strlist.c +++ b/php_http_strlist.c @@ -28,7 +28,7 @@ PHP_HTTP_API php_http_strlist_iterator_t *php_http_strlist_iterator_init(php_htt PHP_HTTP_API const char *php_http_strlist_iterator_this(php_http_strlist_iterator_t *iter, unsigned *id) { if (id) { - *id = iter->major * iter->factor + iter->minor; + *id = (iter->major + 1) * iter->factor + iter->minor; } return iter->p; @@ -46,6 +46,7 @@ PHP_HTTP_API const char *php_http_strlist_iterator_next(php_http_strlist_iterato if (!*iter->p) { ++iter->p; ++iter->major; + iter->minor = 0; } } diff --git a/tests/envresponsecodes.phpt b/tests/envresponsecodes.phpt new file mode 100644 index 0000000..21d7bbf --- /dev/null +++ b/tests/envresponsecodes.phpt @@ -0,0 +1,26 @@ +--TEST-- +http\Env response codes +--SKIPIF-- + +--FILE-- + +Done +--EXPECT-- +Test +array(0) { +} +Done diff --git a/tests/message005.phpt b/tests/message005.phpt index 25e6243..4cf3e23 100644 --- a/tests/message005.phpt +++ b/tests/message005.phpt @@ -27,8 +27,5 @@ String: foobar === UNKNOWN / HTTP/1.1 -Numbers: 1 -Numbers: 2 -Numbers: 3 -Numbers: 4.5%d +Numbers: 1, 2, 3, 4.5 DONE diff --git a/tests/propertyproxy001.phpt b/tests/propertyproxy001.phpt index 3f9d70a..da17577 100644 --- a/tests/propertyproxy001.phpt +++ b/tests/propertyproxy001.phpt @@ -86,9 +86,7 @@ bykey: 1 by1ref: 2 by2ref: 1 byXref: 2 -bynext: 1 -bynext: 2 -bynext: 3 +bynext: 1, 2, 3 DONE -- 2.30.2