diff options
author | Dmitry Stogov <dmitry@zend.com> | 2015-09-24 01:19:15 +0300 |
---|---|---|
committer | Dmitry Stogov <dmitry@zend.com> | 2015-09-24 01:19:15 +0300 |
commit | 5cccd6c5b6288231c4d556174f9ea1207b2e933a (patch) | |
tree | b872dd895e0e2b9983912f114db7939a8d31c771 | |
parent | 51cd49b2cf043f4fe2d701a28504322684bdd6f6 (diff) | |
download | php-git-5cccd6c5b6288231c4d556174f9ea1207b2e933a.tar.gz |
Fixed memory leak and avoid reallocations
-rw-r--r-- | ext/soap/php_http.c | 147 | ||||
-rw-r--r-- | ext/soap/php_http.h | 13 | ||||
-rw-r--r-- | ext/soap/soap.c | 21 |
3 files changed, 96 insertions, 85 deletions
diff --git a/ext/soap/php_http.c b/ext/soap/php_http.c index e85ed68381..de599b229a 100644 --- a/ext/soap/php_http.c +++ b/ext/soap/php_http.c @@ -25,7 +25,7 @@ #include "ext/standard/php_rand.h" static char *get_http_header_value(char *headers, char *type); -static int get_http_body(php_stream *socketd, int close, char *headers, char **response, int *out_size); +static zend_string *get_http_body(php_stream *socketd, int close, char *headers); static zend_string *get_http_headers(php_stream *socketd); #define smart_str_append_const(str, const) \ @@ -326,25 +326,25 @@ static int in_domain(const char *host, const char *domain) } } -int make_http_soap_request(zval *this_ptr, - char *buf, - int buf_size, - char *location, - char *soapaction, - int soap_version, - zval *return_value) +int make_http_soap_request(zval *this_ptr, + zend_string *buf, + char *location, + char *soapaction, + int soap_version, + zval *return_value) { - char *request; + zend_string *request; smart_str soap_headers = {0}; smart_str soap_headers_z = {0}; - int request_size, err; + int err; php_url *phpurl = NULL; php_stream *stream; zval *trace, *tmp; int use_proxy = 0; int use_ssl; - char *http_body, *content_type, *http_version, *cookie_itt; - int http_body_size, http_close; + zend_string *http_body; + char *content_type, *http_version, *cookie_itt; + int http_close; zend_string *http_headers; char *connection; int http_1_1; @@ -363,8 +363,7 @@ int make_http_soap_request(zval *this_ptr, return FALSE; } - request = buf; - request_size = buf_size; + request = buf; /* Compress request */ if ((tmp = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "compression", sizeof("compression")-1)) != NULL && Z_TYPE_P(tmp) == IS_LONG) { int level = Z_LVAL_P(tmp) & 0x0f; @@ -381,7 +380,7 @@ int make_http_soap_request(zval *this_ptr, zval params[3]; int n; - ZVAL_STRINGL(¶ms[0], buf, buf_size); + ZVAL_STR_COPY(¶ms[0], buf); ZVAL_LONG(¶ms[1], level); if (kind == SOAP_COMPRESSION_DEFLATE) { n = 2; @@ -397,13 +396,13 @@ int make_http_soap_request(zval *this_ptr, Z_TYPE(retval) == IS_STRING) { zval_ptr_dtor(¶ms[0]); zval_ptr_dtor(&func); -// TODO: free retval ??? - request = Z_STRVAL(retval); - request_size = Z_STRLEN(retval); + request = Z_STR(retval); } else { zval_ptr_dtor(¶ms[0]); zval_ptr_dtor(&func); - if (request != buf) {efree(request);} + if (request != buf) { + zend_string_release(request); + } smart_str_free(&soap_headers_z); return FALSE; } @@ -439,7 +438,9 @@ int make_http_soap_request(zval *this_ptr, try_again: if (phpurl == NULL || phpurl->host == NULL) { if (phpurl != NULL) {php_url_free(phpurl);} - if (request != buf) {efree(request);} + if (request != buf) { + zend_string_release(request); + } add_soap_fault(this_ptr, "HTTP", "Unable to parse URL", NULL, NULL); smart_str_free(&soap_headers_z); return FALSE; @@ -450,7 +451,9 @@ try_again: use_ssl = 1; } else if (phpurl->scheme == NULL || strcmp(phpurl->scheme, "http") != 0) { php_url_free(phpurl); - if (request != buf) {efree(request);} + if (request != buf) { + zend_string_release(request); + } add_soap_fault(this_ptr, "HTTP", "Unknown protocol. Only http and https are allowed.", NULL, NULL); smart_str_free(&soap_headers_z); return FALSE; @@ -460,7 +463,9 @@ try_again: PG(allow_url_fopen) = 1; if (use_ssl && php_stream_locate_url_wrapper("https://", NULL, STREAM_LOCATE_WRAPPERS_ONLY) == NULL) { php_url_free(phpurl); - if (request != buf) {efree(request);} + if (request != buf) { + zend_string_release(request); + } add_soap_fault(this_ptr, "HTTP", "SSL support is not available in this build", NULL, NULL); PG(allow_url_fopen) = old_allow_url_fopen; smart_str_free(&soap_headers_z); @@ -511,7 +516,9 @@ try_again: add_property_long(this_ptr, "_use_proxy", use_proxy); } else { php_url_free(phpurl); - if (request != buf) {efree(request);} + if (request != buf) { + zend_string_release(request); + } add_soap_fault(this_ptr, "HTTP", "Could not connect to host", NULL, NULL); PG(allow_url_fopen) = old_allow_url_fopen; smart_str_free(&soap_headers_z); @@ -620,7 +627,7 @@ try_again: } } smart_str_append_const(&soap_headers,"Content-Length: "); - smart_str_append_long(&soap_headers, request_size); + smart_str_append_long(&soap_headers, request->len); smart_str_append_const(&soap_headers, "\r\n"); /* HTTP Authentication */ @@ -851,12 +858,14 @@ try_again: (Z_TYPE_P(trace) == IS_TRUE || (Z_TYPE_P(trace) == IS_LONG && Z_LVAL_P(trace) != 0))) { add_property_stringl(this_ptr, "__last_request_headers", ZSTR_VAL(soap_headers.s), ZSTR_LEN(soap_headers.s)); } - smart_str_appendl(&soap_headers, request, request_size); + smart_str_appendl(&soap_headers, request->val, request->len); smart_str_0(&soap_headers); err = php_stream_write(stream, ZSTR_VAL(soap_headers.s), ZSTR_LEN(soap_headers.s)); if (err != ZSTR_LEN(soap_headers.s)) { - if (request != buf) {efree(request);} + if (request != buf) { + zend_string_release(request); + } php_stream_close(stream); zend_hash_str_del(Z_OBJPROP_P(this_ptr), "httpurl", sizeof("httpurl")-1); zend_hash_str_del(Z_OBJPROP_P(this_ptr), "httpsocket", sizeof("httpsocket")-1); @@ -883,7 +892,9 @@ try_again: do { http_headers = get_http_headers(stream); if (!http_headers) { - if (request != buf) {efree(request);} + if (request != buf) { + zend_string_release(request); + } php_stream_close(stream); zend_hash_str_del(Z_OBJPROP_P(this_ptr), "httpsocket", sizeof("httpsocket")-1); zend_hash_str_del(Z_OBJPROP_P(this_ptr), "_use_proxy", sizeof("_use_proxy")-1); @@ -1053,8 +1064,12 @@ try_again: } } - if (!get_http_body(stream, http_close, ZSTR_VAL(http_headers), &http_body, &http_body_size)) { - if (request != buf) {efree(request);} + + http_body = get_http_body(stream, http_close, ZSTR_VAL(http_headers)); + if (!http_body) { + if (request != buf) { + zend_string_release(request); + } php_stream_close(stream); zend_string_release(http_headers); zend_hash_str_del(Z_OBJPROP_P(this_ptr), "httpsocket", sizeof("httpsocket")-1); @@ -1067,7 +1082,9 @@ try_again: return FALSE; } - if (request != buf) {efree(request);} + if (request != buf) { + zend_string_release(request); + } if (http_close) { php_stream_close(stream); @@ -1085,7 +1102,7 @@ try_again: if (new_url != NULL) { zend_string_release(http_headers); - efree(http_body); + zend_string_release(http_body); efree(loc); if (new_url->scheme == NULL && new_url->path != NULL) { new_url->scheme = phpurl->scheme ? estrdup(phpurl->scheme) : NULL; @@ -1193,7 +1210,7 @@ try_again: efree(auth); zend_string_release(http_headers); - efree(http_body); + zend_string_release(http_body); goto try_again; } @@ -1243,15 +1260,15 @@ try_again: strcmp(content_encoding,"x-gzip") == 0) && zend_hash_str_exists(EG(function_table), "gzinflate", sizeof("gzinflate")-1)) { ZVAL_STRING(&func, "gzinflate"); - ZVAL_STRINGL(¶ms[0], http_body+10, http_body_size-10); + ZVAL_STRINGL(¶ms[0], http_body->val+10, http_body->len-10); } else if (strcmp(content_encoding,"deflate") == 0 && zend_hash_str_exists(EG(function_table), "gzuncompress", sizeof("gzuncompress")-1)) { ZVAL_STRING(&func, "gzuncompress"); - ZVAL_STRINGL(¶ms[0], http_body, http_body_size); + ZVAL_STR_COPY(¶ms[0], http_body); } else { efree(content_encoding); zend_string_release(http_headers); - efree(http_body); + zend_string_release(http_body); if (http_msg) { efree(http_msg); } @@ -1262,14 +1279,14 @@ try_again: Z_TYPE(retval) == IS_STRING) { zval_ptr_dtor(¶ms[0]); zval_ptr_dtor(&func); - efree(http_body); + zend_string_release(http_body); ZVAL_COPY_VALUE(return_value, &retval); } else { zval_ptr_dtor(¶ms[0]); zval_ptr_dtor(&func); efree(content_encoding); zend_string_release(http_headers); - efree(http_body); + zend_string_release(http_body); add_soap_fault(this_ptr, "HTTP", "Can't uncompress compressed response", NULL, NULL); if (http_msg) { efree(http_msg); @@ -1278,11 +1295,7 @@ try_again: } efree(content_encoding); } else { - // TODO: avoid reallocation ??? - //???*buffer = http_body; - //???*buffer_len = http_body_size; - ZVAL_STRINGL(return_value, http_body, http_body_size); - efree(http_body); + ZVAL_STR(return_value, http_body); } zend_string_release(http_headers); @@ -1359,9 +1372,10 @@ static char *get_http_header_value(char *headers, char *type) return NULL; } -static int get_http_body(php_stream *stream, int close, char *headers, char **response, int *out_size) +static zend_string* get_http_body(php_stream *stream, int close, char *headers) { - char *header, *http_buf = NULL; + zend_string *http_buf = NULL; + char *header; int header_close = close, header_chunked = 0, header_length = 0, http_buf_size = 0; if (!close) { @@ -1382,11 +1396,7 @@ static int get_http_body(php_stream *stream, int close, char *headers, char **r efree(header); if (!header_length && !header_chunked) { /* Empty response */ - http_buf = emalloc(1); - http_buf[0] = '\0'; - (*response) = http_buf; - (*out_size) = 0; - return TRUE; + return ZSTR_EMPTY_ALLOC(); } } @@ -1404,13 +1414,15 @@ static int get_http_body(php_stream *stream, int close, char *headers, char **r int len_size = 0; if (http_buf_size + buf_size + 1 < 0) { - efree(http_buf); - return FALSE; + if (http_buf) { + zend_string_release(http_buf); + } + return NULL; } - http_buf = erealloc(http_buf, http_buf_size + buf_size + 1); + http_buf = zend_string_realloc(http_buf, http_buf_size + buf_size, 0); while (len_size < buf_size) { - int len_read = php_stream_read(stream, http_buf + http_buf_size, buf_size - len_size); + int len_read = php_stream_read(stream, http_buf->val + http_buf_size, buf_size - len_size); if (len_read <= 0) { /* Error or EOF */ done = TRUE; @@ -1428,17 +1440,17 @@ static int get_http_body(php_stream *stream, int close, char *headers, char **r if (ch != '\n') { /* Somthing wrong in chunked encoding */ if (http_buf) { - efree(http_buf); + zend_string_release(http_buf); } - return FALSE; + return NULL; } } } else { /* Somthing wrong in chunked encoding */ if (http_buf) { - efree(http_buf); + zend_string_release(http_buf); } - return FALSE; + return NULL; } if (buf_size == 0) { done = TRUE; @@ -1459,16 +1471,16 @@ static int get_http_body(php_stream *stream, int close, char *headers, char **r } if (http_buf == NULL) { - http_buf = emalloc(1); + return ZSTR_EMPTY_ALLOC(); } } else if (header_length) { if (header_length < 0 || header_length >= INT_MAX) { - return FALSE; + return NULL; } - http_buf = safe_emalloc(1, header_length, 1); + http_buf = zend_string_alloc(header_length, 0); while (http_buf_size < header_length) { - int len_read = php_stream_read(stream, http_buf + http_buf_size, header_length - http_buf_size); + int len_read = php_stream_read(stream, http_buf->val + http_buf_size, header_length - http_buf_size); if (len_read <= 0) { break; } @@ -1477,20 +1489,19 @@ static int get_http_body(php_stream *stream, int close, char *headers, char **r } else if (header_close) { do { int len_read; - http_buf = erealloc(http_buf, http_buf_size + 4096 + 1); - len_read = php_stream_read(stream, http_buf + http_buf_size, 4096); + http_buf = zend_string_realloc(http_buf, http_buf_size + 4096 + 1, 0); + len_read = php_stream_read(stream, http_buf->val + http_buf_size, 4096); if (len_read > 0) { http_buf_size += len_read; } } while(!php_stream_eof(stream)); } else { - return FALSE; + return NULL; } - http_buf[http_buf_size] = '\0'; - (*response) = http_buf; - (*out_size) = http_buf_size; - return TRUE; + http_buf->val[http_buf_size] = '\0'; + http_buf->len = http_buf_size; + return http_buf; } static zend_string *get_http_headers(php_stream *stream) diff --git a/ext/soap/php_http.h b/ext/soap/php_http.h index a92c7c4e21..00b9fa5643 100644 --- a/ext/soap/php_http.h +++ b/ext/soap/php_http.h @@ -22,13 +22,12 @@ #ifndef PHP_HTTP_H #define PHP_HTTP_H -int make_http_soap_request(zval *this_ptr, - char *request, - int request_size, - char *location, - char *soapaction, - int soap_version, - zval *response); +int make_http_soap_request(zval *this_ptr, + zend_string *request, + char *location, + char *soapaction, + int soap_version, + zval *response); int proxy_authentication(zval* this_ptr, smart_str* soap_headers); int basic_authentication(zval* this_ptr, smart_str* soap_headers); diff --git a/ext/soap/soap.c b/ext/soap/soap.c index d2b1d30ddf..6da617a983 100644 --- a/ext/soap/soap.c +++ b/ext/soap/soap.c @@ -3097,14 +3097,15 @@ PHP_METHOD(SoapClient, __getLastResponseHeaders) SoapClient::__doRequest() */ PHP_METHOD(SoapClient, __doRequest) { - char *buf, *location, *action; - size_t buf_size, location_size, action_size; - zend_long version; - zend_long one_way = 0; - zval *this_ptr = getThis(); - - if (zend_parse_parameters(ZEND_NUM_ARGS(), "sssl|l", - &buf, &buf_size, + zend_string *buf; + char *location, *action; + size_t location_size, action_size; + zend_long version; + zend_long one_way = 0; + zval *this_ptr = getThis(); + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sssl|l", + &buf, &location, &location_size, &action, &action_size, &version, &one_way) == FAILURE) { @@ -3114,10 +3115,10 @@ PHP_METHOD(SoapClient, __doRequest) one_way = 0; } if (one_way) { - if (make_http_soap_request(this_ptr, buf, buf_size, location, action, version, NULL)) { + if (make_http_soap_request(this_ptr, buf, location, action, version, NULL)) { RETURN_EMPTY_STRING(); } - } else if (make_http_soap_request(this_ptr, buf, buf_size, location, action, version, + } else if (make_http_soap_request(this_ptr, buf, location, action, version, return_value)) { return; } |