1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 5 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1997-2009 The PHP Group |
6 : +----------------------------------------------------------------------+
7 : | This source file is subject to version 3.01 of the PHP license, |
8 : | that is bundled with this package in the file LICENSE, and is |
9 : | available through the world-wide-web at the following url: |
10 : | http://www.php.net/license/3_01.txt |
11 : | If you did not receive a copy of the PHP license and are unable to |
12 : | obtain it through the world-wide-web, please send a note to |
13 : | license@php.net so we can mail you a copy immediately. |
14 : +----------------------------------------------------------------------+
15 : | Authors: Brad Lafountain <rodif_bl@yahoo.com> |
16 : | Shane Caraveo <shane@caraveo.com> |
17 : | Dmitry Stogov <dmitry@zend.com> |
18 : +----------------------------------------------------------------------+
19 : */
20 : /* $Id: php_http.c 281589 2009-06-03 12:39:50Z iliaa $ */
21 :
22 : #include "php_soap.h"
23 : #include "ext/standard/base64.h"
24 : #include "ext/standard/md5.h"
25 : #include "ext/standard/php_rand.h"
26 :
27 : static char *get_http_header_value(char *headers, char *type);
28 : static int get_http_body(php_stream *socketd, int close, char *headers, char **response, int *out_size TSRMLS_DC);
29 : static int get_http_headers(php_stream *socketd,char **response, int *out_size TSRMLS_DC);
30 :
31 : #define smart_str_append_const(str, const) \
32 : smart_str_appendl(str,const,sizeof(const)-1)
33 :
34 : /* Proxy HTTP Authentication */
35 : void proxy_authentication(zval* this_ptr, smart_str* soap_headers TSRMLS_DC)
36 0 : {
37 : zval **login, **password;
38 :
39 0 : if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_proxy_login", sizeof("_proxy_login"), (void **)&login) == SUCCESS) {
40 : unsigned char* buf;
41 : int len;
42 0 : smart_str auth = {0};
43 :
44 0 : smart_str_appendl(&auth, Z_STRVAL_PP(login), Z_STRLEN_PP(login));
45 0 : smart_str_appendc(&auth, ':');
46 0 : if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_proxy_password", sizeof("_proxy_password"), (void **)&password) == SUCCESS) {
47 0 : smart_str_appendl(&auth, Z_STRVAL_PP(password), Z_STRLEN_PP(password));
48 : }
49 0 : smart_str_0(&auth);
50 0 : buf = php_base64_encode((unsigned char*)auth.c, auth.len, &len);
51 0 : smart_str_append_const(soap_headers, "Proxy-Authorization: Basic ");
52 0 : smart_str_appendl(soap_headers, (char*)buf, len);
53 0 : smart_str_append_const(soap_headers, "\r\n");
54 0 : efree(buf);
55 0 : smart_str_free(&auth);
56 : }
57 0 : }
58 :
59 : /* HTTP Authentication */
60 : void basic_authentication(zval* this_ptr, smart_str* soap_headers TSRMLS_DC)
61 697 : {
62 : zval **login, **password;
63 :
64 697 : if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_login", sizeof("_login"), (void **)&login) == SUCCESS &&
65 : !zend_hash_exists(Z_OBJPROP_P(this_ptr), "_digest", sizeof("_digest"))) {
66 : unsigned char* buf;
67 : int len;
68 0 : smart_str auth = {0};
69 :
70 0 : smart_str_appendl(&auth, Z_STRVAL_PP(login), Z_STRLEN_PP(login));
71 0 : smart_str_appendc(&auth, ':');
72 0 : if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_password", sizeof("_password"), (void **)&password) == SUCCESS) {
73 0 : smart_str_appendl(&auth, Z_STRVAL_PP(password), Z_STRLEN_PP(password));
74 : }
75 0 : smart_str_0(&auth);
76 0 : buf = php_base64_encode((unsigned char*)auth.c, auth.len, &len);
77 0 : smart_str_append_const(soap_headers, "Authorization: Basic ");
78 0 : smart_str_appendl(soap_headers, (char*)buf, len);
79 0 : smart_str_append_const(soap_headers, "\r\n");
80 0 : efree(buf);
81 0 : smart_str_free(&auth);
82 : }
83 697 : }
84 :
85 : static php_stream* http_connect(zval* this_ptr, php_url *phpurl, int use_ssl, php_stream_context *context, int *use_proxy TSRMLS_DC)
86 1 : {
87 : php_stream *stream;
88 : zval **proxy_host, **proxy_port, **tmp;
89 : char *host;
90 : char *name;
91 : long namelen;
92 : int port;
93 : int old_error_reporting;
94 : struct timeval tv;
95 1 : struct timeval *timeout = NULL;
96 :
97 1 : if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_proxy_host", sizeof("_proxy_host"), (void **) &proxy_host) == SUCCESS &&
98 : Z_TYPE_PP(proxy_host) == IS_STRING &&
99 : zend_hash_find(Z_OBJPROP_P(this_ptr), "_proxy_port", sizeof("_proxy_port"), (void **) &proxy_port) == SUCCESS &&
100 : Z_TYPE_PP(proxy_port) == IS_LONG) {
101 0 : host = Z_STRVAL_PP(proxy_host);
102 0 : port = Z_LVAL_PP(proxy_port);
103 0 : *use_proxy = 1;
104 : } else {
105 1 : host = phpurl->host;
106 1 : port = phpurl->port;
107 : }
108 1 : if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_connection_timeout", sizeof("_connection_timeout"), (void **) &tmp) == SUCCESS &&
109 : Z_TYPE_PP(tmp) == IS_LONG && Z_LVAL_PP(tmp) > 0) {
110 0 : tv.tv_sec = Z_LVAL_PP(tmp);
111 0 : tv.tv_usec = 0;
112 0 : timeout = &tv;
113 : }
114 :
115 1 : old_error_reporting = EG(error_reporting);
116 1 : EG(error_reporting) &= ~(E_WARNING|E_NOTICE|E_USER_WARNING|E_USER_NOTICE);
117 :
118 1 : namelen = spprintf(&name, 0, "%s://%s:%d", (use_ssl && !*use_proxy)? "ssl" : "tcp", host, port);
119 :
120 1 : stream = php_stream_xport_create(name, namelen,
121 : ENFORCE_SAFE_MODE | REPORT_ERRORS,
122 : STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT,
123 : NULL /*persistent_id*/,
124 : timeout,
125 : context,
126 : NULL, NULL);
127 1 : efree(name);
128 :
129 : /* SSL & proxy */
130 1 : if (stream && *use_proxy && use_ssl) {
131 0 : smart_str soap_headers = {0};
132 : char *http_headers;
133 : int http_header_size;
134 :
135 0 : smart_str_append_const(&soap_headers, "CONNECT ");
136 0 : smart_str_appends(&soap_headers, phpurl->host);
137 0 : smart_str_appendc(&soap_headers, ':');
138 0 : smart_str_append_unsigned(&soap_headers, phpurl->port);
139 0 : smart_str_append_const(&soap_headers, " HTTP/1.1\r\n");
140 0 : proxy_authentication(this_ptr, &soap_headers TSRMLS_CC);
141 0 : smart_str_append_const(&soap_headers, "\r\n");
142 0 : if (php_stream_write(stream, soap_headers.c, soap_headers.len) != soap_headers.len) {
143 0 : php_stream_close(stream);
144 0 : stream = NULL;
145 : }
146 0 : smart_str_free(&soap_headers);
147 :
148 0 : if (stream) {
149 0 : if (!get_http_headers(stream, &http_headers, &http_header_size TSRMLS_CC) || http_headers == NULL) {
150 0 : php_stream_close(stream);
151 0 : stream = NULL;
152 : }
153 0 : if (http_headers) {
154 0 : efree(http_headers);
155 : }
156 : }
157 : /* enable SSL transport layer */
158 0 : if (stream) {
159 0 : if (php_stream_xport_crypto_setup(stream, STREAM_CRYPTO_METHOD_SSLv23_CLIENT, NULL TSRMLS_CC) < 0 ||
160 : php_stream_xport_crypto_enable(stream, 1 TSRMLS_CC) < 0) {
161 0 : php_stream_close(stream);
162 0 : stream = NULL;
163 : }
164 : }
165 : }
166 :
167 1 : EG(error_reporting) = old_error_reporting;
168 1 : return stream;
169 : }
170 :
171 : static int in_domain(const char *host, const char *domain)
172 0 : {
173 0 : if (domain[0] == '.') {
174 0 : int l1 = strlen(host);
175 0 : int l2 = strlen(domain);
176 0 : if (l1 > l2) {
177 0 : return strcmp(host+l1-l2,domain) == 0;
178 : } else {
179 0 : return 0;
180 : }
181 : } else {
182 0 : return strcmp(host,domain) == 0;
183 : }
184 : }
185 :
186 : int make_http_soap_request(zval *this_ptr,
187 : char *buf,
188 : int buf_size,
189 : char *location,
190 : char *soapaction,
191 : int soap_version,
192 : char **buffer,
193 : int *buffer_len TSRMLS_DC)
194 316 : {
195 : char *request;
196 316 : smart_str soap_headers = {0};
197 316 : smart_str soap_headers_z = {0};
198 : int request_size, err;
199 316 : php_url *phpurl = NULL;
200 : php_stream *stream;
201 : zval **trace, **tmp;
202 316 : int use_proxy = 0;
203 : int use_ssl;
204 : char *http_headers, *http_body, *content_type, *http_version, *cookie_itt;
205 : int http_header_size, http_body_size, http_close;
206 : char *connection;
207 : int http_1_1;
208 : int http_status;
209 316 : int content_type_xml = 0;
210 : char *content_encoding;
211 316 : char *http_msg = NULL;
212 : zend_bool old_allow_url_fopen;
213 316 : php_stream_context *context = NULL;
214 :
215 316 : if (this_ptr == NULL || Z_TYPE_P(this_ptr) != IS_OBJECT) {
216 0 : return FALSE;
217 : }
218 :
219 316 : request = buf;
220 316 : request_size = buf_size;
221 : /* Compress request */
222 316 : if (zend_hash_find(Z_OBJPROP_P(this_ptr), "compression", sizeof("compression"), (void **)&tmp) == SUCCESS && Z_TYPE_PP(tmp) == IS_LONG) {
223 0 : int level = Z_LVAL_PP(tmp) & 0x0f;
224 0 : int kind = Z_LVAL_PP(tmp) & SOAP_COMPRESSION_DEFLATE;
225 :
226 0 : if (level > 9) {level = 9;}
227 :
228 0 : if ((Z_LVAL_PP(tmp) & SOAP_COMPRESSION_ACCEPT) != 0) {
229 0 : smart_str_append_const(&soap_headers_z,"Accept-Encoding: gzip, deflate\r\n");
230 : }
231 0 : if (level > 0) {
232 : zval func;
233 : zval retval;
234 : zval param1, param2, param3;
235 : zval *params[3];
236 : int n;
237 :
238 0 : params[0] = ¶m1;
239 0 : INIT_PZVAL(params[0]);
240 0 : params[1] = ¶m2;
241 0 : INIT_PZVAL(params[1]);
242 0 : params[2] = ¶m3;
243 0 : INIT_PZVAL(params[2]);
244 0 : ZVAL_STRINGL(params[0], buf, buf_size, 0);
245 0 : ZVAL_LONG(params[1], level);
246 0 : if (kind == SOAP_COMPRESSION_DEFLATE) {
247 0 : n = 2;
248 0 : ZVAL_STRING(&func, "gzcompress", 0);
249 0 : smart_str_append_const(&soap_headers_z,"Content-Encoding: deflate\r\n");
250 : } else {
251 0 : n = 3;
252 0 : ZVAL_STRING(&func, "gzencode", 0);
253 0 : smart_str_append_const(&soap_headers_z,"Content-Encoding: gzip\r\n");
254 0 : ZVAL_LONG(params[2], 1);
255 : }
256 0 : if (call_user_function(CG(function_table), (zval**)NULL, &func, &retval, n, params TSRMLS_CC) == SUCCESS &&
257 : Z_TYPE(retval) == IS_STRING) {
258 0 : request = Z_STRVAL(retval);
259 0 : request_size = Z_STRLEN(retval);
260 : } else {
261 0 : if (request != buf) {efree(request);}
262 0 : smart_str_free(&soap_headers_z);
263 0 : return FALSE;
264 : }
265 : }
266 : }
267 :
268 316 : if (zend_hash_find(Z_OBJPROP_P(this_ptr), "httpsocket", sizeof("httpsocket"), (void **)&tmp) == SUCCESS) {
269 0 : php_stream_from_zval_no_verify(stream,tmp);
270 0 : if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_use_proxy", sizeof("_use_proxy"), (void **)&tmp) == SUCCESS && Z_TYPE_PP(tmp) == IS_LONG) {
271 0 : use_proxy = Z_LVAL_PP(tmp);
272 : }
273 : } else {
274 316 : stream = NULL;
275 : }
276 :
277 316 : if (location != NULL && location[0] != '\000') {
278 316 : phpurl = php_url_parse(location);
279 : }
280 :
281 316 : if (SUCCESS == zend_hash_find(Z_OBJPROP_P(this_ptr),
282 : "_stream_context", sizeof("_stream_context"), (void**)&tmp)) {
283 1 : context = php_stream_context_from_zval(*tmp, 0);
284 : }
285 :
286 316 : try_again:
287 316 : if (phpurl == NULL || phpurl->host == NULL) {
288 315 : if (phpurl != NULL) {php_url_free(phpurl);}
289 315 : if (request != buf) {efree(request);}
290 315 : add_soap_fault(this_ptr, "HTTP", "Unable to parse URL", NULL, NULL TSRMLS_CC);
291 315 : smart_str_free(&soap_headers_z);
292 315 : return FALSE;
293 : }
294 :
295 1 : use_ssl = 0;
296 1 : if (phpurl->scheme != NULL && strcmp(phpurl->scheme, "https") == 0) {
297 0 : use_ssl = 1;
298 1 : } else if (phpurl->scheme == NULL || strcmp(phpurl->scheme, "http") != 0) {
299 0 : php_url_free(phpurl);
300 0 : if (request != buf) {efree(request);}
301 0 : add_soap_fault(this_ptr, "HTTP", "Unknown protocol. Only http and https are allowed.", NULL, NULL TSRMLS_CC);
302 0 : smart_str_free(&soap_headers_z);
303 0 : return FALSE;
304 : }
305 :
306 1 : old_allow_url_fopen = PG(allow_url_fopen);
307 1 : PG(allow_url_fopen) = 1;
308 1 : if (use_ssl && php_stream_locate_url_wrapper("https://", NULL, STREAM_LOCATE_WRAPPERS_ONLY TSRMLS_CC) == NULL) {
309 0 : php_url_free(phpurl);
310 0 : if (request != buf) {efree(request);}
311 0 : add_soap_fault(this_ptr, "HTTP", "SSL support is not available in this build", NULL, NULL TSRMLS_CC);
312 0 : PG(allow_url_fopen) = old_allow_url_fopen;
313 0 : smart_str_free(&soap_headers_z);
314 0 : return FALSE;
315 : }
316 :
317 1 : if (phpurl->port == 0) {
318 1 : phpurl->port = use_ssl ? 443 : 80;
319 : }
320 :
321 : /* Check if request to the same host */
322 1 : if (stream != NULL) {
323 : php_url *orig;
324 0 : if (zend_hash_find(Z_OBJPROP_P(this_ptr), "httpurl", sizeof("httpurl"), (void **)&tmp) == SUCCESS &&
325 : (orig = (php_url *) zend_fetch_resource(tmp TSRMLS_CC, -1, "httpurl", NULL, 1, le_url)) != NULL &&
326 : ((use_proxy && !use_ssl) ||
327 : (((use_ssl && orig->scheme != NULL && strcmp(orig->scheme, "https") == 0) ||
328 : (!use_ssl && orig->scheme == NULL) ||
329 : (!use_ssl && strcmp(orig->scheme, "https") != 0)) &&
330 : strcmp(orig->host, phpurl->host) == 0 &&
331 : orig->port == phpurl->port))) {
332 : } else {
333 0 : php_stream_close(stream);
334 0 : zend_hash_del(Z_OBJPROP_P(this_ptr), "httpurl", sizeof("httpurl"));
335 0 : zend_hash_del(Z_OBJPROP_P(this_ptr), "httpsocket", sizeof("httpsocket"));
336 0 : zend_hash_del(Z_OBJPROP_P(this_ptr), "_use_proxy", sizeof("_use_proxy"));
337 0 : stream = NULL;
338 0 : use_proxy = 0;
339 : }
340 : }
341 :
342 : /* Check if keep-alive connection is still opened */
343 1 : if (stream != NULL && php_stream_eof(stream)) {
344 0 : php_stream_close(stream);
345 0 : zend_hash_del(Z_OBJPROP_P(this_ptr), "httpurl", sizeof("httpurl"));
346 0 : zend_hash_del(Z_OBJPROP_P(this_ptr), "httpsocket", sizeof("httpsocket"));
347 0 : zend_hash_del(Z_OBJPROP_P(this_ptr), "_use_proxy", sizeof("_use_proxy"));
348 0 : stream = NULL;
349 0 : use_proxy = 0;
350 : }
351 :
352 1 : if (!stream) {
353 1 : stream = http_connect(this_ptr, phpurl, use_ssl, context, &use_proxy TSRMLS_CC);
354 1 : if (stream) {
355 : php_stream_auto_cleanup(stream);
356 1 : add_property_resource(this_ptr, "httpsocket", php_stream_get_resource_id(stream));
357 1 : add_property_long(this_ptr, "_use_proxy", use_proxy);
358 : } else {
359 0 : php_url_free(phpurl);
360 0 : if (request != buf) {efree(request);}
361 0 : add_soap_fault(this_ptr, "HTTP", "Could not connect to host", NULL, NULL TSRMLS_CC);
362 0 : PG(allow_url_fopen) = old_allow_url_fopen;
363 0 : smart_str_free(&soap_headers_z);
364 0 : return FALSE;
365 : }
366 : }
367 1 : PG(allow_url_fopen) = old_allow_url_fopen;
368 :
369 1 : if (stream) {
370 : zval **cookies, **login, **password;
371 1 : int ret = zend_list_insert(phpurl, le_url);
372 :
373 1 : add_property_resource(this_ptr, "httpurl", ret);
374 : /*zend_list_addref(ret);*/
375 :
376 1 : if (context &&
377 : php_stream_context_get_option(context, "http", "protocol_version", &tmp) == SUCCESS &&
378 : Z_TYPE_PP(tmp) == IS_DOUBLE &&
379 : Z_DVAL_PP(tmp) == 1.0) {
380 0 : http_1_1 = 0;
381 : } else {
382 1 : http_1_1 = 1;
383 : }
384 :
385 1 : smart_str_append_const(&soap_headers, "POST ");
386 1 : if (use_proxy && !use_ssl) {
387 0 : smart_str_appends(&soap_headers, phpurl->scheme);
388 0 : smart_str_append_const(&soap_headers, "://");
389 0 : smart_str_appends(&soap_headers, phpurl->host);
390 0 : smart_str_appendc(&soap_headers, ':');
391 0 : smart_str_append_unsigned(&soap_headers, phpurl->port);
392 : }
393 1 : if (phpurl->path) {
394 0 : smart_str_appends(&soap_headers, phpurl->path);
395 : } else {
396 1 : smart_str_appendc(&soap_headers, '/');
397 : }
398 1 : if (phpurl->query) {
399 0 : smart_str_appendc(&soap_headers, '?');
400 0 : smart_str_appends(&soap_headers, phpurl->query);
401 : }
402 1 : if (phpurl->fragment) {
403 0 : smart_str_appendc(&soap_headers, '#');
404 0 : smart_str_appends(&soap_headers, phpurl->fragment);
405 : }
406 1 : if (http_1_1) {
407 1 : smart_str_append_const(&soap_headers, " HTTP/1.1\r\n");
408 : } else {
409 0 : smart_str_append_const(&soap_headers, " HTTP/1.0\r\n");
410 : }
411 1 : smart_str_append_const(&soap_headers, "Host: ");
412 1 : smart_str_appends(&soap_headers, phpurl->host);
413 1 : if (phpurl->port != (use_ssl?443:80)) {
414 0 : smart_str_appendc(&soap_headers, ':');
415 0 : smart_str_append_unsigned(&soap_headers, phpurl->port);
416 : }
417 1 : if (http_1_1) {
418 1 : smart_str_append_const(&soap_headers, "\r\n"
419 : "Connection: Keep-Alive\r\n");
420 : } else {
421 0 : smart_str_append_const(&soap_headers, "\r\n"
422 : "Connection: close\r\n");
423 : }
424 1 : if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_user_agent", sizeof("_user_agent"), (void **)&tmp) == SUCCESS &&
425 : Z_TYPE_PP(tmp) == IS_STRING) {
426 0 : if (Z_STRLEN_PP(tmp) > 0) {
427 0 : smart_str_append_const(&soap_headers, "User-Agent: ");
428 0 : smart_str_appendl(&soap_headers, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
429 0 : smart_str_append_const(&soap_headers, "\r\n");
430 : }
431 1 : } else if (context &&
432 : php_stream_context_get_option(context, "http", "user_agent", &tmp) == SUCCESS &&
433 : Z_TYPE_PP(tmp) == IS_STRING) {
434 0 : if (Z_STRLEN_PP(tmp) > 0) {
435 0 : smart_str_append_const(&soap_headers, "User-Agent: ");
436 0 : smart_str_appendl(&soap_headers, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
437 0 : smart_str_append_const(&soap_headers, "\r\n");
438 : }
439 1 : } else if (FG(user_agent)) {
440 0 : smart_str_append_const(&soap_headers, "User-Agent: ");
441 0 : smart_str_appends(&soap_headers, FG(user_agent));
442 0 : smart_str_append_const(&soap_headers, "\r\n");
443 : } else {
444 1 : smart_str_append_const(&soap_headers, "User-Agent: PHP-SOAP/"PHP_VERSION"\r\n");
445 : }
446 :
447 1 : smart_str_append(&soap_headers, &soap_headers_z);
448 :
449 1 : if (soap_version == SOAP_1_2) {
450 0 : smart_str_append_const(&soap_headers,"Content-Type: application/soap+xml; charset=utf-8");
451 0 : if (soapaction) {
452 0 : smart_str_append_const(&soap_headers,"; action=\"");
453 0 : smart_str_appends(&soap_headers, soapaction);
454 0 : smart_str_append_const(&soap_headers,"\"");
455 : }
456 0 : smart_str_append_const(&soap_headers,"\r\n");
457 : } else {
458 1 : smart_str_append_const(&soap_headers,"Content-Type: text/xml; charset=utf-8\r\n");
459 1 : if (soapaction) {
460 1 : smart_str_append_const(&soap_headers, "SOAPAction: \"");
461 1 : smart_str_appends(&soap_headers, soapaction);
462 1 : smart_str_append_const(&soap_headers, "\"\r\n");
463 : }
464 : }
465 1 : smart_str_append_const(&soap_headers,"Content-Length: ");
466 1 : smart_str_append_long(&soap_headers, request_size);
467 1 : smart_str_append_const(&soap_headers, "\r\n");
468 :
469 : /* HTTP Authentication */
470 1 : if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_login", sizeof("_login"), (void **)&login) == SUCCESS &&
471 : Z_TYPE_PP(login) == IS_STRING) {
472 : zval **digest;
473 :
474 0 : if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_digest", sizeof("_digest"), (void **)&digest) == SUCCESS) {
475 0 : if (Z_TYPE_PP(digest) == IS_ARRAY) {
476 : char HA1[33], HA2[33], response[33], cnonce[33], nc[9];
477 : PHP_MD5_CTX md5ctx;
478 : unsigned char hash[16];
479 :
480 0 : PHP_MD5Init(&md5ctx);
481 0 : snprintf(cnonce, sizeof(cnonce), "%ld", php_rand(TSRMLS_C));
482 0 : PHP_MD5Update(&md5ctx, (unsigned char*)cnonce, strlen(cnonce));
483 0 : PHP_MD5Final(hash, &md5ctx);
484 0 : make_digest(cnonce, hash);
485 :
486 0 : if (zend_hash_find(Z_ARRVAL_PP(digest), "nc", sizeof("nc"), (void **)&tmp) == SUCCESS &&
487 : Z_TYPE_PP(tmp) == IS_LONG) {
488 0 : Z_LVAL_PP(tmp)++;
489 0 : snprintf(nc, sizeof(nc), "%08ld", Z_LVAL_PP(tmp));
490 : } else {
491 0 : add_assoc_long(*digest, "nc", 1);
492 0 : strcpy(nc, "00000001");
493 : }
494 :
495 0 : PHP_MD5Init(&md5ctx);
496 0 : PHP_MD5Update(&md5ctx, (unsigned char*)Z_STRVAL_PP(login), Z_STRLEN_PP(login));
497 0 : PHP_MD5Update(&md5ctx, (unsigned char*)":", 1);
498 0 : if (zend_hash_find(Z_ARRVAL_PP(digest), "realm", sizeof("realm"), (void **)&tmp) == SUCCESS &&
499 : Z_TYPE_PP(tmp) == IS_STRING) {
500 0 : PHP_MD5Update(&md5ctx, (unsigned char*)Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
501 : }
502 0 : PHP_MD5Update(&md5ctx, (unsigned char*)":", 1);
503 0 : if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_password", sizeof("_password"), (void **)&password) == SUCCESS &&
504 : Z_TYPE_PP(password) == IS_STRING) {
505 0 : PHP_MD5Update(&md5ctx, (unsigned char*)Z_STRVAL_PP(password), Z_STRLEN_PP(password));
506 : }
507 0 : PHP_MD5Final(hash, &md5ctx);
508 0 : make_digest(HA1, hash);
509 0 : if (zend_hash_find(Z_ARRVAL_PP(digest), "algorithm", sizeof("algorithm"), (void **)&tmp) == SUCCESS &&
510 : Z_TYPE_PP(tmp) == IS_STRING &&
511 : Z_STRLEN_PP(tmp) == sizeof("md5-sess")-1 &&
512 : stricmp(Z_STRVAL_PP(tmp), "md5-sess") == 0) {
513 0 : PHP_MD5Init(&md5ctx);
514 0 : PHP_MD5Update(&md5ctx, (unsigned char*)HA1, 32);
515 0 : PHP_MD5Update(&md5ctx, (unsigned char*)":", 1);
516 0 : if (zend_hash_find(Z_ARRVAL_PP(digest), "nonce", sizeof("nonce"), (void **)&tmp) == SUCCESS &&
517 : Z_TYPE_PP(tmp) == IS_STRING) {
518 0 : PHP_MD5Update(&md5ctx, (unsigned char*)Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
519 : }
520 0 : PHP_MD5Update(&md5ctx, (unsigned char*)":", 1);
521 0 : PHP_MD5Update(&md5ctx, (unsigned char*)cnonce, 8);
522 0 : PHP_MD5Final(hash, &md5ctx);
523 0 : make_digest(HA1, hash);
524 : }
525 :
526 0 : PHP_MD5Init(&md5ctx);
527 0 : PHP_MD5Update(&md5ctx, (unsigned char*)"POST:", sizeof("POST:")-1);
528 0 : if (phpurl->path) {
529 0 : PHP_MD5Update(&md5ctx, (unsigned char*)phpurl->path, strlen(phpurl->path));
530 : } else {
531 0 : PHP_MD5Update(&md5ctx, (unsigned char*)"/", 1);
532 : }
533 0 : if (phpurl->query) {
534 0 : PHP_MD5Update(&md5ctx, (unsigned char*)"?", 1);
535 0 : PHP_MD5Update(&md5ctx, (unsigned char*)phpurl->query, strlen(phpurl->query));
536 : }
537 :
538 : /* TODO: Support for qop="auth-int" */
539 : /*
540 : if (zend_hash_find(Z_ARRVAL_PP(digest), "qop", sizeof("qop"), (void **)&tmp) == SUCCESS &&
541 : Z_TYPE_PP(tmp) == IS_STRING &&
542 : Z_STRLEN_PP(tmp) == sizeof("auth-int")-1 &&
543 : stricmp(Z_STRVAL_PP(tmp), "auth-int") == 0) {
544 : PHP_MD5Update(&md5ctx, ":", 1);
545 : PHP_MD5Update(&md5ctx, HEntity, HASHHEXLEN);
546 : }
547 : */
548 0 : PHP_MD5Final(hash, &md5ctx);
549 0 : make_digest(HA2, hash);
550 :
551 0 : PHP_MD5Init(&md5ctx);
552 0 : PHP_MD5Update(&md5ctx, (unsigned char*)HA1, 32);
553 0 : PHP_MD5Update(&md5ctx, (unsigned char*)":", 1);
554 0 : if (zend_hash_find(Z_ARRVAL_PP(digest), "nonce", sizeof("nonce"), (void **)&tmp) == SUCCESS &&
555 : Z_TYPE_PP(tmp) == IS_STRING) {
556 0 : PHP_MD5Update(&md5ctx, (unsigned char*)Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
557 : }
558 0 : PHP_MD5Update(&md5ctx, (unsigned char*)":", 1);
559 0 : if (zend_hash_find(Z_ARRVAL_PP(digest), "qop", sizeof("qop"), (void **)&tmp) == SUCCESS &&
560 : Z_TYPE_PP(tmp) == IS_STRING) {
561 0 : PHP_MD5Update(&md5ctx, (unsigned char*)nc, 8);
562 0 : PHP_MD5Update(&md5ctx, (unsigned char*)":", 1);
563 0 : PHP_MD5Update(&md5ctx, (unsigned char*)cnonce, 8);
564 0 : PHP_MD5Update(&md5ctx, (unsigned char*)":", 1);
565 : /* TODO: Support for qop="auth-int" */
566 0 : PHP_MD5Update(&md5ctx, (unsigned char*)"auth", sizeof("auth")-1);
567 0 : PHP_MD5Update(&md5ctx, (unsigned char*)":", 1);
568 : }
569 0 : PHP_MD5Update(&md5ctx, (unsigned char*)HA2, 32);
570 0 : PHP_MD5Final(hash, &md5ctx);
571 0 : make_digest(response, hash);
572 :
573 0 : smart_str_append_const(&soap_headers, "Authorization: Digest username=\"");
574 0 : smart_str_appendl(&soap_headers, Z_STRVAL_PP(login), Z_STRLEN_PP(login));
575 0 : if (zend_hash_find(Z_ARRVAL_PP(digest), "realm", sizeof("realm"), (void **)&tmp) == SUCCESS &&
576 : Z_TYPE_PP(tmp) == IS_STRING) {
577 0 : smart_str_append_const(&soap_headers, "\", realm=\"");
578 0 : smart_str_appendl(&soap_headers, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
579 : }
580 0 : if (zend_hash_find(Z_ARRVAL_PP(digest), "nonce", sizeof("nonce"), (void **)&tmp) == SUCCESS &&
581 : Z_TYPE_PP(tmp) == IS_STRING) {
582 0 : smart_str_append_const(&soap_headers, "\", nonce=\"");
583 0 : smart_str_appendl(&soap_headers, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
584 : }
585 0 : smart_str_append_const(&soap_headers, "\", uri=\"");
586 0 : if (phpurl->path) {
587 0 : smart_str_appends(&soap_headers, phpurl->path);
588 : } else {
589 0 : smart_str_appendc(&soap_headers, '/');
590 : }
591 0 : if (phpurl->query) {
592 0 : smart_str_appendc(&soap_headers, '?');
593 0 : smart_str_appends(&soap_headers, phpurl->query);
594 : }
595 0 : if (phpurl->fragment) {
596 0 : smart_str_appendc(&soap_headers, '#');
597 0 : smart_str_appends(&soap_headers, phpurl->fragment);
598 : }
599 0 : if (zend_hash_find(Z_ARRVAL_PP(digest), "qop", sizeof("qop"), (void **)&tmp) == SUCCESS &&
600 : Z_TYPE_PP(tmp) == IS_STRING) {
601 : /* TODO: Support for qop="auth-int" */
602 0 : smart_str_append_const(&soap_headers, "\", qop=\"auth");
603 0 : smart_str_append_const(&soap_headers, "\", nc=\"");
604 0 : smart_str_appendl(&soap_headers, nc, 8);
605 0 : smart_str_append_const(&soap_headers, "\", cnonce=\"");
606 0 : smart_str_appendl(&soap_headers, cnonce, 8);
607 : }
608 0 : smart_str_append_const(&soap_headers, "\", response=\"");
609 0 : smart_str_appendl(&soap_headers, response, 32);
610 0 : if (zend_hash_find(Z_ARRVAL_PP(digest), "opaque", sizeof("opaque"), (void **)&tmp) == SUCCESS &&
611 : Z_TYPE_PP(tmp) == IS_STRING) {
612 0 : smart_str_append_const(&soap_headers, "\", opaque=\"");
613 0 : smart_str_appendl(&soap_headers, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
614 : }
615 0 : if (zend_hash_find(Z_ARRVAL_PP(digest), "algorithm", sizeof("algorithm"), (void **)&tmp) == SUCCESS &&
616 : Z_TYPE_PP(tmp) == IS_STRING) {
617 0 : smart_str_append_const(&soap_headers, "\", algorithm=\"");
618 0 : smart_str_appendl(&soap_headers, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
619 : }
620 0 : smart_str_append_const(&soap_headers, "\"\r\n");
621 : }
622 : } else {
623 : unsigned char* buf;
624 : int len;
625 :
626 0 : smart_str auth = {0};
627 0 : smart_str_appendl(&auth, Z_STRVAL_PP(login), Z_STRLEN_PP(login));
628 0 : smart_str_appendc(&auth, ':');
629 0 : if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_password", sizeof("_password"), (void **)&password) == SUCCESS &&
630 : Z_TYPE_PP(password) == IS_STRING) {
631 0 : smart_str_appendl(&auth, Z_STRVAL_PP(password), Z_STRLEN_PP(password));
632 : }
633 0 : smart_str_0(&auth);
634 0 : buf = php_base64_encode((unsigned char*)auth.c, auth.len, &len);
635 0 : smart_str_append_const(&soap_headers, "Authorization: Basic ");
636 0 : smart_str_appendl(&soap_headers, (char*)buf, len);
637 0 : smart_str_append_const(&soap_headers, "\r\n");
638 0 : efree(buf);
639 0 : smart_str_free(&auth);
640 : }
641 : }
642 :
643 : /* Proxy HTTP Authentication */
644 1 : if (use_proxy && !use_ssl) {
645 0 : proxy_authentication(this_ptr, &soap_headers TSRMLS_CC);
646 : }
647 :
648 : /* Send cookies along with request */
649 1 : if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_cookies", sizeof("_cookies"), (void **)&cookies) == SUCCESS) {
650 : zval **data;
651 : char *key;
652 : int i, n;
653 :
654 0 : n = zend_hash_num_elements(Z_ARRVAL_PP(cookies));
655 0 : if (n > 0) {
656 0 : zend_hash_internal_pointer_reset(Z_ARRVAL_PP(cookies));
657 0 : smart_str_append_const(&soap_headers, "Cookie: ");
658 0 : for (i = 0; i < n; i++) {
659 0 : zend_hash_get_current_data(Z_ARRVAL_PP(cookies), (void **)&data);
660 0 : zend_hash_get_current_key(Z_ARRVAL_PP(cookies), &key, NULL, FALSE);
661 :
662 0 : if (Z_TYPE_PP(data) == IS_ARRAY) {
663 : zval** value;
664 :
665 0 : if (zend_hash_index_find(Z_ARRVAL_PP(data), 0, (void**)&value) == SUCCESS &&
666 : Z_TYPE_PP(value) == IS_STRING) {
667 : zval **tmp;
668 0 : if ((zend_hash_index_find(Z_ARRVAL_PP(data), 1, (void**)&tmp) == FAILURE ||
669 : strncmp(phpurl->path?phpurl->path:"/",Z_STRVAL_PP(tmp),Z_STRLEN_PP(tmp)) == 0) &&
670 : (zend_hash_index_find(Z_ARRVAL_PP(data), 2, (void**)&tmp) == FAILURE ||
671 : in_domain(phpurl->host,Z_STRVAL_PP(tmp))) &&
672 : (use_ssl || zend_hash_index_find(Z_ARRVAL_PP(data), 3, (void**)&tmp) == FAILURE)) {
673 0 : smart_str_appendl(&soap_headers, key, strlen(key));
674 0 : smart_str_appendc(&soap_headers, '=');
675 0 : smart_str_appendl(&soap_headers, Z_STRVAL_PP(value), Z_STRLEN_PP(value));
676 0 : smart_str_appendc(&soap_headers, ';');
677 : }
678 : }
679 : }
680 0 : zend_hash_move_forward(Z_ARRVAL_PP(cookies));
681 : }
682 0 : smart_str_append_const(&soap_headers, "\r\n");
683 : }
684 : }
685 :
686 1 : if (context &&
687 : php_stream_context_get_option(context, "http", "header", &tmp) == SUCCESS &&
688 : Z_TYPE_PP(tmp) == IS_STRING && Z_STRLEN_PP(tmp)) {
689 0 : char *s = Z_STRVAL_PP(tmp);
690 : char *p;
691 : int name_len;
692 :
693 0 : while (*s) {
694 : /* skip leading newlines and spaces */
695 0 : while (*s == ' ' || *s == '\t' || *s == '\r' || *s == '\n') {
696 0 : s++;
697 : }
698 : /* extract header name */
699 0 : p = s;
700 0 : name_len = -1;
701 0 : while (*p) {
702 0 : if (*p == ':') {
703 0 : if (name_len < 0) name_len = p - s;
704 0 : break;
705 0 : } else if (*p == ' ' || *p == '\t') {
706 0 : if (name_len < 0) name_len = p - s;
707 0 : } else if (*p == '\r' || *p == '\n') {
708 : break;
709 : }
710 0 : p++;
711 : }
712 0 : if (*p == ':') {
713 : /* extract header value */
714 0 : while (*p && *p != '\r' && *p != '\n') {
715 0 : p++;
716 : }
717 : /* skip some predefined headers */
718 0 : if ((name_len != sizeof("host")-1 ||
719 : strncasecmp(s, "host", sizeof("host")-1) != 0) &&
720 : (name_len != sizeof("connection")-1 ||
721 : strncasecmp(s, "connection", sizeof("connection")-1) != 0) &&
722 : (name_len != sizeof("user-agent")-1 ||
723 : strncasecmp(s, "user-agent", sizeof("user-agent")-1) != 0) &&
724 : (name_len != sizeof("content-length")-1 ||
725 : strncasecmp(s, "content-length", sizeof("content-length")-1) != 0) &&
726 : (name_len != sizeof("content-type")-1 ||
727 : strncasecmp(s, "content-type", sizeof("content-type")-1) != 0) &&
728 : (name_len != sizeof("cookie")-1 ||
729 : strncasecmp(s, "cookie", sizeof("cookie")-1) != 0) &&
730 : (name_len != sizeof("authorization")-1 ||
731 : strncasecmp(s, "authorization", sizeof("authorization")-1) != 0) &&
732 : (name_len != sizeof("proxy-authorization")-1 ||
733 : strncasecmp(s, "proxy-authorization", sizeof("proxy-authorization")-1) != 0)) {
734 : /* add header */
735 0 : smart_str_appendl(&soap_headers, s, p-s);
736 0 : smart_str_append_const(&soap_headers, "\r\n");
737 : }
738 : }
739 0 : s = (*p) ? (p + 1) : p;
740 : }
741 : }
742 :
743 1 : smart_str_append_const(&soap_headers, "\r\n");
744 1 : smart_str_0(&soap_headers);
745 1 : if (zend_hash_find(Z_OBJPROP_P(this_ptr), "trace", sizeof("trace"), (void **) &trace) == SUCCESS &&
746 : Z_LVAL_PP(trace) > 0) {
747 1 : add_property_stringl(this_ptr, "__last_request_headers", soap_headers.c, soap_headers.len, 1);
748 : }
749 1 : smart_str_appendl(&soap_headers, request, request_size);
750 1 : smart_str_0(&soap_headers);
751 :
752 1 : err = php_stream_write(stream, soap_headers.c, soap_headers.len);
753 1 : if (err != soap_headers.len) {
754 0 : if (request != buf) {efree(request);}
755 0 : smart_str_free(&soap_headers);
756 0 : php_stream_close(stream);
757 0 : zend_hash_del(Z_OBJPROP_P(this_ptr), "httpurl", sizeof("httpurl"));
758 0 : zend_hash_del(Z_OBJPROP_P(this_ptr), "httpsocket", sizeof("httpsocket"));
759 0 : zend_hash_del(Z_OBJPROP_P(this_ptr), "_use_proxy", sizeof("_use_proxy"));
760 0 : add_soap_fault(this_ptr, "HTTP", "Failed Sending HTTP SOAP request", NULL, NULL TSRMLS_CC);
761 0 : return FALSE;
762 : }
763 1 : smart_str_free(&soap_headers);
764 :
765 : } else {
766 0 : add_soap_fault(this_ptr, "HTTP", "Failed to create stream??", NULL, NULL TSRMLS_CC);
767 0 : smart_str_free(&soap_headers_z);
768 0 : return FALSE;
769 : }
770 :
771 1 : if (!buffer) {
772 0 : php_stream_close(stream);
773 0 : zend_hash_del(Z_OBJPROP_P(this_ptr), "httpsocket", sizeof("httpsocket"));
774 0 : zend_hash_del(Z_OBJPROP_P(this_ptr), "_use_proxy", sizeof("_use_proxy"));
775 0 : smart_str_free(&soap_headers_z);
776 0 : return TRUE;
777 : }
778 :
779 : do {
780 1 : if (!get_http_headers(stream, &http_headers, &http_header_size TSRMLS_CC)) {
781 0 : if (http_headers) {efree(http_headers);}
782 0 : if (request != buf) {efree(request);}
783 0 : php_stream_close(stream);
784 0 : zend_hash_del(Z_OBJPROP_P(this_ptr), "httpsocket", sizeof("httpsocket"));
785 0 : zend_hash_del(Z_OBJPROP_P(this_ptr), "_use_proxy", sizeof("_use_proxy"));
786 0 : add_soap_fault(this_ptr, "HTTP", "Error Fetching http headers", NULL, NULL TSRMLS_CC);
787 0 : smart_str_free(&soap_headers_z);
788 0 : return FALSE;
789 : }
790 :
791 1 : if (zend_hash_find(Z_OBJPROP_P(this_ptr), "trace", sizeof("trace"), (void **) &trace) == SUCCESS &&
792 : Z_LVAL_PP(trace) > 0) {
793 1 : add_property_stringl(this_ptr, "__last_response_headers", http_headers, http_header_size, 1);
794 : }
795 :
796 : /* Check to see what HTTP status was sent */
797 1 : http_1_1 = 0;
798 1 : http_status = 0;
799 1 : http_version = get_http_header_value(http_headers,"HTTP/");
800 1 : if (http_version) {
801 : char *tmp;
802 :
803 1 : if (!strncmp(http_version,"1.1", 3)) {
804 1 : http_1_1 = 1;
805 : }
806 :
807 1 : tmp = strstr(http_version," ");
808 1 : if (tmp != NULL) {
809 1 : tmp++;
810 1 : http_status = atoi(tmp);
811 : }
812 1 : tmp = strstr(tmp," ");
813 1 : if (tmp != NULL) {
814 1 : tmp++;
815 1 : if (http_msg) {
816 0 : efree(http_msg);
817 : }
818 1 : http_msg = estrdup(tmp);
819 : }
820 1 : efree(http_version);
821 :
822 : /* Try and get headers again */
823 1 : if (http_status == 100) {
824 0 : efree(http_headers);
825 : }
826 : }
827 1 : } while (http_status == 100);
828 :
829 : /* Grab and send back every cookie */
830 :
831 : /* Not going to worry about Path: because
832 : we shouldn't be changing urls so path dont
833 : matter too much
834 : */
835 1 : cookie_itt = strstr(http_headers,"Set-Cookie: ");
836 2 : while (cookie_itt) {
837 : char *end_pos, *cookie;
838 : char *eqpos, *sempos;
839 : zval **cookies;
840 :
841 0 : if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_cookies", sizeof("_cookies"), (void **)&cookies) == FAILURE) {
842 : zval *tmp_cookies;
843 0 : MAKE_STD_ZVAL(tmp_cookies);
844 0 : array_init(tmp_cookies);
845 0 : zend_hash_update(Z_OBJPROP_P(this_ptr), "_cookies", sizeof("_cookies"), &tmp_cookies, sizeof(zval *), (void **)&cookies);
846 : }
847 :
848 0 : end_pos = strstr(cookie_itt,"\r\n");
849 0 : cookie = get_http_header_value(cookie_itt,"Set-Cookie: ");
850 :
851 0 : eqpos = strstr(cookie, "=");
852 0 : sempos = strstr(cookie, ";");
853 0 : if (eqpos != NULL && (sempos == NULL || sempos > eqpos)) {
854 0 : smart_str name = {0};
855 : int cookie_len;
856 : zval *zcookie;
857 :
858 0 : if (sempos != NULL) {
859 0 : cookie_len = sempos-(eqpos+1);
860 : } else {
861 0 : cookie_len = strlen(cookie)-(eqpos-cookie)-1;
862 : }
863 :
864 0 : smart_str_appendl(&name, cookie, eqpos - cookie);
865 0 : smart_str_0(&name);
866 :
867 0 : ALLOC_INIT_ZVAL(zcookie);
868 0 : array_init(zcookie);
869 0 : add_index_stringl(zcookie, 0, eqpos + 1, cookie_len, 1);
870 :
871 0 : if (sempos != NULL) {
872 0 : char *options = cookie + cookie_len+1;
873 0 : while (*options) {
874 0 : while (*options == ' ') {options++;}
875 0 : sempos = strstr(options, ";");
876 0 : if (strstr(options,"path=") == options) {
877 0 : eqpos = options + sizeof("path=")-1;
878 0 : add_index_stringl(zcookie, 1, eqpos, sempos?(sempos-eqpos):strlen(eqpos), 1);
879 0 : } else if (strstr(options,"domain=") == options) {
880 0 : eqpos = options + sizeof("domain=")-1;
881 0 : add_index_stringl(zcookie, 2, eqpos, sempos?(sempos-eqpos):strlen(eqpos), 1);
882 0 : } else if (strstr(options,"secure") == options) {
883 0 : add_index_bool(zcookie, 3, 1);
884 : }
885 0 : if (sempos != NULL) {
886 0 : options = sempos+1;
887 : } else {
888 0 : break;
889 : }
890 : }
891 : }
892 0 : if (!zend_hash_index_exists(Z_ARRVAL_P(zcookie), 1)) {
893 0 : char *t = phpurl->path?phpurl->path:"/";
894 0 : char *c = strrchr(t, '/');
895 0 : if (c) {
896 0 : add_index_stringl(zcookie, 1, t, c-t, 1);
897 : }
898 : }
899 0 : if (!zend_hash_index_exists(Z_ARRVAL_P(zcookie), 2)) {
900 0 : add_index_string(zcookie, 2, phpurl->host, 1);
901 : }
902 :
903 0 : add_assoc_zval_ex(*cookies, name.c, name.len+1, zcookie);
904 0 : smart_str_free(&name);
905 : }
906 :
907 0 : cookie_itt = strstr(cookie_itt + sizeof("Set-Cookie: "), "Set-Cookie: ");
908 0 : efree(cookie);
909 : }
910 :
911 : /* See if the server requested a close */
912 1 : if (http_1_1) {
913 1 : http_close = FALSE;
914 1 : if (use_proxy && !use_ssl) {
915 0 : connection = get_http_header_value(http_headers,"Proxy-Connection: ");
916 0 : if (connection) {
917 0 : if (strncasecmp(connection, "close", sizeof("close")-1) == 0) {
918 0 : http_close = TRUE;
919 : }
920 0 : efree(connection);
921 : }
922 : }
923 1 : if (http_close == FALSE) {
924 1 : connection = get_http_header_value(http_headers,"Connection: ");
925 1 : if (connection) {
926 1 : if (strncasecmp(connection, "close", sizeof("close")-1) == 0) {
927 1 : http_close = TRUE;
928 : }
929 1 : efree(connection);
930 : }
931 : }
932 : } else {
933 0 : http_close = TRUE;
934 0 : if (use_proxy && !use_ssl) {
935 0 : connection = get_http_header_value(http_headers,"Proxy-Connection: ");
936 0 : if (connection) {
937 0 : if (strncasecmp(connection, "Keep-Alive", sizeof("Keep-Alive")-1) == 0) {
938 0 : http_close = FALSE;
939 : }
940 0 : efree(connection);
941 : }
942 : }
943 0 : if (http_close == TRUE) {
944 0 : connection = get_http_header_value(http_headers,"Connection: ");
945 0 : if (connection) {
946 0 : if (strncasecmp(connection, "Keep-Alive", sizeof("Keep-Alive")-1) == 0) {
947 0 : http_close = FALSE;
948 : }
949 0 : efree(connection);
950 : }
951 : }
952 : }
953 :
954 1 : if (!get_http_body(stream, http_close, http_headers, &http_body, &http_body_size TSRMLS_CC)) {
955 0 : if (request != buf) {efree(request);}
956 0 : php_stream_close(stream);
957 0 : efree(http_headers);
958 0 : zend_hash_del(Z_OBJPROP_P(this_ptr), "httpsocket", sizeof("httpsocket"));
959 0 : zend_hash_del(Z_OBJPROP_P(this_ptr), "_use_proxy", sizeof("_use_proxy"));
960 0 : add_soap_fault(this_ptr, "HTTP", "Error Fetching http body, No Content-Length, connection closed or chunked data", NULL, NULL TSRMLS_CC);
961 0 : if (http_msg) {
962 0 : efree(http_msg);
963 : }
964 0 : smart_str_free(&soap_headers_z);
965 0 : return FALSE;
966 : }
967 :
968 1 : if (request != buf) {efree(request);}
969 :
970 1 : if (http_close) {
971 1 : php_stream_close(stream);
972 1 : zend_hash_del(Z_OBJPROP_P(this_ptr), "httpsocket", sizeof("httpsocket"));
973 1 : zend_hash_del(Z_OBJPROP_P(this_ptr), "_use_proxy", sizeof("_use_proxy"));
974 1 : stream = NULL;
975 : }
976 :
977 : /* Process HTTP status codes */
978 1 : if (http_status >= 300 && http_status < 400) {
979 : char *loc;
980 :
981 0 : if ((loc = get_http_header_value(http_headers,"Location: ")) != NULL) {
982 0 : php_url *new_url = php_url_parse(loc);
983 :
984 0 : if (new_url != NULL) {
985 0 : efree(http_headers);
986 0 : efree(http_body);
987 0 : efree(loc);
988 0 : if (new_url->scheme == NULL && new_url->path != NULL) {
989 0 : new_url->scheme = phpurl->scheme ? estrdup(phpurl->scheme) : NULL;
990 0 : new_url->host = phpurl->host ? estrdup(phpurl->host) : NULL;
991 0 : new_url->port = phpurl->port;
992 0 : if (new_url->path && new_url->path[0] != '/') {
993 0 : char *t = phpurl->path;
994 0 : char *p = strrchr(t, '/');
995 0 : if (p) {
996 0 : char *s = emalloc((p - t) + strlen(new_url->path) + 2);
997 0 : strncpy(s, t, (p - t) + 1);
998 0 : s[(p - t) + 1] = 0;
999 0 : strcat(s, new_url->path);
1000 0 : efree(new_url->path);
1001 0 : new_url->path = s;
1002 : }
1003 : }
1004 : }
1005 0 : phpurl = new_url;
1006 :
1007 0 : goto try_again;
1008 : }
1009 : }
1010 1 : } else if (http_status == 401) {
1011 : /* Digest authentication */
1012 : zval **digest, **login, **password;
1013 0 : char *auth = get_http_header_value(http_headers, "WWW-Authenticate: ");
1014 :
1015 0 : if (auth &&
1016 : strstr(auth, "Digest") == auth &&
1017 : (zend_hash_find(Z_OBJPROP_P(this_ptr), "_digest", sizeof("_digest"), (void **)&digest) == FAILURE ||
1018 : Z_TYPE_PP(digest) != IS_ARRAY) &&
1019 : zend_hash_find(Z_OBJPROP_P(this_ptr), "_login", sizeof("_login"), (void **)&login) == SUCCESS &&
1020 : Z_TYPE_PP(login) == IS_STRING &&
1021 : zend_hash_find(Z_OBJPROP_P(this_ptr), "_password", sizeof("_password"), (void **)&password) == SUCCESS &&
1022 : Z_TYPE_PP(password) == IS_STRING) {
1023 : char *s;
1024 0 : zval *digest = NULL;
1025 :
1026 0 : s = auth + sizeof("Digest")-1;
1027 0 : while (*s != '\0') {
1028 : char *name, *val;
1029 0 : while (*s == ' ') ++s;
1030 0 : name = s;
1031 0 : while (*s != '\0' && *s != '=') ++s;
1032 0 : if (*s == '=') {
1033 0 : *s = '\0';
1034 0 : ++s;
1035 0 : if (*s == '"') {
1036 0 : ++s;
1037 0 : val = s;
1038 0 : while (*s != '\0' && *s != '"') ++s;
1039 : } else {
1040 0 : val = s;
1041 0 : while (*s != '\0' && *s != ' ' && *s != ',') ++s;
1042 : }
1043 0 : if (*s != '\0') {
1044 0 : if (*s != ',') {
1045 0 : *s = '\0';
1046 0 : ++s;
1047 0 : while (*s != '\0' && *s != ',') ++s;
1048 0 : if (*s != '\0') ++s;
1049 : } else {
1050 0 : *s = '\0';
1051 0 : ++s;
1052 : }
1053 : }
1054 0 : if (digest == NULL) {
1055 0 : ALLOC_INIT_ZVAL(digest);
1056 0 : array_init(digest);
1057 : }
1058 0 : add_assoc_string(digest, name, val ,1);
1059 : }
1060 : }
1061 :
1062 0 : if (digest != NULL) {
1063 0 : php_url *new_url = emalloc(sizeof(php_url));
1064 :
1065 0 : Z_DELREF_P(digest);
1066 0 : add_property_zval_ex(this_ptr, "_digest", sizeof("_digest"), digest TSRMLS_CC);
1067 :
1068 0 : *new_url = *phpurl;
1069 0 : if (phpurl->scheme) phpurl->scheme = estrdup(phpurl->scheme);
1070 0 : if (phpurl->user) phpurl->user = estrdup(phpurl->user);
1071 0 : if (phpurl->pass) phpurl->pass = estrdup(phpurl->pass);
1072 0 : if (phpurl->host) phpurl->host = estrdup(phpurl->host);
1073 0 : if (phpurl->path) phpurl->path = estrdup(phpurl->path);
1074 0 : if (phpurl->query) phpurl->query = estrdup(phpurl->query);
1075 0 : if (phpurl->fragment) phpurl->fragment = estrdup(phpurl->fragment);
1076 0 : phpurl = new_url;
1077 :
1078 0 : efree(auth);
1079 0 : efree(http_headers);
1080 0 : efree(http_body);
1081 :
1082 0 : goto try_again;
1083 : }
1084 : }
1085 0 : if (auth) efree(auth);
1086 : }
1087 1 : smart_str_free(&soap_headers_z);
1088 :
1089 : /* Check and see if the server even sent a xml document */
1090 1 : content_type = get_http_header_value(http_headers,"Content-Type: ");
1091 1 : if (content_type) {
1092 1 : char *pos = NULL;
1093 : int cmplen;
1094 1 : pos = strstr(content_type,";");
1095 1 : if (pos != NULL) {
1096 1 : cmplen = pos - content_type;
1097 : } else {
1098 0 : cmplen = strlen(content_type);
1099 : }
1100 1 : if (strncmp(content_type, "text/xml", cmplen) == 0 ||
1101 : strncmp(content_type, "application/soap+xml", cmplen) == 0) {
1102 0 : content_type_xml = 1;
1103 : /*
1104 : if (strncmp(http_body, "<?xml", 5)) {
1105 : zval *err;
1106 : MAKE_STD_ZVAL(err);
1107 : ZVAL_STRINGL(err, http_body, http_body_size, 1);
1108 : add_soap_fault(this_ptr, "HTTP", "Didn't recieve an xml document", NULL, err TSRMLS_CC);
1109 : efree(content_type);
1110 : efree(http_headers);
1111 : efree(http_body);
1112 : return FALSE;
1113 : }
1114 : */
1115 : }
1116 1 : efree(content_type);
1117 : }
1118 :
1119 : /* Decompress response */
1120 1 : content_encoding = get_http_header_value(http_headers,"Content-Encoding: ");
1121 1 : if (content_encoding) {
1122 : zval func;
1123 : zval retval;
1124 : zval param;
1125 : zval *params[1];
1126 :
1127 0 : if ((strcmp(content_encoding,"gzip") == 0 ||
1128 : strcmp(content_encoding,"x-gzip") == 0) &&
1129 : zend_hash_exists(EG(function_table), "gzinflate", sizeof("gzinflate"))) {
1130 0 : ZVAL_STRING(&func, "gzinflate", 0);
1131 0 : params[0] = ¶m;
1132 0 : ZVAL_STRINGL(params[0], http_body+10, http_body_size-10, 0);
1133 0 : INIT_PZVAL(params[0]);
1134 0 : } else if (strcmp(content_encoding,"deflate") == 0 &&
1135 : zend_hash_exists(EG(function_table), "gzuncompress", sizeof("gzuncompress"))) {
1136 0 : ZVAL_STRING(&func, "gzuncompress", 0);
1137 0 : params[0] = ¶m;
1138 0 : ZVAL_STRINGL(params[0], http_body, http_body_size, 0);
1139 0 : INIT_PZVAL(params[0]);
1140 : } else {
1141 0 : efree(content_encoding);
1142 0 : efree(http_headers);
1143 0 : efree(http_body);
1144 0 : if (http_msg) {
1145 0 : efree(http_msg);
1146 : }
1147 0 : add_soap_fault(this_ptr, "HTTP", "Unknown Content-Encoding", NULL, NULL TSRMLS_CC);
1148 0 : return FALSE;
1149 : }
1150 0 : if (call_user_function(CG(function_table), (zval**)NULL, &func, &retval, 1, params TSRMLS_CC) == SUCCESS &&
1151 : Z_TYPE(retval) == IS_STRING) {
1152 0 : efree(http_body);
1153 0 : *buffer = Z_STRVAL(retval);
1154 0 : *buffer_len = Z_STRLEN(retval);
1155 : } else {
1156 0 : efree(content_encoding);
1157 0 : efree(http_headers);
1158 0 : efree(http_body);
1159 0 : add_soap_fault(this_ptr, "HTTP", "Can't uncompress compressed response", NULL, NULL TSRMLS_CC);
1160 0 : if (http_msg) {
1161 0 : efree(http_msg);
1162 : }
1163 0 : return FALSE;
1164 : }
1165 0 : efree(content_encoding);
1166 : } else {
1167 1 : *buffer = http_body;
1168 1 : *buffer_len = http_body_size;
1169 : }
1170 :
1171 1 : efree(http_headers);
1172 :
1173 1 : if (http_status >= 400) {
1174 0 : int error = 0;
1175 :
1176 0 : if (*buffer_len == 0) {
1177 0 : error = 1;
1178 0 : } else if (*buffer_len > 0) {
1179 0 : if (!content_type_xml) {
1180 0 : char *s = *buffer;
1181 :
1182 0 : while (*s != '\0' && *s < ' ') {
1183 0 : s++;
1184 : }
1185 0 : if (strncmp(s, "<?xml", 5)) {
1186 0 : error = 1;
1187 : }
1188 : }
1189 : }
1190 :
1191 0 : if (error) {
1192 0 : efree(*buffer);
1193 0 : add_soap_fault(this_ptr, "HTTP", http_msg, NULL, NULL TSRMLS_CC);
1194 0 : efree(http_msg);
1195 0 : return FALSE;
1196 : }
1197 : }
1198 :
1199 1 : if (http_msg) {
1200 1 : efree(http_msg);
1201 : }
1202 :
1203 1 : return TRUE;
1204 : }
1205 :
1206 : static char *get_http_header_value(char *headers, char *type)
1207 6 : {
1208 6 : char *pos, *tmp = NULL;
1209 : int typelen, headerslen;
1210 :
1211 6 : typelen = strlen(type);
1212 6 : headerslen = strlen(headers);
1213 :
1214 : /* header `titles' can be lower case, or any case combination, according
1215 : * to the various RFC's. */
1216 6 : pos = headers;
1217 : do {
1218 : /* start of buffer or start of line */
1219 35 : if (strncasecmp(pos, type, typelen) == 0) {
1220 : char *eol;
1221 :
1222 : /* match */
1223 4 : tmp = pos + typelen;
1224 4 : eol = strchr(tmp, '\n');
1225 4 : if (eol == NULL) {
1226 0 : eol = headers + headerslen;
1227 4 : } else if (eol > tmp && *(eol-1) == '\r') {
1228 4 : eol--;
1229 : }
1230 4 : return estrndup(tmp, eol - tmp);
1231 : }
1232 :
1233 : /* find next line */
1234 31 : pos = strchr(pos, '\n');
1235 31 : if (pos) {
1236 29 : pos++;
1237 : }
1238 :
1239 31 : } while (pos);
1240 :
1241 2 : return NULL;
1242 : }
1243 :
1244 : static int get_http_body(php_stream *stream, int close, char *headers, char **response, int *out_size TSRMLS_DC)
1245 1 : {
1246 1 : char *header, *http_buf = NULL;
1247 1 : int header_close = close, header_chunked = 0, header_length = 0, http_buf_size = 0;
1248 :
1249 1 : if (!close) {
1250 0 : header = get_http_header_value(headers, "Connection: ");
1251 0 : if (header) {
1252 0 : if(!strncasecmp(header, "close", sizeof("close")-1)) header_close = 1;
1253 0 : efree(header);
1254 : }
1255 : }
1256 1 : header = get_http_header_value(headers, "Transfer-Encoding: ");
1257 1 : if (header) {
1258 0 : if(!strncasecmp(header, "chunked", sizeof("chunked")-1)) header_chunked = 1;
1259 0 : efree(header);
1260 : }
1261 1 : header = get_http_header_value(headers, "Content-Length: ");
1262 1 : if (header) {
1263 1 : header_length = atoi(header);
1264 1 : efree(header);
1265 1 : if (!header_length && !header_chunked) {
1266 : /* Empty response */
1267 0 : http_buf = emalloc(1);
1268 0 : http_buf[0] = '\0';
1269 0 : (*response) = http_buf;
1270 0 : (*out_size) = 0;
1271 0 : return TRUE;
1272 : }
1273 : }
1274 :
1275 1 : if (header_chunked) {
1276 : char ch, done, chunk_size[10], headerbuf[8192];
1277 :
1278 0 : done = FALSE;
1279 :
1280 0 : while (!done) {
1281 0 : int buf_size = 0;
1282 :
1283 0 : php_stream_gets(stream, chunk_size, sizeof(chunk_size));
1284 0 : if (sscanf(chunk_size, "%x", &buf_size) > 0 ) {
1285 0 : if (buf_size > 0) {
1286 0 : int len_size = 0;
1287 :
1288 0 : if (http_buf_size + buf_size + 1 < 0) {
1289 0 : efree(http_buf);
1290 0 : return FALSE;
1291 : }
1292 0 : http_buf = erealloc(http_buf, http_buf_size + buf_size + 1);
1293 :
1294 0 : while (len_size < buf_size) {
1295 0 : int len_read = php_stream_read(stream, http_buf + http_buf_size, buf_size - len_size);
1296 0 : if (len_read <= 0) {
1297 : /* Error or EOF */
1298 0 : done = TRUE;
1299 0 : break;
1300 : }
1301 0 : len_size += len_read;
1302 0 : http_buf_size += len_read;
1303 : }
1304 :
1305 : /* Eat up '\r' '\n' */
1306 0 : ch = php_stream_getc(stream);
1307 0 : if (ch == '\r') {
1308 0 : ch = php_stream_getc(stream);
1309 : }
1310 0 : if (ch != '\n') {
1311 : /* Somthing wrong in chunked encoding */
1312 0 : if (http_buf) {
1313 0 : efree(http_buf);
1314 : }
1315 0 : return FALSE;
1316 : }
1317 : }
1318 : } else {
1319 : /* Somthing wrong in chunked encoding */
1320 0 : if (http_buf) {
1321 0 : efree(http_buf);
1322 : }
1323 0 : return FALSE;
1324 : }
1325 0 : if (buf_size == 0) {
1326 0 : done = TRUE;
1327 : }
1328 : }
1329 :
1330 : /* Ignore trailer headers */
1331 : while (1) {
1332 0 : if (!php_stream_gets(stream, headerbuf, sizeof(headerbuf))) {
1333 0 : break;
1334 : }
1335 :
1336 0 : if ((headerbuf[0] == '\r' && headerbuf[1] == '\n') ||
1337 : (headerbuf[0] == '\n')) {
1338 : /* empty line marks end of headers */
1339 : break;
1340 : }
1341 0 : }
1342 :
1343 0 : if (http_buf == NULL) {
1344 0 : http_buf = emalloc(1);
1345 : }
1346 :
1347 1 : } else if (header_length) {
1348 1 : if (header_length < 0) {
1349 0 : return FALSE;
1350 : }
1351 1 : http_buf = emalloc(header_length + 1);
1352 3 : while (http_buf_size < header_length) {
1353 1 : int len_read = php_stream_read(stream, http_buf + http_buf_size, header_length - http_buf_size);
1354 1 : if (len_read <= 0) {
1355 0 : break;
1356 : }
1357 1 : http_buf_size += len_read;
1358 : }
1359 0 : } else if (header_close) {
1360 : do {
1361 : int len_read;
1362 0 : http_buf = erealloc(http_buf, http_buf_size + 4096 + 1);
1363 0 : len_read = php_stream_read(stream, http_buf + http_buf_size, 4096);
1364 0 : if (len_read > 0) {
1365 0 : http_buf_size += len_read;
1366 : }
1367 0 : } while(!php_stream_eof(stream));
1368 : } else {
1369 0 : return FALSE;
1370 : }
1371 :
1372 1 : http_buf[http_buf_size] = '\0';
1373 1 : (*response) = http_buf;
1374 1 : (*out_size) = http_buf_size;
1375 1 : return TRUE;
1376 : }
1377 :
1378 : static int get_http_headers(php_stream *stream, char **response, int *out_size TSRMLS_DC)
1379 1 : {
1380 1 : int done = FALSE;
1381 1 : smart_str tmp_response = {0};
1382 : char headerbuf[8192];
1383 :
1384 9 : while (!done) {
1385 8 : if (!php_stream_gets(stream, headerbuf, sizeof(headerbuf))) {
1386 0 : break;
1387 : }
1388 :
1389 8 : if ((headerbuf[0] == '\r' && headerbuf[1] == '\n') ||
1390 : (headerbuf[0] == '\n')) {
1391 : /* empty line marks end of headers */
1392 1 : done = TRUE;
1393 1 : break;
1394 : }
1395 :
1396 : /* add header to collection */
1397 7 : smart_str_appends(&tmp_response, headerbuf);
1398 : }
1399 1 : smart_str_0(&tmp_response);
1400 1 : (*response) = tmp_response.c;
1401 1 : (*out_size) = tmp_response.len;
1402 1 : return done;
1403 : }
1404 : /*
1405 : * Local variables:
1406 : * tab-width: 4
1407 : * c-basic-offset: 4
1408 : * End:
1409 : * vim600: sw=4 ts=4 fdm=marker
1410 : * vim<600: sw=4 ts=4
1411 : */
|