From: Dmitry Stogov Date: Mon, 21 Jun 2004 12:56:33 +0000 (+0000) Subject: Support for HTTP redirection. X-Git-Tag: php-5.0.0~155 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d9226a1dd0e0644334adecbfa9ab4b76969610fa;p=php Support for HTTP redirection. --- diff --git a/ext/soap/php_http.c b/ext/soap/php_http.c index b37d507986..6cc6d01683 100644 --- a/ext/soap/php_http.c +++ b/ext/soap/php_http.c @@ -186,7 +186,14 @@ static int in_domain(const char *host, const char *domain) } } -int send_http_soap_request(zval *this_ptr, char *buf, int buf_size, char *location, char *soapaction, int soap_version TSRMLS_DC) +int make_http_soap_request(zval *this_ptr, + char *buf, + int buf_size, + char *location, + char *soapaction, + int soap_version, + char **buffer, + int *buffer_len TSRMLS_DC) { char *request; smart_str soap_headers = {0}; @@ -196,11 +203,63 @@ int send_http_soap_request(zval *this_ptr, char *buf, int buf_size, char *locati zval **trace, **tmp; int use_proxy = 0; int use_ssl; + char *http_headers, *http_body, *content_type, *http_version, *cookie_itt; + int http_header_size, http_body_size, http_close; + char *connection; + int http_1_1 = 0; + int http_status = 0; + char *content_encoding; if (this_ptr == NULL || Z_TYPE_P(this_ptr) != IS_OBJECT) { return FALSE; } + request = buf; + request_size = buf_size; + /* Compress request */ + if (zend_hash_find(Z_OBJPROP_P(this_ptr), "compression", sizeof("compression"), (void **)&tmp) == SUCCESS && Z_TYPE_PP(tmp) == IS_LONG) { + int level = Z_LVAL_PP(tmp) & 0x0f; + int kind = Z_LVAL_PP(tmp) & SOAP_COMPRESSION_DEFLATE; + + if ((Z_LVAL_PP(tmp) & SOAP_COMPRESSION_ACCEPT) != 0) { + smart_str_append_const(&soap_headers,"Accept-Encoding: gzip, deflate\r\n"); + } + if (level > 0) { + zval func; + zval retval; + zval param1, param2, param3; + zval *params[3]; + int n; + + params[0] = ¶m1; + INIT_PZVAL(params[0]); + params[1] = ¶m2; + INIT_PZVAL(params[1]); + params[2] = ¶m3; + INIT_PZVAL(params[2]); + ZVAL_STRINGL(params[0], buf, buf_size, 0); + ZVAL_LONG(params[1], level); + if (kind == SOAP_COMPRESSION_DEFLATE) { + n = 2; + ZVAL_STRING(&func, "gzcompress", 0); + smart_str_append_const(&soap_headers,"Content-Encoding: deflate\r\n"); + } else { + n = 3; + ZVAL_STRING(&func, "gzencode", 0); + smart_str_append_const(&soap_headers,"Content-Encoding: gzip\r\n"); + ZVAL_LONG(params[2], 1); + } + if (call_user_function(CG(function_table), (zval**)NULL, &func, &retval, n, params TSRMLS_CC) == SUCCESS && + Z_TYPE(retval) == IS_STRING) { + request = Z_STRVAL(retval); + request_size = Z_STRLEN(retval); + } else { + if (request != buf) {efree(request);} + return FALSE; + } + } + } + if (zend_hash_find(Z_OBJPROP_P(this_ptr), "httpsocket", sizeof("httpsocket"), (void **)&tmp) == SUCCESS) { php_stream_from_zval_no_verify(stream,tmp); if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_use_proxy", sizeof("_use_proxy"), (void **)&tmp) == SUCCESS && Z_TYPE_PP(tmp) == IS_LONG) { @@ -213,10 +272,11 @@ int send_http_soap_request(zval *this_ptr, char *buf, int buf_size, char *locati if (location != NULL && location[0] != '\000') { phpurl = php_url_parse(location); } + +try_again: if (phpurl == NULL || phpurl->host == NULL) { - if (phpurl != NULL) { - php_url_free(phpurl); - } + if (phpurl != NULL) {php_url_free(phpurl);} + if (request != buf) {efree(request);} add_soap_fault(this_ptr, "HTTP", "Unable to parse URL", NULL, NULL TSRMLS_CC); return FALSE; } @@ -226,12 +286,14 @@ int send_http_soap_request(zval *this_ptr, char *buf, int buf_size, char *locati use_ssl = 1; } else if (phpurl->scheme == NULL || strcmp(phpurl->scheme, "http") != 0) { php_url_free(phpurl); + if (request != buf) {efree(request);} add_soap_fault(this_ptr, "HTTP", "Unknown protocol. Only http and https are allowed.", NULL, NULL TSRMLS_CC); return FALSE; } #ifdef ZEND_ENGINE_2 if (use_ssl && php_stream_locate_url_wrapper("https://", NULL, STREAM_LOCATE_WRAPPERS_ONLY TSRMLS_CC) == NULL) { php_url_free(phpurl); + if (request != buf) {efree(request);} add_soap_fault(this_ptr, "HTTP", "SSL support not available in this build", NULL, NULL TSRMLS_CC); return FALSE; } @@ -239,6 +301,7 @@ int send_http_soap_request(zval *this_ptr, char *buf, int buf_size, char *locati #ifndef HAVE_OPENSSL_EXT if (use_ssl) { php_url_free(phpurl); + if (request != buf) {efree(request);} add_soap_fault(this_ptr, "HTTP", "SSL support not available in this build", NULL, NULL TSRMLS_CC); return FALSE; } @@ -288,6 +351,7 @@ int send_http_soap_request(zval *this_ptr, char *buf, int buf_size, char *locati add_property_long(this_ptr, "_use_proxy", use_proxy); } else { php_url_free(phpurl); + if (request != buf) {efree(request);} add_soap_fault(this_ptr, "HTTP", "Could not connect to host", NULL, NULL TSRMLS_CC); return FALSE; } @@ -338,59 +402,6 @@ int send_http_soap_request(zval *this_ptr, char *buf, int buf_size, char *locati smart_str_append_const(&soap_headers, "\"\r\n"); } } - - request = buf; - request_size = buf_size; - if (zend_hash_find(Z_OBJPROP_P(this_ptr), "compression", sizeof("compression"), (void **)&tmp) == SUCCESS && Z_TYPE_PP(tmp) == IS_LONG) { - int level = Z_LVAL_PP(tmp) & 0x0f; - int kind = Z_LVAL_PP(tmp) & SOAP_COMPRESSION_DEFLATE; - - if ((Z_LVAL_PP(tmp) & SOAP_COMPRESSION_ACCEPT) != 0) { - smart_str_append_const(&soap_headers,"Accept-Encoding: gzip, deflate\r\n"); - } - if (level > 0) { - zval func; - zval retval; - zval param1, param2, param3; - zval *params[3]; - int n; - - - params[0] = ¶m1; - INIT_PZVAL(params[0]); - params[1] = ¶m2; - INIT_PZVAL(params[1]); - params[2] = ¶m3; - INIT_PZVAL(params[2]); - ZVAL_STRINGL(params[0], buf, buf_size, 0); - ZVAL_LONG(params[1], level); - if (kind == SOAP_COMPRESSION_DEFLATE) { - n = 2; - ZVAL_STRING(&func, "gzcompress", 0); - smart_str_append_const(&soap_headers,"Content-Encoding: deflate\r\n"); - } else { - n = 3; - ZVAL_STRING(&func, "gzencode", 0); - smart_str_append_const(&soap_headers,"Content-Encoding: gzip\r\n"); - ZVAL_LONG(params[2], 1); - /* (SOAP_COMPRESSION_GZIP */ - } - if (call_user_function(CG(function_table), (zval**)NULL, &func, &retval, n, params TSRMLS_CC) == SUCCESS && - Z_TYPE(retval) == IS_STRING) { - request = Z_STRVAL(retval); - request_size = Z_STRLEN(retval); - } else { - if (request != buf) {efree(request);} - smart_str_free(&soap_headers); - php_stream_close(stream); - zend_hash_del(Z_OBJPROP_P(this_ptr), "httpurl", sizeof("httpurl")); - zend_hash_del(Z_OBJPROP_P(this_ptr), "httpsocket", sizeof("httpsocket")); - zend_hash_del(Z_OBJPROP_P(this_ptr), "_use_proxy", sizeof("_use_proxy")); - add_soap_fault(this_ptr, "HTTP", "Compression Failed", NULL, NULL TSRMLS_CC); - return FALSE; - } - } - } smart_str_append_const(&soap_headers,"Content-Length: "); smart_str_append_long(&soap_headers, request_size); smart_str_append_const(&soap_headers, "\r\n"); @@ -480,32 +491,9 @@ int send_http_soap_request(zval *this_ptr, char *buf, int buf_size, char *locati smart_str_free(&soap_headers); } - if (request != buf) {efree(request);} - - return TRUE; -} - -int get_http_soap_response(zval *this_ptr, char **buffer, int *buffer_len TSRMLS_DC) -{ - char *http_headers, *http_body, *content_type, *http_version, *cookie_itt; - int http_header_size, http_body_size, http_close; - php_stream *stream; - zval **trace, **tmp; - char *connection; - int http_1_1 = 0; - int http_status = 0; - char *content_encoding; - - if (zend_hash_find(Z_OBJPROP_P(this_ptr), "httpsocket", sizeof("httpsocket"), (void **)&tmp) == SUCCESS) { - php_stream_from_zval_no_verify(stream,tmp); - } else { - stream = NULL; - } - if (stream == NULL) { - return FALSE; - } if (!get_http_headers(stream, &http_headers, &http_header_size TSRMLS_CC)) { + if (request != buf) {efree(request);} php_stream_close(stream); zend_hash_del(Z_OBJPROP_P(this_ptr), "httpsocket", sizeof("httpsocket")); zend_hash_del(Z_OBJPROP_P(this_ptr), "_use_proxy", sizeof("_use_proxy")); @@ -530,15 +518,47 @@ int get_http_soap_response(zval *this_ptr, char **buffer, int *buffer_len TSRMLS http_status = atoi(tmp); } - /* - Try and process any respsone that is xml might contain fault code - - Maybe try and test for some of the 300's 400's specfics but not - right now. - + /* Process HTTP status codes */ if (http_status >= 200 && http_status < 300) { } else if (http_status >= 300 && http_status < 400) { - add_soap_fault(this_ptr, "HTTP", "HTTTP redirection is not supported", NULL, NULL TSRMLS_CC); + char *loc; + + if ((loc = get_http_header_value(http_headers,"Location: ")) != NULL) { + php_url *new_url = php_url_parse(loc); + char *body; + int body_size; + + if (new_url != NULL) { + if (get_http_body(stream, http_headers, &body, &body_size TSRMLS_CC)) { + efree(body); + } else { + php_stream_close(stream); + zend_hash_del(Z_OBJPROP_P(this_ptr), "httpsocket", sizeof("httpsocket")); + stream = NULL; + } + efree(http_version); + efree(http_headers); + efree(loc); + if (new_url->scheme == NULL && new_url->path != NULL) { + new_url->scheme = estrdup(phpurl->scheme); + new_url->host = estrdup(phpurl->host); + new_url->port = phpurl->port; + if (new_url->path[0] != '/') { + char *p = strrchr(phpurl->path, '/'); + char *s = emalloc((p - phpurl->path) + strlen(new_url->path) + 2); + + strncpy(s, phpurl->path, (p - phpurl->path) + 1); + s[(p - phpurl->path) + 1] = 0; + strcat(s, new_url->path); + efree(new_url->path); + new_url->path = s; + } + } + phpurl = new_url; + goto try_again; + } + } +/* } else if (http_status == 400) { add_soap_fault(this_ptr, "HTTP", "Bad Request", NULL, NULL TSRMLS_CC); } else if (http_status == 401) { @@ -555,13 +575,14 @@ int get_http_soap_response(zval *this_ptr, char **buffer, int *buffer_len TSRMLS add_soap_fault(this_ptr, "HTTP", "Server Error", NULL, NULL TSRMLS_CC); } else { add_soap_fault(this_ptr, "HTTP", "Unsupported HTTP status code", NULL, NULL TSRMLS_CC); +*/ } - */ /* Try and get headers again */ if (http_status == 100) { efree(http_headers); if (!get_http_headers(stream, &http_headers, &http_header_size TSRMLS_CC)) { + if (request != buf) {efree(request);} php_stream_close(stream); zend_hash_del(Z_OBJPROP_P(this_ptr), "httpsocket", sizeof("httpsocket")); zend_hash_del(Z_OBJPROP_P(this_ptr), "_use_proxy", sizeof("_use_proxy")); @@ -576,14 +597,99 @@ int get_http_soap_response(zval *this_ptr, char **buffer, int *buffer_len TSRMLS efree(http_version); } + /* Grab and send back every cookie */ + + /* Not going to worry about Path: because + we shouldn't be changing urls so path dont + matter too much + */ + cookie_itt = strstr(http_headers,"Set-Cookie: "); + while (cookie_itt) { + char *end_pos, *cookie; + char *eqpos, *sempos; + zval **cookies; + + if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_cookies", sizeof("_cookies"), (void **)&cookies) == FAILURE) { + zval *tmp_cookies; + MAKE_STD_ZVAL(tmp_cookies); + array_init(tmp_cookies); + zend_hash_update(Z_OBJPROP_P(this_ptr), "_cookies", sizeof("_cookies"), &tmp_cookies, sizeof(zval *), (void **)&cookies); + } + + end_pos = strstr(cookie_itt,"\r\n"); + cookie = get_http_header_value(cookie_itt,"Set-Cookie: "); + + eqpos = strstr(cookie, "="); + sempos = strstr(cookie, ";"); + if (eqpos != NULL && (sempos == NULL || sempos > eqpos)) { + smart_str name = {0}; + int cookie_len; + zval *zcookie; + + if (sempos != NULL) { + cookie_len = sempos-(eqpos+1); + } else { + cookie_len = strlen(cookie)-(eqpos-cookie)-1; + } + + smart_str_appendl(&name, cookie, eqpos - cookie); + smart_str_0(&name); + + ALLOC_INIT_ZVAL(zcookie); + array_init(zcookie); + add_index_stringl(zcookie, 0, eqpos + 1, cookie_len, 1); + + if (sempos != NULL) { + char *options = cookie + cookie_len+1; + while (*options) { + while (*options == ' ') {options++;} + sempos = strstr(options, ";"); + if (strstr(options,"path=") == options) { + eqpos = options + sizeof("path=")-1; + add_index_stringl(zcookie, 1, eqpos, sempos?(sempos-eqpos):strlen(eqpos), 1); + } else if (strstr(options,"domain=") == options) { + eqpos = options + sizeof("domain=")-1; + add_index_stringl(zcookie, 2, eqpos, sempos?(sempos-eqpos):strlen(eqpos), 1); + } else if (strstr(options,"secure") == options) { + add_index_bool(zcookie, 3, 1); + } + if (sempos != NULL) { + options = sempos+1; + } else { + break; + } + } + } + if (!zend_hash_index_exists(Z_ARRVAL_P(zcookie), 1)) { + char *c = strrchr(phpurl->path, '/'); + if (c) { + add_index_stringl(zcookie, 1, phpurl->path, c-phpurl->path, 1); + } + } + if (!zend_hash_index_exists(Z_ARRVAL_P(zcookie), 2)) { + add_index_string(zcookie, 2, phpurl->host, 1); + } + + add_assoc_zval_ex(*cookies, name.c, name.len+1, zcookie); + smart_str_free(&name); + } + + cookie_itt = strstr(cookie_itt + sizeof("Set-Cookie: "), "Set-Cookie: "); + efree(cookie); + } + if (!get_http_body(stream, http_headers, &http_body, &http_body_size TSRMLS_CC)) { + if (request != buf) {efree(request);} php_stream_close(stream); + efree(http_headers); zend_hash_del(Z_OBJPROP_P(this_ptr), "httpsocket", sizeof("httpsocket")); zend_hash_del(Z_OBJPROP_P(this_ptr), "_use_proxy", sizeof("_use_proxy")); add_soap_fault(this_ptr, "HTTP", "Error Fetching http body, No Content-Length, connection closed or chunked data", NULL, NULL TSRMLS_CC); return FALSE; } + if (request != buf) {efree(request);} + /* See if the server requested a close */ http_close = TRUE; connection = get_http_header_value(http_headers,"Proxy-Connection: "); @@ -644,95 +750,7 @@ int get_http_soap_response(zval *this_ptr, char **buffer, int *buffer_len TSRMLS efree(content_type); } - /* Grab and send back every cookie */ - - /* Not going to worry about Path: because - we shouldn't be changing urls so path dont - matter too much - */ - cookie_itt = strstr(http_headers,"Set-Cookie: "); - if (cookie_itt && - zend_hash_find(Z_OBJPROP_P(this_ptr), "httpurl", sizeof("httpurl"), (void **)&tmp) == SUCCESS) { - - php_url *phpurl = (php_url*)zend_fetch_resource(tmp TSRMLS_CC, -1, "httpurl", NULL, 1, le_url); - - if (phpurl) { - while (cookie_itt) { - char *end_pos, *cookie; - char *eqpos, *sempos; - zval **cookies; - - if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_cookies", sizeof("_cookies"), (void **)&cookies) == FAILURE) { - zval *tmp_cookies; - MAKE_STD_ZVAL(tmp_cookies); - array_init(tmp_cookies); - zend_hash_update(Z_OBJPROP_P(this_ptr), "_cookies", sizeof("_cookies"), &tmp_cookies, sizeof(zval *), (void **)&cookies); - } - - end_pos = strstr(cookie_itt,"\r\n"); - cookie = get_http_header_value(cookie_itt,"Set-Cookie: "); - - eqpos = strstr(cookie, "="); - sempos = strstr(cookie, ";"); - if (eqpos != NULL && (sempos == NULL || sempos > eqpos)) { - smart_str name = {0}; - int cookie_len; - zval *zcookie; - - if (sempos != NULL) { - cookie_len = sempos-(eqpos+1); - } else { - cookie_len = strlen(cookie)-(eqpos-cookie)-1; - } - - smart_str_appendl(&name, cookie, eqpos - cookie); - smart_str_0(&name); - - ALLOC_INIT_ZVAL(zcookie); - array_init(zcookie); - add_index_stringl(zcookie, 0, eqpos + 1, cookie_len, 1); - - if (sempos != NULL) { - char *options = cookie + cookie_len+1; - while (*options) { - while (*options == ' ') {options++;} - sempos = strstr(options, ";"); - if (strstr(options,"path=") == options) { - eqpos = options + sizeof("path=")-1; - add_index_stringl(zcookie, 1, eqpos, sempos?(sempos-eqpos):strlen(eqpos), 1); - } else if (strstr(options,"domain=") == options) { - eqpos = options + sizeof("domain=")-1; - add_index_stringl(zcookie, 2, eqpos, sempos?(sempos-eqpos):strlen(eqpos), 1); - } else if (strstr(options,"secure") == options) { - add_index_bool(zcookie, 3, 1); - } - if (sempos != NULL) { - options = sempos+1; - } else { - break; - } - } - } - if (!zend_hash_index_exists(Z_ARRVAL_P(zcookie), 1)) { - char *c = strrchr(phpurl->path, '/'); - if (c) { - add_index_stringl(zcookie, 1, phpurl->path, c-phpurl->path, 1); - } - } - if (!zend_hash_index_exists(Z_ARRVAL_P(zcookie), 2)) { - add_index_string(zcookie, 2, phpurl->host, 1); - } - - add_assoc_zval_ex(*cookies, name.c, name.len+1, zcookie); - smart_str_free(&name); - } - - cookie_itt = strstr(cookie_itt + sizeof("Set-Cookie: "), "Set-Cookie: "); - efree(cookie); - } - } - } - + /* Decompress response */ content_encoding = get_http_header_value(http_headers,"Content-Encoding: "); if (content_encoding) { zval func; diff --git a/ext/soap/php_http.h b/ext/soap/php_http.h index 5aede13270..fc055a144a 100644 --- a/ext/soap/php_http.h +++ b/ext/soap/php_http.h @@ -22,7 +22,13 @@ #ifndef PHP_HTTP_H #define PHP_HTTP_H -int send_http_soap_request(zval *this_ptr, char *request, int request_size, char *location, char *soapaction, int soap_version TSRMLS_DC); -int get_http_soap_response(zval *this_ptr, char **buffer, int *buffer_len TSRMLS_DC); +int make_http_soap_request(zval *this_ptr, + char *request, + int request_size, + char *location, + char *soapaction, + int soap_version, + char **response, + int *response_len TSRMLS_DC); #endif diff --git a/ext/soap/soap.c b/ext/soap/soap.c index 964b354ed4..0d9aa39406 100644 --- a/ext/soap/soap.c +++ b/ext/soap/soap.c @@ -2299,11 +2299,10 @@ PHP_METHOD(SoapClient, __doRequest) &version) == FAILURE) { php_error_docref(NULL TSRMLS_CC, E_ERROR, "wrong parameters"); } - if (send_http_soap_request(this_ptr, buf, buf_size, location, action, version TSRMLS_CC)) { - if (get_http_soap_response(this_ptr, &Z_STRVAL_P(return_value), &Z_STRLEN_P(return_value) TSRMLS_CC)) { - return_value->type = IS_STRING; - return; - } + if (make_http_soap_request(this_ptr, buf, buf_size, location, action, version, + &Z_STRVAL_P(return_value), &Z_STRLEN_P(return_value) TSRMLS_CC)) { + return_value->type = IS_STRING; + return; } RETURN_NULL(); }