- flush
[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 * Accepts an optional string parameter containing a single or several
492 * consecutive HTTP messages. The constructed object will actually
493 * represent the *last* message of the passed string. If there were
494 * prior messages, those can be accessed by HttpMessage::getParentMessage().
495 *
496 * Throws HttpMalformedHeaderException.
497 */
498 PHP_METHOD(HttpMessage, __construct)
499 {
500 char *message = NULL;
501 int length = 0;
502 getObject(http_message_object, obj);
503
504 SET_EH_THROW_HTTP();
505 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &message, &length) && message && length) {
506 if (obj->message = http_message_parse(message, length)) {
507 if (obj->message->parent) {
508 obj->parent = http_message_object_from_msg(obj->message->parent);
509 }
510 }
511 } else if (!obj->message) {
512 obj->message = http_message_new();
513 }
514 SET_EH_NORMAL();
515 }
516 /* }}} */
517
518 /* {{{ proto static HttpMessage HttpMessage::fromString(string raw_message)
519 *
520 * Create an HttpMessage object from a string. Kind of a static constructor.
521 *
522 * Expects a string parameter containing a sinlge or several consecutive
523 * HTTP messages.
524 *
525 * Returns an HttpMessage object on success or NULL on failure.
526 *
527 * Throws HttpMalformedHeadersException.
528 */
529 PHP_METHOD(HttpMessage, fromString)
530 {
531 char *string = NULL;
532 int length = 0;
533 http_message *msg = NULL;
534
535 RETVAL_NULL();
536
537 SET_EH_THROW_HTTP();
538 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &string, &length)) {
539 if (msg = http_message_parse(string, length)) {
540 Z_TYPE_P(return_value) = IS_OBJECT;
541 return_value->value.obj = http_message_object_from_msg(msg);
542 }
543 }
544 SET_EH_NORMAL();
545 }
546 /* }}} */
547
548 /* {{{ proto string HttpMessage::getBody()
549 *
550 * Get the body of the parsed HttpMessage.
551 *
552 * Returns the message body as string.
553 */
554 PHP_METHOD(HttpMessage, getBody)
555 {
556 NO_ARGS;
557
558 IF_RETVAL_USED {
559 getObject(http_message_object, obj);
560 RETURN_PHPSTR(&obj->message->body, PHPSTR_FREE_NOT, 1);
561 }
562 }
563 /* }}} */
564
565 /* {{{ proto void HttpMessage::setBody(string body)
566 *
567 * Set the body of the HttpMessage.
568 * NOTE: Don't forget to update any headers accordingly.
569 *
570 * Expects a string parameter containing the new body of the message.
571 */
572 PHP_METHOD(HttpMessage, setBody)
573 {
574 char *body;
575 int len;
576 getObject(http_message_object, obj);
577
578 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &body, &len)) {
579 phpstr_dtor(PHPSTR(obj->message));
580 phpstr_from_string_ex(PHPSTR(obj->message), body, len);
581 }
582 }
583 /* }}} */
584
585 /* {{{ proto array HttpMessage::getHeaders()
586 *
587 * Get Message Headers.
588 *
589 * Returns an associative array containing the messages HTTP headers.
590 */
591 PHP_METHOD(HttpMessage, getHeaders)
592 {
593 NO_ARGS;
594
595 IF_RETVAL_USED {
596 zval headers;
597 getObject(http_message_object, obj);
598
599 INIT_ZARR(headers, &obj->message->hdrs);
600 array_init(return_value);
601 array_copy(&headers, return_value);
602 }
603 }
604 /* }}} */
605
606 /* {{{ proto void HttpMessage::setHeaders(array headers)
607 *
608 * Sets new headers.
609 *
610 * Expects an associative array as parameter containing the new HTTP headers,
611 * which will replace *all* previous HTTP headers of the message.
612 */
613 PHP_METHOD(HttpMessage, setHeaders)
614 {
615 zval *new_headers, old_headers;
616 getObject(http_message_object, obj);
617
618 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/", &new_headers)) {
619 return;
620 }
621
622 zend_hash_clean(&obj->message->hdrs);
623 INIT_ZARR(old_headers, &obj->message->hdrs);
624 array_copy(new_headers, &old_headers);
625 }
626 /* }}} */
627
628 /* {{{ proto void HttpMessage::addHeaders(array headers[, bool append = false])
629 *
630 * Add headers. If append is true, headers with the same name will be separated, else overwritten.
631 *
632 * Expects an associative array as parameter containing the additional HTTP headers
633 * to add to the messages existing headers. If the optional bool parameter is true,
634 * and a header with the same name of one to add exists already, this respective
635 * header will be converted to an array containing both header values, otherwise
636 * it will be overwritten with the new header value.
637 */
638 PHP_METHOD(HttpMessage, addHeaders)
639 {
640 zval old_headers, *new_headers;
641 zend_bool append = 0;
642 getObject(http_message_object, obj);
643
644 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|b", &new_headers, &append)) {
645 return;
646 }
647
648 INIT_ZARR(old_headers, &obj->message->hdrs);
649 if (append) {
650 array_append(new_headers, &old_headers);
651 } else {
652 array_merge(new_headers, &old_headers);
653 }
654 }
655 /* }}} */
656
657 /* {{{ proto int HttpMessage::getType()
658 *
659 * Get Message Type. (HTTP_MSG_NONE|HTTP_MSG_REQUEST|HTTP_MSG_RESPONSE)
660 *
661 * Returns the HttpMessage::TYPE.
662 */
663 PHP_METHOD(HttpMessage, getType)
664 {
665 NO_ARGS;
666
667 IF_RETVAL_USED {
668 getObject(http_message_object, obj);
669 RETURN_LONG(obj->message->type);
670 }
671 }
672 /* }}} */
673
674 /* {{{ proto void HttpMessage::setType(int type)
675 *
676 * Set Message Type. (HTTP_MSG_NONE|HTTP_MSG_REQUEST|HTTP_MSG_RESPONSE)
677 *
678 * Exptects an int parameter, the HttpMessage::TYPE.
679 */
680 PHP_METHOD(HttpMessage, setType)
681 {
682 long type;
683 getObject(http_message_object, obj);
684
685 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &type)) {
686 return;
687 }
688 http_message_set_type(obj->message, type);
689 }
690 /* }}} */
691
692 /* {{{ proto int HttpMessage::getResponseCode()
693 *
694 * Get the Response Code of the Message.
695 *
696 * Returns the HTTP response code if the message is of type
697 * HttpMessage::TYPE_RESPONSE, else FALSE.
698 */
699 PHP_METHOD(HttpMessage, getResponseCode)
700 {
701 NO_ARGS;
702
703 IF_RETVAL_USED {
704 getObject(http_message_object, obj);
705 HTTP_CHECK_MESSAGE_TYPE_RESPONSE(obj->message, RETURN_FALSE);
706 RETURN_LONG(obj->message->http.info.response.code);
707 }
708 }
709 /* }}} */
710
711 /* {{{ proto bool HttpMessage::setResponseCode(int code)
712 *
713 * Set the response code of an HTTP Response Message.
714 *
715 * Expects an int parameter with the HTTP response code.
716 *
717 * Returns TRUE on success, or FALSE if the message is not of type
718 * HttpMessage::TYPE_RESPONSE or the response code is out of range (100-510).
719 */
720 PHP_METHOD(HttpMessage, setResponseCode)
721 {
722 long code;
723 getObject(http_message_object, obj);
724
725 HTTP_CHECK_MESSAGE_TYPE_RESPONSE(obj->message, RETURN_FALSE);
726
727 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &code)) {
728 RETURN_FALSE;
729 }
730 if (code < 100 || code > 510) {
731 http_error_ex(HE_WARNING, HTTP_E_INVALID_PARAM, "Invalid response code (100-510): %ld", code);
732 RETURN_FALSE;
733 }
734
735 obj->message->http.info.response.code = code;
736 RETURN_TRUE;
737 }
738 /* }}} */
739
740 /* {{{ proto string HttpMessage::getRequestMethod()
741 *
742 * Get the Request Method of the Message.
743 *
744 * Returns the request method name on success, or FALSE if the message is
745 * not of type HttpMessage::TYPE_REQUEST.
746 */
747 PHP_METHOD(HttpMessage, getRequestMethod)
748 {
749 NO_ARGS;
750
751 IF_RETVAL_USED {
752 getObject(http_message_object, obj);
753 HTTP_CHECK_MESSAGE_TYPE_REQUEST(obj->message, RETURN_FALSE);
754 RETURN_STRING(obj->message->http.info.request.method, 1);
755 }
756 }
757 /* }}} */
758
759 /* {{{ proto bool HttpMessage::setRequestMethod(string method)
760 *
761 * Set the Request Method of the HTTP Message.
762 *
763 * Expects a string parameter containing the request method name.
764 *
765 * Returns TRUE on success, or FALSE if the message is not of type
766 * HttpMessage::TYPE_REQUEST or an invalid request method was supplied.
767 */
768 PHP_METHOD(HttpMessage, setRequestMethod)
769 {
770 char *method;
771 int method_len;
772 getObject(http_message_object, obj);
773
774 HTTP_CHECK_MESSAGE_TYPE_REQUEST(obj->message, RETURN_FALSE);
775
776 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &method, &method_len)) {
777 RETURN_FALSE;
778 }
779 if (method_len < 1) {
780 http_error(HE_WARNING, HTTP_E_INVALID_PARAM, "Cannot set HttpMessage::requestMethod to an empty string");
781 RETURN_FALSE;
782 }
783 if (SUCCESS != http_check_method(method)) {
784 http_error_ex(HE_WARNING, HTTP_E_REQUEST_METHOD, "Unkown request method: %s", method);
785 RETURN_FALSE;
786 }
787
788 STR_SET(obj->message->http.info.request.method, estrndup(method, method_len));
789 RETURN_TRUE;
790 }
791 /* }}} */
792
793 /* {{{ proto string HttpMessage::getRequestUri()
794 *
795 * Get the Request URI of the Message.
796 *
797 * Returns the request uri as string on success, or FALSE if the message
798 * is not of type HttpMessage::TYPE_REQUEST.
799 */
800 PHP_METHOD(HttpMessage, getRequestUri)
801 {
802 NO_ARGS;
803
804 IF_RETVAL_USED {
805 getObject(http_message_object, obj);
806 HTTP_CHECK_MESSAGE_TYPE_REQUEST(obj->message, RETURN_FALSE);
807 RETURN_STRING(obj->message->http.info.request.URI, 1);
808 }
809 }
810 /* }}} */
811
812 /* {{{ proto bool HttpMessage::setRequestUri(string URI)
813 *
814 * Set the Request URI of the HTTP Message.
815 *
816 * Expects a string parameters containing the request uri.
817 *
818 * Returns TRUE on success, or FALSE if the message is not of type
819 * HttpMessage::TYPE_REQUEST or supplied URI was empty.
820 */
821 PHP_METHOD(HttpMessage, setRequestUri)
822 {
823 char *URI;
824 int URIlen;
825 getObject(http_message_object, obj);
826
827 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &URI, &URIlen)) {
828 RETURN_FALSE;
829 }
830 HTTP_CHECK_MESSAGE_TYPE_REQUEST(obj->message, RETURN_FALSE);
831 if (URIlen < 1) {
832 http_error(HE_WARNING, HTTP_E_INVALID_PARAM, "Cannot set HttpMessage::requestUri to an empty string");
833 RETURN_FALSE;
834 }
835
836 STR_SET(obj->message->http.info.request.URI, estrndup(URI, URIlen));
837 RETURN_TRUE;
838 }
839 /* }}} */
840
841 /* {{{ proto string HttpMessage::getHttpVersion()
842 *
843 * Get the HTTP Protocol Version of the Message.
844 *
845 * Returns the HTTP protocol version as string.
846 */
847 PHP_METHOD(HttpMessage, getHttpVersion)
848 {
849 NO_ARGS;
850
851 IF_RETVAL_USED {
852 char ver[4] = {0};
853 getObject(http_message_object, obj);
854
855 sprintf(ver, "%1.1lf", obj->message->http.version);
856 RETURN_STRINGL(ver, 3, 1);
857 }
858 }
859 /* }}} */
860
861 /* {{{ proto bool HttpMessage::setHttpVersion(string version)
862 *
863 * Set the HTTP Protocol version of the Message.
864 *
865 * Expects a string parameter containing the HTTP protocol version.
866 *
867 * Returns TRUE on success, or FALSE if supplied version is out of range (1.0/1.1).
868 */
869 PHP_METHOD(HttpMessage, setHttpVersion)
870 {
871 char v[4];
872 zval *zv;
873 getObject(http_message_object, obj);
874
875 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/", &zv)) {
876 return;
877 }
878
879 convert_to_double(zv);
880 sprintf(v, "%1.1lf", Z_DVAL_P(zv));
881 if (strcmp(v, "1.0") && strcmp(v, "1.1")) {
882 http_error_ex(HE_WARNING, HTTP_E_INVALID_PARAM, "Invalid HTTP protocol version (1.0 or 1.1): %s", v);
883 RETURN_FALSE;
884 }
885
886 obj->message->http.version = Z_DVAL_P(zv);
887 RETURN_TRUE;
888 }
889 /* }}} */
890
891 /* {{{ proto HttpMessage HttpMessage::getParentMessage()
892 *
893 * Get parent Message.
894 *
895 * Returns the parent HttpMessage on success, or NULL if there's none.
896 */
897 PHP_METHOD(HttpMessage, getParentMessage)
898 {
899 NO_ARGS;
900
901 IF_RETVAL_USED {
902 getObject(http_message_object, obj);
903
904 if (obj->message->parent) {
905 RETVAL_OBJVAL(obj->parent);
906 } else {
907 RETVAL_NULL();
908 }
909 }
910 }
911 /* }}} */
912
913 /* {{{ proto bool HttpMessage::send()
914 *
915 * Send the Message according to its type as Response or Request.
916 * This provides limited functionality compared to HttpRequest and HttpResponse.
917 *
918 * Returns TRUE on success, or FALSE on failure.
919 */
920 PHP_METHOD(HttpMessage, send)
921 {
922 getObject(http_message_object, obj);
923
924 NO_ARGS;
925
926 RETURN_SUCCESS(http_message_send(obj->message));
927 }
928 /* }}} */
929
930 /* {{{ proto string HttpMessage::toString([bool include_parent = false])
931 *
932 * Get the string representation of the Message.
933 *
934 * Accepts a bool parameter which specifies whether the returned string
935 * should also contain any parent messages.
936 *
937 * Returns the full message as string.
938 */
939 PHP_METHOD(HttpMessage, toString)
940 {
941 IF_RETVAL_USED {
942 char *string;
943 size_t length;
944 zend_bool include_parent = 0;
945 getObject(http_message_object, obj);
946
947 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &include_parent)) {
948 RETURN_FALSE;
949 }
950
951 if (include_parent) {
952 http_message_serialize(obj->message, &string, &length);
953 } else {
954 http_message_tostring(obj->message, &string, &length);
955 }
956 RETURN_STRINGL(string, length, 0);
957 }
958 }
959 /* }}} */
960
961 #endif /* ZEND_ENGINE_2 */
962
963 /*
964 * Local variables:
965 * tab-width: 4
966 * c-basic-offset: 4
967 * End:
968 * vim600: noet sw=4 ts=4 fdm=marker
969 * vim<600: noet sw=4 ts=4
970 */
971