50d949131038d04afc93ae1b85f0f420e70225b8
[m6w6/ext-http] / http_message_object.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-2005, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
11 */
12
13 /* $Id$ */
14
15
16 #ifdef HAVE_CONFIG_H
17 # include "config.h"
18 #endif
19 #include "php.h"
20
21 #ifdef ZEND_ENGINE_2
22
23 #include "php_http.h"
24 #include "php_http_api.h"
25 #include "php_http_std_defs.h"
26 #include "php_http_message_object.h"
27 #include "php_http_exception_object.h"
28
29 #include "phpstr/phpstr.h"
30 #include "missing.h"
31
32 ZEND_EXTERN_MODULE_GLOBALS(http);
33
34 #define HTTP_BEGIN_ARGS(method, ret_ref, req_args) HTTP_BEGIN_ARGS_EX(HttpMessage, method, ret_ref, req_args)
35 #define HTTP_EMPTY_ARGS(method, ret_ref) HTTP_EMPTY_ARGS_EX(HttpMessage, method, ret_ref)
36 #define HTTP_MESSAGE_ME(method, visibility) PHP_ME(HttpMessage, method, HTTP_ARGS(HttpMessage, method), visibility)
37
38 HTTP_BEGIN_ARGS(__construct, 0, 0)
39 HTTP_ARG_VAL(message, 0)
40 HTTP_END_ARGS;
41
42 HTTP_BEGIN_ARGS(fromString, 1, 1)
43 HTTP_ARG_VAL(message, 0)
44 HTTP_END_ARGS;
45
46 HTTP_EMPTY_ARGS(getBody, 0);
47 HTTP_BEGIN_ARGS(setBody, 0, 1)
48 HTTP_ARG_VAL(body, 0)
49 HTTP_END_ARGS;
50
51 HTTP_EMPTY_ARGS(getHeaders, 0);
52 HTTP_BEGIN_ARGS(setHeaders, 0, 1)
53 HTTP_ARG_VAL(headers, 0)
54 HTTP_END_ARGS;
55
56 HTTP_BEGIN_ARGS(addHeaders, 0, 1)
57 HTTP_ARG_VAL(headers, 0)
58 HTTP_ARG_VAL(append, 0)
59 HTTP_END_ARGS;
60
61 HTTP_EMPTY_ARGS(getType, 0);
62 HTTP_BEGIN_ARGS(setType, 0, 1)
63 HTTP_ARG_VAL(type, 0)
64 HTTP_END_ARGS;
65
66 HTTP_EMPTY_ARGS(getResponseCode, 0);
67 HTTP_BEGIN_ARGS(setResponseCode, 0, 1)
68 HTTP_ARG_VAL(response_code, 0)
69 HTTP_END_ARGS;
70
71 HTTP_EMPTY_ARGS(getRequestMethod, 0);
72 HTTP_BEGIN_ARGS(setRequestMethod, 0, 1)
73 HTTP_ARG_VAL(request_method, 0)
74 HTTP_END_ARGS;
75
76 HTTP_EMPTY_ARGS(getRequestUri, 0);
77 HTTP_BEGIN_ARGS(setRequestUri, 0, 1)
78 HTTP_ARG_VAL(uri, 0)
79 HTTP_END_ARGS;
80
81 HTTP_EMPTY_ARGS(getHttpVersion, 0);
82 HTTP_BEGIN_ARGS(setHttpVersion, 0, 1)
83 HTTP_ARG_VAL(http_version, 0)
84 HTTP_END_ARGS;
85
86 HTTP_EMPTY_ARGS(getParentMessage, 1);
87 HTTP_EMPTY_ARGS(send, 0);
88 HTTP_BEGIN_ARGS(toString, 0, 0)
89 HTTP_ARG_VAL(include_parent, 0)
90 HTTP_END_ARGS;
91
92 #define http_message_object_declare_default_properties() _http_message_object_declare_default_properties(TSRMLS_C)
93 static inline void _http_message_object_declare_default_properties(TSRMLS_D);
94 #define http_message_object_read_prop _http_message_object_read_prop
95 static zval *_http_message_object_read_prop(zval *object, zval *member, int type TSRMLS_DC);
96 #define http_message_object_write_prop _http_message_object_write_prop
97 static void _http_message_object_write_prop(zval *object, zval *member, zval *value TSRMLS_DC);
98 #define http_message_object_get_props _http_message_object_get_props
99 static HashTable *_http_message_object_get_props(zval *object TSRMLS_DC);
100 #define http_message_object_clone_obj _http_message_object_clone_obj
101 static inline zend_object_value _http_message_object_clone_obj(zval *object TSRMLS_DC);
102
103 zend_class_entry *http_message_object_ce;
104 zend_function_entry http_message_object_fe[] = {
105 HTTP_MESSAGE_ME(__construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
106 HTTP_MESSAGE_ME(getBody, ZEND_ACC_PUBLIC)
107 HTTP_MESSAGE_ME(setBody, ZEND_ACC_PUBLIC)
108 HTTP_MESSAGE_ME(getHeaders, ZEND_ACC_PUBLIC)
109 HTTP_MESSAGE_ME(setHeaders, ZEND_ACC_PUBLIC)
110 HTTP_MESSAGE_ME(addHeaders, ZEND_ACC_PUBLIC)
111 HTTP_MESSAGE_ME(getType, ZEND_ACC_PUBLIC)
112 HTTP_MESSAGE_ME(setType, ZEND_ACC_PUBLIC)
113 HTTP_MESSAGE_ME(getResponseCode, ZEND_ACC_PUBLIC)
114 HTTP_MESSAGE_ME(setResponseCode, ZEND_ACC_PUBLIC)
115 HTTP_MESSAGE_ME(getRequestMethod, ZEND_ACC_PUBLIC)
116 HTTP_MESSAGE_ME(setRequestMethod, ZEND_ACC_PUBLIC)
117 HTTP_MESSAGE_ME(getRequestUri, ZEND_ACC_PUBLIC)
118 HTTP_MESSAGE_ME(setRequestUri, ZEND_ACC_PUBLIC)
119 HTTP_MESSAGE_ME(getHttpVersion, ZEND_ACC_PUBLIC)
120 HTTP_MESSAGE_ME(setHttpVersion, ZEND_ACC_PUBLIC)
121 HTTP_MESSAGE_ME(getParentMessage, ZEND_ACC_PUBLIC)
122 HTTP_MESSAGE_ME(send, ZEND_ACC_PUBLIC)
123 HTTP_MESSAGE_ME(toString, ZEND_ACC_PUBLIC)
124
125 ZEND_MALIAS(HttpMessage, __toString, toString, HTTP_ARGS(HttpMessage, toString), ZEND_ACC_PUBLIC)
126
127 HTTP_MESSAGE_ME(fromString, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
128
129 EMPTY_FUNCTION_ENTRY
130 };
131 static zend_object_handlers http_message_object_handlers;
132
133 PHP_MINIT_FUNCTION(http_message_object)
134 {
135 HTTP_REGISTER_CLASS_EX(HttpMessage, http_message_object, NULL, 0);
136
137 HTTP_LONG_CONSTANT("HTTP_MSG_NONE", HTTP_MSG_NONE);
138 HTTP_LONG_CONSTANT("HTTP_MSG_REQUEST", HTTP_MSG_REQUEST);
139 HTTP_LONG_CONSTANT("HTTP_MSG_RESPONSE", HTTP_MSG_RESPONSE);
140
141 http_message_object_handlers.clone_obj = http_message_object_clone_obj;
142 http_message_object_handlers.read_property = http_message_object_read_prop;
143 http_message_object_handlers.write_property = http_message_object_write_prop;
144 http_message_object_handlers.get_properties = http_message_object_get_props;
145 http_message_object_handlers.get_property_ptr_ptr = NULL;
146
147 return SUCCESS;
148 }
149
150 zend_object_value _http_message_object_new(zend_class_entry *ce TSRMLS_DC)
151 {
152 return http_message_object_new_ex(ce, NULL, NULL);
153 }
154
155 zend_object_value _http_message_object_new_ex(zend_class_entry *ce, http_message *msg, http_message_object **ptr TSRMLS_DC)
156 {
157 zend_object_value ov;
158 http_message_object *o;
159
160 o = ecalloc(1, sizeof(http_message_object));
161 o->zo.ce = ce;
162
163 if (ptr) {
164 *ptr = o;
165 }
166
167 if (msg) {
168 o->message = msg;
169 if (msg->parent) {
170 o->parent = http_message_object_new_ex(ce, msg->parent, NULL);
171 }
172 }
173
174 ALLOC_HASHTABLE(OBJ_PROP(o));
175 zend_hash_init(OBJ_PROP(o), 0, NULL, ZVAL_PTR_DTOR, 0);
176
177 ov.handle = putObject(http_message_object, o);
178 ov.handlers = &http_message_object_handlers;
179
180 return ov;
181 }
182
183 zend_object_value _http_message_object_clone_obj(zval *this_ptr TSRMLS_DC)
184 {
185 getObject(http_message_object, obj);
186 return http_message_object_new_ex(Z_OBJCE_P(this_ptr), http_message_dup(obj->message), NULL);
187 }
188
189 static inline void _http_message_object_declare_default_properties(TSRMLS_D)
190 {
191 zend_class_entry *ce = http_message_object_ce;
192
193 #ifndef WONKY
194 DCL_CONST(long, "TYPE_NONE", HTTP_MSG_NONE);
195 DCL_CONST(long, "TYPE_REQUEST", HTTP_MSG_REQUEST);
196 DCL_CONST(long, "TYPE_RESPONSE", HTTP_MSG_RESPONSE);
197 #endif
198
199 DCL_PROP(PROTECTED, long, type, HTTP_MSG_NONE);
200 DCL_PROP(PROTECTED, string, body, "");
201 DCL_PROP(PROTECTED, string, requestMethod, "");
202 DCL_PROP(PROTECTED, string, requestUri, "");
203 DCL_PROP(PROTECTED, long, responseCode, 0);
204 DCL_PROP_N(PROTECTED, httpVersion);
205 DCL_PROP_N(PROTECTED, headers);
206 DCL_PROP_N(PROTECTED, parentMessage);
207 }
208
209 void _http_message_object_free(zend_object *object TSRMLS_DC)
210 {
211 http_message_object *o = (http_message_object *) object;
212
213 if (OBJ_PROP(o)) {
214 zend_hash_destroy(OBJ_PROP(o));
215 FREE_HASHTABLE(OBJ_PROP(o));
216 }
217 if (o->message) {
218 http_message_dtor(o->message);
219 efree(o->message);
220 }
221 efree(o);
222 }
223
224 static zval *_http_message_object_read_prop(zval *object, zval *member, int type TSRMLS_DC)
225 {
226 getObjectEx(http_message_object, obj, object);
227 http_message *msg = obj->message;
228 zval *return_value;
229 #ifdef WONKY
230 ulong h = zend_get_hash_value(Z_STRVAL_P(member), Z_STRLEN_P(member)+1);
231 #else
232 zend_property_info *pinfo = zend_get_property_info(obj->zo.ce, member, 1 TSRMLS_CC);
233
234 if (!pinfo || ACC_PROP_PUBLIC(pinfo->flags)) {
235 return zend_get_std_object_handlers()->read_property(object, member, type TSRMLS_CC);
236 }
237 #endif
238
239 return_value = &EG(uninitialized_zval);
240 return_value->refcount = 0;
241 return_value->is_ref = 0;
242
243 #ifdef WONKY
244 switch (h)
245 #else
246 switch (pinfo->h)
247 #endif
248 {
249 case HTTP_MSG_PROPHASH_TYPE:
250 RETVAL_LONG(msg->type);
251 break;
252
253 case HTTP_MSG_PROPHASH_HTTP_VERSION:
254 RETVAL_DOUBLE(msg->http.version);
255 break;
256
257 case HTTP_MSG_PROPHASH_BODY:
258 phpstr_fix(PHPSTR(msg));
259 RETVAL_PHPSTR(PHPSTR(msg), 0, 1);
260 break;
261
262 case HTTP_MSG_PROPHASH_HEADERS:
263 /* This is needed for situations like
264 * $this->headers['foo'] = 'bar';
265 */
266 if (type == BP_VAR_W) {
267 return_value->refcount = 1;
268 return_value->is_ref = 1;
269 Z_TYPE_P(return_value) = IS_ARRAY;
270 Z_ARRVAL_P(return_value) = &msg->hdrs;
271 } else {
272 array_init(return_value);
273 zend_hash_copy(Z_ARRVAL_P(return_value), &msg->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
274 }
275 break;
276
277 case HTTP_MSG_PROPHASH_PARENT_MESSAGE:
278 if (msg->parent) {
279 RETVAL_OBJVAL(obj->parent);
280 } else {
281 RETVAL_NULL();
282 }
283 break;
284
285 case HTTP_MSG_PROPHASH_REQUEST_METHOD:
286 if (HTTP_MSG_TYPE(REQUEST, msg) && msg->http.info.request.method) {
287 RETVAL_STRING(msg->http.info.request.method, 1);
288 } else {
289 RETVAL_NULL();
290 }
291 break;
292
293 case HTTP_MSG_PROPHASH_REQUEST_URI:
294 if (HTTP_MSG_TYPE(REQUEST, msg) && msg->http.info.request.URI) {
295 RETVAL_STRING(msg->http.info.request.URI, 1);
296 } else {
297 RETVAL_NULL();
298 }
299 break;
300
301 case HTTP_MSG_PROPHASH_RESPONSE_CODE:
302 if (HTTP_MSG_TYPE(RESPONSE, msg)) {
303 RETVAL_LONG(msg->http.info.response.code);
304 } else {
305 RETVAL_NULL();
306 }
307 break;
308
309 case HTTP_MSG_PROPHASH_RESPONSE_STATUS:
310 if (HTTP_MSG_TYPE(RESPONSE, msg) && msg->http.info.response.status) {
311 RETVAL_STRING(msg->http.info.response.status, 1);
312 } else {
313 RETVAL_NULL();
314 }
315 break;
316
317 default:
318 #ifdef WONKY
319 return zend_get_std_object_handlers()->read_property(object, member, type TSRMLS_CC);
320 #else
321 RETVAL_NULL();
322 #endif
323 break;
324 }
325
326 return return_value;
327 }
328
329 static void _http_message_object_write_prop(zval *object, zval *member, zval *value TSRMLS_DC)
330 {
331 getObjectEx(http_message_object, obj, object);
332 http_message *msg = obj->message;
333 #ifdef WONKY
334 ulong h = zend_get_hash_value(Z_STRVAL_P(member), Z_STRLEN_P(member) + 1);
335 #else
336 zend_property_info *pinfo = zend_get_property_info(obj->zo.ce, member, 1 TSRMLS_CC);
337
338 if (!pinfo || ACC_PROP_PUBLIC(pinfo->flags)) {
339 zend_get_std_object_handlers()->write_property(object, member, value TSRMLS_CC);
340 return;
341 }
342 #endif
343
344 #ifdef WONKY
345 switch (h)
346 #else
347 switch (pinfo->h)
348 #endif
349 {
350 case HTTP_MSG_PROPHASH_TYPE:
351 convert_to_long_ex(&value);
352 http_message_set_type(msg, Z_LVAL_P(value));
353 break;
354
355 case HTTP_MSG_PROPHASH_HTTP_VERSION:
356 convert_to_double_ex(&value);
357 msg->http.version = Z_DVAL_P(value);
358 break;
359
360 case HTTP_MSG_PROPHASH_BODY:
361 convert_to_string_ex(&value);
362 phpstr_dtor(PHPSTR(msg));
363 phpstr_from_string_ex(PHPSTR(msg), Z_STRVAL_P(value), Z_STRLEN_P(value));
364 break;
365
366 case HTTP_MSG_PROPHASH_HEADERS:
367 convert_to_array_ex(&value);
368 zend_hash_clean(&msg->hdrs);
369 zend_hash_copy(&msg->hdrs, Z_ARRVAL_P(value), (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
370 break;
371
372 case HTTP_MSG_PROPHASH_PARENT_MESSAGE:
373 if (Z_TYPE_P(value) == IS_OBJECT && instanceof_function(Z_OBJCE_P(value), http_message_object_ce TSRMLS_CC)) {
374 if (msg->parent) {
375 zval tmp;
376 tmp.value.obj = obj->parent;
377 Z_OBJ_DELREF(tmp);
378 }
379 Z_OBJ_ADDREF_P(value);
380 obj->parent = value->value.obj;
381 }
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_new_ex(Z_OBJCE_P(getThis()), obj->message->parent, NULL);
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_new_ex(http_message_object_ce, msg, NULL);
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