- fix write_prop() too
[m6w6/ext-http] / http_message_object.c
1 /*
2 +----------------------------------------------------------------------+
3 | PECL :: http |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.0 of the PHP license, that |
6 | is bundled with this package in the file LICENSE, and is available |
7 | through the world-wide-web at http://www.php.net/license/3_0.txt. |
8 | If you did not receive a copy of the PHP license and are unable to |
9 | obtain it through the world-wide-web, please send a note to |
10 | license@php.net so we can mail you a copy immediately. |
11 +----------------------------------------------------------------------+
12 | Copyright (c) 2004-2005 Michael Wallner <mike@php.net> |
13 +----------------------------------------------------------------------+
14 */
15
16 /* $Id$ */
17
18
19 #ifdef HAVE_CONFIG_H
20 # include "config.h"
21 #endif
22 #include "php.h"
23
24 #ifdef ZEND_ENGINE_2
25
26 #include "php_http.h"
27 #include "php_http_api.h"
28 #include "php_http_std_defs.h"
29 #include "php_http_message_object.h"
30 #include "php_http_exception_object.h"
31
32 #include "phpstr/phpstr.h"
33 #include "missing.h"
34
35 ZEND_EXTERN_MODULE_GLOBALS(http);
36
37 #define HTTP_BEGIN_ARGS(method, ret_ref, req_args) HTTP_BEGIN_ARGS_EX(HttpMessage, method, ret_ref, req_args)
38 #define HTTP_EMPTY_ARGS(method, ret_ref) HTTP_EMPTY_ARGS_EX(HttpMessage, method, ret_ref)
39 #define HTTP_MESSAGE_ME(method, visibility) PHP_ME(HttpMessage, method, HTTP_ARGS(HttpMessage, method), visibility)
40
41 HTTP_BEGIN_ARGS(__construct, 0, 0)
42 HTTP_ARG_VAL(message, 0)
43 HTTP_END_ARGS;
44
45 HTTP_BEGIN_ARGS(fromString, 1, 1)
46 HTTP_ARG_VAL(message, 0)
47 HTTP_END_ARGS;
48
49 HTTP_EMPTY_ARGS(getBody, 0);
50 HTTP_BEGIN_ARGS(setBody, 0, 1)
51 HTTP_ARG_VAL(body, 0)
52 HTTP_END_ARGS;
53
54 HTTP_EMPTY_ARGS(getHeaders, 0);
55 HTTP_BEGIN_ARGS(setHeaders, 0, 1)
56 HTTP_ARG_VAL(headers, 0)
57 HTTP_END_ARGS;
58
59 HTTP_BEGIN_ARGS(addHeaders, 0, 1)
60 HTTP_ARG_VAL(headers, 0)
61 HTTP_ARG_VAL(append, 0)
62 HTTP_END_ARGS;
63
64 HTTP_EMPTY_ARGS(getType, 0);
65 HTTP_BEGIN_ARGS(setType, 0, 1)
66 HTTP_ARG_VAL(type, 0)
67 HTTP_END_ARGS;
68
69 HTTP_EMPTY_ARGS(getResponseCode, 0);
70 HTTP_BEGIN_ARGS(setResponseCode, 0, 1)
71 HTTP_ARG_VAL(response_code, 0)
72 HTTP_END_ARGS;
73
74 HTTP_EMPTY_ARGS(getRequestMethod, 0);
75 HTTP_BEGIN_ARGS(setRequestMethod, 0, 1)
76 HTTP_ARG_VAL(request_method, 0)
77 HTTP_END_ARGS;
78
79 HTTP_EMPTY_ARGS(getRequestUri, 0);
80 HTTP_BEGIN_ARGS(setRequestUri, 0, 1)
81 HTTP_ARG_VAL(uri, 0)
82 HTTP_END_ARGS;
83
84 HTTP_EMPTY_ARGS(getHttpVersion, 0);
85 HTTP_BEGIN_ARGS(setHttpVersion, 0, 1)
86 HTTP_ARG_VAL(http_version, 0)
87 HTTP_END_ARGS;
88
89 HTTP_EMPTY_ARGS(getParentMessage, 1);
90 HTTP_EMPTY_ARGS(send, 0);
91 HTTP_BEGIN_ARGS(toString, 0, 0)
92 HTTP_ARG_VAL(include_parent, 0)
93 HTTP_END_ARGS;
94
95 #define http_message_object_declare_default_properties() _http_message_object_declare_default_properties(TSRMLS_C)
96 static inline void _http_message_object_declare_default_properties(TSRMLS_D);
97 #define http_message_object_read_prop _http_message_object_read_prop
98 static zval *_http_message_object_read_prop(zval *object, zval *member, int type TSRMLS_DC);
99 #define http_message_object_write_prop _http_message_object_write_prop
100 static void _http_message_object_write_prop(zval *object, zval *member, zval *value TSRMLS_DC);
101 #define http_message_object_get_props _http_message_object_get_props
102 static HashTable *_http_message_object_get_props(zval *object TSRMLS_DC);
103 #define http_message_object_clone_obj _http_message_object_clone_obj
104 static inline zend_object_value _http_message_object_clone_obj(zval *object TSRMLS_DC);
105
106 zend_class_entry *http_message_object_ce;
107 zend_function_entry http_message_object_fe[] = {
108 HTTP_MESSAGE_ME(__construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
109 HTTP_MESSAGE_ME(getBody, ZEND_ACC_PUBLIC)
110 HTTP_MESSAGE_ME(setBody, ZEND_ACC_PUBLIC)
111 HTTP_MESSAGE_ME(getHeaders, ZEND_ACC_PUBLIC)
112 HTTP_MESSAGE_ME(setHeaders, ZEND_ACC_PUBLIC)
113 HTTP_MESSAGE_ME(addHeaders, ZEND_ACC_PUBLIC)
114 HTTP_MESSAGE_ME(getType, ZEND_ACC_PUBLIC)
115 HTTP_MESSAGE_ME(setType, ZEND_ACC_PUBLIC)
116 HTTP_MESSAGE_ME(getResponseCode, ZEND_ACC_PUBLIC)
117 HTTP_MESSAGE_ME(setResponseCode, ZEND_ACC_PUBLIC)
118 HTTP_MESSAGE_ME(getRequestMethod, ZEND_ACC_PUBLIC)
119 HTTP_MESSAGE_ME(setRequestMethod, ZEND_ACC_PUBLIC)
120 HTTP_MESSAGE_ME(getRequestUri, ZEND_ACC_PUBLIC)
121 HTTP_MESSAGE_ME(setRequestUri, ZEND_ACC_PUBLIC)
122 HTTP_MESSAGE_ME(getHttpVersion, ZEND_ACC_PUBLIC)
123 HTTP_MESSAGE_ME(setHttpVersion, ZEND_ACC_PUBLIC)
124 HTTP_MESSAGE_ME(getParentMessage, ZEND_ACC_PUBLIC)
125 HTTP_MESSAGE_ME(send, ZEND_ACC_PUBLIC)
126 HTTP_MESSAGE_ME(toString, ZEND_ACC_PUBLIC)
127
128 ZEND_MALIAS(HttpMessage, __toString, toString, HTTP_ARGS(HttpMessage, toString), ZEND_ACC_PUBLIC)
129
130 HTTP_MESSAGE_ME(fromString, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
131
132 EMPTY_FUNCTION_ENTRY
133 };
134 static zend_object_handlers http_message_object_handlers;
135
136 void _http_message_object_init(INIT_FUNC_ARGS)
137 {
138 HTTP_REGISTER_CLASS_EX(HttpMessage, http_message_object, NULL, 0);
139
140 HTTP_LONG_CONSTANT("HTTP_MSG_NONE", HTTP_MSG_NONE);
141 HTTP_LONG_CONSTANT("HTTP_MSG_REQUEST", HTTP_MSG_REQUEST);
142 HTTP_LONG_CONSTANT("HTTP_MSG_RESPONSE", HTTP_MSG_RESPONSE);
143
144 http_message_object_handlers.clone_obj = http_message_object_clone_obj;
145 http_message_object_handlers.read_property = http_message_object_read_prop;
146 http_message_object_handlers.write_property = http_message_object_write_prop;
147 http_message_object_handlers.get_properties = http_message_object_get_props;
148 http_message_object_handlers.get_property_ptr_ptr = NULL;
149 }
150
151 zend_object_value _http_message_object_new(zend_class_entry *ce TSRMLS_DC)
152 {
153 return http_message_object_new_ex(ce, NULL);
154 }
155
156 zend_object_value _http_message_object_new_ex(zend_class_entry *ce, http_message *msg TSRMLS_DC)
157 {
158 zend_object_value ov;
159 http_message_object *o;
160
161 o = ecalloc(1, sizeof(http_message_object));
162 o->zo.ce = ce;
163
164 if (msg) {
165 o->message = msg;
166 if (msg->parent) {
167 o->parent = http_message_object_from_msg(msg->parent);
168 }
169 }
170
171 ALLOC_HASHTABLE(OBJ_PROP(o));
172 zend_hash_init(OBJ_PROP(o), 0, NULL, ZVAL_PTR_DTOR, 0);
173
174 ov.handle = putObject(http_message_object, o);
175 ov.handlers = &http_message_object_handlers;
176
177 return ov;
178 }
179
180 zend_object_value _http_message_object_clone(zval *this_ptr TSRMLS_DC)
181 {
182 return http_message_object_clone_obj(this_ptr TSRMLS_CC);
183 }
184
185 static inline void _http_message_object_declare_default_properties(TSRMLS_D)
186 {
187 zend_class_entry *ce = http_message_object_ce;
188
189 #ifndef WONKY
190 DCL_CONST(long, "TYPE_NONE", HTTP_MSG_NONE);
191 DCL_CONST(long, "TYPE_REQUEST", HTTP_MSG_REQUEST);
192 DCL_CONST(long, "TYPE_RESPONSE", HTTP_MSG_RESPONSE);
193 #endif
194
195 DCL_PROP(PROTECTED, long, type, HTTP_MSG_NONE);
196 DCL_PROP(PROTECTED, string, body, "");
197 DCL_PROP(PROTECTED, string, requestMethod, "");
198 DCL_PROP(PROTECTED, string, requestUri, "");
199 DCL_PROP(PROTECTED, long, responseCode, 0);
200 DCL_PROP_N(PROTECTED, httpVersion);
201 DCL_PROP_N(PROTECTED, headers);
202 DCL_PROP_N(PROTECTED, parentMessage);
203 }
204
205 void _http_message_object_free(zend_object *object TSRMLS_DC)
206 {
207 http_message_object *o = (http_message_object *) object;
208
209 if (OBJ_PROP(o)) {
210 zend_hash_destroy(OBJ_PROP(o));
211 FREE_HASHTABLE(OBJ_PROP(o));
212 }
213 if (o->message) {
214 http_message_dtor(o->message);
215 efree(o->message);
216 }
217 efree(o);
218 }
219
220 static inline zend_object_value _http_message_object_clone_obj(zval *this_ptr TSRMLS_DC)
221 {
222 getObject(http_message_object, obj);
223 return http_message_object_from_msg(http_message_dup(obj->message));
224 }
225
226 static zval *_http_message_object_read_prop(zval *object, zval *member, int type TSRMLS_DC)
227 {
228 getObjectEx(http_message_object, obj, object);
229 http_message *msg = obj->message;
230 zval *return_value;
231 #ifdef WONKY
232 ulong h = zend_get_hash_value(Z_STRVAL_P(member), Z_STRLEN_P(member)+1);
233 #else
234 zend_property_info *pinfo = zend_get_property_info(obj->zo.ce, member, 1 TSRMLS_CC);
235
236 if (!pinfo || ACC_PROP_PUBLIC(pinfo->flags)) {
237 return zend_get_std_object_handlers()->read_property(object, member, type TSRMLS_CC);
238 }
239 #endif
240
241 return_value = &EG(uninitialized_zval);
242 return_value->refcount = 0;
243 return_value->is_ref = 0;
244
245 #ifdef WONKY
246 switch (h)
247 #else
248 switch (pinfo->h)
249 #endif
250 {
251 case HTTP_MSG_PROPHASH_TYPE:
252 RETVAL_LONG(msg->type);
253 break;
254
255 case HTTP_MSG_PROPHASH_HTTP_VERSION:
256 RETVAL_DOUBLE(msg->http.version);
257 break;
258
259 case HTTP_MSG_PROPHASH_BODY:
260 phpstr_fix(PHPSTR(msg));
261 RETVAL_PHPSTR(PHPSTR(msg), 0, 1);
262 break;
263
264 case HTTP_MSG_PROPHASH_HEADERS:
265 /* This is needed for situations like
266 * $this->headers['foo'] = 'bar';
267 */
268 if (type == BP_VAR_W) {
269 return_value->refcount = 1;
270 return_value->is_ref = 1;
271 Z_TYPE_P(return_value) = IS_ARRAY;
272 Z_ARRVAL_P(return_value) = &msg->hdrs;
273 } else {
274 array_init(return_value);
275 zend_hash_copy(Z_ARRVAL_P(return_value), &msg->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
276 }
277 break;
278
279 case HTTP_MSG_PROPHASH_PARENT_MESSAGE:
280 if (msg->parent) {
281 RETVAL_OBJVAL(obj->parent);
282 } else {
283 RETVAL_NULL();
284 }
285 break;
286
287 case HTTP_MSG_PROPHASH_REQUEST_METHOD:
288 if (HTTP_MSG_TYPE(REQUEST, msg) && msg->http.info.request.method) {
289 RETVAL_STRING(msg->http.info.request.method, 1);
290 } else {
291 RETVAL_NULL();
292 }
293 break;
294
295 case HTTP_MSG_PROPHASH_REQUEST_URI:
296 if (HTTP_MSG_TYPE(REQUEST, msg) && msg->http.info.request.URI) {
297 RETVAL_STRING(msg->http.info.request.URI, 1);
298 } else {
299 RETVAL_NULL();
300 }
301 break;
302
303 case HTTP_MSG_PROPHASH_RESPONSE_CODE:
304 if (HTTP_MSG_TYPE(RESPONSE, msg)) {
305 RETVAL_LONG(msg->http.info.response.code);
306 } else {
307 RETVAL_NULL();
308 }
309 break;
310
311 case HTTP_MSG_PROPHASH_RESPONSE_STATUS:
312 if (HTTP_MSG_TYPE(RESPONSE, msg) && msg->http.info.response.status) {
313 RETVAL_STRING(msg->http.info.response.status, 1);
314 } else {
315 RETVAL_NULL();
316 }
317 break;
318
319 default:
320 #ifdef WONKY
321 return zend_get_std_object_handlers()->read_property(object, member, type TSRMLS_CC);
322 #else
323 RETVAL_NULL();
324 #endif
325 break;
326 }
327
328 return return_value;
329 }
330
331 static void _http_message_object_write_prop(zval *object, zval *member, zval *value TSRMLS_DC)
332 {
333 getObjectEx(http_message_object, obj, object);
334 http_message *msg = obj->message;
335 #ifdef WONKY
336 ulong h = zend_get_hash_value(Z_STRVAL_P(member), Z_STRLEN_P(member) + 1);
337 #else
338 zend_property_info *pinfo = zend_get_property_info(obj->zo.ce, member, 1 TSRMLS_CC);
339
340 if (!pinfo || ACC_PROP_PUBLIC(pinfo->flags)) {
341 zend_get_std_object_handlers()->write_property(object, member, value TSRMLS_CC);
342 return;
343 }
344 #endif
345
346 #ifdef WONKY
347 switch (h)
348 #else
349 switch (pinfo->h)
350 #endif
351 {
352 case HTTP_MSG_PROPHASH_TYPE:
353 convert_to_long_ex(&value);
354 http_message_set_type(msg, Z_LVAL_P(value));
355 break;
356
357 case HTTP_MSG_PROPHASH_HTTP_VERSION:
358 convert_to_double_ex(&value);
359 msg->http.version = Z_DVAL_P(value);
360 break;
361
362 case HTTP_MSG_PROPHASH_BODY:
363 convert_to_string_ex(&value);
364 phpstr_dtor(PHPSTR(msg));
365 phpstr_from_string_ex(PHPSTR(msg), Z_STRVAL_P(value), Z_STRLEN_P(value));
366 break;
367
368 case HTTP_MSG_PROPHASH_HEADERS:
369 convert_to_array_ex(&value);
370 zend_hash_clean(&msg->hdrs);
371 zend_hash_copy(&msg->hdrs, Z_ARRVAL_P(value), (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
372 break;
373
374 case HTTP_MSG_PROPHASH_PARENT_MESSAGE:
375 if (msg->parent) {
376 zval tmp;
377 tmp.value.obj = obj->parent;
378 zend_objects_store_del_ref(&tmp TSRMLS_CC);
379 }
380 zend_objects_store_add_ref(value TSRMLS_CC);
381 obj->parent = value->value.obj;
382 break;
383
384 case HTTP_MSG_PROPHASH_REQUEST_METHOD:
385 if (HTTP_MSG_TYPE(REQUEST, msg)) {
386 convert_to_string_ex(&value);
387 STR_SET(msg->http.info.request.method, estrndup(Z_STRVAL_P(value), Z_STRLEN_P(value)));
388 }
389 break;
390
391 case HTTP_MSG_PROPHASH_REQUEST_URI:
392 if (HTTP_MSG_TYPE(REQUEST, msg)) {
393 convert_to_string_ex(&value);
394 STR_SET(msg->http.info.request.URI, estrndup(Z_STRVAL_P(value), Z_STRLEN_P(value)));
395 }
396 break;
397
398 case HTTP_MSG_PROPHASH_RESPONSE_CODE:
399 if (HTTP_MSG_TYPE(RESPONSE, msg)) {
400 convert_to_long_ex(&value);
401 msg->http.info.response.code = Z_LVAL_P(value);
402 }
403 break;
404
405 case HTTP_MSG_PROPHASH_RESPONSE_STATUS:
406 if (HTTP_MSG_TYPE(RESPONSE, msg)) {
407 convert_to_string_ex(&value);
408 STR_SET(msg->http.info.response.status, estrndup(Z_STRVAL_P(value), Z_STRLEN_P(value)));
409 }
410 break;
411
412 default:
413 #ifdef WONKY
414 zend_get_std_object_handlers()->write_property(object, member, value TSRMLS_CC);
415 #endif
416 break;
417 }
418 }
419
420 static HashTable *_http_message_object_get_props(zval *object TSRMLS_DC)
421 {
422 zval *headers;
423 getObjectEx(http_message_object, obj, object);
424 http_message *msg = obj->message;
425 HashTable *props = OBJ_PROP(obj);
426 zval array;
427
428 INIT_ZARR(array, props);
429
430 #define ASSOC_PROP(array, ptype, name, val) \
431 { \
432 char *m_prop_name; \
433 int m_prop_len; \
434 zend_mangle_property_name(&m_prop_name, &m_prop_len, "*", 1, name, lenof(name), 0); \
435 add_assoc_ ##ptype## _ex(&array, m_prop_name, sizeof(name)+4, val); \
436 efree(m_prop_name); \
437 }
438 #define ASSOC_STRING(array, name, val) ASSOC_STRINGL(array, name, val, strlen(val))
439 #define ASSOC_STRINGL(array, name, val, len) \
440 { \
441 char *m_prop_name; \
442 int m_prop_len; \
443 zend_mangle_property_name(&m_prop_name, &m_prop_len, "*", 1, name, lenof(name), 0); \
444 add_assoc_stringl_ex(&array, m_prop_name, sizeof(name)+4, val, len, 1); \
445 efree(m_prop_name); \
446 }
447
448 ASSOC_PROP(array, long, "type", msg->type);
449 ASSOC_PROP(array, double, "httpVersion", msg->http.version);
450
451 switch (msg->type)
452 {
453 case HTTP_MSG_REQUEST:
454 ASSOC_PROP(array, long, "responseCode", 0);
455 ASSOC_STRINGL(array, "responseStatus", "", 0);
456 ASSOC_STRING(array, "requestMethod", msg->http.info.request.method);
457 ASSOC_STRING(array, "requestUri", msg->http.info.request.URI);
458 break;
459
460 case HTTP_MSG_RESPONSE:
461 ASSOC_PROP(array, long, "responseCode", msg->http.info.response.code);
462 ASSOC_STRING(array, "responseStatus", msg->http.info.response.status);
463 ASSOC_STRINGL(array, "requestMethod", "", 0);
464 ASSOC_STRINGL(array, "requestUri", "", 0);
465 break;
466
467 case HTTP_MSG_NONE:
468 default:
469 ASSOC_PROP(array, long, "responseCode", 0);
470 ASSOC_STRINGL(array, "responseStatus", "", 0);
471 ASSOC_STRINGL(array, "requestMethod", "", 0);
472 ASSOC_STRINGL(array, "requestUri", "", 0);
473 break;
474 }
475
476 MAKE_STD_ZVAL(headers);
477 array_init(headers);
478 zend_hash_copy(Z_ARRVAL_P(headers), &msg->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
479 ASSOC_PROP(array, zval, "headers", headers);
480 ASSOC_STRINGL(array, "body", PHPSTR_VAL(msg), PHPSTR_LEN(msg));
481
482 return OBJ_PROP(obj);
483 }
484
485 /* ### USERLAND ### */
486
487 /* {{{ proto void HttpMessage::__construct([string message])
488 *
489 * Instantiate a new HttpMessage object.
490 */
491 PHP_METHOD(HttpMessage, __construct)
492 {
493 char *message = NULL;
494 int length = 0;
495 getObject(http_message_object, obj);
496
497 SET_EH_THROW_HTTP();
498 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &message, &length) && message && length) {
499 if (obj->message = http_message_parse(message, length)) {
500 if (obj->message->parent) {
501 obj->parent = http_message_object_from_msg(obj->message->parent);
502 }
503 }
504 } else if (!obj->message) {
505 obj->message = http_message_new();
506 }
507 SET_EH_NORMAL();
508 }
509 /* }}} */
510
511 /* {{{ proto static HttpMessage HttpMessage::fromString(string raw_message)
512 *
513 * Create an HttpMessage object from a string.
514 */
515 PHP_METHOD(HttpMessage, fromString)
516 {
517 char *string = NULL;
518 int length = 0;
519 http_message *msg = NULL;
520
521 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &string, &length)) {
522 RETURN_NULL();
523 }
524
525 if (!(msg = http_message_parse(string, length))) {
526 RETURN_NULL();
527 }
528
529 Z_TYPE_P(return_value) = IS_OBJECT;
530 return_value->value.obj = http_message_object_from_msg(msg);
531 }
532 /* }}} */
533
534 /* {{{ proto string HttpMessage::getBody()
535 *
536 * Get the body of the parsed Message.
537 */
538 PHP_METHOD(HttpMessage, getBody)
539 {
540 NO_ARGS;
541
542 IF_RETVAL_USED {
543 getObject(http_message_object, obj);
544 RETURN_PHPSTR(&obj->message->body, PHPSTR_FREE_NOT, 1);
545 }
546 }
547 /* }}} */
548
549 /* {{{ proto void HttpMessage::setBody(string body)
550 *
551 * Set the body of the HttpMessage.
552 * NOTE: Don't forget to update any headers accordingly.
553 */
554 PHP_METHOD(HttpMessage, setBody)
555 {
556 char *body;
557 int len;
558 getObject(http_message_object, obj);
559
560 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &body, &len)) {
561 phpstr_dtor(PHPSTR(obj->message));
562 phpstr_from_string_ex(PHPSTR(obj->message), body, len);
563 }
564 }
565 /* }}} */
566
567 /* {{{ proto array HttpMessage::getHeaders()
568 *
569 * Get Message Headers.
570 */
571 PHP_METHOD(HttpMessage, getHeaders)
572 {
573 NO_ARGS;
574
575 IF_RETVAL_USED {
576 zval headers;
577 getObject(http_message_object, obj);
578
579 INIT_ZARR(headers, &obj->message->hdrs);
580 array_init(return_value);
581 array_copy(&headers, return_value);
582 }
583 }
584 /* }}} */
585
586 /* {{{ proto void HttpMessage::setHeaders(array headers)
587 *
588 * Sets new headers.
589 */
590 PHP_METHOD(HttpMessage, setHeaders)
591 {
592 zval *new_headers, old_headers;
593 getObject(http_message_object, obj);
594
595 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/", &new_headers)) {
596 return;
597 }
598
599 zend_hash_clean(&obj->message->hdrs);
600 INIT_ZARR(old_headers, &obj->message->hdrs);
601 array_copy(new_headers, &old_headers);
602 }
603 /* }}} */
604
605 /* {{{ proto void HttpMessage::addHeaders(array headers[, bool append = false])
606 *
607 * Add headers. If append is true, headers with the same name will be separated, else overwritten.
608 */
609 PHP_METHOD(HttpMessage, addHeaders)
610 {
611 zval old_headers, *new_headers;
612 zend_bool append = 0;
613 getObject(http_message_object, obj);
614
615 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|b", &new_headers, &append)) {
616 return;
617 }
618
619 INIT_ZARR(old_headers, &obj->message->hdrs);
620 if (append) {
621 array_append(new_headers, &old_headers);
622 } else {
623 array_merge(new_headers, &old_headers);
624 }
625 }
626 /* }}} */
627
628 /* {{{ proto long HttpMessage::getType()
629 *
630 * Get Message Type. (HTTP_MSG_NONE|HTTP_MSG_REQUEST|HTTP_MSG_RESPONSE)
631 */
632 PHP_METHOD(HttpMessage, getType)
633 {
634 NO_ARGS;
635
636 IF_RETVAL_USED {
637 getObject(http_message_object, obj);
638 RETURN_LONG(obj->message->type);
639 }
640 }
641 /* }}} */
642
643 /* {{{ proto void HttpMessage::setType(long type)
644 *
645 * Set Message Type. (HTTP_MSG_NONE|HTTP_MSG_REQUEST|HTTP_MSG_RESPONSE)
646 */
647 PHP_METHOD(HttpMessage, setType)
648 {
649 long type;
650 getObject(http_message_object, obj);
651
652 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &type)) {
653 return;
654 }
655 http_message_set_type(obj->message, type);
656 }
657 /* }}} */
658
659 /* {{{ proto long HttpMessage::getResponseCode()
660 *
661 * Get the Response Code of the Message.
662 */
663 PHP_METHOD(HttpMessage, getResponseCode)
664 {
665 NO_ARGS;
666
667 IF_RETVAL_USED {
668 getObject(http_message_object, obj);
669
670 if (!HTTP_MSG_TYPE(RESPONSE, obj->message)) {
671 http_error(HE_NOTICE, HTTP_E_MESSAGE_TYPE, "HttpMessage is not of type HTTP_MSG_RESPONSE");
672 RETURN_NULL();
673 }
674
675 RETURN_LONG(obj->message->http.info.response.code);
676 }
677 }
678 /* }}} */
679
680 /* {{{ proto bool HttpMessage::setResponseCode(long code)
681 *
682 * Set the response code of an HTTP Response Message.
683 * Returns false if the Message is not of type HTTP_MSG_RESPONSE,
684 * or if the response code is out of range (100-510).
685 */
686 PHP_METHOD(HttpMessage, setResponseCode)
687 {
688 long code;
689 getObject(http_message_object, obj);
690
691 if (!HTTP_MSG_TYPE(RESPONSE, obj->message)) {
692 http_error(HE_WARNING, HTTP_E_MESSAGE_TYPE, "HttpMessage is not of type HTTP_MSG_RESPONSE");
693 RETURN_FALSE;
694 }
695
696 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &code)) {
697 RETURN_FALSE;
698 }
699 if (code < 100 || code > 510) {
700 http_error_ex(HE_WARNING, HTTP_E_INVALID_PARAM, "Invalid response code (100-510): %ld", code);
701 RETURN_FALSE;
702 }
703
704 obj->message->http.info.response.code = code;
705 RETURN_TRUE;
706 }
707 /* }}} */
708
709 /* {{{ proto string HttpMessage::getRequestMethod()
710 *
711 * Get the Request Method of the Message.
712 * Returns false if the Message is not of type HTTP_MSG_REQUEST.
713 */
714 PHP_METHOD(HttpMessage, getRequestMethod)
715 {
716 NO_ARGS;
717
718 IF_RETVAL_USED {
719 getObject(http_message_object, obj);
720
721 if (!HTTP_MSG_TYPE(REQUEST, obj->message)) {
722 http_error(HE_NOTICE, HTTP_E_MESSAGE_TYPE, "HttpMessage is not of type HTTP_MSG_REQUEST");
723 RETURN_NULL();
724 }
725
726 RETURN_STRING(obj->message->http.info.request.method, 1);
727 }
728 }
729 /* }}} */
730
731 /* {{{ proto bool HttpMessage::setRequestMethod(string method)
732 *
733 * Set the Request Method of the HTTP Message.
734 * Returns false if the Message is not of type HTTP_MSG_REQUEST.
735 */
736 PHP_METHOD(HttpMessage, setRequestMethod)
737 {
738 char *method;
739 int method_len;
740 getObject(http_message_object, obj);
741
742 if (!HTTP_MSG_TYPE(REQUEST, obj->message)) {
743 http_error(HE_WARNING, HTTP_E_MESSAGE_TYPE, "HttpMessage is not of type HTTP_MSG_REQUEST");
744 RETURN_FALSE;
745 }
746
747 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &method, &method_len)) {
748 RETURN_FALSE;
749 }
750 if (method_len < 1) {
751 http_error(HE_WARNING, HTTP_E_INVALID_PARAM, "Cannot set HttpMessage::requestMethod to an empty string");
752 RETURN_FALSE;
753 }
754 if (SUCCESS != http_check_method(method)) {
755 http_error_ex(HE_WARNING, HTTP_E_REQUEST_METHOD, "Unkown request method: %s", method);
756 RETURN_FALSE;
757 }
758
759 STR_SET(obj->message->http.info.request.method, estrndup(method, method_len));
760 RETURN_TRUE;
761 }
762 /* }}} */
763
764 /* {{{ proto string HttpMessage::getRequestUri()
765 *
766 * Get the Request URI of the Message.
767 */
768 PHP_METHOD(HttpMessage, getRequestUri)
769 {
770 NO_ARGS;
771
772 IF_RETVAL_USED {
773 getObject(http_message_object, obj);
774
775 if (!HTTP_MSG_TYPE(REQUEST, obj->message)) {
776 http_error(HE_WARNING, HTTP_E_MESSAGE_TYPE, "HttpMessage is not of type HTTP_MSG_REQUEST");
777 RETURN_NULL();
778 }
779
780 RETURN_STRING(obj->message->http.info.request.URI, 1);
781 }
782 }
783 /* }}} */
784
785 /* {{{ proto bool HttpMessage::setRequestUri(string URI)
786 *
787 * Set the Request URI of the HTTP Message.
788 * Returns false if the Message is not of type HTTP_MSG_REQUEST,
789 * or if paramtere URI was empty.
790 */
791 PHP_METHOD(HttpMessage, setRequestUri)
792 {
793 char *URI;
794 int URIlen;
795 getObject(http_message_object, obj);
796
797 if (!HTTP_MSG_TYPE(REQUEST, obj->message)) {
798 http_error(HE_WARNING, HTTP_E_MESSAGE_TYPE, "HttpMessage is not of type HTTP_MSG_REQUEST");
799 RETURN_FALSE;
800 }
801 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &URI, &URIlen)) {
802 RETURN_FALSE;
803 }
804 if (URIlen < 1) {
805 http_error(HE_WARNING, HTTP_E_INVALID_PARAM, "Cannot set HttpMessage::requestUri to an empty string");
806 RETURN_FALSE;
807 }
808
809 STR_SET(obj->message->http.info.request.URI, estrndup(URI, URIlen));
810 RETURN_TRUE;
811 }
812 /* }}} */
813
814 /* {{{ proto string HttpMessage::getHttpVersion()
815 *
816 * Get the HTTP Protocol Version of the Message.
817 */
818 PHP_METHOD(HttpMessage, getHttpVersion)
819 {
820 NO_ARGS;
821
822 IF_RETVAL_USED {
823 char ver[4] = {0};
824 getObject(http_message_object, obj);
825
826 sprintf(ver, "%1.1lf", obj->message->http.version);
827 RETURN_STRINGL(ver, 3, 1);
828 }
829 }
830 /* }}} */
831
832 /* {{{ proto bool HttpMessage::setHttpVersion(string version)
833 *
834 * Set the HTTP Protocol version of the Message.
835 * Returns false if version is invalid (1.0 and 1.1).
836 */
837 PHP_METHOD(HttpMessage, setHttpVersion)
838 {
839 char v[4];
840 zval *zv;
841 getObject(http_message_object, obj);
842
843 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/", &zv)) {
844 return;
845 }
846
847 convert_to_double(zv);
848 sprintf(v, "%1.1lf", Z_DVAL_P(zv));
849 if (strcmp(v, "1.0") && strcmp(v, "1.1")) {
850 http_error_ex(HE_WARNING, HTTP_E_INVALID_PARAM, "Invalid HTTP protocol version (1.0 or 1.1): %s", v);
851 RETURN_FALSE;
852 }
853
854 obj->message->http.version = Z_DVAL_P(zv);
855 RETURN_TRUE;
856 }
857 /* }}} */
858
859 /* {{{ proto HttpMessage HttpMessage::getParentMessage()
860 *
861 * Get parent Message.
862 */
863 PHP_METHOD(HttpMessage, getParentMessage)
864 {
865 NO_ARGS;
866
867 IF_RETVAL_USED {
868 getObject(http_message_object, obj);
869
870 if (obj->message->parent) {
871 RETVAL_OBJVAL(obj->parent);
872 } else {
873 RETVAL_NULL();
874 }
875 }
876 }
877 /* }}} */
878
879 /* {{{ proto bool HttpMessage::send()
880 *
881 * Send the Message according to its type as Response or Request.
882 */
883 PHP_METHOD(HttpMessage, send)
884 {
885 getObject(http_message_object, obj);
886
887 NO_ARGS;
888
889 RETURN_SUCCESS(http_message_send(obj->message));
890 }
891 /* }}} */
892
893 /* {{{ proto string HttpMessage::toString([bool include_parent = false])
894 *
895 * Get the string representation of the Message.
896 */
897 PHP_METHOD(HttpMessage, toString)
898 {
899 IF_RETVAL_USED {
900 char *string;
901 size_t length;
902 zend_bool include_parent = 0;
903 getObject(http_message_object, obj);
904
905 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &include_parent)) {
906 RETURN_FALSE;
907 }
908
909 if (include_parent) {
910 http_message_serialize(obj->message, &string, &length);
911 } else {
912 http_message_tostring(obj->message, &string, &length);
913 }
914 RETURN_STRINGL(string, length, 0);
915 }
916 }
917 /* }}} */
918
919 #endif /* ZEND_ENGINE_2 */
920
921 /*
922 * Local variables:
923 * tab-width: 4
924 * c-basic-offset: 4
925 * End:
926 * vim600: noet sw=4 ts=4 fdm=marker
927 * vim<600: noet sw=4 ts=4
928 */
929