~ubuntu-branches/ubuntu/hardy/php5/hardy-updates

« back to all changes in this revision

Viewing changes to ext/soap/php_http.c

  • Committer: Bazaar Package Importer
  • Author(s): Adam Conrad
  • Date: 2005-10-09 03:14:32 UTC
  • Revision ID: james.westby@ubuntu.com-20051009031432-kspik3lobxstafv9
Tags: upstream-5.0.5
ImportĀ upstreamĀ versionĀ 5.0.5

Show diffs side-by-side

added added

removed removed

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