diff options
Diffstat (limited to 'ext/standard/http_fopen_wrapper.c')
-rw-r--r-- | ext/standard/http_fopen_wrapper.c | 126 |
1 files changed, 62 insertions, 64 deletions
diff --git a/ext/standard/http_fopen_wrapper.c b/ext/standard/http_fopen_wrapper.c index 02b580fa28..9c10c4907b 100644 --- a/ext/standard/http_fopen_wrapper.c +++ b/ext/standard/http_fopen_wrapper.c @@ -117,11 +117,9 @@ php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, php_url *resource = NULL; int use_ssl; int use_proxy = 0; - char *scratch = NULL; zend_string *tmp = NULL; char *ua_str = NULL; zval *ua_zval = NULL, *tmpzval = NULL, ssl_proxy_peer_name; - size_t scratch_len = 0; int body = 0; char location[HTTP_HEADER_BLOCK_SIZE]; zval response_header; @@ -135,8 +133,6 @@ php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, size_t transport_len; int have_header = 0; zend_bool request_fulluri = 0, ignore_errors = 0; - char *protocol_version = NULL; - int protocol_version_len = 3; /* Default: "1.0" */ struct timeval timeout; char *user_headers = NULL; int header_init = ((flags & HTTP_WRAPPER_HEADER_INIT) != 0); @@ -145,6 +141,8 @@ php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, php_stream_filter *transfer_encoding = NULL; int response_code; zend_array *symbol_table; + smart_str req_buf = {0}; + zend_bool custom_request_method; ZVAL_UNDEF(&response_header); tmp_line[0] = '\0'; @@ -362,6 +360,7 @@ finish: redirect_max = (int)zval_get_long(tmpzval); } + custom_request_method = 0; if (context && (tmpzval = php_stream_context_get_option(context, "http", "method")) != NULL) { if (Z_TYPE_P(tmpzval) == IS_STRING && Z_STRLEN_P(tmpzval) > 0) { /* As per the RFC, automatically redirected requests MUST NOT use other methods than @@ -370,22 +369,15 @@ finish: || (Z_STRLEN_P(tmpzval) == 3 && memcmp("GET", Z_STRVAL_P(tmpzval), 3) == 0) || (Z_STRLEN_P(tmpzval) == 4 && memcmp("HEAD",Z_STRVAL_P(tmpzval), 4) == 0) ) { - scratch_len = strlen(path) + 29 + Z_STRLEN_P(tmpzval); - scratch = emalloc(scratch_len); - strlcpy(scratch, Z_STRVAL_P(tmpzval), Z_STRLEN_P(tmpzval) + 1); - strncat(scratch, " ", 1); + custom_request_method = 1; + smart_str_append(&req_buf, Z_STR_P(tmpzval)); + smart_str_appendc(&req_buf, ' '); } } } - if (context && (tmpzval = php_stream_context_get_option(context, "http", "protocol_version")) != NULL) { - protocol_version_len = (int)spprintf(&protocol_version, 0, "%.1F", zval_get_double(tmpzval)); - } - - if (!scratch) { - scratch_len = strlen(path) + 29 + protocol_version_len; - scratch = emalloc(scratch_len); - strncpy(scratch, "GET ", scratch_len); + if (!custom_request_method) { + smart_str_appends(&req_buf, "GET "); } /* Should we send the entire path in the request line, default to no. */ @@ -396,36 +388,37 @@ finish: if (request_fulluri) { /* Ask for everything */ - strcat(scratch, path); + smart_str_appends(&req_buf, path); } else { /* Send the traditional /path/to/file?query_string */ /* file */ if (resource->path && *resource->path) { - strlcat(scratch, resource->path, scratch_len); + smart_str_appends(&req_buf, resource->path); } else { - strlcat(scratch, "/", scratch_len); + smart_str_appendc(&req_buf, '/'); } /* query string */ if (resource->query) { - strlcat(scratch, "?", scratch_len); - strlcat(scratch, resource->query, scratch_len); + smart_str_appendc(&req_buf, '?'); + smart_str_appends(&req_buf, resource->query); } } /* protocol version we are speaking */ - if (protocol_version) { - strlcat(scratch, " HTTP/", scratch_len); - strlcat(scratch, protocol_version, scratch_len); - strlcat(scratch, "\r\n", scratch_len); + if (context && (tmpzval = php_stream_context_get_option(context, "http", "protocol_version")) != NULL) { + char *protocol_version; + spprintf(&protocol_version, 0, "%.1F", zval_get_double(tmpzval)); + + smart_str_appends(&req_buf, " HTTP/"); + smart_str_appends(&req_buf, protocol_version); + smart_str_appends(&req_buf, "\r\n"); + efree(protocol_version); } else { - strlcat(scratch, " HTTP/1.0\r\n", scratch_len); + smart_str_appends(&req_buf, " HTTP/1.0\r\n"); } - /* send it */ - php_stream_write(stream, scratch, strlen(scratch)); - if (context && (tmpzval = php_stream_context_get_option(context, "http", "header")) != NULL) { tmp = NULL; @@ -537,11 +530,14 @@ finish: /* auth header if it was specified */ if (((have_header & HTTP_HEADER_AUTH) == 0) && resource->user) { + /* make scratch large enough to hold the whole URL (over-estimate) */ + size_t scratch_len = strlen(path) + 1; + char *scratch = emalloc(scratch_len); zend_string *stmp; + /* decode the strings first */ php_url_decode(resource->user, strlen(resource->user)); - /* scratch is large enough, since it was made large enough for the whole URL */ strcpy(scratch, resource->user); strcat(scratch, ":"); @@ -553,31 +549,33 @@ finish: stmp = php_base64_encode((unsigned char*)scratch, strlen(scratch)); - if (snprintf(scratch, scratch_len, "Authorization: Basic %s\r\n", ZSTR_VAL(stmp)) > 0) { - php_stream_write(stream, scratch, strlen(scratch)); - php_stream_notify_info(context, PHP_STREAM_NOTIFY_AUTH_REQUIRED, NULL, 0); - } + smart_str_appends(&req_buf, "Authorization: Basic "); + smart_str_appends(&req_buf, ZSTR_VAL(stmp)); + smart_str_appends(&req_buf, "\r\n"); + + php_stream_notify_info(context, PHP_STREAM_NOTIFY_AUTH_REQUIRED, NULL, 0); zend_string_free(stmp); + efree(scratch); } /* if the user has configured who they are, send a From: line */ - if (((have_header & HTTP_HEADER_FROM) == 0) && FG(from_address)) { - if (snprintf(scratch, scratch_len, "From: %s\r\n", FG(from_address)) > 0) - php_stream_write(stream, scratch, strlen(scratch)); + if (!(have_header & HTTP_HEADER_FROM) && FG(from_address)) { + smart_str_appends(&req_buf, "From: "); + smart_str_appends(&req_buf, FG(from_address)); + smart_str_appends(&req_buf, "\r\n"); } /* Send Host: header so name-based virtual hosts work */ if ((have_header & HTTP_HEADER_HOST) == 0) { + smart_str_appends(&req_buf, "Host: "); + smart_str_appends(&req_buf, resource->host); if ((use_ssl && resource->port != 443 && resource->port != 0) || (!use_ssl && resource->port != 80 && resource->port != 0)) { - if (snprintf(scratch, scratch_len, "Host: %s:%i\r\n", resource->host, resource->port) > 0) - php_stream_write(stream, scratch, strlen(scratch)); - } else { - if (snprintf(scratch, scratch_len, "Host: %s\r\n", resource->host) > 0) { - php_stream_write(stream, scratch, strlen(scratch)); - } + smart_str_appendc(&req_buf, ':'); + smart_str_append_unsigned(&req_buf, resource->port); } + smart_str_appends(&req_buf, "\r\n"); } /* Send a Connection: close header to avoid hanging when the server @@ -587,7 +585,7 @@ finish: * HTTP/1.0 to avoid issues when the server respond with a HTTP/1.1 * keep-alive response, which is the preferred response type. */ if ((have_header & HTTP_HEADER_CONNECTION) == 0) { - php_stream_write_string(stream, "Connection: close\r\n"); + smart_str_appends(&req_buf, "Connection: close\r\n"); } if (context && @@ -610,7 +608,7 @@ finish: ua = emalloc(ua_len + 1); if ((ua_len = slprintf(ua, ua_len, _UA_HEADER, ua_str)) > 0) { ua[ua_len] = 0; - php_stream_write(stream, ua, ua_len); + smart_str_appendl(&req_buf, ua, ua_len); } else { php_error_docref(NULL, E_WARNING, "Cannot construct User-agent header"); } @@ -629,13 +627,14 @@ finish: (tmpzval = php_stream_context_get_option(context, "http", "content")) != NULL && Z_TYPE_P(tmpzval) == IS_STRING && Z_STRLEN_P(tmpzval) > 0 ) { - scratch_len = slprintf(scratch, scratch_len, "Content-Length: %d\r\n", Z_STRLEN_P(tmpzval)); - php_stream_write(stream, scratch, scratch_len); + smart_str_appends(&req_buf, "Content-Length: "); + smart_str_append_unsigned(&req_buf, Z_STRLEN_P(tmpzval)); + smart_str_appends(&req_buf, "\r\n"); have_header |= HTTP_HEADER_CONTENT_LENGTH; } - php_stream_write(stream, user_headers, strlen(user_headers)); - php_stream_write(stream, "\r\n", sizeof("\r\n")-1); + smart_str_appends(&req_buf, user_headers); + smart_str_appends(&req_buf, "\r\n"); efree(user_headers); } @@ -644,20 +643,23 @@ finish: (tmpzval = php_stream_context_get_option(context, "http", "content")) != NULL && Z_TYPE_P(tmpzval) == IS_STRING && Z_STRLEN_P(tmpzval) > 0) { if (!(have_header & HTTP_HEADER_CONTENT_LENGTH)) { - scratch_len = slprintf(scratch, scratch_len, "Content-Length: %d\r\n", Z_STRLEN_P(tmpzval)); - php_stream_write(stream, scratch, scratch_len); + smart_str_appends(&req_buf, "Content-Length: "); + smart_str_append_unsigned(&req_buf, Z_STRLEN_P(tmpzval)); + smart_str_appends(&req_buf, "\r\n"); } if (!(have_header & HTTP_HEADER_TYPE)) { - php_stream_write(stream, "Content-Type: application/x-www-form-urlencoded\r\n", - sizeof("Content-Type: application/x-www-form-urlencoded\r\n") - 1); + smart_str_appends(&req_buf, "Content-Type: application/x-www-form-urlencoded\r\n"); php_error_docref(NULL, E_NOTICE, "Content-type not specified assuming application/x-www-form-urlencoded"); } - php_stream_write(stream, "\r\n", sizeof("\r\n")-1); - php_stream_write(stream, Z_STRVAL_P(tmpzval), Z_STRLEN_P(tmpzval)); + smart_str_appends(&req_buf, "\r\n"); + smart_str_appendl(&req_buf, Z_STRVAL_P(tmpzval), Z_STRLEN_P(tmpzval)); } else { - php_stream_write(stream, "\r\n", sizeof("\r\n")-1); + smart_str_appends(&req_buf, "\r\n"); } + /* send it */ + php_stream_write(stream, ZSTR_VAL(req_buf.s), ZSTR_LEN(req_buf.s)); + location[0] = '\0'; symbol_table = zend_rebuild_symbol_table(); @@ -893,18 +895,13 @@ finish: } } out: - if (protocol_version) { - efree(protocol_version); - } + + smart_str_free(&req_buf); if (http_header_line) { efree(http_header_line); } - if (scratch) { - efree(scratch); - } - if (resource) { php_url_free(resource); } @@ -969,7 +966,8 @@ static php_stream_wrapper_ops http_stream_wops = { NULL, /* unlink */ NULL, /* rename */ NULL, /* mkdir */ - NULL /* rmdir */ + NULL, /* rmdir */ + NULL }; PHPAPI php_stream_wrapper php_stream_http_wrapper = { |