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