1 : /*
2 : +--------------------------------------------------------------------+
3 : | PECL :: http |
4 : +--------------------------------------------------------------------+
5 : | Redistribution and use in source and binary forms, with or without |
6 : | modification, are permitted provided that the conditions mentioned |
7 : | in the accompanying LICENSE file are met. |
8 : +--------------------------------------------------------------------+
9 : | Copyright (c) 2004-2007, Michael Wallner <mike@php.net> |
10 : +--------------------------------------------------------------------+
11 : */
12 :
13 : /* $Id: http_message_api.c,v 1.86 2007/02/07 11:50:26 mike Exp $ */
14 :
15 : #define HTTP_WANT_SAPI
16 : #define HTTP_WANT_CURL
17 : #define HTTP_WANT_ZLIB
18 : #include "php_http.h"
19 :
20 : #include "php_http_api.h"
21 : #include "php_http_encoding_api.h"
22 : #include "php_http_headers_api.h"
23 : #include "php_http_message_api.h"
24 : #include "php_http_request_api.h"
25 : #include "php_http_send_api.h"
26 : #include "php_http_url_api.h"
27 :
28 : #define http_message_info_callback _http_message_info_callback
29 : static void _http_message_info_callback(http_message **message, HashTable **headers, http_info *info TSRMLS_DC)
30 155 : {
31 155 : http_message *old = *message;
32 :
33 : /* advance message */
34 155 : if (old->type || zend_hash_num_elements(&old->hdrs) || PHPSTR_LEN(old)) {
35 38 : (*message) = http_message_new();
36 38 : (*message)->parent = old;
37 38 : (*headers) = &((*message)->hdrs);
38 : }
39 :
40 155 : http_message_set_info(*message, info);
41 155 : }
42 :
43 : #define http_message_init_type _http_message_init_type
44 : static inline void _http_message_init_type(http_message *message, http_message_type type)
45 315 : {
46 315 : message->http.version = .0;
47 :
48 315 : switch (message->type = type) {
49 : case HTTP_MSG_RESPONSE:
50 136 : message->http.info.response.code = 0;
51 136 : message->http.info.response.status = NULL;
52 136 : break;
53 :
54 : case HTTP_MSG_REQUEST:
55 21 : message->http.info.request.method = NULL;
56 21 : message->http.info.request.url = NULL;
57 : break;
58 :
59 : case HTTP_MSG_NONE:
60 : default:
61 : break;
62 : }
63 315 : }
64 :
65 : PHP_HTTP_API http_message *_http_message_init_ex(http_message *message, http_message_type type ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
66 158 : {
67 158 : if (!message) {
68 157 : message = ecalloc_rel(1, sizeof(http_message));
69 : }
70 :
71 158 : http_message_init_type(message, type);
72 158 : message->parent = NULL;
73 158 : phpstr_init(&message->body);
74 158 : zend_hash_init(&message->hdrs, 0, NULL, ZVAL_PTR_DTOR, 0);
75 :
76 158 : return message;
77 : }
78 :
79 : PHP_HTTP_API http_message *_http_message_init_env(http_message *message, http_message_type type TSRMLS_DC ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
80 0 : {
81 : int free_msg;
82 : http_info inf;
83 : zval *sval, tval;
84 : char *body_str;
85 : size_t body_len;
86 :
87 0 : if ((free_msg = !message)) {
88 0 : message = http_message_init_rel(NULL, HTTP_MSG_NONE);
89 : }
90 :
91 0 : memset(&inf, 0, sizeof(http_info));
92 0 : switch (inf.type = type) {
93 : case HTTP_MSG_REQUEST:
94 0 : if ((sval = http_get_server_var("SERVER_PROTOCOL", 1)) && !strncmp(Z_STRVAL_P(sval), "HTTP/", lenof("HTTP/"))) {
95 0 : inf.http.version = atof(Z_STRVAL_P(sval) + lenof("HTTP/"));
96 : } else {
97 0 : inf.http.version = 1.1;
98 : }
99 0 : if ((sval = http_get_server_var("REQUEST_METHOD", 1))) {
100 0 : inf.http.info.request.method = estrdup(Z_STRVAL_P(sval));
101 : }
102 0 : if ((sval = http_get_server_var("REQUEST_URI", 1))) {
103 0 : inf.http.info.request.url = estrdup(Z_STRVAL_P(sval));
104 : }
105 :
106 0 : http_message_set_info(message, &inf);
107 0 : http_get_request_headers(&message->hdrs);
108 0 : if (SUCCESS == http_get_request_body_ex(&body_str, &body_len, 0)) {
109 0 : phpstr_from_string_ex(&message->body, body_str, body_len);
110 : }
111 0 : break;
112 :
113 : case HTTP_MSG_RESPONSE:
114 0 : if (!SG(sapi_headers).http_status_line || SUCCESS != http_info_parse_ex(SG(sapi_headers).http_status_line, &inf, 0)) {
115 0 : inf.http.version = 1.1;
116 0 : inf.http.info.response.code = 200;
117 0 : inf.http.info.response.status = estrdup("Ok");
118 : }
119 :
120 0 : http_message_set_info(message, &inf);
121 0 : http_get_response_headers(&message->hdrs);
122 0 : if (SUCCESS == php_ob_get_buffer(&tval TSRMLS_CC)) {
123 0 : message->body.data = Z_STRVAL(tval);
124 0 : message->body.used = Z_STRLEN(tval);
125 0 : message->body.free = 1; /* "\0" */
126 : }
127 0 : break;
128 :
129 : default:
130 0 : if (free_msg) {
131 0 : http_message_free(&message);
132 : } else {
133 0 : message = NULL;
134 : }
135 : break;
136 : }
137 0 : http_info_dtor(&inf);
138 :
139 0 : return message;
140 : }
141 :
142 : PHP_HTTP_API void _http_message_set_type(http_message *message, http_message_type type)
143 157 : {
144 : /* just act if different */
145 157 : if (type != message->type) {
146 :
147 : /* free request info */
148 157 : switch (message->type) {
149 : case HTTP_MSG_REQUEST:
150 0 : STR_FREE(message->http.info.request.method);
151 0 : STR_FREE(message->http.info.request.url);
152 0 : break;
153 :
154 : case HTTP_MSG_RESPONSE:
155 0 : STR_FREE(message->http.info.response.status);
156 : break;
157 :
158 : default:
159 : break;
160 : }
161 :
162 : /* init */
163 157 : http_message_init_type(message, type);
164 : }
165 157 : }
166 :
167 : PHP_HTTP_API void _http_message_set_info(http_message *message, http_info *info)
168 157 : {
169 157 : http_message_set_type(message, info->type);
170 157 : message->http.version = info->http.version;
171 157 : switch (message->type) {
172 : case IS_HTTP_REQUEST:
173 21 : STR_SET(HTTP_INFO(message).request.url, HTTP_INFO(info).request.url ? estrdup(HTTP_INFO(info).request.url) : NULL);
174 21 : STR_SET(HTTP_INFO(message).request.method, HTTP_INFO(info).request.method ? estrdup(HTTP_INFO(info).request.method) : NULL);
175 21 : break;
176 :
177 : case IS_HTTP_RESPONSE:
178 136 : HTTP_INFO(message).response.code = HTTP_INFO(info).response.code;
179 136 : STR_SET(HTTP_INFO(message).response.status, HTTP_INFO(info).response.status ? estrdup(HTTP_INFO(info).response.status) : NULL);
180 : break;
181 :
182 : default:
183 : break;
184 : }
185 157 : }
186 :
187 : #define http_message_body_parse(m, ms, ml, c) _http_message_body_parse((m), (ms), (ml), (c) TSRMLS_CC)
188 : static inline void _http_message_body_parse(http_message *msg, const char *message, size_t message_length, const char **continue_at TSRMLS_DC)
189 117 : {
190 : zval *c;
191 : size_t remaining;
192 : const char *body;
193 :
194 117 : *continue_at = NULL;
195 117 : if ((body = http_locate_body(message))) {
196 93 : remaining = message + message_length - body;
197 :
198 93 : if ((c = http_message_header(msg, "Transfer-Encoding"))) {
199 27 : if (strstr(Z_STRVAL_P(c), "chunked")) {
200 : /* message has chunked transfer encoding */
201 : char *decoded;
202 : size_t decoded_len;
203 :
204 : /* decode and replace Transfer-Encoding with Content-Length header */
205 26 : if ((*continue_at = http_encoding_dechunk(body, message + message_length - body, &decoded, &decoded_len))) {
206 : zval *len;
207 : char *tmp;
208 : int tmp_len;
209 :
210 26 : tmp_len = (int) spprintf(&tmp, 0, "%zu", decoded_len);
211 26 : MAKE_STD_ZVAL(len);
212 26 : ZVAL_STRINGL(len, tmp, tmp_len, 0);
213 :
214 26 : ZVAL_ADDREF(c);
215 26 : zend_hash_update(&msg->hdrs, "X-Original-Transfer-Encoding", sizeof("X-Original-Transfer-Encoding"), (void *) &c, sizeof(zval *), NULL);
216 26 : zend_hash_del(&msg->hdrs, "Transfer-Encoding", sizeof("Transfer-Encoding"));
217 26 : zend_hash_del(&msg->hdrs, "Content-Length", sizeof("Content-Length"));
218 26 : zend_hash_update(&msg->hdrs, "Content-Length", sizeof("Content-Length"), (void *) &len, sizeof(zval *), NULL);
219 :
220 26 : phpstr_from_string_ex(PHPSTR(msg), decoded, decoded_len);
221 26 : efree(decoded);
222 : }
223 : }
224 27 : zval_ptr_dtor(&c);
225 : }
226 :
227 93 : if (!*continue_at && (c = http_message_header(msg, "Content-Length"))) {
228 : /* message has content-length header */
229 59 : ulong len = strtoul(Z_STRVAL_P(c), NULL, 10);
230 59 : if (len > remaining) {
231 0 : http_error_ex(HE_NOTICE, HTTP_E_MALFORMED_HEADERS, "The Content-Length header pretends a larger body than actually received (expected %lu bytes; got %lu bytes)", len, remaining);
232 0 : len = remaining;
233 : }
234 59 : phpstr_from_string_ex(PHPSTR(msg), body, len);
235 59 : *continue_at = body + len;
236 59 : zval_ptr_dtor(&c);
237 : }
238 :
239 93 : if (!*continue_at && (c = http_message_header(msg, "Content-Range"))) {
240 : /* message has content-range header */
241 4 : ulong total = 0, start = 0, end = 0, len = 0;
242 :
243 4 : if (!strncasecmp(Z_STRVAL_P(c), "bytes", lenof("bytes")) &&
244 : ( Z_STRVAL_P(c)[lenof("bytes")] == ':' ||
245 : Z_STRVAL_P(c)[lenof("bytes")] == ' ' ||
246 : Z_STRVAL_P(c)[lenof("bytes")] == '=')) {
247 4 : char *total_at = NULL, *end_at = NULL;
248 4 : char *start_at = Z_STRVAL_P(c) + sizeof("bytes");
249 :
250 4 : start = strtoul(start_at, &end_at, 10);
251 4 : if (end_at) {
252 4 : end = strtoul(end_at + 1, &total_at, 10);
253 4 : if (total_at && strncmp(total_at + 1, "*", 1)) {
254 4 : total = strtoul(total_at + 1, NULL, 10);
255 : }
256 4 : if ((len = (end + 1 - start)) > remaining) {
257 0 : http_error_ex(HE_NOTICE, HTTP_E_MALFORMED_HEADERS, "The Content-Range header pretends a larger body than actually received (expected %lu bytes; got %lu bytes)", len, remaining);
258 0 : len = remaining;
259 : }
260 4 : if (end >= start && (!total || end < total)) {
261 3 : phpstr_from_string_ex(PHPSTR(msg), body, len);
262 3 : *continue_at = body + len;
263 : }
264 : }
265 : }
266 :
267 4 : if (!*continue_at) {
268 1 : http_error_ex(HE_WARNING, HTTP_E_MALFORMED_HEADERS, "Invalid Content-Range header: %s", Z_STRVAL_P(c));
269 : }
270 4 : zval_ptr_dtor(&c);
271 : }
272 :
273 93 : if (!*continue_at) {
274 : /* no headers that indicate content length */
275 6 : if (HTTP_MSG_TYPE(RESPONSE, msg)) {
276 1 : phpstr_from_string_ex(PHPSTR(msg), body, remaining);
277 : } else {
278 4 : *continue_at = body;
279 : }
280 : }
281 :
282 : #ifdef HTTP_HAVE_ZLIB
283 : /* check for compressed data */
284 93 : if ((c = http_message_header(msg, "Vary"))) {
285 32 : zval_ptr_dtor(&c);
286 :
287 32 : if ((c = http_message_header(msg, "Content-Encoding"))) {
288 11 : char *decoded = NULL;
289 11 : size_t decoded_len = 0;
290 :
291 11 : if ( !strcasecmp(Z_STRVAL_P(c), "gzip") ||
292 : !strcasecmp(Z_STRVAL_P(c), "x-gzip") ||
293 : !strcasecmp(Z_STRVAL_P(c), "deflate")) {
294 11 : http_encoding_inflate(PHPSTR_VAL(msg), PHPSTR_LEN(msg), &decoded, &decoded_len);
295 : }
296 :
297 11 : if (decoded) {
298 : zval *len, **original_len;
299 : char *tmp;
300 : int tmp_len;
301 :
302 11 : tmp_len = (int) spprintf(&tmp, 0, "%zu", decoded_len);
303 11 : MAKE_STD_ZVAL(len);
304 11 : ZVAL_STRINGL(len, tmp, tmp_len, 0);
305 :
306 11 : ZVAL_ADDREF(c);
307 11 : zend_hash_update(&msg->hdrs, "X-Original-Content-Encoding", sizeof("X-Original-Content-Encoding"), (void *) &c, sizeof(zval *), NULL);
308 11 : zend_hash_del(&msg->hdrs, "Content-Encoding", sizeof("Content-Encoding"));
309 11 : if (SUCCESS == zend_hash_find(&msg->hdrs, "Content-Length", sizeof("Content-Length"), (void *) &original_len)) {
310 11 : ZVAL_ADDREF(*original_len);
311 11 : zend_hash_update(&msg->hdrs, "X-Original-Content-Length", sizeof("X-Original-Content-Length"), (void *) original_len, sizeof(zval *), NULL);
312 11 : zend_hash_update(&msg->hdrs, "Content-Length", sizeof("Content-Length"), (void *) &len, sizeof(zval *), NULL);
313 : } else {
314 0 : zend_hash_update(&msg->hdrs, "Content-Length", sizeof("Content-Length"), (void *) &len, sizeof(zval *), NULL);
315 : }
316 :
317 11 : phpstr_dtor(PHPSTR(msg));
318 11 : PHPSTR(msg)->data = decoded;
319 11 : PHPSTR(msg)->used = decoded_len;
320 11 : PHPSTR(msg)->free = 1;
321 : }
322 :
323 11 : zval_ptr_dtor(&c);
324 : }
325 : }
326 : #endif /* HTTP_HAVE_ZLIB */
327 : }
328 117 : }
329 :
330 : PHP_HTTP_API http_message *_http_message_parse_ex(http_message *msg, const char *message, size_t message_length ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC)
331 121 : {
332 : const char *continue_at;
333 121 : zend_bool free_msg = msg ? 0 : 1;
334 :
335 121 : if ((!message) || (message_length < HTTP_MSG_MIN_SIZE)) {
336 4 : http_error_ex(HE_WARNING, HTTP_E_INVALID_PARAM, "Empty or too short HTTP message: '%s'", message);
337 4 : return NULL;
338 : }
339 :
340 117 : msg = http_message_init_rel(msg, 0);
341 :
342 117 : if (SUCCESS != http_parse_headers_cb(message, &msg->hdrs, 1, (http_info_callback) http_message_info_callback, (void *) &msg)) {
343 0 : if (free_msg) {
344 0 : http_message_free(&msg);
345 : }
346 0 : http_error(HE_WARNING, HTTP_E_MALFORMED_HEADERS, "Failed to parse message headers");
347 0 : return NULL;
348 : }
349 :
350 117 : http_message_body_parse(msg, message, message_length, &continue_at);
351 :
352 : /* check for following messages */
353 117 : if (continue_at && (continue_at < (message + message_length))) {
354 38 : while (HTTP_IS_CTYPE(space, *continue_at)) ++continue_at;
355 38 : if (continue_at < (message + message_length)) {
356 10 : http_message *next = NULL, *most = NULL;
357 :
358 : /* set current message to parent of most parent following messages and return deepest */
359 10 : if ((most = next = http_message_parse_rel(NULL, continue_at, message + message_length - continue_at))) {
360 10 : while (most->parent) most = most->parent;
361 10 : most->parent = msg;
362 10 : msg = next;
363 : }
364 : }
365 : }
366 :
367 117 : return msg;
368 : }
369 :
370 : PHP_HTTP_API void _http_message_tostring(http_message *msg, char **string, size_t *length)
371 50 : {
372 : phpstr str;
373 50 : HashKey key = initHashKey(0);
374 : zval **header;
375 : char *data;
376 : HashPosition pos1;
377 :
378 50 : phpstr_init_ex(&str, 4096, 0);
379 :
380 50 : switch (msg->type) {
381 : case HTTP_MSG_REQUEST:
382 18 : phpstr_appendf(&str, HTTP_INFO_REQUEST_FMT_ARGS(&msg->http, HTTP_CRLF));
383 18 : break;
384 :
385 : case HTTP_MSG_RESPONSE:
386 32 : phpstr_appendf(&str, HTTP_INFO_RESPONSE_FMT_ARGS(&msg->http, HTTP_CRLF));
387 : break;
388 :
389 : case HTTP_MSG_NONE:
390 : default:
391 : break;
392 : }
393 :
394 123 : FOREACH_HASH_KEYVAL(pos1, &msg->hdrs, key, header) {
395 73 : if (key.type == HASH_KEY_IS_STRING) {
396 : HashPosition pos2;
397 : zval **single_header;
398 :
399 73 : switch (Z_TYPE_PP(header)) {
400 : case IS_STRING:
401 73 : phpstr_appendf(&str, "%s: %s" HTTP_CRLF, key.str, Z_STRVAL_PP(header));
402 73 : break;
403 :
404 : case IS_ARRAY:
405 0 : FOREACH_VAL(pos2, *header, single_header) {
406 0 : phpstr_appendf(&str, "%s: %s" HTTP_CRLF, key.str, Z_STRVAL_PP(single_header));
407 : }
408 : break;
409 : }
410 : }
411 : }
412 :
413 50 : if (PHPSTR_LEN(msg)) {
414 13 : phpstr_appends(&str, HTTP_CRLF);
415 13 : phpstr_append(&str, PHPSTR_VAL(msg), PHPSTR_LEN(msg));
416 13 : phpstr_appends(&str, HTTP_CRLF);
417 : }
418 :
419 50 : data = phpstr_data(&str, string, length);
420 50 : if (!string) {
421 0 : efree(data);
422 : }
423 :
424 50 : phpstr_dtor(&str);
425 50 : }
426 :
427 : PHP_HTTP_API void _http_message_serialize(http_message *message, char **string, size_t *length)
428 10 : {
429 : char *buf;
430 : size_t len;
431 : phpstr str;
432 :
433 10 : phpstr_init(&str);
434 :
435 : do {
436 43 : http_message_tostring(message, &buf, &len);
437 43 : phpstr_prepend(&str, buf, len);
438 43 : efree(buf);
439 43 : } while ((message = message->parent));
440 :
441 10 : buf = phpstr_data(&str, string, length);
442 10 : if (!string) {
443 0 : efree(buf);
444 : }
445 :
446 10 : phpstr_dtor(&str);
447 10 : }
448 :
449 : PHP_HTTP_API http_message *_http_message_reverse(http_message *msg)
450 0 : {
451 : int i, c;
452 :
453 0 : http_message_count(c, msg);
454 :
455 0 : if (c > 1) {
456 0 : http_message *tmp = msg, **arr = ecalloc(c, sizeof(http_message *));
457 :
458 0 : for (i = 0; i < c; ++i) {
459 0 : arr[i] = tmp;
460 0 : tmp = tmp->parent;
461 : }
462 0 : arr[0]->parent = NULL;
463 0 : for (i = 0; i < c-1; ++i) {
464 0 : arr[i+1]->parent = arr[i];
465 : }
466 :
467 0 : msg = arr[c-1];
468 0 : efree(arr);
469 : }
470 :
471 0 : return msg;
472 : }
473 :
474 : PHP_HTTP_API http_message *_http_message_interconnect(http_message *m1, http_message *m2)
475 3 : {
476 6 : if (m1 && m2) {
477 3 : int i = 0, c1, c2;
478 3 : http_message *t1 = m1, *t2 = m2, *p1, *p2;
479 :
480 3 : http_message_count(c1, m1);
481 3 : http_message_count(c2, m2);
482 :
483 7 : while (i++ < (c1 - c2)) {
484 1 : t1 = t1->parent;
485 : }
486 9 : while (i++ <= c1) {
487 3 : p1 = t1->parent;
488 3 : p2 = t2->parent;
489 3 : t1->parent = t2;
490 3 : t2->parent = p1;
491 3 : t1 = p1;
492 3 : t2 = p2;
493 : }
494 0 : } else if (!m1 && m2) {
495 0 : m1 = m2;
496 : }
497 3 : return m1;
498 : }
499 :
500 : PHP_HTTP_API void _http_message_tostruct_recursive(http_message *msg, zval *obj TSRMLS_DC)
501 13 : {
502 : zval strct;
503 : zval *headers;
504 :
505 13 : INIT_ZARR(strct, HASH_OF(obj));
506 :
507 13 : add_assoc_long(&strct, "type", msg->type);
508 13 : add_assoc_double(&strct, "httpVersion", msg->http.version);
509 13 : switch (msg->type)
510 : {
511 : case HTTP_MSG_RESPONSE:
512 11 : add_assoc_long(&strct, "responseCode", msg->http.info.response.code);
513 11 : add_assoc_string(&strct, "responseStatus", STR_PTR(msg->http.info.response.status), 1);
514 11 : break;
515 :
516 : case HTTP_MSG_REQUEST:
517 2 : add_assoc_string(&strct, "requestMethod", STR_PTR(msg->http.info.request.method), 1);
518 2 : add_assoc_string(&strct, "requestUrl", STR_PTR(msg->http.info.request.url), 1);
519 : break;
520 :
521 : case HTTP_MSG_NONE:
522 : /* avoid compiler warning */
523 : break;
524 : }
525 :
526 13 : MAKE_STD_ZVAL(headers);
527 13 : array_init(headers);
528 13 : zend_hash_copy(Z_ARRVAL_P(headers), &msg->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
529 13 : add_assoc_zval(&strct, "headers", headers);
530 :
531 13 : add_assoc_stringl(&strct, "body", PHPSTR_VAL(msg), PHPSTR_LEN(msg), 1);
532 :
533 13 : if (msg->parent) {
534 : zval *parent;
535 :
536 5 : MAKE_STD_ZVAL(parent);
537 5 : if (Z_TYPE_P(obj) == IS_ARRAY) {
538 0 : array_init(parent);
539 : } else {
540 5 : object_init(parent);
541 : }
542 5 : add_assoc_zval(&strct, "parentMessage", parent);
543 5 : http_message_tostruct_recursive(msg->parent, parent);
544 : } else {
545 8 : add_assoc_null(&strct, "parentMessage");
546 : }
547 13 : }
548 :
549 : PHP_HTTP_API STATUS _http_message_send(http_message *message TSRMLS_DC)
550 0 : {
551 0 : STATUS rs = FAILURE;
552 :
553 0 : switch (message->type) {
554 : case HTTP_MSG_RESPONSE:
555 : {
556 0 : HashKey key = initHashKey(0);
557 : zval **val;
558 : HashPosition pos;
559 :
560 0 : FOREACH_HASH_KEYVAL(pos, &message->hdrs, key, val) {
561 0 : if (key.type == HASH_KEY_IS_STRING) {
562 0 : http_send_header_zval_ex(key.str, key.len-1, val, 1);
563 : }
564 : }
565 0 : rs = SUCCESS == http_send_status(message->http.info.response.code) &&
566 : SUCCESS == http_send_data(PHPSTR_VAL(message), PHPSTR_LEN(message)) ?
567 : SUCCESS : FAILURE;
568 0 : break;
569 : }
570 :
571 : case HTTP_MSG_REQUEST:
572 : {
573 : #ifdef HTTP_HAVE_CURL
574 0 : char *uri = NULL;
575 : http_request request;
576 : zval **zhost, options, headers;
577 :
578 0 : INIT_PZVAL(&options);
579 0 : INIT_PZVAL(&headers);
580 0 : array_init(&options);
581 0 : array_init(&headers);
582 0 : zend_hash_copy(Z_ARRVAL(headers), &message->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
583 0 : add_assoc_zval(&options, "headers", &headers);
584 :
585 : /* check host header */
586 0 : if (SUCCESS == zend_hash_find(&message->hdrs, "Host", sizeof("Host"), (void *) &zhost)) {
587 0 : char *colon = NULL;
588 0 : php_url parts, *url = php_url_parse(message->http.info.request.url);
589 :
590 0 : memset(&parts, 0, sizeof(php_url));
591 :
592 : /* check for port */
593 0 : if ((colon = strchr(Z_STRVAL_PP(zhost), ':'))) {
594 0 : parts.port = atoi(colon + 1);
595 0 : parts.host = estrndup(Z_STRVAL_PP(zhost), (Z_STRVAL_PP(zhost) - colon - 1));
596 : } else {
597 0 : parts.host = estrndup(Z_STRVAL_PP(zhost), Z_STRLEN_PP(zhost));
598 : }
599 :
600 0 : http_build_url(HTTP_URL_REPLACE, url, &parts, NULL, &uri, NULL);
601 0 : php_url_free(url);
602 0 : efree(parts.host);
603 : } else {
604 0 : uri = http_absolute_url(message->http.info.request.url);
605 : }
606 :
607 0 : if ((request.meth = http_request_method_exists(1, 0, message->http.info.request.method))) {
608 : http_request_body body;
609 :
610 0 : http_request_init_ex(&request, NULL, request.meth, uri);
611 0 : request.body = http_request_body_init_ex(&body, HTTP_REQUEST_BODY_CSTRING, PHPSTR_VAL(message), PHPSTR_LEN(message), 0);
612 0 : if (SUCCESS == (rs = http_request_prepare(&request, NULL))) {
613 0 : http_request_exec(&request);
614 : }
615 0 : http_request_dtor(&request);
616 : } else {
617 0 : http_error_ex(HE_WARNING, HTTP_E_REQUEST_METHOD,
618 : "Cannot send HttpMessage. Request method %s not supported",
619 : message->http.info.request.method);
620 : }
621 0 : efree(uri);
622 : #else
623 : http_error(HE_WARNING, HTTP_E_RUNTIME, "HTTP requests not supported - ext/http was not linked against libcurl.");
624 : #endif
625 0 : break;
626 : }
627 :
628 : case HTTP_MSG_NONE:
629 : default:
630 0 : http_error(HE_WARNING, HTTP_E_MESSAGE_TYPE, "HttpMessage is neither of type HTTP_MSG_REQUEST nor HTTP_MSG_RESPONSE");
631 : break;
632 : }
633 :
634 0 : return rs;
635 : }
636 :
637 : PHP_HTTP_API http_message *_http_message_dup(http_message *orig TSRMLS_DC)
638 0 : {
639 0 : http_message *temp, *copy = NULL;
640 : http_info info;
641 :
642 0 : if (orig) {
643 0 : info.type = orig->type;
644 0 : info.http = orig->http;
645 :
646 0 : copy = temp = http_message_new();
647 0 : http_message_set_info(temp, &info);
648 0 : zend_hash_copy(&temp->hdrs, &orig->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
649 0 : phpstr_append(&temp->body, orig->body.data, orig->body.used);
650 :
651 0 : while (orig->parent) {
652 0 : info.type = orig->parent->type;
653 0 : info.http = orig->parent->http;
654 :
655 0 : temp->parent = http_message_new();
656 0 : http_message_set_info(temp->parent, &info);
657 0 : zend_hash_copy(&temp->parent->hdrs, &orig->parent->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
658 0 : phpstr_append(&temp->parent->body, orig->parent->body.data, orig->parent->body.used);
659 :
660 0 : temp = temp->parent;
661 0 : orig = orig->parent;
662 : }
663 : }
664 :
665 0 : return copy;
666 : }
667 :
668 : PHP_HTTP_API void _http_message_dtor(http_message *message)
669 165 : {
670 165 : if (message) {
671 158 : zend_hash_destroy(&message->hdrs);
672 158 : phpstr_dtor(PHPSTR(message));
673 :
674 158 : switch (message->type) {
675 : case HTTP_MSG_REQUEST:
676 21 : STR_SET(message->http.info.request.method, NULL);
677 21 : STR_SET(message->http.info.request.url, NULL);
678 21 : break;
679 :
680 : case HTTP_MSG_RESPONSE:
681 136 : STR_SET(message->http.info.response.status, NULL);
682 : break;
683 :
684 : default:
685 : break;
686 : }
687 : }
688 165 : }
689 :
690 : PHP_HTTP_API void _http_message_free(http_message **message)
691 13 : {
692 13 : if (*message) {
693 13 : if ((*message)->parent) {
694 5 : http_message_free(&(*message)->parent);
695 : }
696 13 : http_message_dtor(*message);
697 13 : efree(*message);
698 13 : *message = NULL;
699 : }
700 13 : }
701 :
702 : /*
703 : * Local variables:
704 : * tab-width: 4
705 : * c-basic-offset: 4
706 : * End:
707 : * vim600: noet sw=4 ts=4 fdm=marker
708 : * vim<600: noet sw=4 ts=4
709 : */
710 :
|