PageRenderTime 61ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/ext/soap/php_http.c

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