PageRenderTime 60ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/ext/soap/php_http.c

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