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