mirror of
https://github.com/php/php-src.git
synced 2025-08-16 05:58:45 +02:00

The $Id$ keywords were used in Subversion where they can be substituted with filename, last revision number change, last changed date, and last user who changed it. In Git this functionality is different and can be done with Git attribute ident. These need to be defined manually for each file in the .gitattributes file and are afterwards replaced with 40-character hexadecimal blob object name which is based only on the particular file contents. This patch simplifies handling of $Id$ keywords by removing them since they are not used anymore.
1547 lines
50 KiB
C
1547 lines
50 KiB
C
/*
|
|
+----------------------------------------------------------------------+
|
|
| PHP Version 7 |
|
|
+----------------------------------------------------------------------+
|
|
| Copyright (c) 1997-2018 The PHP Group |
|
|
+----------------------------------------------------------------------+
|
|
| This source file is subject to version 3.01 of the PHP license, |
|
|
| that is bundled with this package in the file LICENSE, and is |
|
|
| available through the world-wide-web at the following url: |
|
|
| http://www.php.net/license/3_01.txt |
|
|
| If you did not receive a copy of the PHP license and are unable to |
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
| license@php.net so we can mail you a copy immediately. |
|
|
+----------------------------------------------------------------------+
|
|
| Authors: Brad Lafountain <rodif_bl@yahoo.com> |
|
|
| Shane Caraveo <shane@caraveo.com> |
|
|
| Dmitry Stogov <dmitry@zend.com> |
|
|
+----------------------------------------------------------------------+
|
|
*/
|
|
|
|
#include "php_soap.h"
|
|
#include "ext/standard/base64.h"
|
|
#include "ext/standard/md5.h"
|
|
#include "ext/standard/php_random.h"
|
|
|
|
static char *get_http_header_value(char *headers, char *type);
|
|
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) \
|
|
smart_str_appendl(str,const,sizeof(const)-1)
|
|
|
|
/* Proxy HTTP Authentication */
|
|
int proxy_authentication(zval* this_ptr, smart_str* soap_headers)
|
|
{
|
|
zval *login, *password;
|
|
|
|
if ((login = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "_proxy_login", sizeof("_proxy_login")-1)) != NULL &&
|
|
Z_TYPE_P(login) == IS_STRING) {
|
|
zend_string *buf;
|
|
smart_str auth = {0};
|
|
|
|
smart_str_appendl(&auth, Z_STRVAL_P(login), Z_STRLEN_P(login));
|
|
smart_str_appendc(&auth, ':');
|
|
if ((password = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "_proxy_password", sizeof("_proxy_password")-1)) != NULL &&
|
|
Z_TYPE_P(password) == IS_STRING) {
|
|
smart_str_appendl(&auth, Z_STRVAL_P(password), Z_STRLEN_P(password));
|
|
}
|
|
smart_str_0(&auth);
|
|
buf = php_base64_encode((unsigned char*)ZSTR_VAL(auth.s), ZSTR_LEN(auth.s));
|
|
smart_str_append_const(soap_headers, "Proxy-Authorization: Basic ");
|
|
smart_str_appendl(soap_headers, (char*)ZSTR_VAL(buf), ZSTR_LEN(buf));
|
|
smart_str_append_const(soap_headers, "\r\n");
|
|
zend_string_release_ex(buf, 0);
|
|
smart_str_free(&auth);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* HTTP Authentication */
|
|
int basic_authentication(zval* this_ptr, smart_str* soap_headers)
|
|
{
|
|
zval *login, *password;
|
|
|
|
if ((login = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "_login", sizeof("_login")-1)) != NULL &&
|
|
Z_TYPE_P(login) == IS_STRING &&
|
|
!zend_hash_str_exists(Z_OBJPROP_P(this_ptr), "_digest", sizeof("_digest")-1)) {
|
|
zend_string* buf;
|
|
smart_str auth = {0};
|
|
|
|
smart_str_appendl(&auth, Z_STRVAL_P(login), Z_STRLEN_P(login));
|
|
smart_str_appendc(&auth, ':');
|
|
if ((password = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "_password", sizeof("_password")-1)) != NULL &&
|
|
Z_TYPE_P(password) == IS_STRING) {
|
|
smart_str_appendl(&auth, Z_STRVAL_P(password), Z_STRLEN_P(password));
|
|
}
|
|
smart_str_0(&auth);
|
|
buf = php_base64_encode((unsigned char*)ZSTR_VAL(auth.s), ZSTR_LEN(auth.s));
|
|
smart_str_append_const(soap_headers, "Authorization: Basic ");
|
|
smart_str_appendl(soap_headers, (char*)ZSTR_VAL(buf), ZSTR_LEN(buf));
|
|
smart_str_append_const(soap_headers, "\r\n");
|
|
zend_string_release_ex(buf, 0);
|
|
smart_str_free(&auth);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* Additional HTTP headers */
|
|
void http_context_headers(php_stream_context* context,
|
|
zend_bool has_authorization,
|
|
zend_bool has_proxy_authorization,
|
|
zend_bool has_cookies,
|
|
smart_str* soap_headers)
|
|
{
|
|
zval *tmp;
|
|
|
|
if (context &&
|
|
(tmp = php_stream_context_get_option(context, "http", "header")) != NULL &&
|
|
Z_TYPE_P(tmp) == IS_STRING && Z_STRLEN_P(tmp)) {
|
|
char *s = Z_STRVAL_P(tmp);
|
|
char *p;
|
|
int name_len;
|
|
|
|
while (*s) {
|
|
/* skip leading newlines and spaces */
|
|
while (*s == ' ' || *s == '\t' || *s == '\r' || *s == '\n') {
|
|
s++;
|
|
}
|
|
/* extract header name */
|
|
p = s;
|
|
name_len = -1;
|
|
while (*p) {
|
|
if (*p == ':') {
|
|
if (name_len < 0) name_len = p - s;
|
|
break;
|
|
} else if (*p == ' ' || *p == '\t') {
|
|
if (name_len < 0) name_len = p - s;
|
|
} else if (*p == '\r' || *p == '\n') {
|
|
break;
|
|
}
|
|
p++;
|
|
}
|
|
if (*p == ':') {
|
|
/* extract header value */
|
|
while (*p && *p != '\r' && *p != '\n') {
|
|
p++;
|
|
}
|
|
/* skip some predefined headers */
|
|
if ((name_len != sizeof("host")-1 ||
|
|
strncasecmp(s, "host", sizeof("host")-1) != 0) &&
|
|
(name_len != sizeof("connection")-1 ||
|
|
strncasecmp(s, "connection", sizeof("connection")-1) != 0) &&
|
|
(name_len != sizeof("user-agent")-1 ||
|
|
strncasecmp(s, "user-agent", sizeof("user-agent")-1) != 0) &&
|
|
(name_len != sizeof("content-length")-1 ||
|
|
strncasecmp(s, "content-length", sizeof("content-length")-1) != 0) &&
|
|
(name_len != sizeof("content-type")-1 ||
|
|
strncasecmp(s, "content-type", sizeof("content-type")-1) != 0) &&
|
|
(!has_cookies ||
|
|
name_len != sizeof("cookie")-1 ||
|
|
strncasecmp(s, "cookie", sizeof("cookie")-1) != 0) &&
|
|
(!has_authorization ||
|
|
name_len != sizeof("authorization")-1 ||
|
|
strncasecmp(s, "authorization", sizeof("authorization")-1) != 0) &&
|
|
(!has_proxy_authorization ||
|
|
name_len != sizeof("proxy-authorization")-1 ||
|
|
strncasecmp(s, "proxy-authorization", sizeof("proxy-authorization")-1) != 0)) {
|
|
/* add header */
|
|
smart_str_appendl(soap_headers, s, p-s);
|
|
smart_str_append_const(soap_headers, "\r\n");
|
|
}
|
|
}
|
|
s = (*p) ? (p + 1) : p;
|
|
}
|
|
}
|
|
}
|
|
|
|
static php_stream* http_connect(zval* this_ptr, php_url *phpurl, int use_ssl, php_stream_context *context, int *use_proxy)
|
|
{
|
|
php_stream *stream;
|
|
zval *proxy_host, *proxy_port, *tmp, ssl_proxy_peer_name;
|
|
char *host;
|
|
char *name;
|
|
char *protocol;
|
|
zend_long namelen;
|
|
int port;
|
|
int old_error_reporting;
|
|
struct timeval tv;
|
|
struct timeval *timeout = NULL;
|
|
|
|
if ((proxy_host = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "_proxy_host", sizeof("_proxy_host")-1)) != NULL &&
|
|
Z_TYPE_P(proxy_host) == IS_STRING &&
|
|
(proxy_port = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "_proxy_port", sizeof("_proxy_port")-1)) != NULL &&
|
|
Z_TYPE_P(proxy_port) == IS_LONG) {
|
|
host = Z_STRVAL_P(proxy_host);
|
|
port = Z_LVAL_P(proxy_port);
|
|
*use_proxy = 1;
|
|
} else {
|
|
host = ZSTR_VAL(phpurl->host);
|
|
port = phpurl->port;
|
|
}
|
|
if ((tmp = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "_connection_timeout", sizeof("_connection_timeout")-1)) != NULL &&
|
|
Z_TYPE_P(tmp) == IS_LONG && Z_LVAL_P(tmp) > 0) {
|
|
tv.tv_sec = Z_LVAL_P(tmp);
|
|
tv.tv_usec = 0;
|
|
timeout = &tv;
|
|
}
|
|
|
|
old_error_reporting = EG(error_reporting);
|
|
EG(error_reporting) &= ~(E_WARNING|E_NOTICE|E_USER_WARNING|E_USER_NOTICE);
|
|
|
|
/* Changed ternary operator to an if/else so that additional comparisons can be done on the ssl_method property */
|
|
if (use_ssl && !*use_proxy) {
|
|
if ((tmp = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "_ssl_method", sizeof("_ssl_method")-1)) != NULL &&
|
|
Z_TYPE_P(tmp) == IS_LONG) {
|
|
/* uses constants declared in soap.c to determine ssl uri protocol */
|
|
switch (Z_LVAL_P(tmp)) {
|
|
case SOAP_SSL_METHOD_TLS:
|
|
protocol = "tls";
|
|
break;
|
|
|
|
case SOAP_SSL_METHOD_SSLv2:
|
|
protocol = "sslv2";
|
|
break;
|
|
|
|
case SOAP_SSL_METHOD_SSLv3:
|
|
protocol = "sslv3";
|
|
break;
|
|
|
|
case SOAP_SSL_METHOD_SSLv23:
|
|
protocol = "ssl";
|
|
break;
|
|
|
|
default:
|
|
protocol = "ssl";
|
|
break;
|
|
|
|
}
|
|
} else {
|
|
protocol = "ssl";
|
|
}
|
|
} else {
|
|
protocol = "tcp";
|
|
}
|
|
|
|
namelen = spprintf(&name, 0, "%s://%s:%d", protocol, host, port);
|
|
|
|
stream = php_stream_xport_create(name, namelen,
|
|
REPORT_ERRORS,
|
|
STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT,
|
|
NULL /*persistent_id*/,
|
|
timeout,
|
|
context,
|
|
NULL, NULL);
|
|
efree(name);
|
|
|
|
/* SSL & proxy */
|
|
if (stream && *use_proxy && use_ssl) {
|
|
smart_str soap_headers = {0};
|
|
|
|
/* Set peer_name or name verification will try to use the proxy server name */
|
|
if (!context || (tmp = php_stream_context_get_option(context, "ssl", "peer_name")) == NULL) {
|
|
ZVAL_STR_COPY(&ssl_proxy_peer_name, phpurl->host);
|
|
php_stream_context_set_option(PHP_STREAM_CONTEXT(stream), "ssl", "peer_name", &ssl_proxy_peer_name);
|
|
zval_ptr_dtor(&ssl_proxy_peer_name);
|
|
}
|
|
|
|
smart_str_append_const(&soap_headers, "CONNECT ");
|
|
smart_str_appends(&soap_headers, ZSTR_VAL(phpurl->host));
|
|
smart_str_appendc(&soap_headers, ':');
|
|
smart_str_append_unsigned(&soap_headers, phpurl->port);
|
|
smart_str_append_const(&soap_headers, " HTTP/1.1\r\n");
|
|
smart_str_append_const(&soap_headers, "Host: ");
|
|
smart_str_appends(&soap_headers, ZSTR_VAL(phpurl->host));
|
|
if (phpurl->port != 80) {
|
|
smart_str_appendc(&soap_headers, ':');
|
|
smart_str_append_unsigned(&soap_headers, phpurl->port);
|
|
}
|
|
smart_str_append_const(&soap_headers, "\r\n");
|
|
proxy_authentication(this_ptr, &soap_headers);
|
|
smart_str_append_const(&soap_headers, "\r\n");
|
|
if (php_stream_write(stream, ZSTR_VAL(soap_headers.s), ZSTR_LEN(soap_headers.s)) != ZSTR_LEN(soap_headers.s)) {
|
|
php_stream_close(stream);
|
|
stream = NULL;
|
|
}
|
|
smart_str_free(&soap_headers);
|
|
|
|
if (stream) {
|
|
zend_string *http_headers = get_http_headers(stream);
|
|
if (http_headers) {
|
|
zend_string_free(http_headers);
|
|
} else {
|
|
php_stream_close(stream);
|
|
stream = NULL;
|
|
}
|
|
}
|
|
/* enable SSL transport layer */
|
|
if (stream) {
|
|
/* if a stream is created without encryption, check to see if SSL method parameter is specified and use
|
|
proper encrypyion method based on constants defined in soap.c */
|
|
int crypto_method = STREAM_CRYPTO_METHOD_SSLv23_CLIENT;
|
|
if ((tmp = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "_ssl_method", sizeof("_ssl_method")-1)) != NULL &&
|
|
Z_TYPE_P(tmp) == IS_LONG) {
|
|
switch (Z_LVAL_P(tmp)) {
|
|
case SOAP_SSL_METHOD_TLS:
|
|
crypto_method = STREAM_CRYPTO_METHOD_TLS_CLIENT;
|
|
break;
|
|
|
|
case SOAP_SSL_METHOD_SSLv2:
|
|
crypto_method = STREAM_CRYPTO_METHOD_SSLv2_CLIENT;
|
|
break;
|
|
|
|
case SOAP_SSL_METHOD_SSLv3:
|
|
crypto_method = STREAM_CRYPTO_METHOD_SSLv3_CLIENT;
|
|
break;
|
|
|
|
case SOAP_SSL_METHOD_SSLv23:
|
|
crypto_method = STREAM_CRYPTO_METHOD_SSLv23_CLIENT;
|
|
break;
|
|
|
|
default:
|
|
crypto_method = STREAM_CRYPTO_METHOD_TLS_CLIENT;
|
|
break;
|
|
}
|
|
}
|
|
if (php_stream_xport_crypto_setup(stream, crypto_method, NULL) < 0 ||
|
|
php_stream_xport_crypto_enable(stream, 1) < 0) {
|
|
php_stream_close(stream);
|
|
stream = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
EG(error_reporting) = old_error_reporting;
|
|
return stream;
|
|
}
|
|
|
|
static int in_domain(const char *host, const char *domain)
|
|
{
|
|
if (domain[0] == '.') {
|
|
int l1 = strlen(host);
|
|
int l2 = strlen(domain);
|
|
if (l1 > l2) {
|
|
return strcmp(host+l1-l2,domain) == 0;
|
|
} else {
|
|
return 0;
|
|
}
|
|
} else {
|
|
return strcmp(host,domain) == 0;
|
|
}
|
|
}
|
|
|
|
int make_http_soap_request(zval *this_ptr,
|
|
zend_string *buf,
|
|
char *location,
|
|
char *soapaction,
|
|
int soap_version,
|
|
zval *return_value)
|
|
{
|
|
zend_string *request;
|
|
smart_str soap_headers = {0};
|
|
smart_str soap_headers_z = {0};
|
|
size_t err;
|
|
php_url *phpurl = NULL;
|
|
php_stream *stream;
|
|
zval *trace, *tmp;
|
|
int use_proxy = 0;
|
|
int use_ssl;
|
|
zend_string *http_body;
|
|
char *content_type, *http_version, *cookie_itt;
|
|
int http_close;
|
|
zend_string *http_headers;
|
|
char *connection;
|
|
int http_1_1;
|
|
int http_status;
|
|
int content_type_xml = 0;
|
|
zend_long redirect_max = 20;
|
|
char *content_encoding;
|
|
char *http_msg = NULL;
|
|
zend_bool old_allow_url_fopen;
|
|
php_stream_context *context = NULL;
|
|
zend_bool has_authorization = 0;
|
|
zend_bool has_proxy_authorization = 0;
|
|
zend_bool has_cookies = 0;
|
|
|
|
if (this_ptr == NULL || Z_TYPE_P(this_ptr) != IS_OBJECT) {
|
|
return FALSE;
|
|
}
|
|
|
|
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;
|
|
int kind = Z_LVAL_P(tmp) & SOAP_COMPRESSION_DEFLATE;
|
|
|
|
if (level > 9) {level = 9;}
|
|
|
|
if ((Z_LVAL_P(tmp) & SOAP_COMPRESSION_ACCEPT) != 0) {
|
|
smart_str_append_const(&soap_headers_z,"Accept-Encoding: gzip, deflate\r\n");
|
|
}
|
|
if (level > 0) {
|
|
zval func;
|
|
zval retval;
|
|
zval params[3];
|
|
int n;
|
|
|
|
ZVAL_STR_COPY(¶ms[0], buf);
|
|
ZVAL_LONG(¶ms[1], level);
|
|
if (kind == SOAP_COMPRESSION_DEFLATE) {
|
|
n = 2;
|
|
ZVAL_STRING(&func, "gzcompress");
|
|
smart_str_append_const(&soap_headers_z,"Content-Encoding: deflate\r\n");
|
|
} else {
|
|
n = 3;
|
|
ZVAL_STRING(&func, "gzencode");
|
|
smart_str_append_const(&soap_headers_z,"Content-Encoding: gzip\r\n");
|
|
ZVAL_LONG(¶ms[2], 0x1f);
|
|
}
|
|
if (call_user_function(CG(function_table), (zval*)NULL, &func, &retval, n, params) == SUCCESS &&
|
|
Z_TYPE(retval) == IS_STRING) {
|
|
zval_ptr_dtor(¶ms[0]);
|
|
zval_ptr_dtor(&func);
|
|
request = Z_STR(retval);
|
|
} else {
|
|
zval_ptr_dtor(¶ms[0]);
|
|
zval_ptr_dtor(&func);
|
|
if (request != buf) {
|
|
zend_string_release_ex(request, 0);
|
|
}
|
|
smart_str_free(&soap_headers_z);
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((tmp = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "httpsocket", sizeof("httpsocket")-1)) != NULL) {
|
|
php_stream_from_zval_no_verify(stream,tmp);
|
|
if ((tmp = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "_use_proxy", sizeof("_use_proxy")-1)) != NULL && Z_TYPE_P(tmp) == IS_LONG) {
|
|
use_proxy = Z_LVAL_P(tmp);
|
|
}
|
|
} else {
|
|
stream = NULL;
|
|
}
|
|
|
|
if (location != NULL && location[0] != '\000') {
|
|
phpurl = php_url_parse(location);
|
|
}
|
|
|
|
if (NULL != (tmp = zend_hash_str_find(Z_OBJPROP_P(this_ptr),
|
|
"_stream_context", sizeof("_stream_context")-1))) {
|
|
context = php_stream_context_from_zval(tmp, 0);
|
|
}
|
|
|
|
if (context &&
|
|
(tmp = php_stream_context_get_option(context, "http", "max_redirects")) != NULL) {
|
|
if (Z_TYPE_P(tmp) != IS_STRING || !is_numeric_string(Z_STRVAL_P(tmp), Z_STRLEN_P(tmp), &redirect_max, NULL, 1)) {
|
|
if (Z_TYPE_P(tmp) == IS_LONG)
|
|
redirect_max = Z_LVAL_P(tmp);
|
|
}
|
|
}
|
|
|
|
try_again:
|
|
if (phpurl == NULL || phpurl->host == NULL) {
|
|
if (phpurl != NULL) {php_url_free(phpurl);}
|
|
if (request != buf) {
|
|
zend_string_release_ex(request, 0);
|
|
}
|
|
add_soap_fault(this_ptr, "HTTP", "Unable to parse URL", NULL, NULL);
|
|
smart_str_free(&soap_headers_z);
|
|
return FALSE;
|
|
}
|
|
|
|
use_ssl = 0;
|
|
if (phpurl->scheme != NULL && zend_string_equals_literal(phpurl->scheme, "https")) {
|
|
use_ssl = 1;
|
|
} else if (phpurl->scheme == NULL || !zend_string_equals_literal(phpurl->scheme, "http")) {
|
|
php_url_free(phpurl);
|
|
if (request != buf) {
|
|
zend_string_release_ex(request, 0);
|
|
}
|
|
add_soap_fault(this_ptr, "HTTP", "Unknown protocol. Only http and https are allowed.", NULL, NULL);
|
|
smart_str_free(&soap_headers_z);
|
|
return FALSE;
|
|
}
|
|
|
|
old_allow_url_fopen = PG(allow_url_fopen);
|
|
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) {
|
|
zend_string_release_ex(request, 0);
|
|
}
|
|
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);
|
|
return FALSE;
|
|
}
|
|
|
|
if (phpurl->port == 0) {
|
|
phpurl->port = use_ssl ? 443 : 80;
|
|
}
|
|
|
|
/* Check if request to the same host */
|
|
if (stream != NULL) {
|
|
php_url *orig;
|
|
if ((tmp = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "httpurl", sizeof("httpurl")-1)) != NULL &&
|
|
(orig = (php_url *) zend_fetch_resource_ex(tmp, "httpurl", le_url)) != NULL &&
|
|
((use_proxy && !use_ssl) ||
|
|
(((use_ssl && orig->scheme != NULL && zend_string_equals_literal(orig->scheme, "https")) ||
|
|
(!use_ssl && orig->scheme == NULL) ||
|
|
(!use_ssl && !zend_string_equals_literal(orig->scheme, "https"))) &&
|
|
strcmp(ZSTR_VAL(orig->host), ZSTR_VAL(phpurl->host)) == 0 &&
|
|
orig->port == phpurl->port))) {
|
|
} else {
|
|
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);
|
|
zend_hash_str_del(Z_OBJPROP_P(this_ptr), "_use_proxy", sizeof("_use_proxy")-1);
|
|
stream = NULL;
|
|
use_proxy = 0;
|
|
}
|
|
}
|
|
|
|
/* Check if keep-alive connection is still opened */
|
|
if (stream != NULL && php_stream_eof(stream)) {
|
|
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);
|
|
zend_hash_str_del(Z_OBJPROP_P(this_ptr), "_use_proxy", sizeof("_use_proxy")-1);
|
|
stream = NULL;
|
|
use_proxy = 0;
|
|
}
|
|
|
|
if (!stream) {
|
|
stream = http_connect(this_ptr, phpurl, use_ssl, context, &use_proxy);
|
|
if (stream) {
|
|
php_stream_auto_cleanup(stream);
|
|
add_property_resource(this_ptr, "httpsocket", stream->res);
|
|
GC_ADDREF(stream->res);
|
|
add_property_long(this_ptr, "_use_proxy", use_proxy);
|
|
} else {
|
|
php_url_free(phpurl);
|
|
if (request != buf) {
|
|
zend_string_release_ex(request, 0);
|
|
}
|
|
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);
|
|
return FALSE;
|
|
}
|
|
}
|
|
PG(allow_url_fopen) = old_allow_url_fopen;
|
|
|
|
if (stream) {
|
|
zval *cookies, *login, *password;
|
|
zend_resource *ret = zend_register_resource(phpurl, le_url);
|
|
|
|
add_property_resource(this_ptr, "httpurl", ret);
|
|
GC_ADDREF(ret);
|
|
/*zend_list_addref(ret);*/
|
|
|
|
if (context &&
|
|
(tmp = php_stream_context_get_option(context, "http", "protocol_version")) != NULL &&
|
|
Z_TYPE_P(tmp) == IS_DOUBLE &&
|
|
Z_DVAL_P(tmp) == 1.0) {
|
|
http_1_1 = 0;
|
|
} else {
|
|
http_1_1 = 1;
|
|
}
|
|
|
|
smart_str_append_const(&soap_headers, "POST ");
|
|
if (use_proxy && !use_ssl) {
|
|
smart_str_appends(&soap_headers, ZSTR_VAL(phpurl->scheme));
|
|
smart_str_append_const(&soap_headers, "://");
|
|
smart_str_appends(&soap_headers, ZSTR_VAL(phpurl->host));
|
|
smart_str_appendc(&soap_headers, ':');
|
|
smart_str_append_unsigned(&soap_headers, phpurl->port);
|
|
}
|
|
if (phpurl->path) {
|
|
smart_str_appends(&soap_headers, ZSTR_VAL(phpurl->path));
|
|
} else {
|
|
smart_str_appendc(&soap_headers, '/');
|
|
}
|
|
if (phpurl->query) {
|
|
smart_str_appendc(&soap_headers, '?');
|
|
smart_str_appends(&soap_headers, ZSTR_VAL(phpurl->query));
|
|
}
|
|
if (phpurl->fragment) {
|
|
smart_str_appendc(&soap_headers, '#');
|
|
smart_str_appends(&soap_headers, ZSTR_VAL(phpurl->fragment));
|
|
}
|
|
if (http_1_1) {
|
|
smart_str_append_const(&soap_headers, " HTTP/1.1\r\n");
|
|
} else {
|
|
smart_str_append_const(&soap_headers, " HTTP/1.0\r\n");
|
|
}
|
|
smart_str_append_const(&soap_headers, "Host: ");
|
|
smart_str_appends(&soap_headers, ZSTR_VAL(phpurl->host));
|
|
if (phpurl->port != (use_ssl?443:80)) {
|
|
smart_str_appendc(&soap_headers, ':');
|
|
smart_str_append_unsigned(&soap_headers, phpurl->port);
|
|
}
|
|
if (!http_1_1 ||
|
|
((tmp = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "_keep_alive", sizeof("_keep_alive")-1)) != NULL &&
|
|
(Z_TYPE_P(tmp) == IS_FALSE || (Z_TYPE_P(tmp) == IS_LONG && Z_LVAL_P(tmp) == 0)))) {
|
|
smart_str_append_const(&soap_headers, "\r\n"
|
|
"Connection: close\r\n");
|
|
} else {
|
|
smart_str_append_const(&soap_headers, "\r\n"
|
|
"Connection: Keep-Alive\r\n");
|
|
}
|
|
if ((tmp = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "_user_agent", sizeof("_user_agent")-1)) != NULL &&
|
|
Z_TYPE_P(tmp) == IS_STRING) {
|
|
if (Z_STRLEN_P(tmp) > 0) {
|
|
smart_str_append_const(&soap_headers, "User-Agent: ");
|
|
smart_str_appendl(&soap_headers, Z_STRVAL_P(tmp), Z_STRLEN_P(tmp));
|
|
smart_str_append_const(&soap_headers, "\r\n");
|
|
}
|
|
} else if (context &&
|
|
(tmp = php_stream_context_get_option(context, "http", "user_agent")) != NULL &&
|
|
Z_TYPE_P(tmp) == IS_STRING) {
|
|
if (Z_STRLEN_P(tmp) > 0) {
|
|
smart_str_append_const(&soap_headers, "User-Agent: ");
|
|
smart_str_appendl(&soap_headers, Z_STRVAL_P(tmp), Z_STRLEN_P(tmp));
|
|
smart_str_append_const(&soap_headers, "\r\n");
|
|
}
|
|
} else if (FG(user_agent)) {
|
|
smart_str_append_const(&soap_headers, "User-Agent: ");
|
|
smart_str_appends(&soap_headers, FG(user_agent));
|
|
smart_str_append_const(&soap_headers, "\r\n");
|
|
} else {
|
|
smart_str_append_const(&soap_headers, "User-Agent: PHP-SOAP/"PHP_VERSION"\r\n");
|
|
}
|
|
|
|
smart_str_append_smart_str(&soap_headers, &soap_headers_z);
|
|
|
|
if (soap_version == SOAP_1_2) {
|
|
smart_str_append_const(&soap_headers,"Content-Type: application/soap+xml; charset=utf-8");
|
|
if (soapaction) {
|
|
smart_str_append_const(&soap_headers,"; action=\"");
|
|
smart_str_appends(&soap_headers, soapaction);
|
|
smart_str_append_const(&soap_headers,"\"");
|
|
}
|
|
smart_str_append_const(&soap_headers,"\r\n");
|
|
} else {
|
|
smart_str_append_const(&soap_headers,"Content-Type: text/xml; charset=utf-8\r\n");
|
|
if (soapaction) {
|
|
smart_str_append_const(&soap_headers, "SOAPAction: \"");
|
|
smart_str_appends(&soap_headers, soapaction);
|
|
smart_str_append_const(&soap_headers, "\"\r\n");
|
|
}
|
|
}
|
|
smart_str_append_const(&soap_headers,"Content-Length: ");
|
|
smart_str_append_long(&soap_headers, request->len);
|
|
smart_str_append_const(&soap_headers, "\r\n");
|
|
|
|
/* HTTP Authentication */
|
|
if ((login = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "_login", sizeof("_login")-1)) != NULL &&
|
|
Z_TYPE_P(login) == IS_STRING) {
|
|
zval *digest;
|
|
|
|
has_authorization = 1;
|
|
if ((digest = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "_digest", sizeof("_digest")-1)) != NULL) {
|
|
if (Z_TYPE_P(digest) == IS_ARRAY) {
|
|
char HA1[33], HA2[33], response[33], cnonce[33], nc[9];
|
|
zend_long nonce;
|
|
PHP_MD5_CTX md5ctx;
|
|
unsigned char hash[16];
|
|
|
|
php_random_bytes_throw(&nonce, sizeof(nonce));
|
|
nonce &= 0x7fffffff;
|
|
|
|
PHP_MD5Init(&md5ctx);
|
|
snprintf(cnonce, sizeof(cnonce), ZEND_LONG_FMT, nonce);
|
|
PHP_MD5Update(&md5ctx, (unsigned char*)cnonce, strlen(cnonce));
|
|
PHP_MD5Final(hash, &md5ctx);
|
|
make_digest(cnonce, hash);
|
|
|
|
if ((tmp = zend_hash_str_find(Z_ARRVAL_P(digest), "nc", sizeof("nc")-1)) != NULL &&
|
|
Z_TYPE_P(tmp) == IS_LONG) {
|
|
Z_LVAL_P(tmp)++;
|
|
snprintf(nc, sizeof(nc), "%08" ZEND_LONG_FMT_SPEC, Z_LVAL_P(tmp));
|
|
} else {
|
|
add_assoc_long(digest, "nc", 1);
|
|
strcpy(nc, "00000001");
|
|
}
|
|
|
|
PHP_MD5Init(&md5ctx);
|
|
PHP_MD5Update(&md5ctx, (unsigned char*)Z_STRVAL_P(login), Z_STRLEN_P(login));
|
|
PHP_MD5Update(&md5ctx, (unsigned char*)":", 1);
|
|
if ((tmp = zend_hash_str_find(Z_ARRVAL_P(digest), "realm", sizeof("realm")-1)) != NULL &&
|
|
Z_TYPE_P(tmp) == IS_STRING) {
|
|
PHP_MD5Update(&md5ctx, (unsigned char*)Z_STRVAL_P(tmp), Z_STRLEN_P(tmp));
|
|
}
|
|
PHP_MD5Update(&md5ctx, (unsigned char*)":", 1);
|
|
if ((password = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "_password", sizeof("_password")-1)) != NULL &&
|
|
Z_TYPE_P(password) == IS_STRING) {
|
|
PHP_MD5Update(&md5ctx, (unsigned char*)Z_STRVAL_P(password), Z_STRLEN_P(password));
|
|
}
|
|
PHP_MD5Final(hash, &md5ctx);
|
|
make_digest(HA1, hash);
|
|
if ((tmp = zend_hash_str_find(Z_ARRVAL_P(digest), "algorithm", sizeof("algorithm")-1)) != NULL &&
|
|
Z_TYPE_P(tmp) == IS_STRING &&
|
|
Z_STRLEN_P(tmp) == sizeof("md5-sess")-1 &&
|
|
stricmp(Z_STRVAL_P(tmp), "md5-sess") == 0) {
|
|
PHP_MD5Init(&md5ctx);
|
|
PHP_MD5Update(&md5ctx, (unsigned char*)HA1, 32);
|
|
PHP_MD5Update(&md5ctx, (unsigned char*)":", 1);
|
|
if ((tmp = zend_hash_str_find(Z_ARRVAL_P(digest), "nonce", sizeof("nonce")-1)) != NULL &&
|
|
Z_TYPE_P(tmp) == IS_STRING) {
|
|
PHP_MD5Update(&md5ctx, (unsigned char*)Z_STRVAL_P(tmp), Z_STRLEN_P(tmp));
|
|
}
|
|
PHP_MD5Update(&md5ctx, (unsigned char*)":", 1);
|
|
PHP_MD5Update(&md5ctx, (unsigned char*)cnonce, 8);
|
|
PHP_MD5Final(hash, &md5ctx);
|
|
make_digest(HA1, hash);
|
|
}
|
|
|
|
PHP_MD5Init(&md5ctx);
|
|
PHP_MD5Update(&md5ctx, (unsigned char*)"POST:", sizeof("POST:")-1);
|
|
if (phpurl->path) {
|
|
PHP_MD5Update(&md5ctx, (unsigned char*)ZSTR_VAL(phpurl->path), ZSTR_LEN(phpurl->path));
|
|
} else {
|
|
PHP_MD5Update(&md5ctx, (unsigned char*)"/", 1);
|
|
}
|
|
if (phpurl->query) {
|
|
PHP_MD5Update(&md5ctx, (unsigned char*)"?", 1);
|
|
PHP_MD5Update(&md5ctx, (unsigned char*)ZSTR_VAL(phpurl->query), ZSTR_LEN(phpurl->query));
|
|
}
|
|
|
|
PHP_MD5Final(hash, &md5ctx);
|
|
make_digest(HA2, hash);
|
|
|
|
PHP_MD5Init(&md5ctx);
|
|
PHP_MD5Update(&md5ctx, (unsigned char*)HA1, 32);
|
|
PHP_MD5Update(&md5ctx, (unsigned char*)":", 1);
|
|
if ((tmp = zend_hash_str_find(Z_ARRVAL_P(digest), "nonce", sizeof("nonce")-1)) != NULL &&
|
|
Z_TYPE_P(tmp) == IS_STRING) {
|
|
PHP_MD5Update(&md5ctx, (unsigned char*)Z_STRVAL_P(tmp), Z_STRLEN_P(tmp));
|
|
}
|
|
PHP_MD5Update(&md5ctx, (unsigned char*)":", 1);
|
|
if ((tmp = zend_hash_str_find(Z_ARRVAL_P(digest), "qop", sizeof("qop")-1)) != NULL &&
|
|
Z_TYPE_P(tmp) == IS_STRING) {
|
|
PHP_MD5Update(&md5ctx, (unsigned char*)nc, 8);
|
|
PHP_MD5Update(&md5ctx, (unsigned char*)":", 1);
|
|
PHP_MD5Update(&md5ctx, (unsigned char*)cnonce, 8);
|
|
PHP_MD5Update(&md5ctx, (unsigned char*)":", 1);
|
|
/* TODO: Support for qop="auth-int" */
|
|
PHP_MD5Update(&md5ctx, (unsigned char*)"auth", sizeof("auth")-1);
|
|
PHP_MD5Update(&md5ctx, (unsigned char*)":", 1);
|
|
}
|
|
PHP_MD5Update(&md5ctx, (unsigned char*)HA2, 32);
|
|
PHP_MD5Final(hash, &md5ctx);
|
|
make_digest(response, hash);
|
|
|
|
smart_str_append_const(&soap_headers, "Authorization: Digest username=\"");
|
|
smart_str_appendl(&soap_headers, Z_STRVAL_P(login), Z_STRLEN_P(login));
|
|
if ((tmp = zend_hash_str_find(Z_ARRVAL_P(digest), "realm", sizeof("realm")-1)) != NULL &&
|
|
Z_TYPE_P(tmp) == IS_STRING) {
|
|
smart_str_append_const(&soap_headers, "\", realm=\"");
|
|
smart_str_appendl(&soap_headers, Z_STRVAL_P(tmp), Z_STRLEN_P(tmp));
|
|
}
|
|
if ((tmp = zend_hash_str_find(Z_ARRVAL_P(digest), "nonce", sizeof("nonce")-1)) != NULL &&
|
|
Z_TYPE_P(tmp) == IS_STRING) {
|
|
smart_str_append_const(&soap_headers, "\", nonce=\"");
|
|
smart_str_appendl(&soap_headers, Z_STRVAL_P(tmp), Z_STRLEN_P(tmp));
|
|
}
|
|
smart_str_append_const(&soap_headers, "\", uri=\"");
|
|
if (phpurl->path) {
|
|
smart_str_appends(&soap_headers, ZSTR_VAL(phpurl->path));
|
|
} else {
|
|
smart_str_appendc(&soap_headers, '/');
|
|
}
|
|
if (phpurl->query) {
|
|
smart_str_appendc(&soap_headers, '?');
|
|
smart_str_appends(&soap_headers, ZSTR_VAL(phpurl->query));
|
|
}
|
|
if (phpurl->fragment) {
|
|
smart_str_appendc(&soap_headers, '#');
|
|
smart_str_appends(&soap_headers, ZSTR_VAL(phpurl->fragment));
|
|
}
|
|
if ((tmp = zend_hash_str_find(Z_ARRVAL_P(digest), "qop", sizeof("qop")-1)) != NULL &&
|
|
Z_TYPE_P(tmp) == IS_STRING) {
|
|
/* TODO: Support for qop="auth-int" */
|
|
smart_str_append_const(&soap_headers, "\", qop=\"auth");
|
|
smart_str_append_const(&soap_headers, "\", nc=\"");
|
|
smart_str_appendl(&soap_headers, nc, 8);
|
|
smart_str_append_const(&soap_headers, "\", cnonce=\"");
|
|
smart_str_appendl(&soap_headers, cnonce, 8);
|
|
}
|
|
smart_str_append_const(&soap_headers, "\", response=\"");
|
|
smart_str_appendl(&soap_headers, response, 32);
|
|
if ((tmp = zend_hash_str_find(Z_ARRVAL_P(digest), "opaque", sizeof("opaque")-1)) != NULL &&
|
|
Z_TYPE_P(tmp) == IS_STRING) {
|
|
smart_str_append_const(&soap_headers, "\", opaque=\"");
|
|
smart_str_appendl(&soap_headers, Z_STRVAL_P(tmp), Z_STRLEN_P(tmp));
|
|
}
|
|
if ((tmp = zend_hash_str_find(Z_ARRVAL_P(digest), "algorithm", sizeof("algorithm")-1)) != NULL &&
|
|
Z_TYPE_P(tmp) == IS_STRING) {
|
|
smart_str_append_const(&soap_headers, "\", algorithm=\"");
|
|
smart_str_appendl(&soap_headers, Z_STRVAL_P(tmp), Z_STRLEN_P(tmp));
|
|
}
|
|
smart_str_append_const(&soap_headers, "\"\r\n");
|
|
}
|
|
} else {
|
|
zend_string *buf;
|
|
|
|
smart_str auth = {0};
|
|
smart_str_appendl(&auth, Z_STRVAL_P(login), Z_STRLEN_P(login));
|
|
smart_str_appendc(&auth, ':');
|
|
if ((password = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "_password", sizeof("_password")-1)) != NULL &&
|
|
Z_TYPE_P(password) == IS_STRING) {
|
|
smart_str_appendl(&auth, Z_STRVAL_P(password), Z_STRLEN_P(password));
|
|
}
|
|
smart_str_0(&auth);
|
|
buf = php_base64_encode((unsigned char*)ZSTR_VAL(auth.s), ZSTR_LEN(auth.s));
|
|
smart_str_append_const(&soap_headers, "Authorization: Basic ");
|
|
smart_str_appendl(&soap_headers, (char*)ZSTR_VAL(buf), ZSTR_LEN(buf));
|
|
smart_str_append_const(&soap_headers, "\r\n");
|
|
zend_string_release_ex(buf, 0);
|
|
smart_str_free(&auth);
|
|
}
|
|
}
|
|
|
|
/* Proxy HTTP Authentication */
|
|
if (use_proxy && !use_ssl) {
|
|
has_proxy_authorization = proxy_authentication(this_ptr, &soap_headers);
|
|
}
|
|
|
|
/* Send cookies along with request */
|
|
if ((cookies = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "_cookies", sizeof("_cookies")-1)) != NULL &&
|
|
Z_TYPE_P(cookies) == IS_ARRAY) {
|
|
zval *data;
|
|
zend_string *key;
|
|
int i, n;
|
|
|
|
has_cookies = 1;
|
|
n = zend_hash_num_elements(Z_ARRVAL_P(cookies));
|
|
if (n > 0) {
|
|
zend_hash_internal_pointer_reset(Z_ARRVAL_P(cookies));
|
|
smart_str_append_const(&soap_headers, "Cookie: ");
|
|
for (i = 0; i < n; i++) {
|
|
zend_ulong numindx;
|
|
int res = zend_hash_get_current_key(Z_ARRVAL_P(cookies), &key, &numindx);
|
|
data = zend_hash_get_current_data(Z_ARRVAL_P(cookies));
|
|
|
|
if (res == HASH_KEY_IS_STRING && Z_TYPE_P(data) == IS_ARRAY) {
|
|
zval *value;
|
|
|
|
if ((value = zend_hash_index_find(Z_ARRVAL_P(data), 0)) != NULL &&
|
|
Z_TYPE_P(value) == IS_STRING) {
|
|
zval *tmp;
|
|
if (((tmp = zend_hash_index_find(Z_ARRVAL_P(data), 1)) == NULL ||
|
|
Z_TYPE_P(tmp) != IS_STRING ||
|
|
strncmp(phpurl->path?ZSTR_VAL(phpurl->path):"/",Z_STRVAL_P(tmp),Z_STRLEN_P(tmp)) == 0) &&
|
|
((tmp = zend_hash_index_find(Z_ARRVAL_P(data), 2)) == NULL ||
|
|
Z_TYPE_P(tmp) != IS_STRING ||
|
|
in_domain(ZSTR_VAL(phpurl->host),Z_STRVAL_P(tmp))) &&
|
|
(use_ssl || (tmp = zend_hash_index_find(Z_ARRVAL_P(data), 3)) == NULL)) {
|
|
smart_str_append(&soap_headers, key);
|
|
smart_str_appendc(&soap_headers, '=');
|
|
smart_str_append(&soap_headers, Z_STR_P(value));
|
|
smart_str_appendc(&soap_headers, ';');
|
|
}
|
|
}
|
|
}
|
|
zend_hash_move_forward(Z_ARRVAL_P(cookies));
|
|
}
|
|
smart_str_append_const(&soap_headers, "\r\n");
|
|
}
|
|
}
|
|
|
|
http_context_headers(context, has_authorization, has_proxy_authorization, has_cookies, &soap_headers);
|
|
|
|
smart_str_append_const(&soap_headers, "\r\n");
|
|
smart_str_0(&soap_headers);
|
|
if ((trace = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "trace", sizeof("trace")-1)) != NULL &&
|
|
(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->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) {
|
|
zend_string_release_ex(request, 0);
|
|
}
|
|
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);
|
|
zend_hash_str_del(Z_OBJPROP_P(this_ptr), "_use_proxy", sizeof("_use_proxy")-1);
|
|
add_soap_fault(this_ptr, "HTTP", "Failed Sending HTTP SOAP request", NULL, NULL);
|
|
smart_str_free(&soap_headers_z);
|
|
return FALSE;
|
|
}
|
|
smart_str_free(&soap_headers);
|
|
} else {
|
|
add_soap_fault(this_ptr, "HTTP", "Failed to create stream??", NULL, NULL);
|
|
smart_str_free(&soap_headers_z);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!return_value) {
|
|
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);
|
|
smart_str_free(&soap_headers_z);
|
|
return TRUE;
|
|
}
|
|
|
|
do {
|
|
http_headers = get_http_headers(stream);
|
|
if (!http_headers) {
|
|
if (request != buf) {
|
|
zend_string_release_ex(request, 0);
|
|
}
|
|
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);
|
|
add_soap_fault(this_ptr, "HTTP", "Error Fetching http headers", NULL, NULL);
|
|
smart_str_free(&soap_headers_z);
|
|
return FALSE;
|
|
}
|
|
|
|
if ((trace = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "trace", sizeof("trace")-1)) != NULL &&
|
|
(Z_TYPE_P(trace) == IS_TRUE || (Z_TYPE_P(trace) == IS_LONG && Z_LVAL_P(trace) != 0))) {
|
|
add_property_str(this_ptr, "__last_response_headers", zend_string_copy(http_headers));
|
|
}
|
|
|
|
/* Check to see what HTTP status was sent */
|
|
http_1_1 = 0;
|
|
http_status = 0;
|
|
http_version = get_http_header_value(ZSTR_VAL(http_headers), "HTTP/");
|
|
if (http_version) {
|
|
char *tmp;
|
|
|
|
if (!strncmp(http_version,"1.1", 3)) {
|
|
http_1_1 = 1;
|
|
}
|
|
|
|
tmp = strstr(http_version," ");
|
|
if (tmp != NULL) {
|
|
tmp++;
|
|
http_status = atoi(tmp);
|
|
}
|
|
tmp = strstr(tmp," ");
|
|
if (tmp != NULL) {
|
|
tmp++;
|
|
if (http_msg) {
|
|
efree(http_msg);
|
|
}
|
|
http_msg = estrdup(tmp);
|
|
}
|
|
efree(http_version);
|
|
|
|
/* Try and get headers again */
|
|
if (http_status == 100) {
|
|
zend_string_release_ex(http_headers, 0);
|
|
}
|
|
}
|
|
} while (http_status == 100);
|
|
|
|
/* 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(ZSTR_VAL(http_headers), "Set-Cookie: ");
|
|
while (cookie_itt) {
|
|
char *cookie;
|
|
char *eqpos, *sempos;
|
|
zval *cookies;
|
|
|
|
if ((cookies = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "_cookies", sizeof("_cookies")-1)) == NULL ||
|
|
Z_TYPE_P(cookies) != IS_ARRAY) {
|
|
zval tmp_cookies;
|
|
array_init(&tmp_cookies);
|
|
cookies = zend_hash_str_update(Z_OBJPROP_P(this_ptr), "_cookies", sizeof("_cookies")-1, &tmp_cookies);
|
|
}
|
|
|
|
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);
|
|
|
|
array_init(&zcookie);
|
|
add_index_stringl(&zcookie, 0, eqpos + 1, cookie_len);
|
|
|
|
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?(size_t)(sempos-eqpos):strlen(eqpos));
|
|
} else if (strstr(options,"domain=") == options) {
|
|
eqpos = options + sizeof("domain=")-1;
|
|
add_index_stringl(&zcookie, 2, eqpos, sempos?(size_t)(sempos-eqpos):strlen(eqpos));
|
|
} 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(zcookie), 1)) {
|
|
char *t = phpurl->path?ZSTR_VAL(phpurl->path):"/";
|
|
char *c = strrchr(t, '/');
|
|
if (c) {
|
|
add_index_stringl(&zcookie, 1, t, c-t);
|
|
}
|
|
}
|
|
if (!zend_hash_index_exists(Z_ARRVAL(zcookie), 2)) {
|
|
add_index_str(&zcookie, 2, phpurl->host);
|
|
GC_ADDREF(phpurl->host);
|
|
}
|
|
|
|
zend_symtable_update(Z_ARRVAL_P(cookies), name.s, &zcookie);
|
|
smart_str_free(&name);
|
|
}
|
|
|
|
cookie_itt = strstr(cookie_itt + sizeof("Set-Cookie: "), "Set-Cookie: ");
|
|
efree(cookie);
|
|
}
|
|
|
|
/* See if the server requested a close */
|
|
if (http_1_1) {
|
|
http_close = FALSE;
|
|
if (use_proxy && !use_ssl) {
|
|
connection = get_http_header_value(ZSTR_VAL(http_headers), "Proxy-Connection: ");
|
|
if (connection) {
|
|
if (strncasecmp(connection, "close", sizeof("close")-1) == 0) {
|
|
http_close = TRUE;
|
|
}
|
|
efree(connection);
|
|
}
|
|
}
|
|
if (http_close == FALSE) {
|
|
connection = get_http_header_value(ZSTR_VAL(http_headers), "Connection: ");
|
|
if (connection) {
|
|
if (strncasecmp(connection, "close", sizeof("close")-1) == 0) {
|
|
http_close = TRUE;
|
|
}
|
|
efree(connection);
|
|
}
|
|
}
|
|
} else {
|
|
http_close = TRUE;
|
|
if (use_proxy && !use_ssl) {
|
|
connection = get_http_header_value(ZSTR_VAL(http_headers), "Proxy-Connection: ");
|
|
if (connection) {
|
|
if (strncasecmp(connection, "Keep-Alive", sizeof("Keep-Alive")-1) == 0) {
|
|
http_close = FALSE;
|
|
}
|
|
efree(connection);
|
|
}
|
|
}
|
|
if (http_close == TRUE) {
|
|
connection = get_http_header_value(ZSTR_VAL(http_headers), "Connection: ");
|
|
if (connection) {
|
|
if (strncasecmp(connection, "Keep-Alive", sizeof("Keep-Alive")-1) == 0) {
|
|
http_close = FALSE;
|
|
}
|
|
efree(connection);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
http_body = get_http_body(stream, http_close, ZSTR_VAL(http_headers));
|
|
if (!http_body) {
|
|
if (request != buf) {
|
|
zend_string_release_ex(request, 0);
|
|
}
|
|
php_stream_close(stream);
|
|
zend_string_release_ex(http_headers, 0);
|
|
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);
|
|
add_soap_fault(this_ptr, "HTTP", "Error Fetching http body, No Content-Length, connection closed or chunked data", NULL, NULL);
|
|
if (http_msg) {
|
|
efree(http_msg);
|
|
}
|
|
smart_str_free(&soap_headers_z);
|
|
return FALSE;
|
|
}
|
|
|
|
if (request != buf) {
|
|
zend_string_release_ex(request, 0);
|
|
}
|
|
|
|
if (http_close) {
|
|
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);
|
|
stream = NULL;
|
|
}
|
|
|
|
/* Process HTTP status codes */
|
|
if (http_status >= 300 && http_status < 400) {
|
|
char *loc;
|
|
|
|
if ((loc = get_http_header_value(ZSTR_VAL(http_headers), "Location: ")) != NULL) {
|
|
php_url *new_url = php_url_parse(loc);
|
|
|
|
if (new_url != NULL) {
|
|
zend_string_release_ex(http_headers, 0);
|
|
zend_string_release_ex(http_body, 0);
|
|
efree(loc);
|
|
if (new_url->scheme == NULL && new_url->path != NULL) {
|
|
new_url->scheme = phpurl->scheme ? zend_string_copy(phpurl->scheme) : NULL;
|
|
new_url->host = phpurl->host ? zend_string_copy(phpurl->host) : NULL;
|
|
new_url->port = phpurl->port;
|
|
if (new_url->path && ZSTR_VAL(new_url->path)[0] != '/') {
|
|
if (phpurl->path) {
|
|
char *t = ZSTR_VAL(phpurl->path);
|
|
char *p = strrchr(t, '/');
|
|
if (p) {
|
|
zend_string *s = zend_string_alloc((p - t) + ZSTR_LEN(new_url->path) + 2, 0);
|
|
strncpy(ZSTR_VAL(s), t, (p - t) + 1);
|
|
ZSTR_VAL(s)[(p - t) + 1] = 0;
|
|
strcat(ZSTR_VAL(s), ZSTR_VAL(new_url->path));
|
|
zend_string_release_ex(new_url->path, 0);
|
|
new_url->path = s;
|
|
}
|
|
} else {
|
|
zend_string *s = zend_string_alloc(ZSTR_LEN(new_url->path) + 2, 0);
|
|
ZSTR_VAL(s)[0] = '/';
|
|
ZSTR_VAL(s)[1] = 0;
|
|
strcat(ZSTR_VAL(s), ZSTR_VAL(new_url->path));
|
|
zend_string_release_ex(new_url->path, 0);
|
|
new_url->path = s;
|
|
}
|
|
}
|
|
}
|
|
phpurl = new_url;
|
|
|
|
if (--redirect_max < 1) {
|
|
add_soap_fault(this_ptr, "HTTP", "Redirection limit reached, aborting", NULL, NULL);
|
|
smart_str_free(&soap_headers_z);
|
|
return FALSE;
|
|
}
|
|
|
|
goto try_again;
|
|
}
|
|
}
|
|
} else if (http_status == 401) {
|
|
/* Digest authentication */
|
|
zval *digest, *login, *password;
|
|
char *auth = get_http_header_value(ZSTR_VAL(http_headers), "WWW-Authenticate: ");
|
|
|
|
if (auth &&
|
|
strstr(auth, "Digest") == auth &&
|
|
((digest = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "_digest", sizeof("_digest")-1)) == NULL ||
|
|
Z_TYPE_P(digest) != IS_ARRAY) &&
|
|
(login = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "_login", sizeof("_login")-1)) != NULL &&
|
|
Z_TYPE_P(login) == IS_STRING &&
|
|
(password = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "_password", sizeof("_password")-1)) != NULL &&
|
|
Z_TYPE_P(password) == IS_STRING) {
|
|
char *s;
|
|
zval digest;
|
|
|
|
ZVAL_UNDEF(&digest);
|
|
s = auth + sizeof("Digest")-1;
|
|
while (*s != '\0') {
|
|
char *name, *val;
|
|
while (*s == ' ') ++s;
|
|
name = s;
|
|
while (*s != '\0' && *s != '=') ++s;
|
|
if (*s == '=') {
|
|
*s = '\0';
|
|
++s;
|
|
if (*s == '"') {
|
|
++s;
|
|
val = s;
|
|
while (*s != '\0' && *s != '"') ++s;
|
|
} else {
|
|
val = s;
|
|
while (*s != '\0' && *s != ' ' && *s != ',') ++s;
|
|
}
|
|
if (*s != '\0') {
|
|
if (*s != ',') {
|
|
*s = '\0';
|
|
++s;
|
|
while (*s != '\0' && *s != ',') ++s;
|
|
if (*s != '\0') ++s;
|
|
} else {
|
|
*s = '\0';
|
|
++s;
|
|
}
|
|
}
|
|
if (Z_TYPE(digest) == IS_UNDEF) {
|
|
array_init(&digest);
|
|
}
|
|
add_assoc_string(&digest, name, val);
|
|
}
|
|
}
|
|
|
|
if (Z_TYPE(digest) != IS_UNDEF) {
|
|
php_url *new_url = emalloc(sizeof(php_url));
|
|
|
|
Z_DELREF(digest);
|
|
add_property_zval_ex(this_ptr, "_digest", sizeof("_digest")-1, &digest);
|
|
|
|
*new_url = *phpurl;
|
|
if (phpurl->scheme) phpurl->scheme = zend_string_copy(phpurl->scheme);
|
|
if (phpurl->user) phpurl->user = zend_string_copy(phpurl->user);
|
|
if (phpurl->pass) phpurl->pass = zend_string_copy(phpurl->pass);
|
|
if (phpurl->host) phpurl->host = zend_string_copy(phpurl->host);
|
|
if (phpurl->path) phpurl->path = zend_string_copy(phpurl->path);
|
|
if (phpurl->query) phpurl->query = zend_string_copy(phpurl->query);
|
|
if (phpurl->fragment) phpurl->fragment = zend_string_copy(phpurl->fragment);
|
|
phpurl = new_url;
|
|
|
|
efree(auth);
|
|
zend_string_release_ex(http_headers, 0);
|
|
zend_string_release_ex(http_body, 0);
|
|
|
|
goto try_again;
|
|
}
|
|
}
|
|
if (auth) efree(auth);
|
|
}
|
|
smart_str_free(&soap_headers_z);
|
|
|
|
/* Check and see if the server even sent a xml document */
|
|
content_type = get_http_header_value(ZSTR_VAL(http_headers), "Content-Type: ");
|
|
if (content_type) {
|
|
char *pos = NULL;
|
|
int cmplen;
|
|
pos = strstr(content_type,";");
|
|
if (pos != NULL) {
|
|
cmplen = pos - content_type;
|
|
} else {
|
|
cmplen = strlen(content_type);
|
|
}
|
|
if (strncmp(content_type, "text/xml", cmplen) == 0 ||
|
|
strncmp(content_type, "application/soap+xml", cmplen) == 0) {
|
|
content_type_xml = 1;
|
|
/*
|
|
if (strncmp(http_body, "<?xml", 5)) {
|
|
zval *err;
|
|
MAKE_STD_ZVAL(err);
|
|
ZVAL_STRINGL(err, http_body, http_body_size, 1);
|
|
add_soap_fault(this_ptr, "HTTP", "Didn't receive an xml document", NULL, err);
|
|
efree(content_type);
|
|
zend_string_release_ex(http_headers, 0);
|
|
efree(http_body);
|
|
return FALSE;
|
|
}
|
|
*/
|
|
}
|
|
efree(content_type);
|
|
}
|
|
|
|
/* Decompress response */
|
|
content_encoding = get_http_header_value(ZSTR_VAL(http_headers), "Content-Encoding: ");
|
|
if (content_encoding) {
|
|
zval func;
|
|
zval retval;
|
|
zval params[1];
|
|
|
|
if ((strcmp(content_encoding,"gzip") == 0 ||
|
|
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->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_STR_COPY(¶ms[0], http_body);
|
|
} else {
|
|
efree(content_encoding);
|
|
zend_string_release_ex(http_headers, 0);
|
|
zend_string_release_ex(http_body, 0);
|
|
if (http_msg) {
|
|
efree(http_msg);
|
|
}
|
|
add_soap_fault(this_ptr, "HTTP", "Unknown Content-Encoding", NULL, NULL);
|
|
return FALSE;
|
|
}
|
|
if (call_user_function(CG(function_table), (zval*)NULL, &func, &retval, 1, params) == SUCCESS &&
|
|
Z_TYPE(retval) == IS_STRING) {
|
|
zval_ptr_dtor(¶ms[0]);
|
|
zval_ptr_dtor(&func);
|
|
zend_string_release_ex(http_body, 0);
|
|
ZVAL_COPY_VALUE(return_value, &retval);
|
|
} else {
|
|
zval_ptr_dtor(¶ms[0]);
|
|
zval_ptr_dtor(&func);
|
|
efree(content_encoding);
|
|
zend_string_release_ex(http_headers, 0);
|
|
zend_string_release_ex(http_body, 0);
|
|
add_soap_fault(this_ptr, "HTTP", "Can't uncompress compressed response", NULL, NULL);
|
|
if (http_msg) {
|
|
efree(http_msg);
|
|
}
|
|
return FALSE;
|
|
}
|
|
efree(content_encoding);
|
|
} else {
|
|
ZVAL_STR(return_value, http_body);
|
|
}
|
|
|
|
zend_string_release_ex(http_headers, 0);
|
|
|
|
if (http_status >= 400) {
|
|
int error = 0;
|
|
|
|
if (Z_STRLEN_P(return_value) == 0) {
|
|
error = 1;
|
|
} else if (Z_STRLEN_P(return_value) > 0) {
|
|
if (!content_type_xml) {
|
|
char *s = Z_STRVAL_P(return_value);
|
|
|
|
while (*s != '\0' && *s < ' ') {
|
|
s++;
|
|
}
|
|
if (strncmp(s, "<?xml", 5)) {
|
|
error = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (error) {
|
|
zval_ptr_dtor(return_value);
|
|
ZVAL_UNDEF(return_value);
|
|
add_soap_fault(this_ptr, "HTTP", http_msg, NULL, NULL);
|
|
efree(http_msg);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if (http_msg) {
|
|
efree(http_msg);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static char *get_http_header_value(char *headers, char *type)
|
|
{
|
|
char *pos, *tmp = NULL;
|
|
int typelen, headerslen;
|
|
|
|
typelen = strlen(type);
|
|
headerslen = strlen(headers);
|
|
|
|
/* header `titles' can be lower case, or any case combination, according
|
|
* to the various RFC's. */
|
|
pos = headers;
|
|
do {
|
|
/* start of buffer or start of line */
|
|
if (strncasecmp(pos, type, typelen) == 0) {
|
|
char *eol;
|
|
|
|
/* match */
|
|
tmp = pos + typelen;
|
|
eol = strchr(tmp, '\n');
|
|
if (eol == NULL) {
|
|
eol = headers + headerslen;
|
|
} else if (eol > tmp && *(eol-1) == '\r') {
|
|
eol--;
|
|
}
|
|
return estrndup(tmp, eol - tmp);
|
|
}
|
|
|
|
/* find next line */
|
|
pos = strchr(pos, '\n');
|
|
if (pos) {
|
|
pos++;
|
|
}
|
|
|
|
} while (pos);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static zend_string* get_http_body(php_stream *stream, int close, char *headers)
|
|
{
|
|
zend_string *http_buf = NULL;
|
|
char *header;
|
|
int header_close = close, header_chunked = 0, header_length = 0, http_buf_size = 0;
|
|
|
|
if (!close) {
|
|
header = get_http_header_value(headers, "Connection: ");
|
|
if (header) {
|
|
if(!strncasecmp(header, "close", sizeof("close")-1)) header_close = 1;
|
|
efree(header);
|
|
}
|
|
}
|
|
header = get_http_header_value(headers, "Transfer-Encoding: ");
|
|
if (header) {
|
|
if(!strncasecmp(header, "chunked", sizeof("chunked")-1)) header_chunked = 1;
|
|
efree(header);
|
|
}
|
|
header = get_http_header_value(headers, "Content-Length: ");
|
|
if (header) {
|
|
header_length = atoi(header);
|
|
efree(header);
|
|
if (!header_length && !header_chunked) {
|
|
/* Empty response */
|
|
return ZSTR_EMPTY_ALLOC();
|
|
}
|
|
}
|
|
|
|
if (header_chunked) {
|
|
char ch, done, headerbuf[8192];
|
|
|
|
done = FALSE;
|
|
|
|
while (!done) {
|
|
int buf_size = 0;
|
|
|
|
php_stream_gets(stream, headerbuf, sizeof(headerbuf));
|
|
if (sscanf(headerbuf, "%x", &buf_size) > 0 ) {
|
|
if (buf_size > 0) {
|
|
int len_size = 0;
|
|
|
|
if (http_buf_size + buf_size + 1 < 0) {
|
|
if (http_buf) {
|
|
zend_string_release_ex(http_buf, 0);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
if (http_buf) {
|
|
http_buf = zend_string_realloc(http_buf, http_buf_size + buf_size, 0);
|
|
} else {
|
|
http_buf = zend_string_alloc(buf_size, 0);
|
|
}
|
|
|
|
while (len_size < buf_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;
|
|
break;
|
|
}
|
|
len_size += len_read;
|
|
http_buf_size += len_read;
|
|
}
|
|
|
|
/* Eat up '\r' '\n' */
|
|
ch = php_stream_getc(stream);
|
|
if (ch == '\r') {
|
|
ch = php_stream_getc(stream);
|
|
}
|
|
if (ch != '\n') {
|
|
/* Somthing wrong in chunked encoding */
|
|
if (http_buf) {
|
|
zend_string_release_ex(http_buf, 0);
|
|
}
|
|
return NULL;
|
|
}
|
|
}
|
|
} else {
|
|
/* Somthing wrong in chunked encoding */
|
|
if (http_buf) {
|
|
zend_string_release_ex(http_buf, 0);
|
|
}
|
|
return NULL;
|
|
}
|
|
if (buf_size == 0) {
|
|
done = TRUE;
|
|
}
|
|
}
|
|
|
|
/* Ignore trailer headers */
|
|
while (1) {
|
|
if (!php_stream_gets(stream, headerbuf, sizeof(headerbuf))) {
|
|
break;
|
|
}
|
|
|
|
if ((headerbuf[0] == '\r' && headerbuf[1] == '\n') ||
|
|
(headerbuf[0] == '\n')) {
|
|
/* empty line marks end of headers */
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (http_buf == NULL) {
|
|
return ZSTR_EMPTY_ALLOC();
|
|
}
|
|
|
|
} else if (header_length) {
|
|
if (header_length < 0 || header_length >= INT_MAX) {
|
|
return NULL;
|
|
}
|
|
http_buf = zend_string_alloc(header_length, 0);
|
|
while (http_buf_size < header_length) {
|
|
int len_read = php_stream_read(stream, http_buf->val + http_buf_size, header_length - http_buf_size);
|
|
if (len_read <= 0) {
|
|
break;
|
|
}
|
|
http_buf_size += len_read;
|
|
}
|
|
} else if (header_close) {
|
|
do {
|
|
int len_read;
|
|
if (http_buf) {
|
|
http_buf = zend_string_realloc(http_buf, http_buf_size + 4096, 0);
|
|
} else {
|
|
http_buf = zend_string_alloc(4096, 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 NULL;
|
|
}
|
|
|
|
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)
|
|
{
|
|
smart_str tmp_response = {0};
|
|
char headerbuf[8192];
|
|
|
|
while (php_stream_gets(stream, headerbuf, sizeof(headerbuf))) {
|
|
if ((headerbuf[0] == '\r' && headerbuf[1] == '\n') ||
|
|
(headerbuf[0] == '\n')) {
|
|
/* empty line marks end of headers */
|
|
smart_str_0(&tmp_response);
|
|
return tmp_response.s;
|
|
}
|
|
|
|
/* add header to collection */
|
|
smart_str_appends(&tmp_response, headerbuf);
|
|
}
|
|
|
|
smart_str_free(&tmp_response);
|
|
return NULL;
|
|
}
|
|
/*
|
|
* Local variables:
|
|
* tab-width: 4
|
|
* c-basic-offset: 4
|
|
* End:
|
|
* vim600: sw=4 ts=4 fdm=marker
|
|
* vim<600: sw=4 ts=4
|
|
*/
|