Back to index

php5  5.3.10
php_http.c
Go to the documentation of this file.
00001 /*
00002   +----------------------------------------------------------------------+
00003   | PHP Version 5                                                        |
00004   +----------------------------------------------------------------------+
00005   | Copyright (c) 1997-2012 The PHP Group                                |
00006   +----------------------------------------------------------------------+
00007   | This source file is subject to version 3.01 of the PHP license,      |
00008   | that is bundled with this package in the file LICENSE, and is        |
00009   | available through the world-wide-web at the following url:           |
00010   | http://www.php.net/license/3_01.txt                                  |
00011   | If you did not receive a copy of the PHP license and are unable to   |
00012   | obtain it through the world-wide-web, please send a note to          |
00013   | license@php.net so we can mail you a copy immediately.               |
00014   +----------------------------------------------------------------------+
00015   | Authors: Brad Lafountain <rodif_bl@yahoo.com>                        |
00016   |          Shane Caraveo <shane@caraveo.com>                           |
00017   |          Dmitry Stogov <dmitry@zend.com>                             |
00018   +----------------------------------------------------------------------+
00019 */
00020 /* $Id: php_http.c 321634 2012-01-01 13:15:04Z felipe $ */
00021 
00022 #include "php_soap.h"
00023 #include "ext/standard/base64.h"
00024 #include "ext/standard/md5.h"
00025 #include "ext/standard/php_rand.h"
00026 
00027 static char *get_http_header_value(char *headers, char *type);
00028 static int get_http_body(php_stream *socketd, int close, char *headers,  char **response, int *out_size TSRMLS_DC);
00029 static int get_http_headers(php_stream *socketd,char **response, int *out_size TSRMLS_DC);
00030 
00031 #define smart_str_append_const(str, const) \
00032        smart_str_appendl(str,const,sizeof(const)-1)
00033 
00034 /* Proxy HTTP Authentication */
00035 void proxy_authentication(zval* this_ptr, smart_str* soap_headers TSRMLS_DC)
00036 {
00037        zval **login, **password;
00038 
00039        if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_proxy_login", sizeof("_proxy_login"), (void **)&login) == SUCCESS) {
00040               unsigned char* buf;
00041               int len;
00042               smart_str auth = {0};
00043 
00044               smart_str_appendl(&auth, Z_STRVAL_PP(login), Z_STRLEN_PP(login));
00045               smart_str_appendc(&auth, ':');
00046               if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_proxy_password", sizeof("_proxy_password"), (void **)&password) == SUCCESS) {
00047                      smart_str_appendl(&auth, Z_STRVAL_PP(password), Z_STRLEN_PP(password));
00048               }
00049               smart_str_0(&auth);
00050               buf = php_base64_encode((unsigned char*)auth.c, auth.len, &len);
00051               smart_str_append_const(soap_headers, "Proxy-Authorization: Basic ");
00052               smart_str_appendl(soap_headers, (char*)buf, len);
00053               smart_str_append_const(soap_headers, "\r\n");
00054               efree(buf);
00055               smart_str_free(&auth);
00056        }
00057 }
00058 
00059 /* HTTP Authentication */
00060 void basic_authentication(zval* this_ptr, smart_str* soap_headers TSRMLS_DC)
00061 {
00062        zval **login, **password;
00063 
00064        if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_login", sizeof("_login"), (void **)&login) == SUCCESS &&
00065                      !zend_hash_exists(Z_OBJPROP_P(this_ptr), "_digest", sizeof("_digest"))) {
00066               unsigned char* buf;
00067               int len;
00068               smart_str auth = {0};
00069 
00070               smart_str_appendl(&auth, Z_STRVAL_PP(login), Z_STRLEN_PP(login));
00071               smart_str_appendc(&auth, ':');
00072               if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_password", sizeof("_password"), (void **)&password) == SUCCESS) {
00073                      smart_str_appendl(&auth, Z_STRVAL_PP(password), Z_STRLEN_PP(password));
00074               }
00075               smart_str_0(&auth);
00076               buf = php_base64_encode((unsigned char*)auth.c, auth.len, &len);
00077               smart_str_append_const(soap_headers, "Authorization: Basic ");
00078               smart_str_appendl(soap_headers, (char*)buf, len);
00079               smart_str_append_const(soap_headers, "\r\n");
00080               efree(buf);
00081               smart_str_free(&auth);
00082        }
00083 }
00084 
00085 static php_stream* http_connect(zval* this_ptr, php_url *phpurl, int use_ssl, php_stream_context *context, int *use_proxy TSRMLS_DC)
00086 {
00087        php_stream *stream;
00088        zval **proxy_host, **proxy_port, **tmp;
00089        char *host;
00090        char *name;
00091        long namelen;
00092        int port;
00093        int old_error_reporting;
00094        struct timeval tv;
00095        struct timeval *timeout = NULL;
00096 
00097        if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_proxy_host", sizeof("_proxy_host"), (void **) &proxy_host) == SUCCESS &&
00098            Z_TYPE_PP(proxy_host) == IS_STRING &&
00099            zend_hash_find(Z_OBJPROP_P(this_ptr), "_proxy_port", sizeof("_proxy_port"), (void **) &proxy_port) == SUCCESS &&
00100            Z_TYPE_PP(proxy_port) == IS_LONG) {
00101               host = Z_STRVAL_PP(proxy_host);
00102               port = Z_LVAL_PP(proxy_port);
00103               *use_proxy = 1;
00104        } else {
00105               host = phpurl->host;
00106               port = phpurl->port;
00107        }
00108        if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_connection_timeout", sizeof("_connection_timeout"), (void **) &tmp) == SUCCESS &&
00109            Z_TYPE_PP(tmp) == IS_LONG && Z_LVAL_PP(tmp) > 0) {
00110          tv.tv_sec = Z_LVAL_PP(tmp);
00111          tv.tv_usec = 0;
00112               timeout = &tv;
00113        }
00114 
00115        old_error_reporting = EG(error_reporting);
00116        EG(error_reporting) &= ~(E_WARNING|E_NOTICE|E_USER_WARNING|E_USER_NOTICE);
00117 
00118        namelen = spprintf(&name, 0, "%s://%s:%d", (use_ssl && !*use_proxy)? "ssl" : "tcp", host, port);
00119 
00120        stream = php_stream_xport_create(name, namelen,
00121               ENFORCE_SAFE_MODE | REPORT_ERRORS,
00122               STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT,
00123               NULL /*persistent_id*/,
00124               timeout,
00125               context,
00126               NULL, NULL);
00127        efree(name);
00128 
00129        /* SSL & proxy */
00130        if (stream && *use_proxy && use_ssl) {
00131               smart_str soap_headers = {0};
00132               char *http_headers;
00133               int http_header_size;
00134 
00135               smart_str_append_const(&soap_headers, "CONNECT ");
00136               smart_str_appends(&soap_headers, phpurl->host);
00137               smart_str_appendc(&soap_headers, ':');
00138               smart_str_append_unsigned(&soap_headers, phpurl->port);
00139               smart_str_append_const(&soap_headers, " HTTP/1.1\r\n");
00140               smart_str_append_const(&soap_headers, "Host: ");
00141               smart_str_appends(&soap_headers, phpurl->host);
00142               if (phpurl->port != 80) {
00143                      smart_str_appendc(&soap_headers, ':');
00144                      smart_str_append_unsigned(&soap_headers, phpurl->port);
00145               }
00146               smart_str_append_const(&soap_headers, "\r\n");
00147               proxy_authentication(this_ptr, &soap_headers TSRMLS_CC);
00148               smart_str_append_const(&soap_headers, "\r\n");
00149               if (php_stream_write(stream, soap_headers.c, soap_headers.len) != soap_headers.len) {
00150                      php_stream_close(stream);
00151                      stream = NULL;
00152               }
00153               smart_str_free(&soap_headers);
00154 
00155               if (stream) {
00156                      if (!get_http_headers(stream, &http_headers, &http_header_size TSRMLS_CC) || http_headers == NULL) {
00157                             php_stream_close(stream);
00158                             stream = NULL;
00159                      }
00160                      if (http_headers) {
00161                             efree(http_headers);
00162                      }
00163               }
00164               /* enable SSL transport layer */
00165               if (stream) {
00166                      if (php_stream_xport_crypto_setup(stream, STREAM_CRYPTO_METHOD_SSLv23_CLIENT, NULL TSRMLS_CC) < 0 ||
00167                          php_stream_xport_crypto_enable(stream, 1 TSRMLS_CC) < 0) {
00168                             php_stream_close(stream);
00169                             stream = NULL;
00170                      }
00171               }
00172        }
00173 
00174        EG(error_reporting) = old_error_reporting;
00175        return stream;
00176 }
00177 
00178 static int in_domain(const char *host, const char *domain)
00179 {
00180   if (domain[0] == '.') {
00181     int l1 = strlen(host);
00182     int l2 = strlen(domain);
00183     if (l1 > l2) {
00184        return strcmp(host+l1-l2,domain) == 0;
00185     } else {
00186       return 0;
00187     }
00188   } else {
00189     return strcmp(host,domain) == 0;
00190   }
00191 }
00192 
00193 int make_http_soap_request(zval  *this_ptr,
00194                            char  *buf,
00195                            int    buf_size,
00196                            char  *location,
00197                            char  *soapaction,
00198                            int    soap_version,
00199                            char **buffer,
00200                            int   *buffer_len TSRMLS_DC)
00201 {
00202        char *request;
00203        smart_str soap_headers = {0};
00204        smart_str soap_headers_z = {0};
00205        int request_size, err;
00206        php_url *phpurl = NULL;
00207        php_stream *stream;
00208        zval **trace, **tmp;
00209        int use_proxy = 0;
00210        int use_ssl;
00211        char *http_headers, *http_body, *content_type, *http_version, *cookie_itt;
00212        int http_header_size, http_body_size, http_close;
00213        char *connection;
00214        int http_1_1;
00215        int http_status;
00216        int content_type_xml = 0;
00217        long redirect_max = 20;
00218        char *content_encoding;
00219        char *http_msg = NULL;
00220        zend_bool old_allow_url_fopen;
00221        php_stream_context *context = NULL;
00222        zend_bool has_authorization = 0;
00223        zend_bool has_proxy_authorization = 0;
00224        zend_bool has_cookies = 0;
00225 
00226        if (this_ptr == NULL || Z_TYPE_P(this_ptr) != IS_OBJECT) {
00227               return FALSE;
00228        }
00229 
00230   request = buf;
00231   request_size = buf_size;
00232        /* Compress request */
00233        if (zend_hash_find(Z_OBJPROP_P(this_ptr), "compression", sizeof("compression"), (void **)&tmp) == SUCCESS && Z_TYPE_PP(tmp) == IS_LONG) {
00234               int level = Z_LVAL_PP(tmp) & 0x0f;
00235               int kind  = Z_LVAL_PP(tmp) & SOAP_COMPRESSION_DEFLATE;
00236 
00237               if (level > 9) {level = 9;}
00238               
00239          if ((Z_LVAL_PP(tmp) & SOAP_COMPRESSION_ACCEPT) != 0) {
00240                      smart_str_append_const(&soap_headers_z,"Accept-Encoding: gzip, deflate\r\n");
00241          }
00242          if (level > 0) {
00243                      zval func;
00244                      zval retval;
00245                      zval param1, param2, param3;
00246                      zval *params[3];
00247                      int n;
00248 
00249                      params[0] = &param1;
00250                      INIT_PZVAL(params[0]);
00251                      params[1] = &param2;
00252                      INIT_PZVAL(params[1]);
00253                      params[2] = &param3;
00254                      INIT_PZVAL(params[2]);
00255                      ZVAL_STRINGL(params[0], buf, buf_size, 0);
00256                      ZVAL_LONG(params[1], level);
00257            if (kind == SOAP_COMPRESSION_DEFLATE) {
00258               n = 2;
00259                             ZVAL_STRING(&func, "gzcompress", 0);
00260                             smart_str_append_const(&soap_headers_z,"Content-Encoding: deflate\r\n");
00261            } else {
00262              n = 3;
00263                             ZVAL_STRING(&func, "gzencode", 0);
00264                             smart_str_append_const(&soap_headers_z,"Content-Encoding: gzip\r\n");
00265                             ZVAL_LONG(params[2], 1);
00266            }
00267                      if (call_user_function(CG(function_table), (zval**)NULL, &func, &retval, n, params TSRMLS_CC) == SUCCESS &&
00268                          Z_TYPE(retval) == IS_STRING) {
00269                             request = Z_STRVAL(retval);
00270                             request_size = Z_STRLEN(retval);
00271                      } else {
00272                             if (request != buf) {efree(request);}
00273                             smart_str_free(&soap_headers_z);
00274                             return FALSE;
00275                      }
00276          }
00277        }
00278 
00279        if (zend_hash_find(Z_OBJPROP_P(this_ptr), "httpsocket", sizeof("httpsocket"), (void **)&tmp) == SUCCESS) {
00280               php_stream_from_zval_no_verify(stream,tmp);
00281               if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_use_proxy", sizeof("_use_proxy"), (void **)&tmp) == SUCCESS && Z_TYPE_PP(tmp) == IS_LONG) {
00282                      use_proxy = Z_LVAL_PP(tmp);
00283               }
00284        } else {
00285               stream = NULL;
00286        }
00287 
00288        if (location != NULL && location[0] != '\000') {
00289               phpurl = php_url_parse(location);
00290        }
00291 
00292        if (SUCCESS == zend_hash_find(Z_OBJPROP_P(this_ptr),
00293                      "_stream_context", sizeof("_stream_context"), (void**)&tmp)) {
00294               context = php_stream_context_from_zval(*tmp, 0);
00295        }
00296 
00297        if (context && 
00298               php_stream_context_get_option(context, "http", "max_redirects", &tmp) == SUCCESS) {
00299               if (Z_TYPE_PP(tmp) != IS_STRING || !is_numeric_string(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp), &redirect_max, NULL, 1)) {
00300                      if (Z_TYPE_PP(tmp) == IS_LONG)
00301                             redirect_max = Z_LVAL_PP(tmp);
00302               }
00303        }
00304 
00305 try_again:
00306        if (phpurl == NULL || phpurl->host == NULL) {
00307          if (phpurl != NULL) {php_url_free(phpurl);}
00308               if (request != buf) {efree(request);}
00309               add_soap_fault(this_ptr, "HTTP", "Unable to parse URL", NULL, NULL TSRMLS_CC);
00310               smart_str_free(&soap_headers_z);
00311               return FALSE;
00312        }
00313 
00314        use_ssl = 0;
00315        if (phpurl->scheme != NULL && strcmp(phpurl->scheme, "https") == 0) {
00316               use_ssl = 1;
00317        } else if (phpurl->scheme == NULL || strcmp(phpurl->scheme, "http") != 0) {
00318               php_url_free(phpurl);
00319               if (request != buf) {efree(request);}
00320               add_soap_fault(this_ptr, "HTTP", "Unknown protocol. Only http and https are allowed.", NULL, NULL TSRMLS_CC);
00321               smart_str_free(&soap_headers_z);
00322               return FALSE;
00323        }
00324 
00325        old_allow_url_fopen = PG(allow_url_fopen);
00326        PG(allow_url_fopen) = 1;
00327        if (use_ssl && php_stream_locate_url_wrapper("https://", NULL, STREAM_LOCATE_WRAPPERS_ONLY TSRMLS_CC) == NULL) {
00328               php_url_free(phpurl);
00329               if (request != buf) {efree(request);}
00330               add_soap_fault(this_ptr, "HTTP", "SSL support is not available in this build", NULL, NULL TSRMLS_CC);
00331               PG(allow_url_fopen) = old_allow_url_fopen;
00332               smart_str_free(&soap_headers_z);
00333               return FALSE;
00334        }
00335 
00336        if (phpurl->port == 0) {
00337               phpurl->port = use_ssl ? 443 : 80;
00338        }
00339 
00340        /* Check if request to the same host */
00341        if (stream != NULL) {
00342          php_url *orig;
00343               if (zend_hash_find(Z_OBJPROP_P(this_ptr), "httpurl", sizeof("httpurl"), (void **)&tmp) == SUCCESS &&
00344                   (orig = (php_url *) zend_fetch_resource(tmp TSRMLS_CC, -1, "httpurl", NULL, 1, le_url)) != NULL &&
00345                   ((use_proxy && !use_ssl) ||
00346                    (((use_ssl && orig->scheme != NULL && strcmp(orig->scheme, "https") == 0) ||
00347                     (!use_ssl && orig->scheme == NULL) ||
00348                     (!use_ssl && strcmp(orig->scheme, "https") != 0)) &&
00349                    strcmp(orig->host, phpurl->host) == 0 &&
00350                    orig->port == phpurl->port))) {
00351     } else {
00352                      php_stream_close(stream);
00353                      zend_hash_del(Z_OBJPROP_P(this_ptr), "httpurl", sizeof("httpurl"));
00354                      zend_hash_del(Z_OBJPROP_P(this_ptr), "httpsocket", sizeof("httpsocket"));
00355                      zend_hash_del(Z_OBJPROP_P(this_ptr), "_use_proxy", sizeof("_use_proxy"));
00356                      stream = NULL;
00357                      use_proxy = 0;
00358     }
00359        }
00360 
00361        /* Check if keep-alive connection is still opened */
00362        if (stream != NULL && php_stream_eof(stream)) {
00363               php_stream_close(stream);
00364               zend_hash_del(Z_OBJPROP_P(this_ptr), "httpurl", sizeof("httpurl"));
00365               zend_hash_del(Z_OBJPROP_P(this_ptr), "httpsocket", sizeof("httpsocket"));
00366               zend_hash_del(Z_OBJPROP_P(this_ptr), "_use_proxy", sizeof("_use_proxy"));
00367               stream = NULL;
00368               use_proxy = 0;
00369        }
00370 
00371        if (!stream) {
00372               stream = http_connect(this_ptr, phpurl, use_ssl, context, &use_proxy TSRMLS_CC);
00373               if (stream) {
00374                      php_stream_auto_cleanup(stream);
00375                      add_property_resource(this_ptr, "httpsocket", php_stream_get_resource_id(stream));
00376                      add_property_long(this_ptr, "_use_proxy", use_proxy);
00377               } else {
00378                      php_url_free(phpurl);
00379                      if (request != buf) {efree(request);}
00380                      add_soap_fault(this_ptr, "HTTP", "Could not connect to host", NULL, NULL TSRMLS_CC);
00381                      PG(allow_url_fopen) = old_allow_url_fopen;
00382                      smart_str_free(&soap_headers_z);
00383                      return FALSE;
00384               }
00385        }
00386        PG(allow_url_fopen) = old_allow_url_fopen;
00387 
00388        if (stream) {
00389               zval **cookies, **login, **password;
00390          int ret = zend_list_insert(phpurl, le_url);
00391 
00392               add_property_resource(this_ptr, "httpurl", ret);
00393               /*zend_list_addref(ret);*/
00394 
00395               if (context && 
00396                   php_stream_context_get_option(context, "http", "protocol_version", &tmp) == SUCCESS &&
00397                   Z_TYPE_PP(tmp) == IS_DOUBLE &&
00398                   Z_DVAL_PP(tmp) == 1.0) {
00399                      http_1_1 = 0;
00400               } else {
00401                      http_1_1 = 1;
00402               }
00403 
00404               smart_str_append_const(&soap_headers, "POST ");
00405               if (use_proxy && !use_ssl) {
00406                      smart_str_appends(&soap_headers, phpurl->scheme);
00407                      smart_str_append_const(&soap_headers, "://");
00408                      smart_str_appends(&soap_headers, phpurl->host);
00409                      smart_str_appendc(&soap_headers, ':');
00410                      smart_str_append_unsigned(&soap_headers, phpurl->port);
00411               }
00412               if (phpurl->path) {
00413                      smart_str_appends(&soap_headers, phpurl->path);
00414               } else {
00415                      smart_str_appendc(&soap_headers, '/');
00416               }
00417               if (phpurl->query) {
00418                      smart_str_appendc(&soap_headers, '?');
00419                      smart_str_appends(&soap_headers, phpurl->query);
00420               }
00421               if (phpurl->fragment) {
00422                      smart_str_appendc(&soap_headers, '#');
00423                      smart_str_appends(&soap_headers, phpurl->fragment);
00424               }
00425               if (http_1_1) {
00426                      smart_str_append_const(&soap_headers, " HTTP/1.1\r\n");
00427               } else {
00428                      smart_str_append_const(&soap_headers, " HTTP/1.0\r\n");
00429               }
00430               smart_str_append_const(&soap_headers, "Host: ");
00431               smart_str_appends(&soap_headers, phpurl->host);
00432               if (phpurl->port != (use_ssl?443:80)) {
00433                      smart_str_appendc(&soap_headers, ':');
00434                      smart_str_append_unsigned(&soap_headers, phpurl->port);
00435               }
00436               if (http_1_1) {
00437                      smart_str_append_const(&soap_headers, "\r\n"
00438                             "Connection: Keep-Alive\r\n");
00439               } else {
00440                      smart_str_append_const(&soap_headers, "\r\n"
00441                             "Connection: close\r\n");
00442               }
00443               if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_user_agent", sizeof("_user_agent"), (void **)&tmp) == SUCCESS &&
00444                   Z_TYPE_PP(tmp) == IS_STRING) {
00445                      if (Z_STRLEN_PP(tmp) > 0) {
00446                             smart_str_append_const(&soap_headers, "User-Agent: ");
00447                             smart_str_appendl(&soap_headers, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
00448                             smart_str_append_const(&soap_headers, "\r\n");
00449                      }
00450               } else if (context && 
00451                          php_stream_context_get_option(context, "http", "user_agent", &tmp) == SUCCESS &&
00452                          Z_TYPE_PP(tmp) == IS_STRING) {
00453                      if (Z_STRLEN_PP(tmp) > 0) {
00454                             smart_str_append_const(&soap_headers, "User-Agent: ");
00455                             smart_str_appendl(&soap_headers, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
00456                             smart_str_append_const(&soap_headers, "\r\n");
00457                      }
00458               } else if (FG(user_agent)) {
00459                      smart_str_append_const(&soap_headers, "User-Agent: ");
00460                      smart_str_appends(&soap_headers, FG(user_agent));
00461                      smart_str_append_const(&soap_headers, "\r\n");
00462               } else {
00463                      smart_str_append_const(&soap_headers, "User-Agent: PHP-SOAP/"PHP_VERSION"\r\n");
00464               }
00465 
00466               smart_str_append(&soap_headers, &soap_headers_z);
00467 
00468               if (soap_version == SOAP_1_2) {
00469                      smart_str_append_const(&soap_headers,"Content-Type: application/soap+xml; charset=utf-8");
00470                      if (soapaction) {
00471                             smart_str_append_const(&soap_headers,"; action=\"");
00472                             smart_str_appends(&soap_headers, soapaction);
00473                             smart_str_append_const(&soap_headers,"\"");
00474                      }
00475                      smart_str_append_const(&soap_headers,"\r\n");
00476               } else {
00477                      smart_str_append_const(&soap_headers,"Content-Type: text/xml; charset=utf-8\r\n");
00478                      if (soapaction) {
00479                             smart_str_append_const(&soap_headers, "SOAPAction: \"");
00480                             smart_str_appends(&soap_headers, soapaction);
00481                             smart_str_append_const(&soap_headers, "\"\r\n");
00482                      }
00483               }
00484               smart_str_append_const(&soap_headers,"Content-Length: ");
00485               smart_str_append_long(&soap_headers, request_size);
00486               smart_str_append_const(&soap_headers, "\r\n");
00487 
00488               /* HTTP Authentication */
00489               if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_login", sizeof("_login"), (void **)&login) == SUCCESS &&
00490                   Z_TYPE_PP(login) == IS_STRING) {
00491                      zval **digest;
00492 
00493                      has_authorization = 1;
00494                      if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_digest", sizeof("_digest"), (void **)&digest) == SUCCESS) {
00495                             if (Z_TYPE_PP(digest) == IS_ARRAY) {
00496                                    char          HA1[33], HA2[33], response[33], cnonce[33], nc[9];
00497                                    PHP_MD5_CTX   md5ctx;
00498                                    unsigned char hash[16];
00499 
00500                                    PHP_MD5Init(&md5ctx);
00501                                    snprintf(cnonce, sizeof(cnonce), "%ld", php_rand(TSRMLS_C));
00502                                    PHP_MD5Update(&md5ctx, (unsigned char*)cnonce, strlen(cnonce));
00503                                    PHP_MD5Final(hash, &md5ctx);
00504                                    make_digest(cnonce, hash);
00505 
00506                                    if (zend_hash_find(Z_ARRVAL_PP(digest), "nc", sizeof("nc"), (void **)&tmp) == SUCCESS &&
00507                                        Z_TYPE_PP(tmp) == IS_LONG) {
00508                                           Z_LVAL_PP(tmp)++;
00509                                           snprintf(nc, sizeof(nc), "%08ld", Z_LVAL_PP(tmp));
00510                                    } else {
00511                                           add_assoc_long(*digest, "nc", 1);
00512                                           strcpy(nc, "00000001");
00513                                    }
00514 
00515                                    PHP_MD5Init(&md5ctx);
00516                                    PHP_MD5Update(&md5ctx, (unsigned char*)Z_STRVAL_PP(login), Z_STRLEN_PP(login));
00517                                    PHP_MD5Update(&md5ctx, (unsigned char*)":", 1);
00518                                    if (zend_hash_find(Z_ARRVAL_PP(digest), "realm", sizeof("realm"), (void **)&tmp) == SUCCESS &&
00519                                        Z_TYPE_PP(tmp) == IS_STRING) {
00520                                           PHP_MD5Update(&md5ctx, (unsigned char*)Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
00521                                    }
00522                                    PHP_MD5Update(&md5ctx, (unsigned char*)":", 1);
00523                                    if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_password", sizeof("_password"), (void **)&password) == SUCCESS &&
00524                                        Z_TYPE_PP(password) == IS_STRING) {
00525                                           PHP_MD5Update(&md5ctx, (unsigned char*)Z_STRVAL_PP(password), Z_STRLEN_PP(password));
00526                                    }
00527                                    PHP_MD5Final(hash, &md5ctx);
00528                                    make_digest(HA1, hash);
00529                                    if (zend_hash_find(Z_ARRVAL_PP(digest), "algorithm", sizeof("algorithm"), (void **)&tmp) == SUCCESS &&
00530                                        Z_TYPE_PP(tmp) == IS_STRING &&
00531                                        Z_STRLEN_PP(tmp) == sizeof("md5-sess")-1 &&
00532                                        stricmp(Z_STRVAL_PP(tmp), "md5-sess") == 0) {
00533                                           PHP_MD5Init(&md5ctx);
00534                                           PHP_MD5Update(&md5ctx, (unsigned char*)HA1, 32);
00535                                           PHP_MD5Update(&md5ctx, (unsigned char*)":", 1);
00536                                           if (zend_hash_find(Z_ARRVAL_PP(digest), "nonce", sizeof("nonce"), (void **)&tmp) == SUCCESS &&
00537                                               Z_TYPE_PP(tmp) == IS_STRING) {
00538                                                  PHP_MD5Update(&md5ctx, (unsigned char*)Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
00539                                           }
00540                                           PHP_MD5Update(&md5ctx, (unsigned char*)":", 1);
00541                                           PHP_MD5Update(&md5ctx, (unsigned char*)cnonce, 8);
00542                                           PHP_MD5Final(hash, &md5ctx);
00543                                           make_digest(HA1, hash);
00544                                    }
00545 
00546                                    PHP_MD5Init(&md5ctx);
00547                                    PHP_MD5Update(&md5ctx, (unsigned char*)"POST:", sizeof("POST:")-1);
00548                                    if (phpurl->path) {
00549                                           PHP_MD5Update(&md5ctx, (unsigned char*)phpurl->path, strlen(phpurl->path));
00550                                    } else {
00551                                           PHP_MD5Update(&md5ctx, (unsigned char*)"/", 1);
00552                                    }
00553                                    if (phpurl->query) {
00554                                           PHP_MD5Update(&md5ctx, (unsigned char*)"?", 1);
00555                                           PHP_MD5Update(&md5ctx, (unsigned char*)phpurl->query, strlen(phpurl->query));
00556                                    }
00557 
00558                                    /* TODO: Support for qop="auth-int" */
00559 /*
00560                                    if (zend_hash_find(Z_ARRVAL_PP(digest), "qop", sizeof("qop"), (void **)&tmp) == SUCCESS &&
00561                                        Z_TYPE_PP(tmp) == IS_STRING &&
00562                                        Z_STRLEN_PP(tmp) == sizeof("auth-int")-1 &&
00563                                        stricmp(Z_STRVAL_PP(tmp), "auth-int") == 0) {
00564                                           PHP_MD5Update(&md5ctx, ":", 1);
00565                                           PHP_MD5Update(&md5ctx, HEntity, HASHHEXLEN);
00566                                    }
00567 */
00568                                    PHP_MD5Final(hash, &md5ctx);
00569                                    make_digest(HA2, hash);
00570 
00571                                    PHP_MD5Init(&md5ctx);
00572                                    PHP_MD5Update(&md5ctx, (unsigned char*)HA1, 32);
00573                                    PHP_MD5Update(&md5ctx, (unsigned char*)":", 1);
00574                                    if (zend_hash_find(Z_ARRVAL_PP(digest), "nonce", sizeof("nonce"), (void **)&tmp) == SUCCESS &&
00575                                        Z_TYPE_PP(tmp) == IS_STRING) {
00576                                           PHP_MD5Update(&md5ctx, (unsigned char*)Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
00577                                    }
00578                                    PHP_MD5Update(&md5ctx, (unsigned char*)":", 1);
00579                                    if (zend_hash_find(Z_ARRVAL_PP(digest), "qop", sizeof("qop"), (void **)&tmp) == SUCCESS &&
00580                                        Z_TYPE_PP(tmp) == IS_STRING) {
00581                                           PHP_MD5Update(&md5ctx, (unsigned char*)nc, 8);
00582                                           PHP_MD5Update(&md5ctx, (unsigned char*)":", 1);
00583                                           PHP_MD5Update(&md5ctx, (unsigned char*)cnonce, 8);
00584                                           PHP_MD5Update(&md5ctx, (unsigned char*)":", 1);
00585                                           /* TODO: Support for qop="auth-int" */
00586                                           PHP_MD5Update(&md5ctx, (unsigned char*)"auth", sizeof("auth")-1);
00587                                           PHP_MD5Update(&md5ctx, (unsigned char*)":", 1);
00588                                    }
00589                                    PHP_MD5Update(&md5ctx, (unsigned char*)HA2, 32);
00590                                    PHP_MD5Final(hash, &md5ctx);
00591                                    make_digest(response, hash);
00592        
00593                                    smart_str_append_const(&soap_headers, "Authorization: Digest username=\"");
00594                                    smart_str_appendl(&soap_headers, Z_STRVAL_PP(login), Z_STRLEN_PP(login));
00595                                    if (zend_hash_find(Z_ARRVAL_PP(digest), "realm", sizeof("realm"), (void **)&tmp) == SUCCESS &&
00596                                        Z_TYPE_PP(tmp) == IS_STRING) {
00597                                           smart_str_append_const(&soap_headers, "\", realm=\"");
00598                                           smart_str_appendl(&soap_headers, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
00599                                    }
00600                                    if (zend_hash_find(Z_ARRVAL_PP(digest), "nonce", sizeof("nonce"), (void **)&tmp) == SUCCESS &&
00601                                        Z_TYPE_PP(tmp) == IS_STRING) {
00602                                           smart_str_append_const(&soap_headers, "\", nonce=\"");
00603                                           smart_str_appendl(&soap_headers, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
00604                                    }
00605                                    smart_str_append_const(&soap_headers, "\", uri=\"");
00606                                    if (phpurl->path) {
00607                                           smart_str_appends(&soap_headers, phpurl->path);
00608                                    } else {
00609                                           smart_str_appendc(&soap_headers, '/');
00610                                    } 
00611                                    if (phpurl->query) {
00612                                           smart_str_appendc(&soap_headers, '?');
00613                                           smart_str_appends(&soap_headers, phpurl->query);
00614                                    }
00615                                    if (phpurl->fragment) {
00616                                           smart_str_appendc(&soap_headers, '#');
00617                                           smart_str_appends(&soap_headers, phpurl->fragment);
00618                                    }
00619                                    if (zend_hash_find(Z_ARRVAL_PP(digest), "qop", sizeof("qop"), (void **)&tmp) == SUCCESS &&
00620                                        Z_TYPE_PP(tmp) == IS_STRING) {
00621                                    /* TODO: Support for qop="auth-int" */
00622                                           smart_str_append_const(&soap_headers, "\", qop=\"auth");
00623                                           smart_str_append_const(&soap_headers, "\", nc=\"");
00624                                           smart_str_appendl(&soap_headers, nc, 8);
00625                                           smart_str_append_const(&soap_headers, "\", cnonce=\"");
00626                                           smart_str_appendl(&soap_headers, cnonce, 8);
00627                                    }
00628                                    smart_str_append_const(&soap_headers, "\", response=\"");
00629                                    smart_str_appendl(&soap_headers, response, 32);
00630                                    if (zend_hash_find(Z_ARRVAL_PP(digest), "opaque", sizeof("opaque"), (void **)&tmp) == SUCCESS &&
00631                                        Z_TYPE_PP(tmp) == IS_STRING) {
00632                                           smart_str_append_const(&soap_headers, "\", opaque=\"");
00633                                           smart_str_appendl(&soap_headers, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
00634                                    }
00635                                    if (zend_hash_find(Z_ARRVAL_PP(digest), "algorithm", sizeof("algorithm"), (void **)&tmp) == SUCCESS &&
00636                                           Z_TYPE_PP(tmp) == IS_STRING) {
00637                                           smart_str_append_const(&soap_headers, "\", algorithm=\"");
00638                                           smart_str_appendl(&soap_headers, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
00639                                    }
00640                                    smart_str_append_const(&soap_headers, "\"\r\n");
00641                             }
00642                      } else {
00643                             unsigned char* buf;
00644                             int len;
00645 
00646                             smart_str auth = {0};
00647                             smart_str_appendl(&auth, Z_STRVAL_PP(login), Z_STRLEN_PP(login));
00648                             smart_str_appendc(&auth, ':');
00649                             if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_password", sizeof("_password"), (void **)&password) == SUCCESS &&
00650                                 Z_TYPE_PP(password) == IS_STRING) {
00651                                    smart_str_appendl(&auth, Z_STRVAL_PP(password), Z_STRLEN_PP(password));
00652                             }
00653                             smart_str_0(&auth);
00654                             buf = php_base64_encode((unsigned char*)auth.c, auth.len, &len);
00655                             smart_str_append_const(&soap_headers, "Authorization: Basic ");
00656                             smart_str_appendl(&soap_headers, (char*)buf, len);
00657                             smart_str_append_const(&soap_headers, "\r\n");
00658                             efree(buf);
00659                             smart_str_free(&auth);
00660                      }
00661               }
00662 
00663               /* Proxy HTTP Authentication */
00664               if (use_proxy && !use_ssl) {
00665                      has_proxy_authorization = 1;
00666                      proxy_authentication(this_ptr, &soap_headers TSRMLS_CC);
00667               }
00668 
00669               /* Send cookies along with request */
00670               if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_cookies", sizeof("_cookies"), (void **)&cookies) == SUCCESS) {
00671                      zval **data;
00672                      char *key;
00673                      int i, n;
00674 
00675                      has_cookies = 1;
00676                      n = zend_hash_num_elements(Z_ARRVAL_PP(cookies));
00677                      if (n > 0) {
00678                             zend_hash_internal_pointer_reset(Z_ARRVAL_PP(cookies));
00679                             smart_str_append_const(&soap_headers, "Cookie: ");
00680                             for (i = 0; i < n; i++) {
00681                                    zend_hash_get_current_data(Z_ARRVAL_PP(cookies), (void **)&data);
00682                                    zend_hash_get_current_key(Z_ARRVAL_PP(cookies), &key, NULL, FALSE);
00683 
00684                                    if (Z_TYPE_PP(data) == IS_ARRAY) {
00685                                      zval** value;
00686 
00687                                           if (zend_hash_index_find(Z_ARRVAL_PP(data), 0, (void**)&value) == SUCCESS &&
00688                                               Z_TYPE_PP(value) == IS_STRING) {
00689                                             zval **tmp;
00690                                             if ((zend_hash_index_find(Z_ARRVAL_PP(data), 1, (void**)&tmp) == FAILURE ||
00691                                                  strncmp(phpurl->path?phpurl->path:"/",Z_STRVAL_PP(tmp),Z_STRLEN_PP(tmp)) == 0) &&
00692                                                 (zend_hash_index_find(Z_ARRVAL_PP(data), 2, (void**)&tmp) == FAILURE ||
00693                                                  in_domain(phpurl->host,Z_STRVAL_PP(tmp))) &&
00694                                                 (use_ssl || zend_hash_index_find(Z_ARRVAL_PP(data), 3, (void**)&tmp) == FAILURE)) {
00695                                                         smart_str_appendl(&soap_headers, key, strlen(key));
00696                                                         smart_str_appendc(&soap_headers, '=');
00697                                                         smart_str_appendl(&soap_headers, Z_STRVAL_PP(value), Z_STRLEN_PP(value));
00698                                                         smart_str_appendc(&soap_headers, ';');
00699                                                  }
00700                                           }
00701                                    }
00702                                    zend_hash_move_forward(Z_ARRVAL_PP(cookies));
00703                             }
00704                             smart_str_append_const(&soap_headers, "\r\n");
00705                      }
00706               }
00707 
00708               if (context &&
00709                      php_stream_context_get_option(context, "http", "header", &tmp) == SUCCESS &&
00710                      Z_TYPE_PP(tmp) == IS_STRING && Z_STRLEN_PP(tmp)) {
00711                      char *s = Z_STRVAL_PP(tmp);
00712                      char *p;
00713                      int name_len;
00714 
00715                      while (*s) {
00716                             /* skip leading newlines and spaces */
00717                             while (*s == ' ' || *s == '\t' || *s == '\r' || *s == '\n') {
00718                                    s++;
00719                             }
00720                             /* extract header name */
00721                             p = s;
00722                             name_len = -1;
00723                             while (*p) {
00724                                    if (*p == ':') {
00725                                           if (name_len < 0) name_len = p - s;
00726                                           break;
00727                                    } else if (*p == ' ' || *p == '\t') {
00728                                           if (name_len < 0) name_len = p - s;
00729                                    } else if (*p == '\r' || *p == '\n') {
00730                                           break;
00731                                    }
00732                                    p++;
00733                             }
00734                             if (*p == ':') {
00735                                    /* extract header value */
00736                                    while (*p && *p != '\r' && *p != '\n') {
00737                                           p++;
00738                                    }
00739                                    /* skip some predefined headers */
00740                                    if ((name_len != sizeof("host")-1 ||
00741                                         strncasecmp(s, "host", sizeof("host")-1) != 0) &&
00742                                        (name_len != sizeof("connection")-1 ||
00743                                         strncasecmp(s, "connection", sizeof("connection")-1) != 0) &&
00744                                        (name_len != sizeof("user-agent")-1 ||
00745                                         strncasecmp(s, "user-agent", sizeof("user-agent")-1) != 0) &&
00746                                        (name_len != sizeof("content-length")-1 ||
00747                                         strncasecmp(s, "content-length", sizeof("content-length")-1) != 0) &&
00748                                        (name_len != sizeof("content-type")-1 ||
00749                                         strncasecmp(s, "content-type", sizeof("content-type")-1) != 0) &&
00750                                        (!has_cookies ||
00751                                         name_len != sizeof("cookie")-1 ||
00752                                         strncasecmp(s, "cookie", sizeof("cookie")-1) != 0) &&
00753                                        (!has_authorization ||
00754                                         name_len != sizeof("authorization")-1 ||
00755                                         strncasecmp(s, "authorization", sizeof("authorization")-1) != 0) &&
00756                                        (!has_proxy_authorization ||
00757                                         name_len != sizeof("proxy-authorization")-1 ||
00758                                         strncasecmp(s, "proxy-authorization", sizeof("proxy-authorization")-1) != 0)) {
00759                                        /* add header */
00760                                           smart_str_appendl(&soap_headers, s, p-s);
00761                                           smart_str_append_const(&soap_headers, "\r\n");
00762                                    }
00763                             }
00764                             s = (*p) ? (p + 1) : p;
00765                      }
00766               }
00767 
00768               smart_str_append_const(&soap_headers, "\r\n");
00769               smart_str_0(&soap_headers);
00770               if (zend_hash_find(Z_OBJPROP_P(this_ptr), "trace", sizeof("trace"), (void **) &trace) == SUCCESS &&
00771                   Z_LVAL_PP(trace) > 0) {
00772                      add_property_stringl(this_ptr, "__last_request_headers", soap_headers.c, soap_headers.len, 1);
00773               }
00774               smart_str_appendl(&soap_headers, request, request_size);
00775               smart_str_0(&soap_headers);
00776 
00777               err = php_stream_write(stream, soap_headers.c, soap_headers.len);
00778               if (err != soap_headers.len) {
00779                      if (request != buf) {efree(request);}
00780                      php_stream_close(stream);
00781                      zend_hash_del(Z_OBJPROP_P(this_ptr), "httpurl", sizeof("httpurl"));
00782                      zend_hash_del(Z_OBJPROP_P(this_ptr), "httpsocket", sizeof("httpsocket"));
00783                      zend_hash_del(Z_OBJPROP_P(this_ptr), "_use_proxy", sizeof("_use_proxy"));
00784                      add_soap_fault(this_ptr, "HTTP", "Failed Sending HTTP SOAP request", NULL, NULL TSRMLS_CC);
00785                      smart_str_free(&soap_headers_z);
00786                      return FALSE;
00787               }
00788               smart_str_free(&soap_headers);
00789        } else {
00790               add_soap_fault(this_ptr, "HTTP", "Failed to create stream??", NULL, NULL TSRMLS_CC);
00791               smart_str_free(&soap_headers_z);
00792               return FALSE;
00793        }
00794 
00795        if (!buffer) {
00796               php_stream_close(stream);
00797               zend_hash_del(Z_OBJPROP_P(this_ptr), "httpsocket", sizeof("httpsocket"));
00798               zend_hash_del(Z_OBJPROP_P(this_ptr), "_use_proxy", sizeof("_use_proxy"));
00799               smart_str_free(&soap_headers_z);
00800               return TRUE;
00801        }
00802 
00803        do {
00804               if (!get_http_headers(stream, &http_headers, &http_header_size TSRMLS_CC)) {
00805                      if (http_headers) {efree(http_headers);}
00806                      if (request != buf) {efree(request);}
00807                      php_stream_close(stream);
00808                      zend_hash_del(Z_OBJPROP_P(this_ptr), "httpsocket", sizeof("httpsocket"));
00809                      zend_hash_del(Z_OBJPROP_P(this_ptr), "_use_proxy", sizeof("_use_proxy"));
00810                      add_soap_fault(this_ptr, "HTTP", "Error Fetching http headers", NULL, NULL TSRMLS_CC);
00811                      smart_str_free(&soap_headers_z);
00812                      return FALSE;
00813               }
00814 
00815               if (zend_hash_find(Z_OBJPROP_P(this_ptr), "trace", sizeof("trace"), (void **) &trace) == SUCCESS &&
00816                   Z_LVAL_PP(trace) > 0) {
00817                      add_property_stringl(this_ptr, "__last_response_headers", http_headers, http_header_size, 1);
00818               }
00819 
00820               /* Check to see what HTTP status was sent */
00821               http_1_1 = 0;
00822               http_status = 0;
00823               http_version = get_http_header_value(http_headers,"HTTP/");
00824               if (http_version) {
00825                      char *tmp;
00826 
00827                      if (!strncmp(http_version,"1.1", 3)) {
00828                             http_1_1 = 1;
00829                      }
00830 
00831                      tmp = strstr(http_version," ");
00832                      if (tmp != NULL) {
00833                             tmp++;
00834                             http_status = atoi(tmp);
00835                      }
00836                      tmp = strstr(tmp," ");
00837                      if (tmp != NULL) {
00838                             tmp++;
00839                             if (http_msg) {
00840                                    efree(http_msg);
00841                             }
00842                             http_msg = estrdup(tmp);
00843                      }
00844                      efree(http_version);
00845 
00846                      /* Try and get headers again */
00847                      if (http_status == 100) {
00848                             efree(http_headers);
00849                      }
00850               }
00851        } while (http_status == 100);
00852 
00853        /* Grab and send back every cookie */
00854 
00855        /* Not going to worry about Path: because
00856           we shouldn't be changing urls so path dont
00857           matter too much
00858        */
00859        cookie_itt = strstr(http_headers,"Set-Cookie: ");
00860        while (cookie_itt) {
00861               char *end_pos, *cookie;
00862               char *eqpos, *sempos;
00863               zval **cookies;
00864 
00865               if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_cookies", sizeof("_cookies"), (void **)&cookies) == FAILURE) {
00866                      zval *tmp_cookies;
00867                      MAKE_STD_ZVAL(tmp_cookies);
00868                      array_init(tmp_cookies);
00869                      zend_hash_update(Z_OBJPROP_P(this_ptr), "_cookies", sizeof("_cookies"), &tmp_cookies, sizeof(zval *), (void **)&cookies);
00870               }
00871 
00872               end_pos = strstr(cookie_itt,"\r\n");
00873               cookie = get_http_header_value(cookie_itt,"Set-Cookie: ");
00874 
00875               eqpos = strstr(cookie, "=");
00876               sempos = strstr(cookie, ";");
00877               if (eqpos != NULL && (sempos == NULL || sempos > eqpos)) {
00878                      smart_str name = {0};
00879                      int cookie_len;
00880                      zval *zcookie;
00881 
00882                      if (sempos != NULL) {
00883                             cookie_len = sempos-(eqpos+1);
00884                      } else {
00885                             cookie_len = strlen(cookie)-(eqpos-cookie)-1;
00886                      }
00887 
00888                      smart_str_appendl(&name, cookie, eqpos - cookie);
00889                      smart_str_0(&name);
00890 
00891                      ALLOC_INIT_ZVAL(zcookie);
00892                      array_init(zcookie);
00893                      add_index_stringl(zcookie, 0, eqpos + 1, cookie_len, 1);
00894 
00895                      if (sempos != NULL) {
00896                             char *options = cookie + cookie_len+1;
00897                             while (*options) {
00898                                    while (*options == ' ') {options++;}
00899                                    sempos = strstr(options, ";");
00900                                    if (strstr(options,"path=") == options) {
00901                                           eqpos = options + sizeof("path=")-1;
00902                                           add_index_stringl(zcookie, 1, eqpos, sempos?(sempos-eqpos):strlen(eqpos), 1);
00903                                    } else if (strstr(options,"domain=") == options) {
00904                                           eqpos = options + sizeof("domain=")-1;
00905                                           add_index_stringl(zcookie, 2, eqpos, sempos?(sempos-eqpos):strlen(eqpos), 1);
00906                                    } else if (strstr(options,"secure") == options) {
00907                                           add_index_bool(zcookie, 3, 1);
00908                                    }
00909                                    if (sempos != NULL) {
00910                                           options = sempos+1;
00911                                    } else {
00912                                      break;
00913                                    }
00914                             }
00915                      }
00916                      if (!zend_hash_index_exists(Z_ARRVAL_P(zcookie), 1)) {
00917                             char *t = phpurl->path?phpurl->path:"/";
00918                             char *c = strrchr(t, '/');
00919                             if (c) {
00920                                    add_index_stringl(zcookie, 1, t, c-t, 1);
00921                             }
00922                      }
00923                      if (!zend_hash_index_exists(Z_ARRVAL_P(zcookie), 2)) {
00924                             add_index_string(zcookie, 2, phpurl->host, 1);
00925                      }
00926 
00927                      add_assoc_zval_ex(*cookies, name.c, name.len+1, zcookie);
00928                      smart_str_free(&name);
00929               }
00930 
00931               cookie_itt = strstr(cookie_itt + sizeof("Set-Cookie: "), "Set-Cookie: ");
00932               efree(cookie);
00933        }
00934 
00935        /* See if the server requested a close */
00936        if (http_1_1) {
00937               http_close = FALSE;
00938               if (use_proxy && !use_ssl) {
00939                      connection = get_http_header_value(http_headers,"Proxy-Connection: ");
00940                      if (connection) {
00941                             if (strncasecmp(connection, "close", sizeof("close")-1) == 0) {
00942                                    http_close = TRUE;
00943                             }
00944                             efree(connection);
00945                      }
00946               }
00947               if (http_close == FALSE) {
00948                      connection = get_http_header_value(http_headers,"Connection: ");
00949                      if (connection) {
00950                             if (strncasecmp(connection, "close", sizeof("close")-1) == 0) {
00951                                    http_close = TRUE;
00952                             }
00953                             efree(connection);
00954                      }
00955               }
00956        } else {
00957               http_close = TRUE;
00958               if (use_proxy && !use_ssl) {
00959                      connection = get_http_header_value(http_headers,"Proxy-Connection: ");
00960                      if (connection) {
00961                             if (strncasecmp(connection, "Keep-Alive", sizeof("Keep-Alive")-1) == 0) {
00962                                    http_close = FALSE;
00963                             }
00964                             efree(connection);
00965                      }
00966               }
00967               if (http_close == TRUE) {
00968                      connection = get_http_header_value(http_headers,"Connection: ");
00969                      if (connection) {
00970                             if (strncasecmp(connection, "Keep-Alive", sizeof("Keep-Alive")-1) == 0) {
00971                                    http_close = FALSE;
00972                             }
00973                             efree(connection);
00974                      }
00975               }
00976        }      
00977 
00978        if (!get_http_body(stream, http_close, http_headers, &http_body, &http_body_size TSRMLS_CC)) {
00979               if (request != buf) {efree(request);}
00980               php_stream_close(stream);
00981               efree(http_headers);
00982               zend_hash_del(Z_OBJPROP_P(this_ptr), "httpsocket", sizeof("httpsocket"));
00983               zend_hash_del(Z_OBJPROP_P(this_ptr), "_use_proxy", sizeof("_use_proxy"));
00984               add_soap_fault(this_ptr, "HTTP", "Error Fetching http body, No Content-Length, connection closed or chunked data", NULL, NULL TSRMLS_CC);
00985               if (http_msg) {
00986                      efree(http_msg);
00987               }
00988               smart_str_free(&soap_headers_z);
00989               return FALSE;
00990        }
00991 
00992        if (request != buf) {efree(request);}
00993 
00994        if (http_close) {
00995               php_stream_close(stream);
00996               zend_hash_del(Z_OBJPROP_P(this_ptr), "httpsocket", sizeof("httpsocket"));
00997               zend_hash_del(Z_OBJPROP_P(this_ptr), "_use_proxy", sizeof("_use_proxy"));
00998               stream = NULL;
00999        }
01000 
01001        /* Process HTTP status codes */
01002        if (http_status >= 300 && http_status < 400) {
01003               char *loc;
01004 
01005               if ((loc = get_http_header_value(http_headers,"Location: ")) != NULL) {
01006                      php_url *new_url  = php_url_parse(loc);
01007 
01008                      if (new_url != NULL) {
01009                             efree(http_headers);
01010                             efree(http_body);
01011                             efree(loc);
01012                             if (new_url->scheme == NULL && new_url->path != NULL) {
01013                                    new_url->scheme = phpurl->scheme ? estrdup(phpurl->scheme) : NULL;
01014                                    new_url->host = phpurl->host ? estrdup(phpurl->host) : NULL;
01015                                    new_url->port = phpurl->port;
01016                                    if (new_url->path && new_url->path[0] != '/') {
01017                                           if (phpurl->path) {
01018                                                  char *t = phpurl->path;
01019                                                  char *p = strrchr(t, '/');
01020                                                  if (p) {
01021                                                         char *s = emalloc((p - t) + strlen(new_url->path) + 2);
01022                                                         strncpy(s, t, (p - t) + 1);
01023                                                         s[(p - t) + 1] = 0;
01024                                                         strcat(s, new_url->path);
01025                                                         efree(new_url->path);
01026                                                         new_url->path = s;
01027                                                  } 
01028                                           } else {
01029                                                  char *s = emalloc(strlen(new_url->path) + 2);
01030                                                  s[0] = '/'; s[1] = 0;
01031                                                  strcat(s, new_url->path);
01032                                                  efree(new_url->path);
01033                                                  new_url->path = s;
01034                                           }
01035                                    }
01036                             }
01037                             phpurl = new_url;
01038 
01039                             if (--redirect_max < 1) {
01040                                    add_soap_fault(this_ptr, "HTTP", "Redirection limit reached, aborting", NULL, NULL TSRMLS_CC);
01041                                    smart_str_free(&soap_headers_z);
01042                                    return FALSE;
01043                             }
01044 
01045                             goto try_again;
01046                      }
01047               }
01048        } else if (http_status == 401) {
01049               /* Digest authentication */
01050               zval **digest, **login, **password;
01051               char *auth = get_http_header_value(http_headers, "WWW-Authenticate: ");
01052 
01053               if (auth &&
01054                             strstr(auth, "Digest") == auth &&
01055                   (zend_hash_find(Z_OBJPROP_P(this_ptr), "_digest", sizeof("_digest"), (void **)&digest) == FAILURE ||
01056                    Z_TYPE_PP(digest) != IS_ARRAY) &&
01057                   zend_hash_find(Z_OBJPROP_P(this_ptr), "_login", sizeof("_login"), (void **)&login) == SUCCESS &&
01058                   Z_TYPE_PP(login) == IS_STRING &&
01059                   zend_hash_find(Z_OBJPROP_P(this_ptr), "_password", sizeof("_password"), (void **)&password) == SUCCESS &&
01060                   Z_TYPE_PP(password) == IS_STRING) {
01061                      char *s;
01062                      zval *digest = NULL;
01063 
01064                      s = auth + sizeof("Digest")-1;
01065                      while (*s != '\0') {
01066                             char *name, *val;
01067                             while (*s == ' ') ++s;
01068                             name = s;
01069                             while (*s != '\0' && *s != '=') ++s;
01070                             if (*s == '=') {
01071                                    *s = '\0';
01072                                    ++s;
01073                                    if (*s == '"') {
01074                                           ++s;
01075                                           val = s;
01076                                           while (*s != '\0' && *s != '"') ++s;
01077                                    } else {
01078                                           val = s;
01079                                           while (*s != '\0' && *s != ' ' && *s != ',') ++s;
01080                                    }
01081                                    if (*s != '\0') {
01082                                           if (*s != ',') {
01083                                                  *s = '\0';
01084                                                  ++s;
01085                                                  while (*s != '\0' && *s != ',') ++s;
01086                                                  if (*s != '\0') ++s;
01087                                           } else {
01088                                                  *s = '\0';
01089                                                  ++s;
01090                                           }
01091                                    }
01092                                    if (digest == NULL) {
01093                                           ALLOC_INIT_ZVAL(digest);
01094                                           array_init(digest);
01095                                    }
01096                                    add_assoc_string(digest, name, val ,1);
01097                             }
01098                      }
01099 
01100                      if (digest != NULL) {
01101                             php_url *new_url  = emalloc(sizeof(php_url));
01102 
01103                             Z_DELREF_P(digest);
01104                             add_property_zval_ex(this_ptr, "_digest", sizeof("_digest"), digest TSRMLS_CC);
01105 
01106                             *new_url = *phpurl;
01107                             if (phpurl->scheme) phpurl->scheme = estrdup(phpurl->scheme);
01108                             if (phpurl->user) phpurl->user = estrdup(phpurl->user);
01109                             if (phpurl->pass) phpurl->pass = estrdup(phpurl->pass);
01110                             if (phpurl->host) phpurl->host = estrdup(phpurl->host);
01111                             if (phpurl->path) phpurl->path = estrdup(phpurl->path);
01112                             if (phpurl->query) phpurl->query = estrdup(phpurl->query);
01113                             if (phpurl->fragment) phpurl->fragment = estrdup(phpurl->fragment);
01114                             phpurl = new_url;
01115 
01116                             efree(auth);
01117                             efree(http_headers);
01118                             efree(http_body);
01119 
01120                             goto try_again;
01121                      }
01122               }
01123               if (auth) efree(auth);
01124        }
01125        smart_str_free(&soap_headers_z);
01126 
01127        /* Check and see if the server even sent a xml document */
01128        content_type = get_http_header_value(http_headers,"Content-Type: ");
01129        if (content_type) {
01130               char *pos = NULL;
01131               int cmplen;
01132               pos = strstr(content_type,";");
01133               if (pos != NULL) {
01134                      cmplen = pos - content_type;
01135               } else {
01136                      cmplen = strlen(content_type);
01137               }
01138               if (strncmp(content_type, "text/xml", cmplen) == 0 ||
01139                   strncmp(content_type, "application/soap+xml", cmplen) == 0) {
01140                      content_type_xml = 1;
01141 /*
01142                      if (strncmp(http_body, "<?xml", 5)) {
01143                             zval *err;
01144                             MAKE_STD_ZVAL(err);
01145                             ZVAL_STRINGL(err, http_body, http_body_size, 1);
01146                             add_soap_fault(this_ptr, "HTTP", "Didn't recieve an xml document", NULL, err TSRMLS_CC);
01147                             efree(content_type);
01148                             efree(http_headers);
01149                             efree(http_body);
01150                             return FALSE;
01151                      }
01152 */
01153               }
01154               efree(content_type);
01155        }
01156 
01157        /* Decompress response */
01158        content_encoding = get_http_header_value(http_headers,"Content-Encoding: ");
01159        if (content_encoding) {
01160               zval func;
01161               zval retval;
01162          zval param;
01163               zval *params[1];
01164 
01165               if ((strcmp(content_encoding,"gzip") == 0 ||
01166                    strcmp(content_encoding,"x-gzip") == 0) &&
01167                    zend_hash_exists(EG(function_table), "gzinflate", sizeof("gzinflate"))) {
01168                      ZVAL_STRING(&func, "gzinflate", 0);
01169                      params[0] = &param;
01170                      ZVAL_STRINGL(params[0], http_body+10, http_body_size-10, 0);
01171                      INIT_PZVAL(params[0]);
01172               } else if (strcmp(content_encoding,"deflate") == 0 &&
01173                          zend_hash_exists(EG(function_table), "gzuncompress", sizeof("gzuncompress"))) {
01174                      ZVAL_STRING(&func, "gzuncompress", 0);
01175                      params[0] = &param;
01176                      ZVAL_STRINGL(params[0], http_body, http_body_size, 0);
01177                      INIT_PZVAL(params[0]);
01178               } else {
01179                      efree(content_encoding);
01180                      efree(http_headers);
01181                      efree(http_body);
01182                      if (http_msg) {
01183                             efree(http_msg);
01184                      }
01185                      add_soap_fault(this_ptr, "HTTP", "Unknown Content-Encoding", NULL, NULL TSRMLS_CC);
01186                      return FALSE;
01187               }
01188               if (call_user_function(CG(function_table), (zval**)NULL, &func, &retval, 1, params TSRMLS_CC) == SUCCESS &&
01189                   Z_TYPE(retval) == IS_STRING) {
01190                      efree(http_body);
01191                      *buffer = Z_STRVAL(retval);
01192                      *buffer_len = Z_STRLEN(retval);
01193               } else {
01194                      efree(content_encoding);
01195                      efree(http_headers);
01196                      efree(http_body);
01197                      add_soap_fault(this_ptr, "HTTP", "Can't uncompress compressed response", NULL, NULL TSRMLS_CC);
01198                      if (http_msg) {
01199                             efree(http_msg);
01200                      }
01201                      return FALSE;
01202               }
01203               efree(content_encoding);
01204        } else {
01205               *buffer = http_body;
01206               *buffer_len = http_body_size;
01207        }
01208 
01209        efree(http_headers);
01210 
01211        if (http_status >= 400) {
01212               int error = 0;
01213 
01214               if (*buffer_len == 0) {
01215                      error = 1;
01216               } else if (*buffer_len > 0) {
01217                      if (!content_type_xml) {
01218                             char *s = *buffer;
01219 
01220                             while (*s != '\0' && *s < ' ') {
01221                                    s++;
01222                             }
01223                             if (strncmp(s, "<?xml", 5)) {
01224                                    error = 1;
01225                             }
01226                      }
01227               }
01228 
01229               if (error) {
01230                      efree(*buffer);
01231                      add_soap_fault(this_ptr, "HTTP", http_msg, NULL, NULL TSRMLS_CC);
01232                      efree(http_msg);
01233                      return FALSE;
01234               }
01235        }
01236 
01237        if (http_msg) {
01238               efree(http_msg);
01239        }
01240 
01241        return TRUE;
01242 }
01243 
01244 static char *get_http_header_value(char *headers, char *type)
01245 {
01246        char *pos, *tmp = NULL;
01247        int typelen, headerslen;
01248 
01249        typelen = strlen(type);
01250        headerslen = strlen(headers);
01251 
01252        /* header `titles' can be lower case, or any case combination, according
01253         * to the various RFC's. */
01254        pos = headers;
01255        do {
01256               /* start of buffer or start of line */
01257               if (strncasecmp(pos, type, typelen) == 0) {
01258                      char *eol;
01259 
01260                      /* match */
01261                      tmp = pos + typelen;
01262                      eol = strchr(tmp, '\n');
01263                      if (eol == NULL) {
01264                             eol = headers + headerslen;
01265                      } else if (eol > tmp && *(eol-1) == '\r') {
01266                             eol--;
01267                      }
01268                      return estrndup(tmp, eol - tmp);
01269               }
01270 
01271               /* find next line */
01272               pos = strchr(pos, '\n');
01273               if (pos) {
01274                      pos++;
01275               }
01276 
01277        } while (pos);
01278 
01279        return NULL;
01280 }
01281 
01282 static int get_http_body(php_stream *stream, int close, char *headers,  char **response, int *out_size TSRMLS_DC)
01283 {
01284        char *header, *http_buf = NULL;
01285        int header_close = close, header_chunked = 0, header_length = 0, http_buf_size = 0;
01286 
01287        if (!close) {
01288               header = get_http_header_value(headers, "Connection: ");
01289               if (header) {
01290                      if(!strncasecmp(header, "close", sizeof("close")-1)) header_close = 1;
01291                      efree(header);
01292               }
01293        }
01294        header = get_http_header_value(headers, "Transfer-Encoding: ");
01295        if (header) {
01296               if(!strncasecmp(header, "chunked", sizeof("chunked")-1)) header_chunked = 1;
01297               efree(header);
01298        }
01299        header = get_http_header_value(headers, "Content-Length: ");
01300        if (header) {
01301               header_length = atoi(header);
01302               efree(header);
01303               if (!header_length && !header_chunked) {
01304                      /* Empty response */
01305                      http_buf = emalloc(1);
01306                      http_buf[0] = '\0';
01307                      (*response) = http_buf;
01308                      (*out_size) = 0;
01309                      return TRUE;
01310               }
01311        }
01312 
01313        if (header_chunked) {
01314               char ch, done, chunk_size[10], headerbuf[8192];
01315 
01316               done = FALSE;
01317 
01318               while (!done) {
01319                      int buf_size = 0;
01320 
01321                      php_stream_gets(stream, chunk_size, sizeof(chunk_size));
01322                      if (sscanf(chunk_size, "%x", &buf_size) > 0 ) {
01323                             if (buf_size > 0) {
01324                                    int len_size = 0;
01325 
01326                                    if (http_buf_size + buf_size + 1 < 0) {
01327                                           efree(http_buf);
01328                                           return FALSE;
01329                                    }
01330                                    http_buf = erealloc(http_buf, http_buf_size + buf_size + 1);
01331 
01332                                    while (len_size < buf_size) {
01333                                           int len_read = php_stream_read(stream, http_buf + http_buf_size, buf_size - len_size);
01334                                           if (len_read <= 0) {
01335                                                  /* Error or EOF */
01336                                                  done = TRUE;
01337                                             break;
01338                                           }
01339                                           len_size += len_read;
01340                                           http_buf_size += len_read;
01341                                    }
01342 
01343                                    /* Eat up '\r' '\n' */
01344                                    ch = php_stream_getc(stream);
01345                                    if (ch == '\r') {
01346                                           ch = php_stream_getc(stream);
01347                                    }
01348                                    if (ch != '\n') {
01349                                           /* Somthing wrong in chunked encoding */
01350                                           if (http_buf) {
01351                                                  efree(http_buf);
01352                                           }
01353                                           return FALSE;
01354                                    }
01355                             }
01356                      } else {
01357                             /* Somthing wrong in chunked encoding */
01358                             if (http_buf) {
01359                                    efree(http_buf);
01360                             }
01361                             return FALSE;
01362                      }
01363                      if (buf_size == 0) {
01364                             done = TRUE;
01365                      }
01366               }
01367 
01368               /* Ignore trailer headers */
01369               while (1) {
01370                      if (!php_stream_gets(stream, headerbuf, sizeof(headerbuf))) {
01371                             break;
01372                      }
01373 
01374                      if ((headerbuf[0] == '\r' && headerbuf[1] == '\n') ||
01375                          (headerbuf[0] == '\n')) {
01376                             /* empty line marks end of headers */
01377                             break;
01378                      }
01379               }
01380 
01381               if (http_buf == NULL) {
01382                      http_buf = emalloc(1);
01383               }
01384 
01385        } else if (header_length) {
01386               if (header_length < 0 || header_length >= INT_MAX) {
01387                      return FALSE;
01388               }
01389               http_buf = emalloc(header_length + 1);
01390               while (http_buf_size < header_length) {
01391                      int len_read = php_stream_read(stream, http_buf + http_buf_size, header_length - http_buf_size);
01392                      if (len_read <= 0) {
01393                             break;
01394                      }
01395                      http_buf_size += len_read;
01396               }
01397        } else if (header_close) {
01398               do {
01399                      int len_read;
01400                      http_buf = erealloc(http_buf, http_buf_size + 4096 + 1);
01401                      len_read = php_stream_read(stream, http_buf + http_buf_size, 4096);
01402                      if (len_read > 0) {
01403                             http_buf_size += len_read;
01404                      }
01405               } while(!php_stream_eof(stream));
01406        } else {
01407               return FALSE;
01408        }
01409 
01410        http_buf[http_buf_size] = '\0';
01411        (*response) = http_buf;
01412        (*out_size) = http_buf_size;
01413        return TRUE;
01414 }
01415 
01416 static int get_http_headers(php_stream *stream, char **response, int *out_size TSRMLS_DC)
01417 {
01418        int done = FALSE;
01419        smart_str tmp_response = {0};
01420        char headerbuf[8192];
01421 
01422        while (!done) {
01423               if (!php_stream_gets(stream, headerbuf, sizeof(headerbuf))) {
01424                      break;
01425               }
01426 
01427               if ((headerbuf[0] == '\r' && headerbuf[1] == '\n') ||
01428                   (headerbuf[0] == '\n')) {
01429                      /* empty line marks end of headers */
01430                      done = TRUE;
01431                      break;
01432               }
01433 
01434               /* add header to collection */
01435               smart_str_appends(&tmp_response, headerbuf);
01436        }
01437        smart_str_0(&tmp_response);
01438        (*response) = tmp_response.c;
01439        (*out_size) = tmp_response.len;
01440        return done;
01441 }
01442 /*
01443  * Local variables:
01444  * tab-width: 4
01445  * c-basic-offset: 4
01446  * End:
01447  * vim600: sw=4 ts=4 fdm=marker
01448  * vim<600: sw=4 ts=4
01449  */