From 13662c61792685435496cd25c95ee1c1950cd9d7 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Thu, 22 Feb 2018 17:35:13 +0100 Subject: [PATCH] performance improvements --- src/php_http_buffer.c | 6 +- src/php_http_buffer.h | 2 +- src/php_http_env_response.c | 100 +++++++++++++++--------------- src/php_http_exception.h | 2 +- src/php_http_header_parser.c | 73 ++++++++-------------- src/php_http_header_parser.h | 2 - src/php_http_info.c | 18 +++--- src/php_http_message.c | 16 ++--- src/php_http_message_parser.c | 106 +++++++++++++++----------------- src/php_http_message_parser.h | 2 - src/php_http_misc.c | 38 +++++++----- src/php_http_misc.h | 58 +++--------------- src/php_http_url.c | 112 ++++++++++++++++++---------------- src/php_http_utf8.h | 17 +++--- 14 files changed, 246 insertions(+), 306 deletions(-) diff --git a/src/php_http_buffer.c b/src/php_http_buffer.c index d7cfd56..9ff4065 100644 --- a/src/php_http_buffer.c +++ b/src/php_http_buffer.c @@ -37,7 +37,7 @@ PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_from_string_ex( { int free_buf = !!buf; - if ((buf = php_http_buffer_init(buf))) { + if (EXPECTED(buf = php_http_buffer_init(buf))) { if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_append(buf, str, len)) { if (free_buf) { pefree(buf, buf->pmem); @@ -59,7 +59,7 @@ PHP_HTTP_BUFFER_API size_t php_http_buffer_resize_ex( if (buf->free < len) { size_t size = override_size ? override_size : buf->size; - while ((size + buf->free) < len) { + while (UNEXPECTED((size + buf->free) < len)) { size <<= 1; } @@ -300,7 +300,7 @@ PHP_HTTP_BUFFER_API size_t php_http_buffer_chunked_input(php_http_buffer_t **s, php_http_buffer_t *str; size_t passed; - if (!*s) { + if (UNEXPECTED(!*s)) { *s = php_http_buffer_init_ex(NULL, chunk_size, chunk_size ? PHP_HTTP_BUFFER_INIT_PREALLOC : 0); } diff --git a/src/php_http_buffer.h b/src/php_http_buffer.h index 818c443..6592ec4 100644 --- a/src/php_http_buffer.h +++ b/src/php_http_buffer.h @@ -24,7 +24,7 @@ #ifndef PTR_FREE # define PTR_FREE(PTR) \ { \ - if (PTR) { \ + if (EXPECTED(PTR)) { \ efree(PTR); \ } \ } diff --git a/src/php_http_env_response.c b/src/php_http_env_response.c index 7406857..ab959f3 100644 --- a/src/php_http_env_response.c +++ b/src/php_http_env_response.c @@ -15,7 +15,7 @@ static void set_option(zval *options, const char *name_str, size_t name_len, int type, void *value_ptr, size_t value_len) { if (Z_TYPE_P(options) == IS_OBJECT) { - if (value_ptr) { + if (EXPECTED(value_ptr)) { switch (type) { case IS_DOUBLE: zend_update_property_double(Z_OBJCE_P(options), options, name_str, name_len, *(double *)value_ptr); @@ -36,7 +36,7 @@ static void set_option(zval *options, const char *name_str, size_t name_len, int } } else { convert_to_array(options); - if (value_ptr) { + if (EXPECTED(value_ptr)) { switch (type) { case IS_DOUBLE: add_assoc_double_ex(options, name_str, name_len, *(double *)value_ptr); @@ -64,9 +64,9 @@ static zval *get_option(zval *options, const char *name_str, size_t name_len, zv { zval *val = NULL; - if (Z_TYPE_P(options) == IS_OBJECT) { + if (EXPECTED(Z_TYPE_P(options) == IS_OBJECT)) { val = zend_read_property(Z_OBJCE_P(options), options, name_str, name_len, 0, tmp); - } else if (Z_TYPE_P(options) == IS_ARRAY) { + } else if (EXPECTED(Z_TYPE_P(options) == IS_ARRAY)) { val = zend_symtable_str_find(Z_ARRVAL_P(options), name_str, name_len); } else { abort(); @@ -81,7 +81,7 @@ static php_http_message_body_t *get_body(zval *options) zval zbody_tmp, *zbody; php_http_message_body_t *body = NULL; - if ((zbody = get_option(options, ZEND_STRL("body"), &zbody_tmp))) { + if (EXPECTED(zbody = get_option(options, ZEND_STRL("body"), &zbody_tmp))) { if ((Z_TYPE_P(zbody) == IS_OBJECT) && instanceof_function(Z_OBJCE_P(zbody), php_http_get_message_body_class_entry())) { php_http_message_body_object_t *body_obj = PHP_HTTP_OBJ(NULL, zbody); @@ -97,8 +97,8 @@ static php_http_message_t *get_request(zval *options) zval zrequest_tmp, *zrequest; php_http_message_t *request = NULL; - if ((zrequest = get_option(options, ZEND_STRL("request"), &zrequest_tmp))) { - if (Z_TYPE_P(zrequest) == IS_OBJECT && instanceof_function(Z_OBJCE_P(zrequest), php_http_message_get_class_entry())) { + if (EXPECTED(zrequest = get_option(options, ZEND_STRL("request"), &zrequest_tmp))) { + if (UNEXPECTED(Z_TYPE_P(zrequest) == IS_OBJECT && instanceof_function(Z_OBJCE_P(zrequest), php_http_message_get_class_entry()))) { php_http_message_object_t *request_obj = PHP_HTTP_OBJ(NULL, zrequest); request = request_obj->message; @@ -144,11 +144,11 @@ php_http_cache_status_t php_http_env_is_response_cached_by_etag(zval *options, c zval zetag_tmp, *zetag; - if (!(body = get_body(options))) { + if (UNEXPECTED(!(body = get_body(options)))) { return ret; } - if ((zetag = get_option(options, ZEND_STRL("etag"), &zetag_tmp)) && Z_TYPE_P(zetag) != IS_NULL) { + if (EXPECTED(zetag = get_option(options, ZEND_STRL("etag"), &zetag_tmp)) && Z_TYPE_P(zetag) != IS_NULL) { zend_string *zs = zval_get_string(zetag); etag = estrndup(zs->val, zs->len); zend_string_release(zs); @@ -177,16 +177,16 @@ php_http_cache_status_t php_http_env_is_response_cached_by_last_modified(zval *o php_http_message_body_t *body; zval zlm_tmp, *zlm; - if (!(body = get_body(options))) { + if (UNEXPECTED(!(body = get_body(options)))) { return ret; } - if ((zlm = get_option(options, ZEND_STRL("lastModified"), &zlm_tmp))) { + if (EXPECTED(zlm = get_option(options, ZEND_STRL("lastModified"), &zlm_tmp))) { lm = zval_get_long(zlm); zval_ptr_dtor(zlm); } - if (lm <= 0) { + if (EXPECTED(lm <= 0)) { lm = php_http_message_body_mtime(body); set_option(options, ZEND_STRL("lastModified"), IS_LONG, &lm, 0); } @@ -228,13 +228,13 @@ static size_t output(void *context, char *buf, size_t len) { php_http_env_response_t *r = context; - if (SUCCESS != r->ops->write(r, buf, len)) { + if (UNEXPECTED(SUCCESS != r->ops->write(r, buf, len))) { return (size_t) -1; } /* we really only need to flush when throttling is enabled, because we push the data as fast as possible anyway if not */ - if (r->throttle.delay >= PHP_HTTP_DIFFSEC) { + if (UNEXPECTED(r->throttle.delay >= PHP_HTTP_DIFFSEC)) { r->ops->flush(r); php_http_sleep(r->throttle.delay); } @@ -339,14 +339,14 @@ static ZEND_RESULT_CODE php_http_env_response_send_head(php_http_env_response_t return ret; } - if ((zoption = get_option(options, ZEND_STRL("headers"), &zoption_tmp))) { - if (Z_TYPE_P(zoption) == IS_ARRAY) { + if (EXPECTED(zoption = get_option(options, ZEND_STRL("headers"), &zoption_tmp))) { + if (EXPECTED(Z_TYPE_P(zoption) == IS_ARRAY)) { php_http_header_to_callback(Z_ARRVAL_P(zoption), 0, (php_http_pass_format_callback_t) r->ops->set_header, r); } zval_ptr_dtor(zoption); } - if ((zoption = get_option(options, ZEND_STRL("responseCode"), &zoption_tmp))) { + if (EXPECTED(zoption = get_option(options, ZEND_STRL("responseCode"), &zoption_tmp))) { zend_long rc = zval_get_long(zoption); zval_ptr_dtor(zoption); @@ -359,12 +359,12 @@ static ZEND_RESULT_CODE php_http_env_response_send_head(php_http_env_response_t return ret; } - if ((zoption = get_option(options, ZEND_STRL("httpVersion"), &zoption_tmp))) { + if (EXPECTED(zoption = get_option(options, ZEND_STRL("httpVersion"), &zoption_tmp))) { php_http_version_t v; zend_string *zs = zval_get_string(zoption); zval_ptr_dtor(zoption); - if (zs->len && php_http_version_parse(&v, zs->val)) { + if (EXPECTED(zs->len && php_http_version_parse(&v, zs->val))) { ret = r->ops->set_protocol_version(r, &v); php_http_version_dtor(&v); } @@ -375,7 +375,7 @@ static ZEND_RESULT_CODE php_http_env_response_send_head(php_http_env_response_t return ret; } - if ((zoption = get_option(options, ZEND_STRL("cookies"), &zoption_tmp))) { + if (EXPECTED(zoption = get_option(options, ZEND_STRL("cookies"), &zoption_tmp))) { if (Z_TYPE_P(zoption) == IS_ARRAY) { zval *zcookie; @@ -403,7 +403,7 @@ static ZEND_RESULT_CODE php_http_env_response_send_head(php_http_env_response_t return ret; } - if ((zoption = get_option(options, ZEND_STRL("contentType"), &zoption_tmp))) { + if (EXPECTED(zoption = get_option(options, ZEND_STRL("contentType"), &zoption_tmp))) { zend_string *zs = zval_get_string(zoption); zval_ptr_dtor(zoption); @@ -419,12 +419,12 @@ static ZEND_RESULT_CODE php_http_env_response_send_head(php_http_env_response_t return ret; } - if (r->range.status == PHP_HTTP_RANGE_OK) { + if (UNEXPECTED(r->range.status == PHP_HTTP_RANGE_OK)) { if (zend_hash_num_elements(&r->range.values) == 1) { zval *range, *begin, *end; - if ( 1 == php_http_array_list(&r->range.values, 1, &range) - && 2 == php_http_array_list(Z_ARRVAL_P(range), 2, &begin, &end) + if (EXPECTED( 1 == php_http_array_list(&r->range.values, 1, &range) + && 2 == php_http_array_list(Z_ARRVAL_P(range), 2, &begin, &end)) ) { if (SUCCESS == (ret = r->ops->set_status(r, 206))) { ret = r->ops->set_header(r, "Content-Range: bytes %ld-%ld/%zu", Z_LVAL_P(begin), Z_LVAL_P(end), r->content.length); @@ -441,7 +441,7 @@ static ZEND_RESULT_CODE php_http_env_response_send_head(php_http_env_response_t } } } else { - if ((zoption = get_option(options, ZEND_STRL("cacheControl"), &zoption_tmp))) { + if (EXPECTED(zoption = get_option(options, ZEND_STRL("cacheControl"), &zoption_tmp))) { zend_string *zs = zval_get_string(zoption); zval_ptr_dtor(zoption); @@ -455,7 +455,7 @@ static ZEND_RESULT_CODE php_http_env_response_send_head(php_http_env_response_t return ret; } - if ((zoption = get_option(options, ZEND_STRL("contentDisposition"), &zoption_tmp))) { + if (EXPECTED(zoption = get_option(options, ZEND_STRL("contentDisposition"), &zoption_tmp))) { if (Z_TYPE_P(zoption) == IS_ARRAY) { php_http_buffer_t buf; @@ -476,7 +476,7 @@ static ZEND_RESULT_CODE php_http_env_response_send_head(php_http_env_response_t return ret; } - if ((zoption = get_option(options, ZEND_STRL("contentEncoding"), &zoption_tmp))) { + if (EXPECTED(zoption = get_option(options, ZEND_STRL("contentEncoding"), &zoption_tmp))) { zend_long ce = zval_get_long(zoption); zval zsupported; HashTable *result = NULL; @@ -551,22 +551,22 @@ static ZEND_RESULT_CODE php_http_env_response_send_head(php_http_env_response_t break; } - if ((zoption = get_option(options, ZEND_STRL("etag"), &zoption_tmp))) { + if (EXPECTED(zoption = get_option(options, ZEND_STRL("etag"), &zoption_tmp))) { zend_string *zs = zval_get_string(zoption); zval_ptr_dtor(zoption); - if (*zs->val != '"' && strncmp(zs->val, "W/\"", 3)) { + if (EXPECTED(*zs->val != '"' && strncmp(zs->val, "W/\"", 3))) { ret = r->ops->set_header(r, "ETag: \"%s\"", zs->val); } else { ret = r->ops->set_header(r, "ETag: %s", zs->val); } zend_string_release(zs); } - if ((zoption = get_option(options, ZEND_STRL("lastModified"), &zoption_tmp))) { + if (EXPECTED(zoption = get_option(options, ZEND_STRL("lastModified"), &zoption_tmp))) { zend_long lm = zval_get_long(zoption); zval_ptr_dtor(zoption); - if (lm) { + if (EXPECTED(lm)) { zend_string *date = php_format_date(ZEND_STRL(PHP_HTTP_DATE_FORMAT), lm, 0); if (date) { ret = r->ops->set_header(r, "Last-Modified: %s", date->val); @@ -590,17 +590,17 @@ static ZEND_RESULT_CODE php_http_env_response_send_body(php_http_env_response_t return ret; } - if ((body = get_body(&r->options))) { - if ((zoption = get_option(&r->options, ZEND_STRL("throttleDelay"), &zoption_tmp))) { + if (EXPECTED(body = get_body(&r->options))) { + if (EXPECTED(zoption = get_option(&r->options, ZEND_STRL("throttleDelay"), &zoption_tmp))) { r->throttle.delay = zval_get_double(zoption); zval_ptr_dtor(zoption); } - if ((zoption = get_option(&r->options, ZEND_STRL("throttleChunk"), &zoption_tmp))) { + if (EXPECTED(zoption = get_option(&r->options, ZEND_STRL("throttleChunk"), &zoption_tmp))) { r->throttle.chunk = zval_get_long(zoption); zval_ptr_dtor(zoption); } - if (r->range.status == PHP_HTTP_RANGE_OK) { + if (UNEXPECTED(r->range.status == PHP_HTTP_RANGE_OK)) { if (zend_hash_num_elements(&r->range.values) == 1) { /* single range */ zval *range, *begin, *end; @@ -672,10 +672,10 @@ ZEND_RESULT_CODE php_http_env_response_send(php_http_env_response_t *r) request = get_request(&r->options); /* check for ranges */ - if ((body = get_body(&r->options))) { + if (EXPECTED(body = get_body(&r->options))) { r->content.length = php_http_message_body_size(body); - if (SUCCESS != r->ops->set_header(r, "Accept-Ranges: bytes")) { + if (UNEXPECTED(SUCCESS != r->ops->set_header(r, "Accept-Ranges: bytes"))) { return FAILURE; } else { ZEND_INIT_SYMTABLE_EX(&r->range.values, 0, 0); @@ -727,17 +727,17 @@ ZEND_RESULT_CODE php_http_env_response_send(php_http_env_response_t *r) } } - if (SUCCESS != php_http_env_response_send_head(r, request)) { + if (UNEXPECTED(SUCCESS != php_http_env_response_send_head(r, request))) { php_error_docref(NULL, E_WARNING, "Failed to send response headers"); return FAILURE; } - if (SUCCESS != php_http_env_response_send_body(r)) { + if (UNEXPECTED(SUCCESS != php_http_env_response_send_body(r))) { php_error_docref(NULL, E_WARNING, "Failed to send response body"); return FAILURE; } - if (SUCCESS != r->ops->finish(r)) { + if (UNEXPECTED(SUCCESS != r->ops->finish(r))) { php_error_docref(NULL, E_WARNING, "Failed to finish response"); return FAILURE; } @@ -857,7 +857,7 @@ static ZEND_RESULT_CODE php_http_env_response_stream_init(php_http_env_response_ ctx->request = get_request(&r->options); /* there are some limitations regarding TE:chunked, see https://tools.ietf.org/html/rfc7230#section-3.3.1 */ - if (ctx->request && ctx->request->http.version.major == 1 && ctx->request->http.version.minor == 0) { + if (UNEXPECTED(ctx->request && ctx->request->http.version.major == 1 && ctx->request->http.version.minor == 0)) { ctx->version.minor = 0; } @@ -869,7 +869,7 @@ static void php_http_env_response_stream_dtor(php_http_env_response_t *r) { php_http_env_response_stream_ctx_t *ctx = r->ctx; - if (ctx->chunked_filter) { + if (UNEXPECTED(ctx->chunked_filter)) { ctx->chunked_filter = php_stream_filter_remove(ctx->chunked_filter, 1); } zend_hash_destroy(&ctx->header); @@ -883,7 +883,7 @@ static void php_http_env_response_stream_header(php_http_env_response_stream_ctx ZEND_HASH_FOREACH_VAL(header, val) { - if (Z_TYPE_P(val) == IS_ARRAY) { + if (UNEXPECTED(Z_TYPE_P(val) == IS_ARRAY)) { php_http_env_response_stream_header(ctx, Z_ARRVAL_P(val), buf); } else { zend_string *zs = zval_get_string(val); @@ -913,11 +913,11 @@ static ZEND_RESULT_CODE php_http_env_response_stream_start(php_http_env_response php_http_buffer_appendf(&header_buf, "HTTP/%u.%u %ld %s" PHP_HTTP_CRLF, ctx->version.major, ctx->version.minor, ctx->status_code, php_http_env_get_response_status_for_code(ctx->status_code)); /* there are some limitations regarding TE:chunked, see https://tools.ietf.org/html/rfc7230#section-3.3.1 */ - if (ctx->version.major == 1 && ctx->version.minor == 0) { + if (UNEXPECTED(ctx->version.major == 1 && ctx->version.minor == 0)) { ctx->chunked = 0; - } else if (ctx->status_code == 204 || ctx->status_code/100 == 1) { + } else if (UNEXPECTED(ctx->status_code == 204 || ctx->status_code/100 == 1)) { ctx->chunked = 0; - } else if (ctx->request && ctx->status_code/100 == 2 && !strcasecmp(ctx->request->http.info.request.method, "CONNECT")) { + } else if (UNEXPECTED(ctx->request && ctx->status_code/100 == 2 && !strcasecmp(ctx->request->http.info.request.method, "CONNECT"))) { ctx->chunked = 0; } @@ -982,13 +982,13 @@ static ZEND_RESULT_CODE php_http_env_response_stream_set_header_ex(php_http_env_ zend_string *header_key; ZEND_RESULT_CODE rv; - if (stream_ctx->started || stream_ctx->finished) { + if (UNEXPECTED(stream_ctx->started || stream_ctx->finished)) { return FAILURE; } header_len = vspprintf(&header_str, 0, fmt, argv); - if (!(header_end = strchr(header_str, ':'))) { + if (UNEXPECTED(!(header_end = strchr(header_str, ':')))) { efree(header_str); return FAILURE; } @@ -1080,10 +1080,10 @@ static ZEND_RESULT_CODE php_http_env_response_stream_finish(php_http_env_respons { php_http_env_response_stream_ctx_t *ctx = r->ctx; - if (ctx->finished) { + if (UNEXPECTED(ctx->finished)) { return FAILURE; } - if (!ctx->started) { + if (UNEXPECTED(!ctx->started)) { if (SUCCESS != php_http_env_response_stream_start(ctx)) { return FAILURE; } diff --git a/src/php_http_exception.h b/src/php_http_exception.h index 5acf280..e3e66f1 100644 --- a/src/php_http_exception.h +++ b/src/php_http_exception.h @@ -22,7 +22,7 @@ do { \ zend_error_handling __zeh; \ zend_replace_error_handling(EH_THROW, php_http_get_exception_ ##e## _class_entry(), &__zeh); \ - if (!(test)) { \ + if (UNEXPECTED(!(test))) { \ zend_restore_error_handling(&__zeh); \ fail; \ } \ diff --git a/src/php_http_header_parser.c b/src/php_http_header_parser.c index fb84452..b97ae6b 100644 --- a/src/php_http_header_parser.c +++ b/src/php_http_header_parser.c @@ -40,42 +40,19 @@ php_http_header_parser_t *php_http_header_parser_init(php_http_header_parser_t * return parser; } -php_http_header_parser_state_t php_http_header_parser_state_push(php_http_header_parser_t *parser, unsigned argc, ...) -{ - va_list va_args; - unsigned i; - php_http_header_parser_state_t state = 0; - - /* short circuit */ - ZEND_PTR_STACK_RESIZE_IF_NEEDED((&parser->stack), argc); - - va_start(va_args, argc); - for (i = 0; i < argc; ++i) { - state = va_arg(va_args, php_http_header_parser_state_t); - zend_ptr_stack_push(&parser->stack, (void *) state); - } - va_end(va_args); - - return state; -} +#define php_http_header_parser_state_push(parser, state) zend_ptr_stack_push(&(parser)->stack, (void *) (state)), (state) +#define php_http_header_parser_state_ex(parser) ((parser)->stack.top \ + ? (php_http_header_parser_state_t) (parser)->stack.elements[(parser)->stack.top - 1] \ + : PHP_HTTP_HEADER_PARSER_STATE_START) php_http_header_parser_state_t php_http_header_parser_state_is(php_http_header_parser_t *parser) { - if (parser->stack.top) { - return (php_http_header_parser_state_t) parser->stack.elements[parser->stack.top - 1]; - } - - return PHP_HTTP_HEADER_PARSER_STATE_START; + return php_http_header_parser_state_ex(parser); } -php_http_header_parser_state_t php_http_header_parser_state_pop(php_http_header_parser_t *parser) -{ - if (parser->stack.top) { - return (php_http_header_parser_state_t) zend_ptr_stack_pop(&parser->stack); - } - - return PHP_HTTP_HEADER_PARSER_STATE_START; -} +#define php_http_header_parser_state_pop(parser) ((parser)->stack.top \ + ? (php_http_header_parser_state_t) zend_ptr_stack_pop(&(parser)->stack) \ + : PHP_HTTP_HEADER_PARSER_STATE_START) void php_http_header_parser_dtor(php_http_header_parser_t *parser) { @@ -114,7 +91,7 @@ static void php_http_header_parser_error(size_t valid_len, char *str, size_t len php_http_header_parser_state_t php_http_header_parser_parse(php_http_header_parser_t *parser, php_http_buffer_t *buffer, unsigned flags, HashTable *headers, php_http_info_callback_t callback_func, void *callback_arg) { - while (buffer->used || !php_http_header_parser_states[php_http_header_parser_state_is(parser)].need_data) { + while (buffer->used || !php_http_header_parser_states[php_http_header_parser_state_ex(parser)].need_data) { #if DBG_PARSER const char *state[] = {"START", "KEY", "VALUE", "VALUE_EX", "HEADER_DONE", "DONE"}; fprintf(stderr, "#HP: %s (avail:%zu, num:%d cleanup:%u)\n", php_http_header_parser_state_is(parser) < 0 ? "FAILURE" : state[php_http_header_parser_state_is(parser)], buffer->used, headers?zend_hash_num_elements(headers):0, flags); @@ -123,7 +100,7 @@ php_http_header_parser_state_t php_http_header_parser_parse(php_http_header_pars switch (php_http_header_parser_state_pop(parser)) { case PHP_HTTP_HEADER_PARSER_STATE_FAILURE: php_error_docref(NULL, E_WARNING, "Failed to parse headers"); - return php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_FAILURE); + return php_http_header_parser_state_push(parser, PHP_HTTP_HEADER_PARSER_STATE_FAILURE); case PHP_HTTP_HEADER_PARSER_STATE_START: { char *ptr = buffer->data; @@ -133,7 +110,7 @@ php_http_header_parser_state_t php_http_header_parser_parse(php_http_header_pars } php_http_buffer_cut(buffer, 0, ptr - buffer->data); - php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_KEY); + php_http_header_parser_state_push(parser, PHP_HTTP_HEADER_PARSER_STATE_KEY); break; } @@ -147,7 +124,7 @@ php_http_header_parser_state_t php_http_header_parser_parse(php_http_header_pars if (buffer->data == (eol_str = php_http_locate_bin_eol(buffer->data, buffer->used, &eol_len))) { /* end of headers */ php_http_buffer_cut(buffer, 0, eol_len); - php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_DONE); + php_http_header_parser_state_push(parser, PHP_HTTP_HEADER_PARSER_STATE_DONE); } else if (php_http_info_parse(&parser->info, buffer->data)) { /* new message starting with request/response line */ if (callback_func) { @@ -155,7 +132,7 @@ php_http_header_parser_state_t php_http_header_parser_parse(php_http_header_pars } php_http_info_dtor(&parser->info); php_http_buffer_cut(buffer, 0, eol_str + eol_len - buffer->data); - php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_HEADER_DONE); + php_http_header_parser_state_push(parser, PHP_HTTP_HEADER_PARSER_STATE_HEADER_DONE); } else if ((colon = memchr(buffer->data, ':', buffer->used)) && (!eol_str || eol_str > colon)) { /* header: string */ size_t valid_len; @@ -167,18 +144,18 @@ php_http_header_parser_state_t php_http_header_parser_parse(php_http_header_pars if (valid_len != parser->_key.len) { php_http_header_parser_error(valid_len, parser->_key.str, parser->_key.len, eol_str); PTR_SET(parser->_key.str, NULL); - return php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_FAILURE); + return php_http_header_parser_state_push(parser, PHP_HTTP_HEADER_PARSER_STATE_FAILURE); } while (PHP_HTTP_IS_CTYPE(space, *++colon) && *colon != '\n' && *colon != '\r'); php_http_buffer_cut(buffer, 0, colon - buffer->data); - php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_VALUE); + php_http_header_parser_state_push(parser, PHP_HTTP_HEADER_PARSER_STATE_VALUE); } else if (eol_str || (flags & PHP_HTTP_HEADER_PARSER_CLEANUP)) { /* neither reqeust/response line nor 'header:' string, or injected new line or NUL etc. */ php_http_header_parser_error(strspn(buffer->data, PHP_HTTP_HEADER_NAME_CHARS), buffer->data, buffer->used, eol_str); - return php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_FAILURE); + return php_http_header_parser_state_push(parser, PHP_HTTP_HEADER_PARSER_STATE_FAILURE); } else { /* keep feeding */ - return php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_KEY); + return php_http_header_parser_state_push(parser, PHP_HTTP_HEADER_PARSER_STATE_KEY); } break; } @@ -217,26 +194,26 @@ php_http_header_parser_state_t php_http_header_parser_parse(php_http_header_pars if ((eol_str = php_http_locate_bin_eol(buffer->data, buffer->used, &eol_len))) { SET_ADD_VAL(eol_str - buffer->data, eol_len); - php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_VALUE_EX); + php_http_header_parser_state_push(parser, PHP_HTTP_HEADER_PARSER_STATE_VALUE_EX); } else if (flags & PHP_HTTP_HEADER_PARSER_CLEANUP) { if (buffer->used) { SET_ADD_VAL(buffer->used, 0); } - php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_HEADER_DONE); + php_http_header_parser_state_push(parser, PHP_HTTP_HEADER_PARSER_STATE_HEADER_DONE); } else { - return php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_VALUE); + return php_http_header_parser_state_push(parser, PHP_HTTP_HEADER_PARSER_STATE_VALUE); } break; } case PHP_HTTP_HEADER_PARSER_STATE_VALUE_EX: if (buffer->used && (*buffer->data == ' ' || *buffer->data == '\t')) { - php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_VALUE); + php_http_header_parser_state_push(parser, PHP_HTTP_HEADER_PARSER_STATE_VALUE); } else if (buffer->used || (flags & PHP_HTTP_HEADER_PARSER_CLEANUP)) { - php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_HEADER_DONE); + php_http_header_parser_state_push(parser, PHP_HTTP_HEADER_PARSER_STATE_HEADER_DONE); } else { /* keep feeding */ - return php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_VALUE_EX); + return php_http_header_parser_state_push(parser, PHP_HTTP_HEADER_PARSER_STATE_VALUE_EX); } break; @@ -252,7 +229,7 @@ php_http_header_parser_state_t php_http_header_parser_parse(php_http_header_pars PTR_SET(parser->_key.str, NULL); PTR_SET(parser->_val.str, NULL); - return php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_FAILURE); + return php_http_header_parser_state_push(parser, PHP_HTTP_HEADER_PARSER_STATE_FAILURE); } if (!headers && callback_func) { @@ -273,7 +250,7 @@ php_http_header_parser_state_t php_http_header_parser_parse(php_http_header_pars PTR_SET(parser->_key.str, NULL); PTR_SET(parser->_val.str, NULL); - php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_KEY); + php_http_header_parser_state_push(parser, PHP_HTTP_HEADER_PARSER_STATE_KEY); break; case PHP_HTTP_HEADER_PARSER_STATE_DONE: diff --git a/src/php_http_header_parser.h b/src/php_http_header_parser.h index c22c6a7..c923998 100644 --- a/src/php_http_header_parser.h +++ b/src/php_http_header_parser.h @@ -41,9 +41,7 @@ typedef struct php_http_header_parser { } php_http_header_parser_t; PHP_HTTP_API php_http_header_parser_t *php_http_header_parser_init(php_http_header_parser_t *parser); -PHP_HTTP_API php_http_header_parser_state_t php_http_header_parser_state_push(php_http_header_parser_t *parser, unsigned argc, ...); PHP_HTTP_API php_http_header_parser_state_t php_http_header_parser_state_is(php_http_header_parser_t *parser); -PHP_HTTP_API php_http_header_parser_state_t php_http_header_parser_state_pop(php_http_header_parser_t *parser); PHP_HTTP_API void php_http_header_parser_dtor(php_http_header_parser_t *parser); PHP_HTTP_API void php_http_header_parser_free(php_http_header_parser_t **parser); PHP_HTTP_API php_http_header_parser_state_t php_http_header_parser_parse(php_http_header_parser_t *parser, php_http_buffer_t *buffer, unsigned flags, HashTable *headers, php_http_info_callback_t callback_func, void *callback_arg); diff --git a/src/php_http_info.c b/src/php_http_info.c index 1470f97..5125a94 100644 --- a/src/php_http_info.c +++ b/src/php_http_info.c @@ -96,12 +96,12 @@ php_http_info_t *php_http_info_parse(php_http_info_t *info, const char *pre_head zend_bool free_info = !info; /* sane parameter */ - if ((!pre_header) || (!*pre_header)) { + if (UNEXPECTED((!pre_header) || (!*pre_header))) { return NULL; } /* where's the end of the line */ - if (!(end = php_http_locate_eol(pre_header, NULL))) { + if (UNEXPECTED(!(end = php_http_locate_eol(pre_header, NULL)))) { end = pre_header + strlen(pre_header); } @@ -112,7 +112,7 @@ php_http_info_t *php_http_info_parse(php_http_info_t *info, const char *pre_head info = php_http_info_init(info); - if (!php_http_version_parse(&info->http.version, http)) { + if (UNEXPECTED(!php_http_version_parse(&info->http.version, http))) { if (free_info) { php_http_info_free(&info); } @@ -126,7 +126,7 @@ php_http_info_t *php_http_info_parse(php_http_info_t *info, const char *pre_head } /* and nothing than SPACE or NUL after HTTP/X(.x) */ - if (*off && (!PHP_HTTP_IS_CTYPE(space, *off))) { + if (UNEXPECTED(*off && (!PHP_HTTP_IS_CTYPE(space, *off)))) { if (free_info) { php_http_info_free(&info); } @@ -147,7 +147,7 @@ php_http_info_t *php_http_info_parse(php_http_info_t *info, const char *pre_head info->type = PHP_HTTP_RESPONSE; while (code < end && ' ' == *code) ++code; - if (end > code) { + if (EXPECTED(end > code)) { /* rfc7230#3.1.2 The status-code element is a 3-digit integer code */ PHP_HTTP_INFO(info).response.code = 100*(*code++ - '0'); PHP_HTTP_INFO(info).response.code += 10*(*code++ - '0'); @@ -162,7 +162,7 @@ php_http_info_t *php_http_info_parse(php_http_info_t *info, const char *pre_head } else { PHP_HTTP_INFO(info).response.code = 0; } - if (status && end > status) { + if (EXPECTED(status && end > status)) { while (' ' == *status) ++status; PHP_HTTP_INFO(info).response.status = estrndup(status, end - status); } else { @@ -177,7 +177,7 @@ php_http_info_t *php_http_info_parse(php_http_info_t *info, const char *pre_head const char *url = strchr(pre_header, ' '); info->type = PHP_HTTP_REQUEST; - if (url && http > url) { + if (EXPECTED(url && http > url)) { size_t url_len = url - pre_header; PHP_HTTP_INFO(info).request.method = estrndup(pre_header, url_len); @@ -185,9 +185,9 @@ php_http_info_t *php_http_info_parse(php_http_info_t *info, const char *pre_head while (' ' == *url) ++url; while (' ' == *(http-1)) --http; - if (http > url) { + if (EXPECTED(http > url)) { /* CONNECT presents an authority only */ - if (strcasecmp(PHP_HTTP_INFO(info).request.method, "CONNECT")) { + if (UNEXPECTED(strcasecmp(PHP_HTTP_INFO(info).request.method, "CONNECT"))) { PHP_HTTP_INFO(info).request.url = php_http_url_parse(url, http - url, PHP_HTTP_URL_STDFLAGS); } else { PHP_HTTP_INFO(info).request.url = php_http_url_parse_authority(url, http - url, PHP_HTTP_URL_STDFLAGS); diff --git a/src/php_http_message.c b/src/php_http_message.c index 7d8a6f7..55225d3 100644 --- a/src/php_http_message.c +++ b/src/php_http_message.c @@ -177,24 +177,24 @@ zend_bool php_http_message_is_multipart(php_http_message_t *msg, char **boundary popts.input.str = ct->val; popts.input.len = ct->len; - if (php_http_params_parse(¶ms, &popts)) { + if (EXPECTED(php_http_params_parse(¶ms, &popts))) { zval *cur, *arg; zend_string *ct_str; zend_ulong index; zend_hash_internal_pointer_reset(¶ms); - if ((cur = zend_hash_get_current_data(¶ms)) + if (EXPECTED((cur = zend_hash_get_current_data(¶ms)) && (Z_TYPE_P(cur) == IS_ARRAY) - && (HASH_KEY_IS_STRING == zend_hash_get_current_key(¶ms, &ct_str, &index)) + && (HASH_KEY_IS_STRING == zend_hash_get_current_key(¶ms, &ct_str, &index))) ) { if (php_http_match(ct_str->val, "multipart", PHP_HTTP_MATCH_WORD)) { is_multipart = 1; /* get boundary */ - if (boundary + if (EXPECTED(boundary && (arg = zend_hash_str_find(Z_ARRVAL_P(cur), ZEND_STRL("arguments"))) - && Z_TYPE_P(arg) == IS_ARRAY + && Z_TYPE_P(arg) == IS_ARRAY) ) { zval *val; php_http_arrkey_t key; @@ -204,7 +204,7 @@ zend_bool php_http_message_is_multipart(php_http_message_t *msg, char **boundary if (key.key && key.key->len == lenof("boundary") && !strcasecmp(key.key->val, "boundary")) { zend_string *bnd = zval_get_string(val); - if (bnd->len) { + if (EXPECTED(bnd->len)) { *boundary = estrndup(bnd->val, bnd->len); } zend_string_release(bnd); @@ -471,7 +471,7 @@ php_http_message_t *php_http_message_copy_ex(php_http_message_t *from, php_http_ void php_http_message_dtor(php_http_message_t *message) { - if (message) { + if (EXPECTED(message)) { zend_hash_destroy(&message->hdrs); php_http_message_body_free(&message->body); @@ -493,7 +493,7 @@ void php_http_message_dtor(php_http_message_t *message) void php_http_message_free(php_http_message_t **message) { - if (*message) { + if (EXPECTED(*message)) { if ((*message)->parent) { php_http_message_free(&(*message)->parent); } diff --git a/src/php_http_message_parser.c b/src/php_http_message_parser.c index db935d9..49a6013 100644 --- a/src/php_http_message_parser.c +++ b/src/php_http_message_parser.c @@ -57,41 +57,16 @@ php_http_message_parser_t *php_http_message_parser_init(php_http_message_parser_ return parser; } -php_http_message_parser_state_t php_http_message_parser_state_push(php_http_message_parser_t *parser, unsigned argc, ...) -{ - php_http_message_parser_state_t state = PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE; - va_list va_args; - unsigned i; - - if (argc > 0) { - /* short circuit */ - ZEND_PTR_STACK_RESIZE_IF_NEEDED((&parser->stack), argc); - - va_start(va_args, argc); - for (i = 0; i < argc; ++i) { - state = va_arg(va_args, php_http_message_parser_state_t); - zend_ptr_stack_push(&parser->stack, (void *) state); - } - va_end(va_args); - } - - return state; -} - +#define php_http_message_parser_state_push(parser, state) zend_ptr_stack_push(&(parser)->stack, (void *) (state)), (state) +#define php_http_message_parser_state_pop(parser) ((parser)->stack.top \ + ? (php_http_message_parser_state_t) zend_ptr_stack_pop(&parser->stack) \ + : PHP_HTTP_MESSAGE_PARSER_STATE_START) +#define php_http_message_parser_state_is_ex(parser) ((parser)->stack.top \ + ? (php_http_message_parser_state_t) (parser)->stack.elements[(parser)->stack.top - 1] \ + : PHP_HTTP_MESSAGE_PARSER_STATE_START) php_http_message_parser_state_t php_http_message_parser_state_is(php_http_message_parser_t *parser) { - if (parser->stack.top) { - return (php_http_message_parser_state_t) parser->stack.elements[parser->stack.top - 1]; - } - return PHP_HTTP_MESSAGE_PARSER_STATE_START; -} - -php_http_message_parser_state_t php_http_message_parser_state_pop(php_http_message_parser_t *parser) -{ - if (parser->stack.top) { - return (php_http_message_parser_state_t) zend_ptr_stack_pop(&parser->stack); - } - return PHP_HTTP_MESSAGE_PARSER_STATE_START; + return php_http_message_parser_state_is_ex(parser); } void php_http_message_parser_dtor(php_http_message_parser_t *parser) @@ -188,7 +163,7 @@ php_http_message_parser_state_t php_http_message_parser_parse_stream(php_http_me case PHP_HTTP_MESSAGE_PARSER_STATE_DONE: case PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE: - return php_http_message_parser_state_is(parser); + return php_http_message_parser_state_is_ex(parser); } if (justread) { @@ -210,7 +185,7 @@ php_http_message_parser_state_t php_http_message_parser_parse(php_http_message_p size_t len = 0; size_t cut = 0; - while (buffer->used || !php_http_message_parser_states[php_http_message_parser_state_is(parser)].need_data) { + while (buffer->used || !php_http_message_parser_states[php_http_message_parser_state_is_ex(parser)].need_data) { #if DBG_PARSER fprintf(stderr, "#MP: %s (f: %u, t:%d, l:%zu)\n", php_http_message_parser_state_name(php_http_message_parser_state_is(parser)), @@ -224,7 +199,7 @@ php_http_message_parser_state_t php_http_message_parser_parse(php_http_message_p switch (php_http_message_parser_state_pop(parser)) { case PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE: - return php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE); + return php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE); case PHP_HTTP_MESSAGE_PARSER_STATE_START: { @@ -237,7 +212,7 @@ php_http_message_parser_state_t php_http_message_parser_parse(php_http_message_p php_http_buffer_cut(buffer, 0, ptr - buffer->data); if (buffer->used) { - php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_HEADER); + php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_HEADER); } break; } @@ -251,14 +226,14 @@ php_http_message_parser_state_t php_http_message_parser_parse(php_http_message_p return PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE; case PHP_HTTP_HEADER_PARSER_STATE_DONE: - php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_HEADER_DONE); + php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_HEADER_DONE); break; default: if (buffer->used || !(flags & PHP_HTTP_MESSAGE_PARSER_CLEANUP)) { - return php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_HEADER); + return php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_HEADER); } else { - php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_HEADER_DONE); + php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_HEADER_DONE); } } break; @@ -313,7 +288,7 @@ php_http_message_parser_state_t php_http_message_parser_parse(php_http_message_p if (php_http_match(con->val, "close", PHP_HTTP_MATCH_WORD)) { zend_string_release(con); - php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_DONE); + php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_DONE); break; } zend_string_release(con); @@ -339,11 +314,11 @@ php_http_message_parser_state_t php_http_message_parser_parse(php_http_message_p } if ((flags & PHP_HTTP_MESSAGE_PARSER_DUMB_BODIES)) { - php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DUMB); + php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DUMB); } else { if (chunked) { parser->dechunk = php_http_encoding_stream_init(parser->dechunk, php_http_encoding_stream_get_dechunk_ops(), 0); - php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_CHUNKED); + php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_CHUNKED); break; } @@ -368,7 +343,11 @@ php_http_message_parser_state_t php_http_message_parser_parse(php_http_message_p if (end >= start && (!total || end <= total)) { parser->body_length = end + 1 - start; - 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); + if (parser->body_length) { + php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH); + } else { + php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE); + } zend_string_release(content_range); break; } @@ -380,14 +359,18 @@ php_http_message_parser_state_t php_http_message_parser_parse(php_http_message_p if (content_length >= 0) { parser->body_length = content_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); + if (parser->body_length) { + php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH); + } else { + php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE); + } break; } if ((*message)->type == PHP_HTTP_REQUEST) { - php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_DONE); + php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_DONE); } else { - php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DUMB); + php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DUMB); } } break; @@ -401,7 +384,7 @@ php_http_message_parser_state_t php_http_message_parser_parse(php_http_message_p size_t dec_len; if (SUCCESS != php_http_encoding_stream_update(parser->inflate, str, len, &dec_str, &dec_len)) { - return php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE); + return php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE); } if (str != buffer->data) { @@ -434,7 +417,8 @@ php_http_message_parser_state_t php_http_message_parser_parse(php_http_message_p len = buffer->used; cut = len; - php_http_message_parser_state_push(parser, 2, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE, PHP_HTTP_MESSAGE_PARSER_STATE_BODY); + php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE); + php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY); break; } @@ -446,7 +430,12 @@ php_http_message_parser_state_t php_http_message_parser_parse(php_http_message_p parser->body_length -= len; - php_http_message_parser_state_push(parser, 2, !parser->body_length?PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE:PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH, PHP_HTTP_MESSAGE_PARSER_STATE_BODY); + if (parser->body_length) { + php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH); + } else { + php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE); + } + php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY); break; } @@ -472,24 +461,26 @@ php_http_message_parser_state_t php_http_message_parser_parse(php_http_message_p if (php_http_encoding_stream_done(parser->dechunk)) { cut = buffer->used - PHP_HTTP_BUFFER(parser->dechunk->ctx)->used; - php_http_message_parser_state_push(parser, 2, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE, PHP_HTTP_MESSAGE_PARSER_STATE_BODY); + php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE); + php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY); } else { cut = buffer->used; - php_http_message_parser_state_push(parser, 2, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_CHUNKED, PHP_HTTP_MESSAGE_PARSER_STATE_BODY); + php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_CHUNKED); + php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY); } break; } case PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE: { - php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_DONE); + php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_DONE); if (parser->dechunk && parser->dechunk->ctx) { char *dec_str = NULL; size_t dec_len; if (SUCCESS != php_http_encoding_stream_finish(parser->dechunk, &dec_str, &dec_len)) { - return php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE); + return php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE); } php_http_encoding_stream_dtor(parser->dechunk); @@ -497,7 +488,8 @@ php_http_message_parser_state_t php_http_message_parser_parse(php_http_message_p str = dec_str; len = dec_len; cut = 0; - php_http_message_parser_state_push(parser, 2, PHP_HTTP_MESSAGE_PARSER_STATE_UPDATE_CL, PHP_HTTP_MESSAGE_PARSER_STATE_BODY); + php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_UPDATE_CL); + php_http_message_parser_state_push(parser, PHP_HTTP_MESSAGE_PARSER_STATE_BODY); } } @@ -531,7 +523,7 @@ php_http_message_parser_state_t php_http_message_parser_parse(php_http_message_p } } - return php_http_message_parser_state_is(parser); + return php_http_message_parser_state_is_ex(parser); } static zend_class_entry *php_http_message_parser_class_entry; @@ -584,7 +576,7 @@ static PHP_METHOD(HttpMessageParser, getState) zend_parse_parameters_none(); /* always return the real state */ - RETVAL_LONG(php_http_message_parser_state_is(parser_obj->parser)); + RETVAL_LONG(php_http_message_parser_state_is_ex(parser_obj->parser)); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessageParser_parse, 0, 0, 3) diff --git a/src/php_http_message_parser.h b/src/php_http_message_parser.h index 9b6174d..edc6c2b 100644 --- a/src/php_http_message_parser.h +++ b/src/php_http_message_parser.h @@ -46,9 +46,7 @@ typedef struct php_http_message_parser { } php_http_message_parser_t; PHP_HTTP_API php_http_message_parser_t *php_http_message_parser_init(php_http_message_parser_t *parser); -PHP_HTTP_API php_http_message_parser_state_t php_http_message_parser_state_push(php_http_message_parser_t *parser, unsigned argc, ...); PHP_HTTP_API php_http_message_parser_state_t php_http_message_parser_state_is(php_http_message_parser_t *parser); -PHP_HTTP_API php_http_message_parser_state_t php_http_message_parser_state_pop(php_http_message_parser_t *parser); PHP_HTTP_API void php_http_message_parser_dtor(php_http_message_parser_t *parser); PHP_HTTP_API void php_http_message_parser_free(php_http_message_parser_t **parser); PHP_HTTP_API php_http_message_parser_state_t php_http_message_parser_parse(php_http_message_parser_t *parser, php_http_buffer_t *buffer, unsigned flags, php_http_message_t **message); diff --git a/src/php_http_misc.c b/src/php_http_misc.c index 467988b..f0cc25f 100644 --- a/src/php_http_misc.c +++ b/src/php_http_misc.c @@ -50,11 +50,11 @@ int php_http_match(const char *haystack_str, const char *needle_str, int flags) { int result = 0; - if (!haystack_str || !needle_str) { + if (UNEXPECTED(!haystack_str || !needle_str)) { return result; } - if (flags & PHP_HTTP_MATCH_FULL) { + if (UNEXPECTED(flags & PHP_HTTP_MATCH_FULL)) { if (flags & PHP_HTTP_MATCH_CASE) { result = !strcmp(haystack_str, needle_str); } else { @@ -64,7 +64,7 @@ int php_http_match(const char *haystack_str, const char *needle_str, int flags) const char *found; char *haystack = estrdup(haystack_str), *needle = estrdup(needle_str); - if (flags & PHP_HTTP_MATCH_CASE) { + if (UNEXPECTED(flags & PHP_HTTP_MATCH_CASE)) { found = zend_memnstr(haystack, needle, strlen(needle), haystack+strlen(haystack)); } else { found = php_stristr(haystack, needle, strlen(haystack), strlen(needle)); @@ -73,7 +73,7 @@ int php_http_match(const char *haystack_str, const char *needle_str, int flags) if (found) { if (!(flags & PHP_HTTP_MATCH_WORD) || ( (found == haystack || !PHP_HTTP_IS_CTYPE(alnum, *(found - 1))) - && (!*(found + strlen(needle)) || !PHP_HTTP_IS_CTYPE(alnum, *(found + strlen(needle)))) + && EXPECTED(!*(found + strlen(needle)) || !PHP_HTTP_IS_CTYPE(alnum, *(found + strlen(needle)))) ) ) { result = 1; @@ -89,25 +89,35 @@ int php_http_match(const char *haystack_str, const char *needle_str, int flags) char *php_http_pretty_key(char *key, size_t key_len, zend_bool uctitle, zend_bool xhyphen) { - size_t i = 1; + size_t i; int wasalpha; if (key && key_len) { - 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])); + if (EXPECTED(wasalpha = PHP_HTTP_IS_CTYPE(alpha, key[0]))) { + if (EXPECTED(uctitle)) { + key[0] = PHP_HTTP_TO_CTYPE(upper, key[0]); + } else { + key[0] = PHP_HTTP_TO_CTYPE(lower, key[0]); + } } - 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; + for (i = 1; i < key_len; ++i) { + if (EXPECTED(PHP_HTTP_IS_CTYPE(alpha, key[i]))) { + if (EXPECTED(wasalpha)) { + key[i] = PHP_HTTP_TO_CTYPE(lower, key[i]); + } else if (EXPECTED(uctitle)) { + key[i] = PHP_HTTP_TO_CTYPE(upper, key[i]); + wasalpha = 1; + } else { + key[i] = PHP_HTTP_TO_CTYPE(lower, key[i]); + wasalpha = 1; + } } else { - if (xhyphen && (key[i] == '_')) { + if (EXPECTED(xhyphen && (key[i] == '_'))) { key[i] = '-'; } wasalpha = 0; } - ++i; - ); + } } return key; } diff --git a/src/php_http_misc.h b/src/php_http_misc.h index c8ab922..35de35e 100644 --- a/src/php_http_misc.h +++ b/src/php_http_misc.h @@ -67,47 +67,7 @@ char *php_http_pretty_key(register char *key, size_t key_len, zend_bool uctitle, size_t php_http_boundary(char *buf, size_t len); 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() 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) -{ - 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; -} +#define php_http_locate_str(h, h_len, n, n_len) zend_memnstr((h), (n), (n_len), (h)+(h_len)) static inline const char *php_http_locate_eol(const char *line, int *eol_len) { @@ -123,16 +83,14 @@ static inline const char *php_http_locate_bin_eol(const char *bin, size_t len, i { register const char *eol = bin; - if (len > 0) { - PHP_HTTP_DUFF(len, - if (*eol == '\r' || *eol == '\n') { - if (eol_len) { - *eol_len = ((eol[0] == '\r' && eol[1] == '\n') ? 2 : 1); - } - return eol; + while (len--) { + if (UNEXPECTED(*eol == '\r' || *eol == '\n')) { + if (EXPECTED(eol_len)) { + *eol_len = (EXPECTED(eol[0] == '\r' && eol[1] == '\n') ? 2 : 1); } - ++eol; - ); + return eol; + } + ++eol; } return NULL; } diff --git a/src/php_http_url.c b/src/php_http_url.c index 65cc3d8..ad4f14c 100644 --- a/src/php_http_url.c +++ b/src/php_http_url.c @@ -752,16 +752,17 @@ static inline size_t parse_mb(struct parse_state *state, parse_mb_what_t what, c } #endif } - PHP_HTTP_DUFF(consumed, state->buffer[state->offset++] = *ptr++); + + memcpy(&state->buffer[state->offset], ptr, consumed); + state->offset += consumed; } else { - int i = 0; - - PHP_HTTP_DUFF(consumed, - state->buffer[state->offset++] = '%'; - state->buffer[state->offset++] = parse_xdigits[((unsigned char) ptr[i]) >> 4]; - state->buffer[state->offset++] = parse_xdigits[((unsigned char) ptr[i]) & 0xf]; - ++i; - ); + size_t i; + + for (i = 0; i < consumed; ++i) { + state->buffer[state->offset++] = '%'; + state->buffer[state->offset++] = parse_xdigits[((unsigned char) ptr[i]) >> 4]; + state->buffer[state->offset++] = parse_xdigits[((unsigned char) ptr[i]) & 0xf]; + } } return consumed; @@ -982,10 +983,10 @@ typedef uint16_t UChar; typedef enum { U_ZERO_ERROR = 0 } UErrorCode; int32_t uidna_IDNToASCII(const UChar *src, int32_t srcLength, UChar *dest, int32_t destCapacity, int32_t options, void *parseError, UErrorCode *status); # endif -static ZEND_RESULT_CODE parse_uidn_2003(struct parse_state *state) +static ZEND_RESULT_CODE parse_uidn_2003(struct parse_state *state, size_t prev_len) { - char *host_ptr = state->url.host, ebuf[64] = {0}, *error = NULL; - uint16_t *uhost_str, ahost_str[256], *ahost_ptr; + char ebuf[64] = {0}, *error = NULL; + uint16_t *uhost_str, ahost_str[256]; size_t uhost_len, ahost_len; UErrorCode rc = U_ZERO_ERROR; @@ -1019,10 +1020,11 @@ static ZEND_RESULT_CODE parse_uidn_2003(struct parse_state *state) goto error; } - ahost_ptr = ahost_str; - PHP_HTTP_DUFF(ahost_len, *host_ptr++ = *ahost_ptr++); - *host_ptr = '\0'; - state->offset += host_ptr - state->url.host; + state->url.host[ahost_len] = '\0'; + state->offset += ahost_len - prev_len; + while (ahost_len--) { + state->url.host[ahost_len] = ahost_str[ahost_len]; + } return SUCCESS; @@ -1038,9 +1040,9 @@ static ZEND_RESULT_CODE parse_uidn_2003(struct parse_state *state) #endif #if PHP_HTTP_HAVE_LIBICU && HAVE_UIDNA_NAMETOASCII_UTF8 -static ZEND_RESULT_CODE parse_uidn_2008(struct parse_state *state) +static ZEND_RESULT_CODE parse_uidn_2008(struct parse_state *state, size_t prev_len) { - char *host_ptr, *error = NULL, ebuf[64] = {0}; + char *error = NULL, ebuf[64] = {0}; UErrorCode rc = U_ZERO_ERROR; UIDNAInfo info = UIDNA_INFO_INITIALIZER; UIDNA *uidna = uidna_openUTS46(UIDNA_ALLOW_UNASSIGNED, &rc); @@ -1049,42 +1051,46 @@ static ZEND_RESULT_CODE parse_uidn_2008(struct parse_state *state) return FAILURE; } - host_ptr = state->url.host; - if (state->flags & PHP_HTTP_URL_PARSE_MBUTF8) { - char ahost_str[256], *ahost_ptr = &ahost_str[0]; - size_t ahost_len = uidna_nameToASCII_UTF8(uidna, host_ptr, -1, ahost_str, sizeof(ahost_str)-1, &info, &rc); + char ahost_str[256]; + size_t ahost_len = uidna_nameToASCII_UTF8(uidna, state->url.host, -1, ahost_str, sizeof(ahost_str)-1, &info, &rc); if (U_FAILURE(rc) || info.errors) { goto error; } - PHP_HTTP_DUFF(ahost_len, *host_ptr++ = *ahost_ptr++); + + memcpy(state->url.host, ahost_str, ahost_len); + state->url.host[ahost_len] = '\0'; + state->offset += ahost_len - prev_len; + #if PHP_HTTP_HAVE_WCHAR } else if (state->flags & PHP_HTTP_URL_PARSE_MBLOC) { - uint16_t *uhost_str, whost_str[256], *whost_ptr = &whost_str[0]; + uint16_t *uhost_str, whost_str[256]; size_t uhost_len, whost_len; - if (SUCCESS != to_utf16(parse_mb_loc, host_ptr, &uhost_str, &uhost_len)) { + if (SUCCESS != to_utf16(parse_mb_loc, state->url.host, &uhost_str, &uhost_len)) { error = "could not convert to UTF-16"; goto error; } whost_len = uidna_nameToASCII(uidna, uhost_str, uhost_len, whost_str, sizeof(whost_str)-1, &info, &rc); - whost_ptr = whost_str; efree(uhost_str); + if (U_FAILURE(rc) || info.errors) { goto error; } - PHP_HTTP_DUFF(whost_len, *host_ptr++ = *whost_ptr++); + + state->url.host[whost_len] = '\0'; + state->offset += whost_len - prev_len; + while (whost_len--) { + state->url.host[whost_len] = whost_str[whost_len]; + } #endif } else { error = "codepage not specified"; goto error; } - *host_ptr = '\0'; - state->offset += host_ptr - state->url.host; - uidna_close(uidna); return SUCCESS; @@ -1111,7 +1117,7 @@ static ZEND_RESULT_CODE parse_uidn_2008(struct parse_state *state) # if __GNUC__ __attribute__ ((unused)) # endif -static ZEND_RESULT_CODE parse_kidn(struct parse_state *state) +static ZEND_RESULT_CODE parse_kidn(struct parse_state *state, size_t prev_len) { idn_result_t rc; #if PHP_HTTP_HAVE_LIBIDNKIT @@ -1119,7 +1125,7 @@ static ZEND_RESULT_CODE parse_kidn(struct parse_state *state) #elif PHP_HTTP_HAVE_LIBIDNKIT2 int actions = IDN_MAP|IDN_ASCLOWER|IDN_RTCONV|IDN_PROHCHECK|IDN_NFCCHECK|IDN_PREFCHECK|IDN_COMBCHECK|IDN_CTXOLITECHECK|IDN_BIDICHECK|IDN_LOCALCHECK|IDN_IDNCONV|IDN_LENCHECK|IDN_RTCHECK; #endif - char ahost_str[256] = {0}, *ahost_ptr = &ahost_str[0], *host_ptr = state->url.host; + char ahost_str[256] = {0}; if (state->flags & PHP_HTTP_URL_PARSE_MBLOC) { #if PHP_HTTP_HAVE_LIBIDNKIT @@ -1131,10 +1137,10 @@ static ZEND_RESULT_CODE parse_kidn(struct parse_state *state) rc = idn_encodename(actions, state->url.host, ahost_str, 256); if (rc == idn_success) { - PHP_HTTP_DUFF(strlen(ahost_str), *host_ptr++ = *ahost_ptr++); + size_t ahost_len = strlen(ahost_str); - *host_ptr = '\0'; - state->offset += host_ptr - state->url.host; + memcpy(state->url.host, ahost_str, ahost_len + 1); + state->offset += ahost_len - prev_len; return SUCCESS; } else { @@ -1145,11 +1151,11 @@ static ZEND_RESULT_CODE parse_kidn(struct parse_state *state) #endif #if 0 && PHP_WIN32 -static ZEND_RESULT_CODE parse_widn_2003(struct parse_state *state) +static ZEND_RESULT_CODE parse_widn_2003(struct parse_state *state, size_t prev_len) { char *host_ptr; - uint16_t *uhost_str, ahost_str[256], *ahost_ptr; - size_t uhost_len; + uint16_t *uhost_str, ahost_str[256]; + size_t uhost_len, ahost_len; if (state->flags & PHP_HTTP_URL_PARSE_MBUTF8) { if (SUCCESS != to_utf16(parse_mb_utf8, state->url.host, &uhost_str, &uhost_len)) { @@ -1175,12 +1181,12 @@ static ZEND_RESULT_CODE parse_widn_2003(struct parse_state *state) } efree(uhost_str); - host_ptr = state->url.host; - ahost_ptr = ahost_str; - PHP_HTTP_DUFF(wcslen(ahost_str), *host_ptr++ = *ahost_ptr++); - - *host_ptr = '\0'; - state->offset += host_ptr - state->url.host; + ahost_len = wcslen(ahost_str); + state->url.host[ahost_len] = '\0'; + state->offset += ahost_len - prev_len; + while (ahost_len--) { + state->url.host[ahost_len] = ahost_str[ahost_len]; + } return SUCCESS; } @@ -1195,11 +1201,11 @@ static ZEND_RESULT_CODE parse_idna(struct parse_state *state, size_t len) # endif ) { #if PHP_HTTP_HAVE_LIBICU && HAVE_UIDNA_NAMETOASCII_UTF8 - return parse_uidn_2008(state); + return parse_uidn_2008(state, len); #elif PHP_HTTP_HAVE_LIBIDN2 return parse_gidn_2008(state, len); #elif PHP_HTTP_HAVE_LIBIDNKIT2 - return parse_kidn(state); + return parse_kidn(state, len); #endif } #endif @@ -1211,31 +1217,31 @@ static ZEND_RESULT_CODE parse_idna(struct parse_state *state, size_t len) #endif ) { #if HAVE_UIDNA_IDNTOASCII - return parse_uidn_2003(state); + return parse_uidn_2003(state, len); #elif PHP_HTTP_HAVE_LIBIDN return parse_gidn_2003(state, len); #elif PHP_HTTP_HAVE_LIBIDNKIT - return parse_kidn(state); + return parse_kidn(state, len); #endif } #endif #if 0 && PHP_WIN32 - return parse_widn_2003(state); + return parse_widn_2003(state, len); #endif #if PHP_HTTP_HAVE_LIBICU && HAVE_UIDNA_NAMETOASCII_UTF8 - return parse_uidn_2008(state); + return parse_uidn_2008(state, len); #elif PHP_HTTP_HAVE_LIBIDN2 return parse_gidn_2008(state, len); #elif PHP_HTTP_HAVE_LIBIDNKIT2 - return parse_kidn(state); + return parse_kidn(state, len); #elif HAVE_UIDNA_IDNTOASCII - return parse_uidn_2003(state); + return parse_uidn_2003(state, len); #elif PHP_HTTP_HAVE_LIBIDN return parse_gidn_2003(state, len); #elif PHP_HTTP_HAVE_LIBIDNKIT - return parse_kidn(state); + return parse_kidn(state, len); #endif return SUCCESS; diff --git a/src/php_http_utf8.h b/src/php_http_utf8.h index f900803..02fd8d7 100644 --- a/src/php_http_utf8.h +++ b/src/php_http_utf8.h @@ -595,24 +595,25 @@ static inline size_t utf8towc(unsigned *wc, const unsigned char *uc, size_t len) static inline zend_bool isualpha(unsigned ch) { - unsigned i = 0, j; + unsigned j; + const utf8_range_t *u = &utf8_ranges[0], *e = &utf8_ranges[sizeof(utf8_ranges)/sizeof(utf8_range_t)-1]; - PHP_HTTP_DUFF(sizeof(utf8_ranges)/sizeof(utf8_range_t), - if (utf8_ranges[i].start == ch) { + do { + if (u->start == ch) { return 1; - } else if (utf8_ranges[i].start <= ch && utf8_ranges[i].end >= ch) { - if (utf8_ranges[i].step == 1) { + } else if (u->start <= ch && u->end >= ch) { + if (u->step == 1) { return 1; } - for (j = utf8_ranges[i].start; j <= utf8_ranges[i].end; j+= utf8_ranges[i].step) { + for (j = u->start; j <= u->end; j+= u->step) { if (ch == j) { return 1; } } return 0; } - ++i; - ); + } while (++u != e); + return 0; } -- 2.30.2