merged response-streams branch
[m6w6/ext-http] / php_http_message.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-2011, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
11 */
12
13 #include "php_http_api.h"
14
15 static void message_headers(php_http_message_t *msg, php_http_buffer_t *str);
16
17 PHP_HTTP_API zend_bool php_http_message_info_callback(php_http_message_t **message, HashTable **headers, php_http_info_t *info TSRMLS_DC)
18 {
19 php_http_message_t *old = *message;
20
21 /* advance message */
22 if (!old || old->type || zend_hash_num_elements(&old->hdrs)) {
23 (*message) = php_http_message_init(NULL, 0 TSRMLS_CC);
24 (*message)->parent = old;
25 if (headers) {
26 (*headers) = &((*message)->hdrs);
27 }
28 }
29
30 if (info) {
31 php_http_message_set_info(*message, info);
32 }
33
34 return old != *message;
35 }
36
37 PHP_HTTP_API php_http_message_t *php_http_message_init(php_http_message_t *message, php_http_message_type_t type TSRMLS_DC)
38 {
39 if (!message) {
40 message = emalloc(sizeof(*message));
41 }
42 memset(message, 0, sizeof(*message));
43 TSRMLS_SET_CTX(message->ts);
44
45 php_http_message_set_type(message, type);
46 message->http.version.major = 1;
47 message->http.version.minor = 1;
48 zend_hash_init(&message->hdrs, 0, NULL, ZVAL_PTR_DTOR, 0);
49 php_http_message_body_init(&message->body, NULL TSRMLS_CC);
50
51 return message;
52 }
53
54 PHP_HTTP_API php_http_message_t *php_http_message_init_env(php_http_message_t *message, php_http_message_type_t type TSRMLS_DC)
55 {
56 int free_msg = !message;
57 zval *sval, tval;
58 php_http_message_body_t *mbody;
59
60 message = php_http_message_init(message, type TSRMLS_CC);
61
62 switch (type) {
63 case PHP_HTTP_REQUEST:
64 if ((sval = php_http_env_get_server_var(ZEND_STRL("SERVER_PROTOCOL"), 1 TSRMLS_CC)) && !strncmp(Z_STRVAL_P(sval), "HTTP/", lenof("HTTP/"))) {
65 php_http_version_parse(&message->http.version, Z_STRVAL_P(sval) TSRMLS_CC);
66 }
67 if ((sval = php_http_env_get_server_var(ZEND_STRL("REQUEST_METHOD"), 1 TSRMLS_CC))) {
68 message->http.info.request.method = estrdup(Z_STRVAL_P(sval));
69 }
70 if ((sval = php_http_env_get_server_var(ZEND_STRL("REQUEST_URI"), 1 TSRMLS_CC))) {
71 message->http.info.request.url = estrdup(Z_STRVAL_P(sval));
72 }
73
74 php_http_env_get_request_headers(&message->hdrs TSRMLS_CC);
75
76 if ((mbody = php_http_env_get_request_body(TSRMLS_C))) {
77 php_http_message_body_dtor(&message->body);
78 php_http_message_body_copy(mbody, &message->body, 0);
79 }
80 break;
81
82 case PHP_HTTP_RESPONSE:
83 if (!SG(sapi_headers).http_status_line || !php_http_info_parse((php_http_info_t *) &message->http, SG(sapi_headers).http_status_line TSRMLS_CC)) {
84 if (!(message->http.info.response.code = SG(sapi_headers).http_response_code)) {
85 message->http.info.response.code = 200;
86 }
87 message->http.info.response.status = estrdup(php_http_env_get_response_status_for_code(message->http.info.response.code));
88 }
89
90 php_http_env_get_response_headers(&message->hdrs TSRMLS_CC);
91 #if PHP_VERSION_ID >= 50400
92 if (php_output_get_level(TSRMLS_C)) {
93 if (php_output_get_status(TSRMLS_C) & PHP_OUTPUT_SENT) {
94 php_http_error(HE_WARNING, PHP_HTTP_E_RUNTIME, "Could not fetch response body, output has already been sent at %s:%d", php_output_get_start_filename(TSRMLS_C), php_output_get_start_lineno(TSRMLS_C));
95 goto error;
96 } else if (SUCCESS != php_output_get_contents(&tval TSRMLS_CC)) {
97 php_http_error(HE_WARNING, PHP_HTTP_E_RUNTIME, "Could not fetch response body");
98 goto error;
99 } else {
100 php_http_message_body_append(&message->body, Z_STRVAL(tval), Z_STRLEN(tval));
101 zval_dtor(&tval);
102 }
103 }
104 #endif
105 break;
106
107 default:
108 error:
109 if (free_msg) {
110 php_http_message_free(&message);
111 } else {
112 message = NULL;
113 }
114 break;
115 }
116
117 return message;
118 }
119
120 PHP_HTTP_API php_http_message_t *php_http_message_parse(php_http_message_t *msg, const char *str, size_t len, zend_bool greedy TSRMLS_DC)
121 {
122 php_http_message_parser_t p;
123 php_http_buffer_t buf;
124 unsigned flags = PHP_HTTP_MESSAGE_PARSER_CLEANUP;
125 int free_msg;
126
127 php_http_buffer_from_string_ex(&buf, str, len);
128 php_http_message_parser_init(&p TSRMLS_CC);
129
130 if ((free_msg = !msg)) {
131 msg = php_http_message_init(NULL, 0 TSRMLS_CC);
132 }
133
134 if (greedy) {
135 flags |= PHP_HTTP_MESSAGE_PARSER_GREEDY;
136 }
137 if (FAILURE == php_http_message_parser_parse(&p, &buf, flags, &msg)) {
138 if (free_msg) {
139 php_http_message_free(&msg);
140 }
141 msg = NULL;
142 }
143
144 php_http_message_parser_dtor(&p);
145 php_http_buffer_dtor(&buf);
146
147 return msg;
148 }
149
150 PHP_HTTP_API zval *php_http_message_header(php_http_message_t *msg, const char *key_str, size_t key_len, int join)
151 {
152 zval *ret = NULL, **header;
153 char *key = php_http_pretty_key(estrndup(key_str, key_len), key_len, 1, 1);
154
155 if (SUCCESS == zend_symtable_find(&msg->hdrs, key, key_len + 1, (void *) &header)) {
156 if (join && Z_TYPE_PP(header) == IS_ARRAY) {
157 TSRMLS_FETCH_FROM_CTX(msg->ts);
158
159 ret = php_http_header_value_to_string(*header TSRMLS_CC);
160 } else {
161 Z_ADDREF_PP(header);
162 ret = *header;
163 }
164 }
165
166 efree(key);
167
168 return ret;
169 }
170
171 PHP_HTTP_API zend_bool php_http_message_is_multipart(php_http_message_t *msg, char **boundary)
172 {
173 zval *ct = php_http_message_header(msg, ZEND_STRL("Content-Type"), 1);
174 zend_bool is_multipart = 0;
175 TSRMLS_FETCH_FROM_CTX(msg->ts);
176
177 if (ct) {
178 php_http_params_opts_t popts;
179 HashTable params;
180
181 ZEND_INIT_SYMTABLE(&params);
182 php_http_params_opts_default_get(&popts);
183 popts.input.str = Z_STRVAL_P(ct);
184 popts.input.len = Z_STRLEN_P(ct);
185
186 if (php_http_params_parse(&params, &popts TSRMLS_CC)) {
187 zval **cur, **arg;
188 char *ct_str;
189
190 zend_hash_internal_pointer_reset(&params);
191
192 if (SUCCESS == zend_hash_get_current_data(&params, (void *) &cur)
193 && Z_TYPE_PP(cur) == IS_ARRAY
194 && HASH_KEY_IS_STRING == zend_hash_get_current_key(&params, &ct_str, NULL, 0)
195 ) {
196 if (php_http_match(ct_str, "multipart", PHP_HTTP_MATCH_WORD)) {
197 is_multipart = 1;
198
199 /* get boundary */
200 if (boundary
201 && SUCCESS == zend_hash_find(Z_ARRVAL_PP(cur), ZEND_STRS("arguments"), (void *) &arg)
202 && Z_TYPE_PP(arg) == IS_ARRAY
203 ) {
204 zval **val;
205 HashPosition pos;
206 php_http_array_hashkey_t key = php_http_array_hashkey_init(0);
207
208 FOREACH_KEYVAL(pos, *arg, key, val) {
209 if (key.type == HASH_KEY_IS_STRING && !strcasecmp(key.str, "boundary")) {
210 zval *bnd = php_http_ztyp(IS_STRING, *val);
211
212 if (Z_STRLEN_P(bnd)) {
213 *boundary = estrndup(Z_STRVAL_P(bnd), Z_STRLEN_P(bnd));
214 }
215 zval_ptr_dtor(&bnd);
216 }
217 }
218 }
219 }
220 }
221 }
222 zend_hash_destroy(&params);
223 zval_ptr_dtor(&ct);
224 }
225
226 return is_multipart;
227 }
228
229 /* */
230 PHP_HTTP_API void php_http_message_set_type(php_http_message_t *message, php_http_message_type_t type)
231 {
232 /* just act if different */
233 if (type != message->type) {
234
235 /* free request info */
236 switch (message->type) {
237 case PHP_HTTP_REQUEST:
238 STR_FREE(message->http.info.request.method);
239 STR_FREE(message->http.info.request.url);
240 break;
241
242 case PHP_HTTP_RESPONSE:
243 STR_FREE(message->http.info.response.status);
244 break;
245
246 default:
247 break;
248 }
249
250 message->type = type;
251 memset(&message->http, 0, sizeof(message->http));
252 }
253 }
254
255 PHP_HTTP_API void php_http_message_set_info(php_http_message_t *message, php_http_info_t *info)
256 {
257 php_http_message_set_type(message, info->type);
258 message->http.version = info->http.version;
259 switch (message->type) {
260 case PHP_HTTP_REQUEST:
261 STR_SET(PHP_HTTP_INFO(message).request.url, PHP_HTTP_INFO(info).request.url ? estrdup(PHP_HTTP_INFO(info).request.url) : NULL);
262 STR_SET(PHP_HTTP_INFO(message).request.method, PHP_HTTP_INFO(info).request.method ? estrdup(PHP_HTTP_INFO(info).request.method) : NULL);
263 break;
264
265 case PHP_HTTP_RESPONSE:
266 PHP_HTTP_INFO(message).response.code = PHP_HTTP_INFO(info).response.code;
267 STR_SET(PHP_HTTP_INFO(message).response.status, PHP_HTTP_INFO(info).response.status ? estrdup(PHP_HTTP_INFO(info).response.status) : NULL);
268 break;
269
270 default:
271 break;
272 }
273 }
274
275 PHP_HTTP_API void php_http_message_update_headers(php_http_message_t *msg)
276 {
277 zval *h;
278 size_t size;
279
280 if (php_http_message_body_stream(&msg->body)->readfilters.head) {
281 /* if a read stream filter is attached to the body the caller must also care for the headers */
282 } else if ((size = php_http_message_body_size(&msg->body))) {
283 MAKE_STD_ZVAL(h);
284 ZVAL_LONG(h, size);
285 zend_hash_update(&msg->hdrs, "Content-Length", sizeof("Content-Length"), &h, sizeof(zval *), NULL);
286
287 if (msg->body.boundary) {
288 char *str;
289 size_t len;
290
291 if (!(h = php_http_message_header(msg, ZEND_STRL("Content-Type"), 1))) {
292 len = spprintf(&str, 0, "multipart/form-data; boundary=\"%s\"", msg->body.boundary);
293 MAKE_STD_ZVAL(h);
294 ZVAL_STRINGL(h, str, len, 0);
295 zend_hash_update(&msg->hdrs, "Content-Type", sizeof("Content-Type"), &h, sizeof(zval *), NULL);
296 } else if (!php_http_match(Z_STRVAL_P(h), "boundary=", PHP_HTTP_MATCH_WORD)) {
297 zval_dtor(h);
298 Z_STRLEN_P(h) = spprintf(&Z_STRVAL_P(h), 0, "%s; boundary=\"%s\"", Z_STRVAL_P(h), msg->body.boundary);
299 zend_hash_update(&msg->hdrs, "Content-Type", sizeof("Content-Type"), &h, sizeof(zval *), NULL);
300 } else {
301 zval_ptr_dtor(&h);
302 }
303 }
304 }
305 }
306
307 static void message_headers(php_http_message_t *msg, php_http_buffer_t *str)
308 {
309 TSRMLS_FETCH_FROM_CTX(msg->ts);
310
311 switch (msg->type) {
312 case PHP_HTTP_REQUEST:
313 php_http_buffer_appendf(str, PHP_HTTP_INFO_REQUEST_FMT_ARGS(&msg->http, PHP_HTTP_CRLF));
314 break;
315
316 case PHP_HTTP_RESPONSE:
317 php_http_buffer_appendf(str, PHP_HTTP_INFO_RESPONSE_FMT_ARGS(&msg->http, PHP_HTTP_CRLF));
318 break;
319
320 default:
321 break;
322 }
323
324 php_http_message_update_headers(msg);
325 php_http_headers_to_string(str, &msg->hdrs TSRMLS_CC);
326 }
327
328 PHP_HTTP_API void php_http_message_to_callback(php_http_message_t *msg, php_http_pass_callback_t cb, void *cb_arg)
329 {
330 php_http_buffer_t str;
331
332 php_http_buffer_init_ex(&str, 0x1000, 0);
333 message_headers(msg, &str);
334 cb(cb_arg, str.data, str.used);
335 php_http_buffer_dtor(&str);
336
337 if (php_http_message_body_size(&msg->body)) {
338 cb(cb_arg, ZEND_STRL(PHP_HTTP_CRLF));
339 php_http_message_body_to_callback(&msg->body, cb, cb_arg, 0, 0);
340 }
341 }
342
343 PHP_HTTP_API void php_http_message_to_string(php_http_message_t *msg, char **string, size_t *length)
344 {
345 php_http_buffer_t str;
346 char *data;
347
348 php_http_buffer_init_ex(&str, 0x1000, 0);
349 message_headers(msg, &str);
350 if (php_http_message_body_size(&msg->body)) {
351 php_http_buffer_appends(&str, PHP_HTTP_CRLF);
352 php_http_message_body_to_callback(&msg->body, (php_http_pass_callback_t) php_http_buffer_append, &str, 0, 0);
353 }
354
355 data = php_http_buffer_data(&str, string, length);
356 if (!string) {
357 efree(data);
358 }
359
360 php_http_buffer_dtor(&str);
361 }
362
363 PHP_HTTP_API void php_http_message_serialize(php_http_message_t *message, char **string, size_t *length)
364 {
365 char *buf;
366 php_http_buffer_t str;
367 php_http_message_t *msg;
368
369 php_http_buffer_init(&str);
370
371 msg = message = php_http_message_reverse(message);
372 do {
373 php_http_message_to_callback(message, (php_http_pass_callback_t) php_http_buffer_append, &str);
374 php_http_buffer_appends(&str, PHP_HTTP_CRLF);
375 } while ((message = message->parent));
376 php_http_message_reverse(msg);
377
378 buf = php_http_buffer_data(&str, string, length);
379 if (!string) {
380 efree(buf);
381 }
382
383 php_http_buffer_dtor(&str);
384 }
385
386 PHP_HTTP_API php_http_message_t *php_http_message_reverse(php_http_message_t *msg)
387 {
388 int i, c = 0;
389
390 php_http_message_count(c, msg);
391
392 if (c > 1) {
393 php_http_message_t *tmp = msg, **arr;
394
395 arr = ecalloc(c, sizeof(**arr));
396 for (i = 0; i < c; ++i) {
397 arr[i] = tmp;
398 tmp = tmp->parent;
399 }
400 arr[0]->parent = NULL;
401 for (i = 0; i < c-1; ++i) {
402 arr[i+1]->parent = arr[i];
403 }
404
405 msg = arr[c-1];
406 efree(arr);
407 }
408
409 return msg;
410 }
411
412 PHP_HTTP_API php_http_message_t *php_http_message_zip(php_http_message_t *one, php_http_message_t *two)
413 {
414 php_http_message_t *dst = php_http_message_copy(one, NULL), *src = php_http_message_copy(two, NULL), *tmp_dst, *tmp_src, *ret = dst;
415
416 while(dst && src) {
417 tmp_dst = dst->parent;
418 tmp_src = src->parent;
419 dst->parent = src;
420 if (tmp_dst) {
421 src->parent = tmp_dst;
422 }
423 src = tmp_src;
424 dst = tmp_dst;
425 }
426
427 return ret;
428 }
429
430 PHP_HTTP_API php_http_message_t *php_http_message_copy_ex(php_http_message_t *from, php_http_message_t *to, zend_bool parents)
431 {
432 php_http_message_t *temp, *copy = NULL;
433 php_http_info_t info;
434 TSRMLS_FETCH_FROM_CTX(from->ts);
435
436 if (from) {
437 info.type = from->type;
438 info.http = from->http;
439
440 copy = temp = php_http_message_init(to, 0 TSRMLS_CC);
441 php_http_message_set_info(temp, &info);
442 zend_hash_copy(&temp->hdrs, &from->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
443 php_http_message_body_copy(&from->body, &temp->body, 1);
444
445 if (parents) while (from->parent) {
446 info.type = from->parent->type;
447 info.http = from->parent->http;
448
449 temp->parent = php_http_message_init(NULL, 0 TSRMLS_CC);
450 php_http_message_set_info(temp->parent, &info);
451 zend_hash_copy(&temp->parent->hdrs, &from->parent->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
452 php_http_message_body_copy(&from->parent->body, &temp->parent->body, 1);
453
454 temp = temp->parent;
455 from = from->parent;
456 }
457 }
458
459 return copy;
460 }
461
462 PHP_HTTP_API php_http_message_t *php_http_message_copy(php_http_message_t *from, php_http_message_t *to)
463 {
464 return php_http_message_copy_ex(from, to, 1);
465 }
466
467 PHP_HTTP_API void php_http_message_dtor(php_http_message_t *message)
468 {
469 if (message) {
470 zend_hash_destroy(&message->hdrs);
471 php_http_message_body_dtor(&message->body);
472
473 switch (message->type) {
474 case PHP_HTTP_REQUEST:
475 STR_SET(message->http.info.request.method, NULL);
476 STR_SET(message->http.info.request.url, NULL);
477 break;
478
479 case PHP_HTTP_RESPONSE:
480 STR_SET(message->http.info.response.status, NULL);
481 break;
482
483 default:
484 break;
485 }
486 }
487 }
488
489 PHP_HTTP_API void php_http_message_free(php_http_message_t **message)
490 {
491 if (*message) {
492 if ((*message)->parent) {
493 php_http_message_free(&(*message)->parent);
494 }
495 php_http_message_dtor(*message);
496 efree(*message);
497 *message = NULL;
498 }
499 }
500
501 #define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpMessage, method, 0, req_args)
502 #define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpMessage, method, 0)
503 #define PHP_HTTP_MESSAGE_ME(method, visibility) PHP_ME(HttpMessage, method, PHP_HTTP_ARGS(HttpMessage, method), visibility)
504
505 PHP_HTTP_BEGIN_ARGS(__construct, 0)
506 PHP_HTTP_ARG_VAL(message, 0)
507 PHP_HTTP_ARG_VAL(greedy, 0)
508 PHP_HTTP_END_ARGS;
509
510 PHP_HTTP_EMPTY_ARGS(getBody);
511 PHP_HTTP_BEGIN_ARGS(setBody, 1)
512 PHP_HTTP_ARG_VAL(body, 0)
513 PHP_HTTP_END_ARGS;
514
515 PHP_HTTP_BEGIN_ARGS(addBody, 1)
516 PHP_HTTP_ARG_VAL(body, 0)
517 PHP_HTTP_END_ARGS;
518
519 PHP_HTTP_BEGIN_ARGS(getHeader, 1)
520 PHP_HTTP_ARG_VAL(header, 0)
521 PHP_HTTP_END_ARGS;
522
523 PHP_HTTP_BEGIN_ARGS(setHeader, 1)
524 PHP_HTTP_ARG_VAL(header, 0)
525 PHP_HTTP_ARG_VAL(value, 0)
526 PHP_HTTP_END_ARGS;
527
528 PHP_HTTP_BEGIN_ARGS(addHeader, 2)
529 PHP_HTTP_ARG_VAL(header, 0)
530 PHP_HTTP_ARG_VAL(value, 0)
531 PHP_HTTP_END_ARGS;
532
533 PHP_HTTP_EMPTY_ARGS(getHeaders);
534 PHP_HTTP_BEGIN_ARGS(setHeaders, 1)
535 PHP_HTTP_ARG_VAL(headers, 0)
536 PHP_HTTP_END_ARGS;
537
538 PHP_HTTP_BEGIN_ARGS(addHeaders, 1)
539 PHP_HTTP_ARG_VAL(headers, 0)
540 PHP_HTTP_ARG_VAL(append, 0)
541 PHP_HTTP_END_ARGS;
542
543 PHP_HTTP_EMPTY_ARGS(getType);
544 PHP_HTTP_BEGIN_ARGS(setType, 1)
545 PHP_HTTP_ARG_VAL(type, 0)
546 PHP_HTTP_END_ARGS;
547
548 PHP_HTTP_EMPTY_ARGS(getInfo);
549 PHP_HTTP_BEGIN_ARGS(setInfo, 1)
550 PHP_HTTP_ARG_VAL(http_info, 0)
551 PHP_HTTP_END_ARGS;
552
553 PHP_HTTP_EMPTY_ARGS(getResponseCode);
554 PHP_HTTP_BEGIN_ARGS(setResponseCode, 1)
555 PHP_HTTP_ARG_VAL(response_code, 0)
556 PHP_HTTP_END_ARGS;
557
558 PHP_HTTP_EMPTY_ARGS(getResponseStatus);
559 PHP_HTTP_BEGIN_ARGS(setResponseStatus, 1)
560 PHP_HTTP_ARG_VAL(response_status, 0)
561 PHP_HTTP_END_ARGS;
562
563 PHP_HTTP_EMPTY_ARGS(getRequestMethod);
564 PHP_HTTP_BEGIN_ARGS(setRequestMethod, 1)
565 PHP_HTTP_ARG_VAL(request_method, 0)
566 PHP_HTTP_END_ARGS;
567
568 PHP_HTTP_EMPTY_ARGS(getRequestUrl);
569 PHP_HTTP_BEGIN_ARGS(setRequestUrl, 1)
570 PHP_HTTP_ARG_VAL(url, 0)
571 PHP_HTTP_END_ARGS;
572
573 PHP_HTTP_EMPTY_ARGS(getHttpVersion);
574 PHP_HTTP_BEGIN_ARGS(setHttpVersion, 1)
575 PHP_HTTP_ARG_VAL(http_version, 0)
576 PHP_HTTP_END_ARGS;
577
578 PHP_HTTP_EMPTY_ARGS(getParentMessage);
579 PHP_HTTP_EMPTY_ARGS(__toString);
580 PHP_HTTP_BEGIN_ARGS(toString, 0)
581 PHP_HTTP_ARG_VAL(include_parent, 0)
582 PHP_HTTP_END_ARGS;
583 PHP_HTTP_BEGIN_ARGS(toCallback, 1)
584 PHP_HTTP_ARG_VAL(callback, 0)
585 PHP_HTTP_END_ARGS;
586 PHP_HTTP_BEGIN_ARGS(toStream, 1)
587 PHP_HTTP_ARG_VAL(stream, 0)
588 PHP_HTTP_END_ARGS;
589
590 PHP_HTTP_EMPTY_ARGS(count);
591
592 PHP_HTTP_EMPTY_ARGS(serialize);
593 PHP_HTTP_BEGIN_ARGS(unserialize, 1)
594 PHP_HTTP_ARG_VAL(serialized, 0)
595 PHP_HTTP_END_ARGS;
596
597 PHP_HTTP_EMPTY_ARGS(rewind);
598 PHP_HTTP_EMPTY_ARGS(valid);
599 PHP_HTTP_EMPTY_ARGS(key);
600 PHP_HTTP_EMPTY_ARGS(current);
601 PHP_HTTP_EMPTY_ARGS(next);
602
603 PHP_HTTP_EMPTY_ARGS(detach);
604 PHP_HTTP_BEGIN_ARGS(prepend, 1)
605 PHP_HTTP_ARG_OBJ(http\\Message, message, 0)
606 PHP_HTTP_END_ARGS;
607 PHP_HTTP_EMPTY_ARGS(reverse);
608
609 PHP_HTTP_BEGIN_ARGS(isMultipart, 0)
610 PHP_HTTP_ARG_VAL(boundary, 1)
611 PHP_HTTP_END_ARGS;
612 PHP_HTTP_EMPTY_ARGS(splitMultipartBody);
613
614 static zval *php_http_message_object_read_prop(zval *object, zval *member, int type PHP_HTTP_ZEND_LITERAL_DC TSRMLS_DC);
615 static void php_http_message_object_write_prop(zval *object, zval *member, zval *value PHP_HTTP_ZEND_LITERAL_DC TSRMLS_DC);
616 static zval **php_http_message_object_get_prop_ptr(zval *object, zval *member PHP_HTTP_ZEND_LITERAL_DC TSRMLS_DC);
617 static HashTable *php_http_message_object_get_props(zval *object TSRMLS_DC);
618
619 static zend_class_entry *php_http_message_class_entry;
620
621 zend_class_entry *php_http_message_get_class_entry(void)
622 {
623 return php_http_message_class_entry;
624 }
625
626 static zend_function_entry php_http_message_method_entry[] = {
627 PHP_HTTP_MESSAGE_ME(__construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
628 PHP_HTTP_MESSAGE_ME(getBody, ZEND_ACC_PUBLIC)
629 PHP_HTTP_MESSAGE_ME(setBody, ZEND_ACC_PUBLIC)
630 PHP_HTTP_MESSAGE_ME(addBody, ZEND_ACC_PUBLIC)
631 PHP_HTTP_MESSAGE_ME(getHeader, ZEND_ACC_PUBLIC)
632 PHP_HTTP_MESSAGE_ME(setHeader, ZEND_ACC_PUBLIC)
633 PHP_HTTP_MESSAGE_ME(addHeader, ZEND_ACC_PUBLIC)
634 PHP_HTTP_MESSAGE_ME(getHeaders, ZEND_ACC_PUBLIC)
635 PHP_HTTP_MESSAGE_ME(setHeaders, ZEND_ACC_PUBLIC)
636 PHP_HTTP_MESSAGE_ME(addHeaders, ZEND_ACC_PUBLIC)
637 PHP_HTTP_MESSAGE_ME(getType, ZEND_ACC_PUBLIC)
638 PHP_HTTP_MESSAGE_ME(setType, ZEND_ACC_PUBLIC)
639 PHP_HTTP_MESSAGE_ME(getInfo, ZEND_ACC_PUBLIC)
640 PHP_HTTP_MESSAGE_ME(setInfo, ZEND_ACC_PUBLIC)
641 PHP_HTTP_MESSAGE_ME(getResponseCode, ZEND_ACC_PUBLIC)
642 PHP_HTTP_MESSAGE_ME(setResponseCode, ZEND_ACC_PUBLIC)
643 PHP_HTTP_MESSAGE_ME(getResponseStatus, ZEND_ACC_PUBLIC)
644 PHP_HTTP_MESSAGE_ME(setResponseStatus, ZEND_ACC_PUBLIC)
645 PHP_HTTP_MESSAGE_ME(getRequestMethod, ZEND_ACC_PUBLIC)
646 PHP_HTTP_MESSAGE_ME(setRequestMethod, ZEND_ACC_PUBLIC)
647 PHP_HTTP_MESSAGE_ME(getRequestUrl, ZEND_ACC_PUBLIC)
648 PHP_HTTP_MESSAGE_ME(setRequestUrl, ZEND_ACC_PUBLIC)
649 PHP_HTTP_MESSAGE_ME(getHttpVersion, ZEND_ACC_PUBLIC)
650 PHP_HTTP_MESSAGE_ME(setHttpVersion, ZEND_ACC_PUBLIC)
651 PHP_HTTP_MESSAGE_ME(getParentMessage, ZEND_ACC_PUBLIC)
652 PHP_HTTP_MESSAGE_ME(toString, ZEND_ACC_PUBLIC)
653 PHP_HTTP_MESSAGE_ME(toCallback, ZEND_ACC_PUBLIC)
654 PHP_HTTP_MESSAGE_ME(toStream, ZEND_ACC_PUBLIC)
655
656 /* implements Countable */
657 PHP_HTTP_MESSAGE_ME(count, ZEND_ACC_PUBLIC)
658
659 /* implements Serializable */
660 PHP_HTTP_MESSAGE_ME(serialize, ZEND_ACC_PUBLIC)
661 PHP_HTTP_MESSAGE_ME(unserialize, ZEND_ACC_PUBLIC)
662
663 /* implements Iterator */
664 PHP_HTTP_MESSAGE_ME(rewind, ZEND_ACC_PUBLIC)
665 PHP_HTTP_MESSAGE_ME(valid, ZEND_ACC_PUBLIC)
666 PHP_HTTP_MESSAGE_ME(current, ZEND_ACC_PUBLIC)
667 PHP_HTTP_MESSAGE_ME(key, ZEND_ACC_PUBLIC)
668 PHP_HTTP_MESSAGE_ME(next, ZEND_ACC_PUBLIC)
669
670 ZEND_MALIAS(HttpMessage, __toString, toString, PHP_HTTP_ARGS(HttpMessage, __toString), ZEND_ACC_PUBLIC)
671
672 PHP_HTTP_MESSAGE_ME(detach, ZEND_ACC_PUBLIC)
673 PHP_HTTP_MESSAGE_ME(prepend, ZEND_ACC_PUBLIC)
674 PHP_HTTP_MESSAGE_ME(reverse, ZEND_ACC_PUBLIC)
675
676 PHP_HTTP_MESSAGE_ME(isMultipart, ZEND_ACC_PUBLIC)
677 PHP_HTTP_MESSAGE_ME(splitMultipartBody, ZEND_ACC_PUBLIC)
678
679 EMPTY_FUNCTION_ENTRY
680 };
681 static zend_object_handlers php_http_message_object_handlers;
682 static HashTable php_http_message_object_prophandlers;
683
684 typedef void (*php_http_message_object_prophandler_func_t)(php_http_message_object_t *o, zval *v TSRMLS_DC);
685
686 typedef struct php_http_message_object_prophandler {
687 php_http_message_object_prophandler_func_t read;
688 php_http_message_object_prophandler_func_t write;
689 } php_http_message_object_prophandler_t;
690
691 static STATUS php_http_message_object_add_prophandler(const char *prop_str, size_t prop_len, php_http_message_object_prophandler_func_t read, php_http_message_object_prophandler_func_t write) {
692 php_http_message_object_prophandler_t h = { read, write };
693 return zend_hash_add(&php_http_message_object_prophandlers, prop_str, prop_len + 1, (void *) &h, sizeof(h), NULL);
694 }
695 /*
696 static int php_http_message_object_has_prophandler(const char *prop_str, size_t prop_len) {
697 return zend_hash_exists(&php_http_message_object_prophandlers, prop_str, prop_len + 1);
698 }
699 */
700 static STATUS php_http_message_object_get_prophandler(const char *prop_str, size_t prop_len, php_http_message_object_prophandler_t **handler) {
701 return zend_hash_find(&php_http_message_object_prophandlers, prop_str, prop_len + 1, (void *) handler);
702 }
703 static void php_http_message_object_prophandler_get_type(php_http_message_object_t *obj, zval *return_value TSRMLS_DC) {
704 RETVAL_LONG(obj->message->type);
705 }
706 static void php_http_message_object_prophandler_set_type(php_http_message_object_t *obj, zval *value TSRMLS_DC) {
707 zval *cpy = php_http_ztyp(IS_LONG, value);
708 php_http_message_set_type(obj->message, Z_LVAL_P(cpy));
709 zval_ptr_dtor(&cpy);
710 }
711 static void php_http_message_object_prophandler_get_request_method(php_http_message_object_t *obj, zval *return_value TSRMLS_DC) {
712 if (PHP_HTTP_MESSAGE_TYPE(REQUEST, obj->message) && obj->message->http.info.request.method) {
713 RETVAL_STRING(obj->message->http.info.request.method, 1);
714 } else {
715 RETVAL_NULL();
716 }
717 }
718 static void php_http_message_object_prophandler_set_request_method(php_http_message_object_t *obj, zval *value TSRMLS_DC) {
719 if (PHP_HTTP_MESSAGE_TYPE(REQUEST, obj->message)) {
720 zval *cpy = php_http_ztyp(IS_STRING, value);
721 STR_SET(obj->message->http.info.request.method, estrndup(Z_STRVAL_P(cpy), Z_STRLEN_P(cpy)));
722 zval_ptr_dtor(&cpy);
723 }
724 }
725 static void php_http_message_object_prophandler_get_request_url(php_http_message_object_t *obj, zval *return_value TSRMLS_DC) {
726 if (PHP_HTTP_MESSAGE_TYPE(REQUEST, obj->message) && obj->message->http.info.request.url) {
727 RETVAL_STRING(obj->message->http.info.request.url, 1);
728 } else {
729 RETVAL_NULL();
730 }
731 }
732 static void php_http_message_object_prophandler_set_request_url(php_http_message_object_t *obj, zval *value TSRMLS_DC) {
733 if (PHP_HTTP_MESSAGE_TYPE(REQUEST, obj->message)) {
734 zval *cpy = php_http_ztyp(IS_STRING, value);
735 STR_SET(obj->message->http.info.request.url, estrndup(Z_STRVAL_P(cpy), Z_STRLEN_P(cpy)));
736 zval_ptr_dtor(&cpy);
737 }
738 }
739 static void php_http_message_object_prophandler_get_response_status(php_http_message_object_t *obj, zval *return_value TSRMLS_DC) {
740 if (PHP_HTTP_MESSAGE_TYPE(RESPONSE, obj->message) && obj->message->http.info.response.status) {
741 RETVAL_STRING(obj->message->http.info.response.status, 1);
742 } else {
743 RETVAL_NULL();
744 }
745 }
746 static void php_http_message_object_prophandler_set_response_status(php_http_message_object_t *obj, zval *value TSRMLS_DC) {
747 if (PHP_HTTP_MESSAGE_TYPE(RESPONSE, obj->message)) {
748 zval *cpy = php_http_ztyp(IS_STRING, value);
749 STR_SET(obj->message->http.info.response.status, estrndup(Z_STRVAL_P(cpy), Z_STRLEN_P(cpy)));
750 zval_ptr_dtor(&cpy);
751 }
752 }
753 static void php_http_message_object_prophandler_get_response_code(php_http_message_object_t *obj, zval *return_value TSRMLS_DC) {
754 if (PHP_HTTP_MESSAGE_TYPE(RESPONSE, obj->message)) {
755 RETVAL_LONG(obj->message->http.info.response.code);
756 } else {
757 RETVAL_NULL();
758 }
759 }
760 static void php_http_message_object_prophandler_set_response_code(php_http_message_object_t *obj, zval *value TSRMLS_DC) {
761 if (PHP_HTTP_MESSAGE_TYPE(RESPONSE, obj->message)) {
762 zval *cpy = php_http_ztyp(IS_LONG, value);
763 obj->message->http.info.response.code = Z_LVAL_P(cpy);
764 STR_SET(obj->message->http.info.response.status, estrdup(php_http_env_get_response_status_for_code(obj->message->http.info.response.code)));
765 zval_ptr_dtor(&cpy);
766 }
767 }
768 static void php_http_message_object_prophandler_get_http_version(php_http_message_object_t *obj, zval *return_value TSRMLS_DC) {
769 char *version_str;
770 size_t version_len;
771
772 php_http_version_to_string(&obj->message->http.version, &version_str, &version_len, NULL, NULL TSRMLS_CC);
773 RETVAL_STRINGL(version_str, version_len, 0);
774 }
775 static void php_http_message_object_prophandler_set_http_version(php_http_message_object_t *obj, zval *value TSRMLS_DC) {
776 zval *cpy = php_http_ztyp(IS_STRING, value);
777 php_http_version_parse(&obj->message->http.version, Z_STRVAL_P(cpy) TSRMLS_CC);
778 zval_ptr_dtor(&cpy);
779 }
780 static void php_http_message_object_prophandler_get_headers(php_http_message_object_t *obj, zval *return_value TSRMLS_DC) {
781 array_init(return_value);
782 zend_hash_copy(Z_ARRVAL_P(return_value), &obj->message->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
783 }
784 static void php_http_message_object_prophandler_set_headers(php_http_message_object_t *obj, zval *value TSRMLS_DC) {
785 zval *cpy = php_http_ztyp(IS_ARRAY, value);
786
787 zend_hash_clean(&obj->message->hdrs);
788 zend_hash_copy(&obj->message->hdrs, Z_ARRVAL_P(cpy), (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
789 zval_ptr_dtor(&cpy);
790 }
791 static void php_http_message_object_prophandler_get_body(php_http_message_object_t *obj, zval *return_value TSRMLS_DC) {
792 if (obj->body.handle) {
793 RETVAL_OBJVAL(obj->body, 1);
794 } else {
795 RETVAL_NULL();
796 }
797 }
798 static void php_http_message_object_prophandler_set_body(php_http_message_object_t *obj, zval *value TSRMLS_DC) {
799 php_http_message_object_set_body(obj, value TSRMLS_CC);
800 }
801 static void php_http_message_object_prophandler_get_parent_message(php_http_message_object_t *obj, zval *return_value TSRMLS_DC) {
802 if (obj->message->parent) {
803 RETVAL_OBJVAL(obj->parent, 1);
804 } else {
805 RETVAL_NULL();
806 }
807 }
808 static void php_http_message_object_prophandler_set_parent_message(php_http_message_object_t *obj, zval *value TSRMLS_DC) {
809 if (Z_TYPE_P(value) == IS_OBJECT && instanceof_function(Z_OBJCE_P(value), php_http_message_class_entry TSRMLS_CC)) {
810 php_http_message_object_t *parent_obj = zend_object_store_get_object(value TSRMLS_CC);
811
812 if (obj->message->parent) {
813 zend_objects_store_del_ref_by_handle(obj->parent.handle TSRMLS_CC);
814 }
815 Z_OBJ_ADDREF_P(value);
816 obj->parent = Z_OBJVAL_P(value);
817 obj->message->parent = parent_obj->message;
818 }
819 }
820
821 PHP_MINIT_FUNCTION(http_message)
822 {
823 PHP_HTTP_REGISTER_CLASS(http, Message, http_message, php_http_object_get_class_entry(), 0);
824 php_http_message_class_entry->create_object = php_http_message_object_new;
825 memcpy(&php_http_message_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
826 php_http_message_object_handlers.clone_obj = php_http_message_object_clone;
827 php_http_message_object_handlers.read_property = php_http_message_object_read_prop;
828 php_http_message_object_handlers.write_property = php_http_message_object_write_prop;
829 php_http_message_object_handlers.get_properties = php_http_message_object_get_props;
830 php_http_message_object_handlers.get_property_ptr_ptr = php_http_message_object_get_prop_ptr;
831
832 zend_class_implements(php_http_message_class_entry TSRMLS_CC, 3, spl_ce_Countable, zend_ce_serializable, zend_ce_iterator);
833
834 zend_hash_init(&php_http_message_object_prophandlers, 9, NULL, NULL, 1);
835 zend_declare_property_long(php_http_message_class_entry, ZEND_STRL("type"), PHP_HTTP_NONE, ZEND_ACC_PROTECTED TSRMLS_CC);
836 php_http_message_object_add_prophandler(ZEND_STRL("type"), php_http_message_object_prophandler_get_type, php_http_message_object_prophandler_set_type);
837 zend_declare_property_null(php_http_message_class_entry, ZEND_STRL("body"), ZEND_ACC_PROTECTED TSRMLS_CC);
838 php_http_message_object_add_prophandler(ZEND_STRL("body"), php_http_message_object_prophandler_get_body, php_http_message_object_prophandler_set_body);
839 zend_declare_property_string(php_http_message_class_entry, ZEND_STRL("requestMethod"), "", ZEND_ACC_PROTECTED TSRMLS_CC);
840 php_http_message_object_add_prophandler(ZEND_STRL("requestMethod"), php_http_message_object_prophandler_get_request_method, php_http_message_object_prophandler_set_request_method);
841 zend_declare_property_string(php_http_message_class_entry, ZEND_STRL("requestUrl"), "", ZEND_ACC_PROTECTED TSRMLS_CC);
842 php_http_message_object_add_prophandler(ZEND_STRL("requestUrl"), php_http_message_object_prophandler_get_request_url, php_http_message_object_prophandler_set_request_url);
843 zend_declare_property_string(php_http_message_class_entry, ZEND_STRL("responseStatus"), "", ZEND_ACC_PROTECTED TSRMLS_CC);
844 php_http_message_object_add_prophandler(ZEND_STRL("responseStatus"), php_http_message_object_prophandler_get_response_status, php_http_message_object_prophandler_set_response_status);
845 zend_declare_property_long(php_http_message_class_entry, ZEND_STRL("responseCode"), 0, ZEND_ACC_PROTECTED TSRMLS_CC);
846 php_http_message_object_add_prophandler(ZEND_STRL("responseCode"), php_http_message_object_prophandler_get_response_code, php_http_message_object_prophandler_set_response_code);
847 zend_declare_property_null(php_http_message_class_entry, ZEND_STRL("httpVersion"), ZEND_ACC_PROTECTED TSRMLS_CC);
848 php_http_message_object_add_prophandler(ZEND_STRL("httpVersion"), php_http_message_object_prophandler_get_http_version, php_http_message_object_prophandler_set_http_version);
849 zend_declare_property_null(php_http_message_class_entry, ZEND_STRL("headers"), ZEND_ACC_PROTECTED TSRMLS_CC);
850 php_http_message_object_add_prophandler(ZEND_STRL("headers"), php_http_message_object_prophandler_get_headers, php_http_message_object_prophandler_set_headers);
851 zend_declare_property_null(php_http_message_class_entry, ZEND_STRL("parentMessage"), ZEND_ACC_PROTECTED TSRMLS_CC);
852 php_http_message_object_add_prophandler(ZEND_STRL("parentMessage"), php_http_message_object_prophandler_get_parent_message, php_http_message_object_prophandler_set_parent_message);
853
854 zend_declare_class_constant_long(php_http_message_class_entry, ZEND_STRL("TYPE_NONE"), PHP_HTTP_NONE TSRMLS_CC);
855 zend_declare_class_constant_long(php_http_message_class_entry, ZEND_STRL("TYPE_REQUEST"), PHP_HTTP_REQUEST TSRMLS_CC);
856 zend_declare_class_constant_long(php_http_message_class_entry, ZEND_STRL("TYPE_RESPONSE"), PHP_HTTP_RESPONSE TSRMLS_CC);
857
858 return SUCCESS;
859 }
860
861 PHP_MSHUTDOWN_FUNCTION(http_message)
862 {
863 zend_hash_destroy(&php_http_message_object_prophandlers);
864
865 return SUCCESS;
866 }
867
868 void php_http_message_object_reverse(zval *this_ptr, zval *return_value TSRMLS_DC)
869 {
870 int i = 0;
871 php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
872
873 /* count */
874 php_http_message_count(i, obj->message);
875
876 if (i > 1) {
877 zend_object_value *ovalues = NULL;
878 php_http_message_object_t **objects = NULL;
879 int last;
880
881 objects = ecalloc(i, sizeof(**objects));
882 ovalues = ecalloc(i, sizeof(*ovalues));
883
884 /* we are the first message */
885 objects[0] = obj;
886 ovalues[0] = getThis()->value.obj;
887
888 /* fetch parents */
889 for (i = 1; obj->parent.handle; ++i) {
890 ovalues[i] = obj->parent;
891 objects[i] = obj = zend_object_store_get_object_by_handle(obj->parent.handle TSRMLS_CC);
892 }
893
894 /* reorder parents */
895 for (last = --i; i; --i) {
896 objects[i]->message->parent = objects[i-1]->message;
897 objects[i]->parent = ovalues[i-1];
898 }
899
900 objects[0]->message->parent = NULL;
901 objects[0]->parent.handle = 0;
902 objects[0]->parent.handlers = NULL;
903
904 /* add ref, because we previously have not been a parent message */
905 Z_OBJ_ADDREF_P(getThis());
906 RETVAL_OBJVAL(ovalues[last], 1);
907
908 efree(objects);
909 efree(ovalues);
910 } else {
911 RETURN_ZVAL(getThis(), 1, 0);
912 }
913 }
914
915 void php_http_message_object_prepend(zval *this_ptr, zval *prepend, zend_bool top TSRMLS_DC)
916 {
917 zval m;
918 php_http_message_t *save_parent_msg = NULL;
919 zend_object_value save_parent_obj = {0, NULL};
920 php_http_message_object_t *obj = zend_object_store_get_object(this_ptr TSRMLS_CC);
921 php_http_message_object_t *prepend_obj = zend_object_store_get_object(prepend TSRMLS_CC);
922
923 INIT_PZVAL(&m);
924 m.type = IS_OBJECT;
925
926 if (!top) {
927 save_parent_obj = obj->parent;
928 save_parent_msg = obj->message->parent;
929 } else {
930 /* iterate to the most parent object */
931 while (obj->parent.handle) {
932 m.value.obj = obj->parent;
933 obj = zend_object_store_get_object(&m TSRMLS_CC);
934 }
935 }
936
937 /* prepend */
938 obj->parent = prepend->value.obj;
939 obj->message->parent = prepend_obj->message;
940
941 /* add ref */
942 zend_objects_store_add_ref(prepend TSRMLS_CC);
943 while (prepend_obj->parent.handle) {
944 m.value.obj = prepend_obj->parent;
945 zend_objects_store_add_ref(&m TSRMLS_CC);
946 prepend_obj = zend_object_store_get_object(&m TSRMLS_CC);
947 }
948
949 if (!top) {
950 prepend_obj->parent = save_parent_obj;
951 prepend_obj->message->parent = save_parent_msg;
952 }
953 }
954
955 STATUS php_http_message_object_set_body(php_http_message_object_t *msg_obj, zval *zbody TSRMLS_DC)
956 {
957 zval *tmp = NULL;
958 php_stream *s;
959 zend_object_value ov;
960 php_http_message_body_t *body;
961 php_http_message_body_object_t *body_obj;
962
963 switch (Z_TYPE_P(zbody)) {
964 case IS_RESOURCE:
965 php_stream_from_zval_no_verify(s, &zbody);
966 if (!s) {
967 php_http_error(HE_THROW, PHP_HTTP_E_CLIENT, "not a valid stream resource");
968 return FAILURE;
969 }
970
971 is_resource:
972
973 body = php_http_message_body_init(NULL, s TSRMLS_CC);
974 if (SUCCESS != php_http_new(&ov, php_http_message_body_get_class_entry(), (php_http_new_t) php_http_message_body_object_new_ex, NULL, body, NULL TSRMLS_CC)) {
975 php_http_message_body_free(&body);
976 return FAILURE;
977 }
978 MAKE_STD_ZVAL(tmp);
979 ZVAL_OBJVAL(tmp, ov, 0);
980 zbody = tmp;
981 break;
982
983 case IS_OBJECT:
984 if (instanceof_function(Z_OBJCE_P(zbody), php_http_message_body_get_class_entry() TSRMLS_CC)) {
985 Z_OBJ_ADDREF_P(zbody);
986 break;
987 }
988 /* no break */
989
990 default:
991 tmp = php_http_ztyp(IS_STRING, zbody);
992 s = php_stream_temp_new();
993 php_stream_write(s, Z_STRVAL_P(tmp), Z_STRLEN_P(tmp));
994 zval_ptr_dtor(&tmp);
995 tmp = NULL;
996 goto is_resource;
997
998 }
999
1000 body_obj = zend_object_store_get_object(zbody TSRMLS_CC);
1001
1002 if (msg_obj->body.handle) {
1003 zend_objects_store_del_ref_by_handle(msg_obj->body.handle TSRMLS_CC);
1004 php_http_message_body_dtor(&msg_obj->message->body);
1005 }
1006
1007 php_http_message_body_copy(body_obj->body, &msg_obj->message->body, 0);
1008 msg_obj->body = Z_OBJVAL_P(zbody);
1009
1010 if (tmp) {
1011 zval_ptr_dtor(&tmp);
1012 }
1013
1014 return SUCCESS;
1015 }
1016
1017 zend_object_value php_http_message_object_new(zend_class_entry *ce TSRMLS_DC)
1018 {
1019 return php_http_message_object_new_ex(ce, NULL, NULL TSRMLS_CC);
1020 }
1021
1022 zend_object_value php_http_message_object_new_ex(zend_class_entry *ce, php_http_message_t *msg, php_http_message_object_t **ptr TSRMLS_DC)
1023 {
1024 zend_object_value ov;
1025 php_http_message_object_t *o;
1026
1027 o = ecalloc(1, sizeof(php_http_message_object_t));
1028 zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
1029 object_properties_init((zend_object *) o, ce);
1030
1031 if (ptr) {
1032 *ptr = o;
1033 }
1034
1035 if (msg) {
1036 php_http_message_body_object_t *body_obj;
1037
1038 o->message = msg;
1039 if (msg->parent) {
1040 o->parent = php_http_message_object_new_ex(ce, msg->parent, NULL TSRMLS_CC);
1041 }
1042 o->body = php_http_message_body_object_new_ex(php_http_message_body_get_class_entry(), &msg->body, &body_obj TSRMLS_CC);
1043 body_obj->shared = 1;
1044 }
1045
1046 ov.handle = zend_objects_store_put((zend_object *) o, NULL, php_http_message_object_free, NULL TSRMLS_CC);
1047 ov.handlers = &php_http_message_object_handlers;
1048
1049 return ov;
1050 }
1051
1052 zend_object_value php_http_message_object_clone(zval *this_ptr TSRMLS_DC)
1053 {
1054 zend_object_value new_ov;
1055 php_http_message_object_t *new_obj = NULL;
1056 php_http_message_object_t *old_obj = zend_object_store_get_object(this_ptr TSRMLS_CC);
1057
1058 new_ov = php_http_message_object_new_ex(old_obj->zo.ce, php_http_message_copy(old_obj->message, NULL), &new_obj TSRMLS_CC);
1059 zend_objects_clone_members(&new_obj->zo, new_ov, &old_obj->zo, Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC);
1060
1061 return new_ov;
1062 }
1063
1064 void php_http_message_object_free(void *object TSRMLS_DC)
1065 {
1066 php_http_message_object_t *o = (php_http_message_object_t *) object;
1067
1068 if (o->iterator) {
1069 zval_ptr_dtor(&o->iterator);
1070 o->iterator = NULL;
1071 }
1072 if (o->message) {
1073 /* do NOT free recursivly */
1074 php_http_message_dtor(o->message);
1075 efree(o->message);
1076 o->message = NULL;
1077 }
1078 if (o->parent.handle) {
1079 zend_objects_store_del_ref_by_handle(o->parent.handle TSRMLS_CC);
1080 }
1081 if (o->body.handle) {
1082 zend_objects_store_del_ref_by_handle(o->body.handle TSRMLS_CC);
1083 }
1084 zend_object_std_dtor((zend_object *) o TSRMLS_CC);
1085 efree(o);
1086 }
1087
1088
1089 static zval **php_http_message_object_get_prop_ptr(zval *object, zval *member PHP_HTTP_ZEND_LITERAL_DC TSRMLS_DC)
1090 {
1091 php_http_message_object_prophandler_t *handler;
1092 zval *copy = php_http_ztyp(IS_STRING, member);
1093
1094 if (SUCCESS == php_http_message_object_get_prophandler(Z_STRVAL_P(copy), Z_STRLEN_P(copy), &handler)) {
1095 zval_ptr_dtor(&copy);
1096 return &php_http_property_proxy_init(NULL, object, member, NULL TSRMLS_CC)->myself;
1097 }
1098 zval_ptr_dtor(&copy);
1099
1100 return zend_get_std_object_handlers()->get_property_ptr_ptr(object, member PHP_HTTP_ZEND_LITERAL_CC TSRMLS_CC);
1101 }
1102
1103 static zval *php_http_message_object_read_prop(zval *object, zval *member, int type PHP_HTTP_ZEND_LITERAL_DC TSRMLS_DC)
1104 {
1105 php_http_message_object_t *obj = zend_object_store_get_object(object TSRMLS_CC);
1106 php_http_message_object_prophandler_t *handler;
1107 zval *return_value, *copy = php_http_ztyp(IS_STRING, member);
1108
1109 if (SUCCESS == php_http_message_object_get_prophandler(Z_STRVAL_P(copy), Z_STRLEN_P(copy), &handler)) {
1110 if (type == BP_VAR_R) {
1111 ALLOC_ZVAL(return_value);
1112 Z_SET_REFCOUNT_P(return_value, 0);
1113 Z_UNSET_ISREF_P(return_value);
1114
1115 handler->read(obj, return_value TSRMLS_CC);
1116 } else {
1117 zend_error(E_ERROR, "Cannot access HttpMessage properties by reference or array key/index");
1118 return_value = NULL;
1119 }
1120 } else {
1121 return_value = zend_get_std_object_handlers()->read_property(object, member, type PHP_HTTP_ZEND_LITERAL_CC TSRMLS_CC);
1122 }
1123
1124 zval_ptr_dtor(&copy);
1125
1126 return return_value;
1127 }
1128
1129 static void php_http_message_object_write_prop(zval *object, zval *member, zval *value PHP_HTTP_ZEND_LITERAL_DC TSRMLS_DC)
1130 {
1131 php_http_message_object_t *obj = zend_object_store_get_object(object TSRMLS_CC);
1132 php_http_message_object_prophandler_t *handler;
1133 zval *copy = php_http_ztyp(IS_STRING, member);
1134
1135 if (SUCCESS == php_http_message_object_get_prophandler(Z_STRVAL_P(copy), Z_STRLEN_P(copy), &handler)) {
1136 handler->write(obj, value TSRMLS_CC);
1137 } else {
1138 zend_get_std_object_handlers()->write_property(object, member, value PHP_HTTP_ZEND_LITERAL_CC TSRMLS_CC);
1139 }
1140
1141 zval_ptr_dtor(&copy);
1142 }
1143
1144
1145 static HashTable *php_http_message_object_get_props(zval *object TSRMLS_DC)
1146 {
1147 zval *headers;
1148 php_http_message_object_t *obj = zend_object_store_get_object(object TSRMLS_CC);
1149 php_http_message_t *msg = obj->message;
1150 HashTable *props = zend_get_std_object_handlers()->get_properties(object TSRMLS_CC);
1151 zval array, *parent, *body;
1152 char *version;
1153
1154 INIT_PZVAL_ARRAY(&array, props);
1155
1156 #define ASSOC_PROP(array, ptype, name, val) \
1157 { \
1158 char *m_prop_name; \
1159 int m_prop_len; \
1160 zend_mangle_property_name(&m_prop_name, &m_prop_len, "*", 1, name, lenof(name), 0); \
1161 add_assoc_ ##ptype## _ex(&array, m_prop_name, sizeof(name)+3, val); \
1162 efree(m_prop_name); \
1163 }
1164 #define ASSOC_STRING(array, name, val) ASSOC_STRINGL(array, name, val, strlen(val))
1165 #define ASSOC_STRINGL(array, name, val, len) ASSOC_STRINGL_EX(array, name, val, len, 1)
1166 #define ASSOC_STRINGL_EX(array, name, val, len, cpy) \
1167 { \
1168 char *m_prop_name; \
1169 int m_prop_len; \
1170 zend_mangle_property_name(&m_prop_name, &m_prop_len, "*", 1, name, lenof(name), 0); \
1171 add_assoc_stringl_ex(&array, m_prop_name, sizeof(name)+3, val, len, cpy); \
1172 efree(m_prop_name); \
1173 }
1174
1175 ASSOC_PROP(array, long, "type", msg->type);
1176 ASSOC_STRINGL_EX(array, "httpVersion", version, spprintf(&version, 0, "%u.%u", msg->http.version.major, msg->http.version.minor), 0);
1177
1178 switch (msg->type) {
1179 case PHP_HTTP_REQUEST:
1180 ASSOC_PROP(array, long, "responseCode", 0);
1181 ASSOC_STRINGL(array, "responseStatus", "", 0);
1182 ASSOC_STRING(array, "requestMethod", STR_PTR(msg->http.info.request.method));
1183 ASSOC_STRING(array, "requestUrl", STR_PTR(msg->http.info.request.url));
1184 break;
1185
1186 case PHP_HTTP_RESPONSE:
1187 ASSOC_PROP(array, long, "responseCode", msg->http.info.response.code);
1188 ASSOC_STRING(array, "responseStatus", STR_PTR(msg->http.info.response.status));
1189 ASSOC_STRINGL(array, "requestMethod", "", 0);
1190 ASSOC_STRINGL(array, "requestUrl", "", 0);
1191 break;
1192
1193 case PHP_HTTP_NONE:
1194 default:
1195 ASSOC_PROP(array, long, "responseCode", 0);
1196 ASSOC_STRINGL(array, "responseStatus", "", 0);
1197 ASSOC_STRINGL(array, "requestMethod", "", 0);
1198 ASSOC_STRINGL(array, "requestUrl", "", 0);
1199 break;
1200 }
1201
1202 MAKE_STD_ZVAL(headers);
1203 array_init(headers);
1204 zend_hash_copy(Z_ARRVAL_P(headers), &msg->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
1205 ASSOC_PROP(array, zval, "headers", headers);
1206
1207 MAKE_STD_ZVAL(body);
1208 if (!obj->body.handle) {
1209 php_http_new(&obj->body, php_http_message_body_get_class_entry(), (php_http_new_t) php_http_message_body_object_new_ex, NULL, (void *) php_http_message_body_copy(&obj->message->body, NULL, 0), NULL TSRMLS_CC);
1210 }
1211 ZVAL_OBJVAL(body, obj->body, 1);
1212 ASSOC_PROP(array, zval, "body", body);
1213
1214 MAKE_STD_ZVAL(parent);
1215 if (msg->parent) {
1216 ZVAL_OBJVAL(parent, obj->parent, 1);
1217 } else {
1218 ZVAL_NULL(parent);
1219 }
1220 ASSOC_PROP(array, zval, "parentMessage", parent);
1221
1222 return props;
1223 }
1224
1225 /* PHP */
1226
1227 PHP_METHOD(HttpMessage, __construct)
1228 {
1229 zend_bool greedy = 1;
1230 zval *zmessage = NULL;
1231 php_http_message_t *msg = NULL;
1232 php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1233
1234 with_error_handling(EH_THROW, php_http_exception_get_class_entry()) {
1235 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z!b", &zmessage, &greedy) && zmessage) {
1236 if (Z_TYPE_P(zmessage) == IS_RESOURCE) {
1237 php_stream *s;
1238 php_http_message_parser_t p;
1239
1240 php_stream_from_zval(s, &zmessage);
1241 if (s && php_http_message_parser_init(&p TSRMLS_CC)) {
1242 unsigned flags = (greedy ? PHP_HTTP_MESSAGE_PARSER_GREEDY : 0);
1243
1244 php_http_message_parser_parse_stream(&p, s, flags, &msg);
1245 php_http_message_parser_dtor(&p);
1246 }
1247
1248 if (!msg) {
1249 php_http_error(HE_THROW, PHP_HTTP_E_MESSAGE, "could not parse message from stream");
1250 }
1251 } else {
1252 zmessage = php_http_ztyp(IS_STRING, zmessage);
1253 if (!(msg = php_http_message_parse(NULL, Z_STRVAL_P(zmessage), Z_STRLEN_P(zmessage), greedy TSRMLS_CC))) {
1254 php_http_error(HE_THROW, PHP_HTTP_E_MESSAGE, "could not parse message: %.*s", MIN(25, Z_STRLEN_P(zmessage)), Z_STRVAL_P(zmessage));
1255 }
1256 zval_ptr_dtor(&zmessage);
1257 }
1258
1259 if (msg) {
1260 php_http_message_dtor(obj->message);
1261 obj->message = msg;
1262 if (obj->message->parent) {
1263 obj->parent = php_http_message_object_new_ex(Z_OBJCE_P(getThis()), obj->message->parent, NULL TSRMLS_CC);
1264 }
1265 }
1266 }
1267 if (!obj->message) {
1268 obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
1269 }
1270 } end_error_handling();
1271
1272 }
1273
1274 PHP_METHOD(HttpMessage, getBody)
1275 {
1276 with_error_handling(EH_THROW, php_http_exception_get_class_entry()) {
1277 if (SUCCESS == zend_parse_parameters_none()) {
1278 php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1279
1280 if (!obj->message) {
1281 obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
1282 }
1283 if (!obj->body.handle) {
1284 php_http_message_body_object_t *body_obj;
1285 obj->body = php_http_message_body_object_new_ex(php_http_message_body_get_class_entry(), &obj->message->body, &body_obj TSRMLS_CC);
1286 body_obj->shared = 1;
1287 }
1288 if (obj->body.handle) {
1289 RETVAL_OBJVAL(obj->body, 1);
1290 }
1291 }
1292 } end_error_handling();
1293 }
1294
1295 PHP_METHOD(HttpMessage, setBody)
1296 {
1297 zval *zbody;
1298
1299 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &zbody, php_http_message_body_get_class_entry())) {
1300 php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1301
1302 if (!obj->message) {
1303 obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
1304 }
1305 php_http_message_object_prophandler_set_body(obj, zbody TSRMLS_CC);
1306 }
1307 RETVAL_ZVAL(getThis(), 1, 0);
1308 }
1309
1310 PHP_METHOD(HttpMessage, addBody)
1311 {
1312 zval *new_body;
1313
1314 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &new_body, php_http_message_body_get_class_entry())) {
1315 php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1316 php_http_message_body_object_t *new_obj = zend_object_store_get_object(new_body TSRMLS_CC);
1317
1318 php_http_message_body_to_callback(new_obj->body, (php_http_pass_callback_t) php_http_message_body_append, &obj->message->body, 0, 0);
1319 }
1320 RETVAL_ZVAL(getThis(), 1, 0);
1321 }
1322
1323
1324 PHP_METHOD(HttpMessage, getHeader)
1325 {
1326 char *header_str;
1327 int header_len;
1328
1329 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &header_str, &header_len)) {
1330 php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1331 zval *header;
1332
1333 if (!obj->message) {
1334 obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
1335 }
1336
1337 if ((header = php_http_message_header(obj->message, header_str, header_len, 0))) {
1338 RETURN_ZVAL(header, 1, 1);
1339 }
1340 }
1341 RETURN_FALSE;
1342 }
1343
1344 PHP_METHOD(HttpMessage, getHeaders)
1345 {
1346 if (SUCCESS == zend_parse_parameters_none()) {
1347 php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1348
1349 if (!obj->message) {
1350 obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
1351 }
1352
1353 array_init(return_value);
1354 array_copy(&obj->message->hdrs, Z_ARRVAL_P(return_value));
1355 }
1356 }
1357
1358 PHP_METHOD(HttpMessage, setHeader)
1359 {
1360 zval *zvalue = NULL;
1361 char *name_str;
1362 int name_len;
1363
1364 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z!", &name_str, &name_len, &zvalue)) {
1365 php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1366 char *name = php_http_pretty_key(estrndup(name_str, name_len), name_len, 1, 1);
1367
1368 if (!obj->message) {
1369 obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
1370 }
1371
1372 if (!zvalue) {
1373 zend_symtable_del(&obj->message->hdrs, name, name_len + 1);
1374 } else {
1375 Z_ADDREF_P(zvalue);
1376 zend_symtable_update(&obj->message->hdrs, name, name_len + 1, &zvalue, sizeof(void *), NULL);
1377 }
1378 efree(name);
1379 }
1380 RETVAL_ZVAL(getThis(), 1, 0);
1381 }
1382
1383 PHP_METHOD(HttpMessage, setHeaders)
1384 {
1385 zval *new_headers = NULL;
1386
1387 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/!", &new_headers)) {
1388 php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1389
1390 if (!obj->message) {
1391 obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
1392 }
1393
1394 zend_hash_clean(&obj->message->hdrs);
1395 if (new_headers) {
1396 array_join(Z_ARRVAL_P(new_headers), &obj->message->hdrs, 0, ARRAY_JOIN_PRETTIFY|ARRAY_JOIN_STRONLY);
1397 }
1398 }
1399 RETVAL_ZVAL(getThis(), 1, 0);
1400 }
1401
1402 PHP_METHOD(HttpMessage, addHeader)
1403 {
1404 zval *zvalue;
1405 char *name_str;
1406 int name_len;
1407
1408 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &name_str, &name_len, &zvalue)) {
1409 php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1410 char *name = php_http_pretty_key(estrndup(name_str, name_len), name_len, 1, 1);
1411 zval *header;
1412
1413 if (!obj->message) {
1414 obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
1415 }
1416
1417 Z_ADDREF_P(zvalue);
1418 if ((header = php_http_message_header(obj->message, name, name_len, 0))) {
1419 convert_to_array(header);
1420 zend_hash_next_index_insert(Z_ARRVAL_P(header), &zvalue, sizeof(void *), NULL);
1421 zval_ptr_dtor(&header);
1422 } else {
1423 zend_symtable_update(&obj->message->hdrs, name, name_len + 1, &zvalue, sizeof(void *), NULL);
1424 }
1425 efree(name);
1426 }
1427 RETVAL_ZVAL(getThis(), 1, 0);
1428 }
1429
1430 PHP_METHOD(HttpMessage, addHeaders)
1431 {
1432 zval *new_headers;
1433 zend_bool append = 0;
1434
1435 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|b", &new_headers, &append)) {
1436 php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1437
1438 if (!obj->message) {
1439 obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
1440 }
1441
1442 array_join(Z_ARRVAL_P(new_headers), &obj->message->hdrs, append, ARRAY_JOIN_STRONLY|ARRAY_JOIN_PRETTIFY);
1443 }
1444 RETVAL_ZVAL(getThis(), 1, 0);
1445 }
1446
1447 PHP_METHOD(HttpMessage, getType)
1448 {
1449 if (SUCCESS == zend_parse_parameters_none()) {
1450 php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1451
1452 if (!obj->message) {
1453 obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
1454 }
1455
1456 RETURN_LONG(obj->message->type);
1457 }
1458 }
1459
1460 PHP_METHOD(HttpMessage, setType)
1461 {
1462 long type;
1463
1464 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &type)) {
1465 php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1466
1467 if (!obj->message) {
1468 obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
1469 }
1470
1471 php_http_message_set_type(obj->message, type);
1472 }
1473 RETVAL_ZVAL(getThis(), 1, 0);
1474 }
1475
1476 PHP_METHOD(HttpMessage, getInfo)
1477 {
1478 if (SUCCESS == zend_parse_parameters_none()) {
1479 php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1480
1481 if (!obj->message) {
1482 obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
1483 }
1484
1485 switch (obj->message->type) {
1486 case PHP_HTTP_REQUEST:
1487 Z_STRLEN_P(return_value) = spprintf(&Z_STRVAL_P(return_value), 0, PHP_HTTP_INFO_REQUEST_FMT_ARGS(&obj->message->http, ""));
1488 break;
1489 case PHP_HTTP_RESPONSE:
1490 Z_STRLEN_P(return_value) = spprintf(&Z_STRVAL_P(return_value), 0, PHP_HTTP_INFO_RESPONSE_FMT_ARGS(&obj->message->http, ""));
1491 break;
1492 default:
1493 RETURN_NULL();
1494 break;
1495 }
1496 Z_TYPE_P(return_value) = IS_STRING;
1497 return;
1498 }
1499 RETURN_FALSE;
1500 }
1501
1502 PHP_METHOD(HttpMessage, setInfo)
1503 {
1504 char *str;
1505 int len;
1506 php_http_info_t inf;
1507
1508 if ( SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len)
1509 && php_http_info_parse(&inf, str TSRMLS_CC)) {
1510 php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1511
1512 if (!obj->message) {
1513 obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
1514 }
1515
1516 php_http_message_set_info(obj->message, &inf);
1517 php_http_info_dtor(&inf);
1518 }
1519 RETVAL_ZVAL(getThis(), 1, 0);
1520 }
1521
1522 PHP_METHOD(HttpMessage, getHttpVersion)
1523 {
1524 if (SUCCESS == zend_parse_parameters_none()) {
1525 char *str;
1526 size_t len;
1527 php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1528
1529 if (!obj->message) {
1530 obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
1531 }
1532
1533 php_http_version_to_string(&obj->message->http.version, &str, &len, NULL, NULL TSRMLS_CC);
1534 RETURN_STRINGL(str, len, 0);
1535 }
1536
1537 RETURN_FALSE;
1538 }
1539
1540 PHP_METHOD(HttpMessage, setHttpVersion)
1541 {
1542 char *v_str;
1543 int v_len;
1544
1545 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &v_str, &v_len)) {
1546 php_http_version_t version;
1547 php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1548
1549 if (!obj->message) {
1550 obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
1551 }
1552
1553 if (php_http_version_parse(&version, v_str TSRMLS_CC)) {
1554 obj->message->http.version = version;
1555 }
1556 }
1557 RETVAL_ZVAL(getThis(), 1, 0);
1558 }
1559
1560 PHP_METHOD(HttpMessage, getResponseCode)
1561 {
1562 if (SUCCESS == zend_parse_parameters_none()) {
1563 php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1564
1565 if (!obj->message) {
1566 obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
1567 }
1568
1569 PHP_HTTP_MESSAGE_TYPE_CHECK(RESPONSE, obj->message, RETURN_FALSE);
1570 RETURN_LONG(obj->message->http.info.response.code);
1571 }
1572 RETURN_FALSE;
1573 }
1574
1575 PHP_METHOD(HttpMessage, setResponseCode)
1576 {
1577 long code;
1578 zend_bool strict = 1;
1579
1580 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|b", &code, &strict)) {
1581 php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1582
1583 if (!obj->message) {
1584 obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
1585 }
1586
1587 PHP_HTTP_MESSAGE_TYPE_CHECK(RESPONSE, obj->message, RETURN_FALSE);
1588 if (strict && (code < 100 || code > 599)) {
1589 php_http_error(HE_WARNING, PHP_HTTP_E_INVALID_PARAM, "Invalid response code (100-599): %ld", code);
1590 RETURN_FALSE;
1591 }
1592
1593 obj->message->http.info.response.code = code;
1594 STR_SET(obj->message->http.info.response.status, estrdup(php_http_env_get_response_status_for_code(code)));
1595 }
1596 RETVAL_ZVAL(getThis(), 1, 0);
1597 }
1598
1599 PHP_METHOD(HttpMessage, getResponseStatus)
1600 {
1601 if (SUCCESS == zend_parse_parameters_none()) {
1602 php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1603
1604 if (!obj->message) {
1605 obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
1606 }
1607
1608 PHP_HTTP_MESSAGE_TYPE_CHECK(RESPONSE, obj->message, RETURN_FALSE);
1609 if (obj->message->http.info.response.status) {
1610 RETURN_STRING(obj->message->http.info.response.status, 1);
1611 } else {
1612 RETURN_EMPTY_STRING();
1613 }
1614 }
1615
1616 RETURN_FALSE;
1617 }
1618
1619 PHP_METHOD(HttpMessage, setResponseStatus)
1620 {
1621 char *status;
1622 int status_len;
1623
1624 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &status, &status_len)) {
1625 php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1626
1627 if (!obj->message) {
1628 obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
1629 }
1630
1631 PHP_HTTP_MESSAGE_TYPE_CHECK(RESPONSE, obj->message, RETURN_FALSE);
1632 STR_SET(obj->message->http.info.response.status, estrndup(status, status_len));
1633 }
1634 RETVAL_ZVAL(getThis(), 1, 0);
1635 }
1636
1637 PHP_METHOD(HttpMessage, getRequestMethod)
1638 {
1639 if (SUCCESS == zend_parse_parameters_none()) {
1640 php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1641
1642 if (!obj->message) {
1643 obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
1644 }
1645
1646 PHP_HTTP_MESSAGE_TYPE_CHECK(REQUEST, obj->message, RETURN_FALSE);
1647 if (obj->message->http.info.request.method) {
1648 RETURN_STRING(obj->message->http.info.request.method, 1);
1649 } else {
1650 RETURN_EMPTY_STRING();
1651 }
1652 }
1653
1654 RETURN_FALSE;
1655 }
1656
1657 PHP_METHOD(HttpMessage, setRequestMethod)
1658 {
1659 char *method;
1660 int method_len;
1661
1662 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &method, &method_len)) {
1663 php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1664
1665 if (!obj->message) {
1666 obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
1667 }
1668
1669 PHP_HTTP_MESSAGE_TYPE_CHECK(REQUEST, obj->message, RETURN_FALSE);
1670 if (method_len < 1) {
1671 php_http_error(HE_WARNING, PHP_HTTP_E_INVALID_PARAM, "Cannot set HttpMessage::requestMethod to an empty string");
1672 RETURN_FALSE;
1673 }
1674
1675 STR_SET(obj->message->http.info.request.method, estrndup(method, method_len));
1676 }
1677 RETVAL_ZVAL(getThis(), 1, 0);
1678 }
1679
1680 PHP_METHOD(HttpMessage, getRequestUrl)
1681 {
1682 if (SUCCESS == zend_parse_parameters_none()) {
1683 php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1684
1685 if (!obj->message) {
1686 obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
1687 }
1688
1689 PHP_HTTP_MESSAGE_TYPE_CHECK(REQUEST, obj->message, RETURN_FALSE);
1690 if (obj->message->http.info.request.url) {
1691 RETURN_STRING(obj->message->http.info.request.url, 1);
1692 } else {
1693 RETURN_EMPTY_STRING();
1694 }
1695 }
1696
1697 RETURN_FALSE;
1698 }
1699
1700 PHP_METHOD(HttpMessage, setRequestUrl)
1701 {
1702 char *url_str;
1703 int url_len;
1704
1705 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &url_str, &url_len)) {
1706 php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1707
1708 if (!obj->message) {
1709 obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
1710 }
1711
1712 PHP_HTTP_MESSAGE_TYPE_CHECK(REQUEST, obj->message, RETURN_FALSE);
1713 if (url_len < 1) {
1714 php_http_error(HE_WARNING, PHP_HTTP_E_INVALID_PARAM, "Cannot set HttpMessage::requestUrl to an empty string");
1715 RETURN_FALSE;
1716 }
1717 STR_SET(obj->message->http.info.request.url, estrndup(url_str, url_len));
1718 }
1719 RETVAL_ZVAL(getThis(), 1, 0);
1720 }
1721
1722
1723 PHP_METHOD(HttpMessage, getParentMessage)
1724 {
1725 with_error_handling(EH_THROW, php_http_exception_get_class_entry()) {
1726 if (SUCCESS == zend_parse_parameters_none()) {
1727 php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1728
1729 if (!obj->message) {
1730 obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
1731 }
1732
1733 if (obj->message->parent) {
1734 RETVAL_OBJVAL(obj->parent, 1);
1735 } else {
1736 php_http_error(HE_WARNING, PHP_HTTP_E_RUNTIME, "HttpMessage does not have a parent message");
1737 }
1738 }
1739 } end_error_handling();
1740 }
1741
1742 PHP_METHOD(HttpMessage, toString)
1743 {
1744 zend_bool include_parent = 0;
1745
1746 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &include_parent)) {
1747 php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1748 char *string;
1749 size_t length;
1750
1751 if (!obj->message) {
1752 obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
1753 }
1754
1755 if (include_parent) {
1756 php_http_message_serialize(obj->message, &string, &length);
1757 } else {
1758 php_http_message_to_string(obj->message, &string, &length);
1759 }
1760 if (string) {
1761 RETURN_STRINGL(string, length, 0);
1762 }
1763 }
1764 RETURN_EMPTY_STRING();
1765 }
1766
1767 PHP_METHOD(HttpMessage, toStream)
1768 {
1769 zval *zstream;
1770
1771 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zstream)) {
1772 php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1773 php_stream *s;
1774
1775 php_stream_from_zval(s, &zstream);
1776
1777 if (!obj->message) {
1778 obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
1779 }
1780
1781 php_http_message_to_callback(obj->message, (php_http_pass_callback_t) _php_stream_write, s);
1782 }
1783 }
1784
1785 PHP_METHOD(HttpMessage, toCallback)
1786 {
1787 php_http_pass_fcall_arg_t fcd;
1788
1789 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "f", &fcd.fci, &fcd.fcc)) {
1790 php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1791
1792 fcd.fcz = getThis();
1793 Z_ADDREF_P(fcd.fcz);
1794 TSRMLS_SET_CTX(fcd.ts);
1795
1796 php_http_message_to_callback(obj->message, php_http_pass_fcall_callback, &fcd);
1797 zend_fcall_info_args_clear(&fcd.fci, 1);
1798
1799 zval_ptr_dtor(&fcd.fcz);
1800 RETURN_TRUE;
1801 }
1802 RETURN_FALSE;
1803 }
1804
1805 PHP_METHOD(HttpMessage, serialize)
1806 {
1807 if (SUCCESS == zend_parse_parameters_none()) {
1808 php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1809 char *string;
1810 size_t length;
1811
1812 if (!obj->message) {
1813 obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
1814 }
1815
1816 php_http_message_serialize(obj->message, &string, &length);
1817 RETURN_STRINGL(string, length, 0);
1818 }
1819 RETURN_EMPTY_STRING();
1820 }
1821
1822 PHP_METHOD(HttpMessage, unserialize)
1823 {
1824 int length;
1825 char *serialized;
1826
1827 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &serialized, &length)) {
1828 php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1829 php_http_message_t *msg;
1830
1831 if (obj->message) {
1832 php_http_message_dtor(obj->message);
1833 efree(obj->message);
1834 }
1835 if ((msg = php_http_message_parse(NULL, serialized, (size_t) length, 1 TSRMLS_CC))) {
1836 obj->message = msg;
1837 } else {
1838 obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
1839 php_http_error(HE_ERROR, PHP_HTTP_E_RUNTIME, "Could not unserialize HttpMessage");
1840 }
1841 }
1842 }
1843
1844 PHP_METHOD(HttpMessage, detach)
1845 {
1846 with_error_handling(EH_THROW, php_http_exception_get_class_entry()) {
1847 if (SUCCESS == zend_parse_parameters_none()) {
1848 php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1849
1850 if (!obj->message) {
1851 obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
1852 }
1853
1854 RETVAL_OBJVAL(php_http_message_object_new_ex(obj->zo.ce, php_http_message_copy_ex(obj->message, NULL, 0), NULL TSRMLS_CC), 0);
1855 }
1856 } end_error_handling();
1857 }
1858
1859 PHP_METHOD(HttpMessage, prepend)
1860 {
1861 zval *prepend;
1862 zend_bool top = 1;
1863
1864 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|b", &prepend, php_http_message_class_entry, &top)) {
1865 php_http_message_t *msg[2];
1866 php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1867 php_http_message_object_t *prepend_obj = zend_object_store_get_object(prepend TSRMLS_CC);
1868
1869 if (!obj->message) {
1870 obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
1871 }
1872 if (!prepend_obj->message) {
1873 prepend_obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
1874 }
1875
1876 /* safety check */
1877 for (msg[0] = obj->message; msg[0]; msg[0] = msg[0]->parent) {
1878 for (msg[1] = prepend_obj->message; msg[1]; msg[1] = msg[1]->parent) {
1879 if (msg[0] == msg[1]) {
1880 php_http_error(HE_THROW, PHP_HTTP_E_INVALID_PARAM, "Cannot prepend a message located within the same message chain");
1881 return;
1882 }
1883 }
1884 }
1885
1886 php_http_message_object_prepend(getThis(), prepend, top TSRMLS_CC);
1887 }
1888 }
1889
1890 PHP_METHOD(HttpMessage, reverse)
1891 {
1892 if (SUCCESS == zend_parse_parameters_none()) {
1893 php_http_message_object_reverse(getThis(), return_value TSRMLS_CC);
1894 }
1895 }
1896
1897 PHP_METHOD(HttpMessage, isMultipart)
1898 {
1899 zval *zboundary = NULL;
1900
1901 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z", &zboundary)) {
1902 php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1903 char *boundary = NULL;
1904
1905 RETVAL_BOOL(php_http_message_is_multipart(obj->message, zboundary ? &boundary : NULL));
1906
1907 if (zboundary && boundary) {
1908 zval_dtor(zboundary);
1909 ZVAL_STRING(zboundary, boundary, 0);
1910 }
1911 }
1912 }
1913
1914 PHP_METHOD(HttpMessage, splitMultipartBody)
1915 {
1916 if (SUCCESS == zend_parse_parameters_none()) {
1917 php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1918 char *boundary = NULL;
1919
1920 if (php_http_message_is_multipart(obj->message, &boundary)) {
1921 php_http_message_t *msg;
1922
1923 if ((msg = php_http_message_body_split(&obj->message->body, boundary))) {
1924 RETVAL_OBJVAL(php_http_message_object_new_ex(php_http_message_class_entry, msg, NULL TSRMLS_CC), 0);
1925 }
1926 }
1927 STR_FREE(boundary);
1928 }
1929 }
1930
1931 PHP_METHOD(HttpMessage, count)
1932 {
1933 if (SUCCESS == zend_parse_parameters_none()) {
1934 long i = 0;
1935 php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1936
1937 if (!obj->message) {
1938 obj->message = php_http_message_init(NULL, 0 TSRMLS_CC);
1939 }
1940
1941 php_http_message_count(i, obj->message);
1942 RETURN_LONG(i);
1943 }
1944 RETURN_FALSE;
1945 }
1946
1947 PHP_METHOD(HttpMessage, rewind)
1948 {
1949 if (SUCCESS == zend_parse_parameters_none()) {
1950 zval *zobj = getThis();
1951 php_http_message_object_t *obj = zend_object_store_get_object(zobj TSRMLS_CC);
1952
1953 if (obj->iterator) {
1954 zval_ptr_dtor(&obj->iterator);
1955 }
1956 Z_ADDREF_P(zobj);
1957 obj->iterator = zobj;
1958 }
1959 }
1960
1961 PHP_METHOD(HttpMessage, valid)
1962 {
1963 if (SUCCESS == zend_parse_parameters_none()) {
1964 php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1965
1966 RETURN_BOOL(obj->iterator != NULL);
1967 }
1968 }
1969
1970 PHP_METHOD(HttpMessage, next)
1971 {
1972 if (SUCCESS == zend_parse_parameters_none()) {
1973 php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1974
1975 if (obj->iterator) {
1976 php_http_message_object_t *itr = zend_object_store_get_object(obj->iterator TSRMLS_CC);
1977
1978 if (itr && itr->parent.handle) {
1979 zval *old = obj->iterator;
1980 MAKE_STD_ZVAL(obj->iterator);
1981 ZVAL_OBJVAL(obj->iterator, itr->parent, 1);
1982 zval_ptr_dtor(&old);
1983 } else {
1984 zval_ptr_dtor(&obj->iterator);
1985 obj->iterator = NULL;
1986 }
1987 }
1988 }
1989 }
1990
1991 PHP_METHOD(HttpMessage, key)
1992 {
1993 if (SUCCESS == zend_parse_parameters_none()) {
1994 php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1995
1996 RETURN_LONG(obj->iterator ? obj->iterator->value.obj.handle:0);
1997 }
1998 }
1999
2000 PHP_METHOD(HttpMessage, current)
2001 {
2002 if (SUCCESS == zend_parse_parameters_none()) {
2003 php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2004
2005 if (obj->iterator) {
2006 RETURN_ZVAL(obj->iterator, 1, 0);
2007 }
2008 }
2009 }
2010
2011 /*
2012 * Local variables:
2013 * tab-width: 4
2014 * c-basic-offset: 4
2015 * End:
2016 * vim600: noet sw=4 ts=4 fdm=marker
2017 * vim<600: noet sw=4 ts=4
2018 */
2019