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