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