- attempt to fix win32 build
[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-2006, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
11 */
12
13 /* $Id$ */
14
15 #define HTTP_WANT_SAPI
16 #define HTTP_WANT_CURL
17 #define HTTP_WANT_MAGIC
18 #include "php_http.h"
19
20 #ifdef ZEND_ENGINE_2
21
22 #include "zend_interfaces.h"
23 #include "ext/standard/url.h"
24
25 #include "php_http_api.h"
26 #include "php_http_send_api.h"
27 #include "php_http_url_api.h"
28 #include "php_http_message_api.h"
29 #include "php_http_message_object.h"
30 #include "php_http_exception_object.h"
31 #include "php_http_response_object.h"
32 #include "php_http_request_method_api.h"
33 #include "php_http_request_api.h"
34 #include "php_http_request_object.h"
35
36 #if defined(HTTP_HAVE_SPL) && !defined(WONKY)
37 /* SPL doesn't install its headers */
38 extern PHPAPI zend_class_entry *spl_ce_Countable;
39 #endif
40
41 #define HTTP_BEGIN_ARGS(method, req_args) HTTP_BEGIN_ARGS_EX(HttpMessage, method, 0, req_args)
42 #define HTTP_EMPTY_ARGS(method) HTTP_EMPTY_ARGS_EX(HttpMessage, method, 0)
43 #define HTTP_MESSAGE_ME(method, visibility) PHP_ME(HttpMessage, method, HTTP_ARGS(HttpMessage, method), visibility)
44
45 HTTP_BEGIN_ARGS(__construct, 0)
46 HTTP_ARG_VAL(message, 0)
47 HTTP_END_ARGS;
48
49 HTTP_BEGIN_ARGS(factory, 0)
50 HTTP_ARG_VAL(message, 0)
51 HTTP_ARG_VAL(class_name, 0)
52 HTTP_END_ARGS;
53
54 HTTP_EMPTY_ARGS(getBody);
55 HTTP_BEGIN_ARGS(setBody, 1)
56 HTTP_ARG_VAL(body, 0)
57 HTTP_END_ARGS;
58
59 HTTP_BEGIN_ARGS(getHeader, 1)
60 HTTP_ARG_VAL(header, 0)
61 HTTP_END_ARGS;
62
63 HTTP_EMPTY_ARGS(getHeaders);
64 HTTP_BEGIN_ARGS(setHeaders, 1)
65 HTTP_ARG_VAL(headers, 0)
66 HTTP_END_ARGS;
67
68 HTTP_BEGIN_ARGS(addHeaders, 1)
69 HTTP_ARG_VAL(headers, 0)
70 HTTP_ARG_VAL(append, 0)
71 HTTP_END_ARGS;
72
73 HTTP_EMPTY_ARGS(getType);
74 HTTP_BEGIN_ARGS(setType, 1)
75 HTTP_ARG_VAL(type, 0)
76 HTTP_END_ARGS;
77
78 HTTP_EMPTY_ARGS(getResponseCode);
79 HTTP_BEGIN_ARGS(setResponseCode, 1)
80 HTTP_ARG_VAL(response_code, 0)
81 HTTP_END_ARGS;
82
83 HTTP_EMPTY_ARGS(getResponseStatus);
84 HTTP_BEGIN_ARGS(setResponseStatus, 1)
85 HTTP_ARG_VAL(response_status, 0)
86 HTTP_END_ARGS;
87
88 HTTP_EMPTY_ARGS(getRequestMethod);
89 HTTP_BEGIN_ARGS(setRequestMethod, 1)
90 HTTP_ARG_VAL(request_method, 0)
91 HTTP_END_ARGS;
92
93 HTTP_EMPTY_ARGS(getRequestUrl);
94 HTTP_BEGIN_ARGS(setRequestUrl, 1)
95 HTTP_ARG_VAL(url, 0)
96 HTTP_END_ARGS;
97
98 HTTP_EMPTY_ARGS(getHttpVersion);
99 HTTP_BEGIN_ARGS(setHttpVersion, 1)
100 HTTP_ARG_VAL(http_version, 0)
101 HTTP_END_ARGS;
102
103 HTTP_BEGIN_ARGS(guessContentType, 1)
104 HTTP_ARG_VAL(magic_file, 0)
105 HTTP_ARG_VAL(magic_mode, 0)
106 HTTP_END_ARGS;
107
108 HTTP_EMPTY_ARGS(getParentMessage);
109 HTTP_EMPTY_ARGS(send);
110 HTTP_BEGIN_ARGS(toString, 0)
111 HTTP_ARG_VAL(include_parent, 0)
112 HTTP_END_ARGS;
113
114 HTTP_EMPTY_ARGS(toMessageTypeObject);
115
116 HTTP_EMPTY_ARGS(count);
117
118 HTTP_EMPTY_ARGS(serialize);
119 HTTP_BEGIN_ARGS(unserialize, 1)
120 HTTP_ARG_VAL(serialized, 0)
121 HTTP_END_ARGS;
122
123 HTTP_EMPTY_ARGS(rewind);
124 HTTP_EMPTY_ARGS(valid);
125 HTTP_EMPTY_ARGS(key);
126 HTTP_EMPTY_ARGS(current);
127 HTTP_EMPTY_ARGS(next);
128
129 HTTP_EMPTY_ARGS(detach);
130 HTTP_BEGIN_ARGS(prepend, 1)
131 HTTP_ARG_OBJ(HttpMessage, message, 0)
132 HTTP_END_ARGS;
133 HTTP_EMPTY_ARGS(reverse);
134
135 #define http_message_object_read_prop _http_message_object_read_prop
136 static zval *_http_message_object_read_prop(zval *object, zval *member, int type TSRMLS_DC);
137 #define http_message_object_write_prop _http_message_object_write_prop
138 static void _http_message_object_write_prop(zval *object, zval *member, zval *value TSRMLS_DC);
139 #define http_message_object_get_props _http_message_object_get_props
140 static HashTable *_http_message_object_get_props(zval *object TSRMLS_DC);
141
142 #define OBJ_PROP_CE http_message_object_ce
143 zend_class_entry *http_message_object_ce;
144 zend_function_entry http_message_object_fe[] = {
145 HTTP_MESSAGE_ME(__construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
146 HTTP_MESSAGE_ME(getBody, ZEND_ACC_PUBLIC)
147 HTTP_MESSAGE_ME(setBody, ZEND_ACC_PUBLIC)
148 HTTP_MESSAGE_ME(getHeader, ZEND_ACC_PUBLIC)
149 HTTP_MESSAGE_ME(getHeaders, ZEND_ACC_PUBLIC)
150 HTTP_MESSAGE_ME(setHeaders, ZEND_ACC_PUBLIC)
151 HTTP_MESSAGE_ME(addHeaders, ZEND_ACC_PUBLIC)
152 HTTP_MESSAGE_ME(getType, ZEND_ACC_PUBLIC)
153 HTTP_MESSAGE_ME(setType, ZEND_ACC_PUBLIC)
154 HTTP_MESSAGE_ME(getResponseCode, ZEND_ACC_PUBLIC)
155 HTTP_MESSAGE_ME(setResponseCode, ZEND_ACC_PUBLIC)
156 HTTP_MESSAGE_ME(getResponseStatus, ZEND_ACC_PUBLIC)
157 HTTP_MESSAGE_ME(setResponseStatus, ZEND_ACC_PUBLIC)
158 HTTP_MESSAGE_ME(getRequestMethod, ZEND_ACC_PUBLIC)
159 HTTP_MESSAGE_ME(setRequestMethod, ZEND_ACC_PUBLIC)
160 HTTP_MESSAGE_ME(getRequestUrl, ZEND_ACC_PUBLIC)
161 HTTP_MESSAGE_ME(setRequestUrl, ZEND_ACC_PUBLIC)
162 HTTP_MESSAGE_ME(getHttpVersion, ZEND_ACC_PUBLIC)
163 HTTP_MESSAGE_ME(setHttpVersion, ZEND_ACC_PUBLIC)
164 HTTP_MESSAGE_ME(guessContentType, ZEND_ACC_PUBLIC)
165 HTTP_MESSAGE_ME(getParentMessage, ZEND_ACC_PUBLIC)
166 HTTP_MESSAGE_ME(send, ZEND_ACC_PUBLIC)
167 HTTP_MESSAGE_ME(toString, ZEND_ACC_PUBLIC)
168 HTTP_MESSAGE_ME(toMessageTypeObject, ZEND_ACC_PUBLIC)
169
170 /* implements Countable */
171 HTTP_MESSAGE_ME(count, ZEND_ACC_PUBLIC)
172
173 /* implements Serializable */
174 HTTP_MESSAGE_ME(serialize, ZEND_ACC_PUBLIC)
175 HTTP_MESSAGE_ME(unserialize, ZEND_ACC_PUBLIC)
176
177 /* implements Iterator */
178 HTTP_MESSAGE_ME(rewind, ZEND_ACC_PUBLIC)
179 HTTP_MESSAGE_ME(valid, ZEND_ACC_PUBLIC)
180 HTTP_MESSAGE_ME(current, ZEND_ACC_PUBLIC)
181 HTTP_MESSAGE_ME(key, ZEND_ACC_PUBLIC)
182 HTTP_MESSAGE_ME(next, ZEND_ACC_PUBLIC)
183
184 ZEND_MALIAS(HttpMessage, __toString, toString, HTTP_ARGS(HttpMessage, toString), ZEND_ACC_PUBLIC)
185
186 HTTP_MESSAGE_ME(factory, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
187 ZEND_MALIAS(HttpMessage, fromString, factory, HTTP_ARGS(HttpMessage, factory), ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
188
189 HTTP_MESSAGE_ME(detach, ZEND_ACC_PUBLIC)
190 HTTP_MESSAGE_ME(prepend, ZEND_ACC_PUBLIC)
191 HTTP_MESSAGE_ME(reverse, ZEND_ACC_PUBLIC)
192
193 EMPTY_FUNCTION_ENTRY
194 };
195 static zend_object_handlers http_message_object_handlers;
196
197 PHP_MINIT_FUNCTION(http_message_object)
198 {
199 HTTP_REGISTER_CLASS_EX(HttpMessage, http_message_object, NULL, 0);
200
201 #ifndef WONKY
202 # ifdef HTTP_HAVE_SPL
203 zend_class_implements(http_message_object_ce TSRMLS_CC, 3, spl_ce_Countable, zend_ce_serializable, zend_ce_iterator);
204 # else
205 zend_class_implements(http_message_object_ce TSRMLS_CC, 2, zend_ce_serializable, zend_ce_iterator);
206 # endif
207 #else
208 zend_class_implements(http_message_object_ce TSRMLS_CC, 1, zend_ce_iterator);
209 #endif
210
211 http_message_object_handlers.clone_obj = _http_message_object_clone_obj;
212 http_message_object_handlers.read_property = http_message_object_read_prop;
213 http_message_object_handlers.write_property = http_message_object_write_prop;
214 http_message_object_handlers.get_properties = http_message_object_get_props;
215 http_message_object_handlers.get_property_ptr_ptr = NULL;
216
217 DCL_PROP(PROTECTED, long, type, HTTP_MSG_NONE);
218 DCL_PROP(PROTECTED, string, body, "");
219 DCL_PROP(PROTECTED, string, requestMethod, "");
220 DCL_PROP(PROTECTED, string, requestUrl, "");
221 DCL_PROP(PROTECTED, string, responseStatus, "");
222 DCL_PROP(PROTECTED, long, responseCode, 0);
223 DCL_PROP_N(PROTECTED, httpVersion);
224 DCL_PROP_N(PROTECTED, headers);
225 DCL_PROP_N(PROTECTED, parentMessage);
226
227 #ifndef WONKY
228 DCL_CONST(long, "TYPE_NONE", HTTP_MSG_NONE);
229 DCL_CONST(long, "TYPE_REQUEST", HTTP_MSG_REQUEST);
230 DCL_CONST(long, "TYPE_RESPONSE", HTTP_MSG_RESPONSE);
231 #endif
232
233 HTTP_LONG_CONSTANT("HTTP_MSG_NONE", HTTP_MSG_NONE);
234 HTTP_LONG_CONSTANT("HTTP_MSG_REQUEST", HTTP_MSG_REQUEST);
235 HTTP_LONG_CONSTANT("HTTP_MSG_RESPONSE", HTTP_MSG_RESPONSE);
236
237 return SUCCESS;
238 }
239
240 void _http_message_object_reverse(zval *this_ptr, zval *return_value TSRMLS_DC)
241 {
242 int i;
243 getObject(http_message_object, obj);
244
245 /* count */
246 http_message_count(i, obj->message);
247
248 if (i > 1) {
249 zval o;
250 zend_object_value *ovalues = NULL;
251 http_message_object **objects = NULL;
252 int last = i - 1;
253
254 objects = ecalloc(i, sizeof(http_message_object *));
255 ovalues = ecalloc(i, sizeof(zend_object_value));
256
257 /* we are the first message */
258 objects[0] = obj;
259 ovalues[0] = getThis()->value.obj;
260
261 /* fetch parents */
262 INIT_PZVAL(&o);
263 o.type = IS_OBJECT;
264 for (i = 1; obj->parent.handle; ++i) {
265 o.value.obj = obj->parent;
266 ovalues[i] = o.value.obj;
267 objects[i] = obj = zend_object_store_get_object(&o TSRMLS_CC);
268 }
269
270 /* reorder parents */
271 for (last = --i; i; --i) {
272 objects[i]->message->parent = objects[i-1]->message;
273 objects[i]->parent = ovalues[i-1];
274 }
275 objects[0]->message->parent = NULL;
276 objects[0]->parent.handle = 0;
277 objects[0]->parent.handlers = NULL;
278
279 /* add ref (why?) */
280 Z_OBJ_ADDREF_P(getThis());
281 RETVAL_OBJVAL(ovalues[last], 1);
282
283 efree(objects);
284 efree(ovalues);
285 } else {
286 RETURN_ZVAL(getThis(), 1, 0);
287 }
288 }
289
290 void _http_message_object_prepend_ex(zval *this_ptr, zval *prepend, zend_bool top TSRMLS_DC)
291 {
292 zval m;
293 http_message *save_parent_msg = NULL;
294 zend_object_value save_parent_obj = {0, NULL};
295 getObject(http_message_object, obj);
296 getObjectEx(http_message_object, prepend_obj, prepend);
297
298 INIT_PZVAL(&m);
299 m.type = IS_OBJECT;
300
301 if (!top) {
302 save_parent_obj = obj->parent;
303 save_parent_msg = obj->message->parent;
304 } else {
305 /* iterate to the most parent object */
306 while (obj->parent.handle) {
307 m.value.obj = obj->parent;
308 obj = zend_object_store_get_object(&m TSRMLS_CC);
309 }
310 }
311
312 /* prepend */
313 obj->parent = prepend->value.obj;
314 obj->message->parent = prepend_obj->message;
315
316 /* add ref */
317 zend_objects_store_add_ref(prepend TSRMLS_CC);
318 while (prepend_obj->parent.handle) {
319 m.value.obj = prepend_obj->parent;
320 zend_objects_store_add_ref(&m TSRMLS_CC);
321 prepend_obj = zend_object_store_get_object(&m TSRMLS_CC);
322 }
323
324 if (!top) {
325 prepend_obj->parent = save_parent_obj;
326 prepend_obj->message->parent = save_parent_msg;
327 }
328 }
329
330 zend_object_value _http_message_object_new(zend_class_entry *ce TSRMLS_DC)
331 {
332 return http_message_object_new_ex(ce, NULL, NULL);
333 }
334
335 zend_object_value _http_message_object_new_ex(zend_class_entry *ce, http_message *msg, http_message_object **ptr TSRMLS_DC)
336 {
337 zend_object_value ov;
338 http_message_object *o;
339
340 o = ecalloc(1, sizeof(http_message_object));
341 o->zo.ce = ce;
342
343 if (ptr) {
344 *ptr = o;
345 }
346
347 if (msg) {
348 o->message = msg;
349 if (msg->parent) {
350 o->parent = http_message_object_new_ex(ce, msg->parent, NULL);
351 }
352 }
353
354 ALLOC_HASHTABLE(OBJ_PROP(o));
355 zend_hash_init(OBJ_PROP(o), zend_hash_num_elements(&ce->default_properties), NULL, ZVAL_PTR_DTOR, 0);
356 zend_hash_copy(OBJ_PROP(o), &ce->default_properties, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
357
358 ov.handle = putObject(http_message_object, o);
359 ov.handlers = &http_message_object_handlers;
360
361 return ov;
362 }
363
364 zend_object_value _http_message_object_clone_obj(zval *this_ptr TSRMLS_DC)
365 {
366 zend_object_value new_ov;
367 http_message_object *new_obj = NULL;
368 getObject(http_message_object, old_obj);
369
370 new_ov = http_message_object_new_ex(old_obj->zo.ce, http_message_dup(old_obj->message), &new_obj);
371 zend_objects_clone_members(&new_obj->zo, new_ov, &old_obj->zo, Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC);
372
373 return new_ov;
374 }
375
376 void _http_message_object_free(zend_object *object TSRMLS_DC)
377 {
378 http_message_object *o = (http_message_object *) object;
379
380 if (o->message) {
381 http_message_dtor(o->message);
382 efree(o->message);
383 }
384 if (o->parent.handle) {
385 zval p;
386
387 INIT_PZVAL(&p);
388 p.type = IS_OBJECT;
389 p.value.obj = o->parent;
390 zend_objects_store_del_ref(&p TSRMLS_CC);
391 }
392 freeObject(o);
393 }
394
395 static zval *_http_message_object_read_prop(zval *object, zval *member, int type TSRMLS_DC)
396 {
397 getObjectEx(http_message_object, obj, object);
398 http_message *msg = obj->message;
399 zval *return_value;
400 #ifdef WONKY
401 ulong h = zend_get_hash_value(Z_STRVAL_P(member), Z_STRLEN_P(member)+1);
402 #else
403 zend_property_info *pinfo = zend_get_property_info(obj->zo.ce, member, 1 TSRMLS_CC);
404
405 if (!pinfo || ACC_PROP_PUBLIC(pinfo->flags)) {
406 return zend_get_std_object_handlers()->read_property(object, member, type TSRMLS_CC);
407 }
408 #endif
409
410 if (type == BP_VAR_W) {
411 zend_error(E_ERROR, "Cannot access HttpMessage properties by reference or array key/index");
412 return NULL;
413 }
414
415 ALLOC_ZVAL(return_value);
416 return_value->refcount = 0;
417 return_value->is_ref = 0;
418
419 #ifdef WONKY
420 switch (h)
421 #else
422 switch (pinfo->h)
423 #endif
424 {
425 case HTTP_MSG_PROPHASH_TYPE:
426 case HTTP_MSG_CHILD_PROPHASH_TYPE:
427 RETVAL_LONG(msg->type);
428 break;
429
430 case HTTP_MSG_PROPHASH_HTTP_VERSION:
431 case HTTP_MSG_CHILD_PROPHASH_HTTP_VERSION:
432 RETVAL_DOUBLE(msg->http.version);
433 break;
434
435 case HTTP_MSG_PROPHASH_BODY:
436 case HTTP_MSG_CHILD_PROPHASH_BODY:
437 phpstr_fix(PHPSTR(msg));
438 RETVAL_PHPSTR(PHPSTR(msg), 0, 1);
439 break;
440
441 case HTTP_MSG_PROPHASH_HEADERS:
442 case HTTP_MSG_CHILD_PROPHASH_HEADERS:
443 array_init(return_value);
444 zend_hash_copy(Z_ARRVAL_P(return_value), &msg->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
445 break;
446
447 case HTTP_MSG_PROPHASH_PARENT_MESSAGE:
448 case HTTP_MSG_CHILD_PROPHASH_PARENT_MESSAGE:
449 if (msg->parent) {
450 RETVAL_OBJVAL(obj->parent, 1);
451 } else {
452 RETVAL_NULL();
453 }
454 break;
455
456 case HTTP_MSG_PROPHASH_REQUEST_METHOD:
457 case HTTP_MSG_CHILD_PROPHASH_REQUEST_METHOD:
458 if (HTTP_MSG_TYPE(REQUEST, msg) && msg->http.info.request.method) {
459 RETVAL_STRING(msg->http.info.request.method, 1);
460 } else {
461 RETVAL_NULL();
462 }
463 break;
464
465 case HTTP_MSG_PROPHASH_REQUEST_URL:
466 case HTTP_MSG_CHILD_PROPHASH_REQUEST_URL:
467 if (HTTP_MSG_TYPE(REQUEST, msg) && msg->http.info.request.url) {
468 RETVAL_STRING(msg->http.info.request.url, 1);
469 } else {
470 RETVAL_NULL();
471 }
472 break;
473
474 case HTTP_MSG_PROPHASH_RESPONSE_CODE:
475 case HTTP_MSG_CHILD_PROPHASH_RESPONSE_CODE:
476 if (HTTP_MSG_TYPE(RESPONSE, msg)) {
477 RETVAL_LONG(msg->http.info.response.code);
478 } else {
479 RETVAL_NULL();
480 }
481 break;
482
483 case HTTP_MSG_PROPHASH_RESPONSE_STATUS:
484 case HTTP_MSG_CHILD_PROPHASH_RESPONSE_STATUS:
485 if (HTTP_MSG_TYPE(RESPONSE, msg) && msg->http.info.response.status) {
486 RETVAL_STRING(msg->http.info.response.status, 1);
487 } else {
488 RETVAL_NULL();
489 }
490 break;
491
492 default:
493 #ifdef WONKY
494 return zend_get_std_object_handlers()->read_property(object, member, type TSRMLS_CC);
495 #else
496 RETVAL_NULL();
497 #endif
498 }
499
500 return return_value;
501 }
502
503 static void _http_message_object_write_prop(zval *object, zval *member, zval *value TSRMLS_DC)
504 {
505 getObjectEx(http_message_object, obj, object);
506 http_message *msg = obj->message;
507 zval *cpy = NULL;
508 #ifdef WONKY
509 ulong h = zend_get_hash_value(Z_STRVAL_P(member), Z_STRLEN_P(member) + 1);
510 #else
511 zend_property_info *pinfo = zend_get_property_info(obj->zo.ce, member, 1 TSRMLS_CC);
512
513 if (!pinfo || ACC_PROP_PUBLIC(pinfo->flags)) {
514 zend_get_std_object_handlers()->write_property(object, member, value TSRMLS_CC);
515 return;
516 }
517 #endif
518
519 cpy = zval_copy(Z_TYPE_P(value), value);
520
521 #ifdef WONKY
522 switch (h)
523 #else
524 switch (pinfo->h)
525 #endif
526 {
527 case HTTP_MSG_PROPHASH_TYPE:
528 case HTTP_MSG_CHILD_PROPHASH_TYPE:
529 convert_to_long(cpy);
530 http_message_set_type(msg, Z_LVAL_P(cpy));
531 break;
532
533 case HTTP_MSG_PROPHASH_HTTP_VERSION:
534 case HTTP_MSG_CHILD_PROPHASH_HTTP_VERSION:
535 convert_to_double(cpy);
536 msg->http.version = Z_DVAL_P(cpy);
537 break;
538
539 case HTTP_MSG_PROPHASH_BODY:
540 case HTTP_MSG_CHILD_PROPHASH_BODY:
541 convert_to_string(cpy);
542 phpstr_dtor(PHPSTR(msg));
543 phpstr_from_string_ex(PHPSTR(msg), Z_STRVAL_P(cpy), Z_STRLEN_P(cpy));
544 break;
545
546 case HTTP_MSG_PROPHASH_HEADERS:
547 case HTTP_MSG_CHILD_PROPHASH_HEADERS:
548 convert_to_array(cpy);
549 zend_hash_clean(&msg->hdrs);
550 zend_hash_copy(&msg->hdrs, Z_ARRVAL_P(cpy), (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
551 break;
552
553 case HTTP_MSG_PROPHASH_PARENT_MESSAGE:
554 case HTTP_MSG_CHILD_PROPHASH_PARENT_MESSAGE:
555 if (Z_TYPE_P(value) == IS_OBJECT && instanceof_function(Z_OBJCE_P(value), http_message_object_ce TSRMLS_CC)) {
556 if (msg->parent) {
557 zval tmp;
558 tmp.value.obj = obj->parent;
559 Z_OBJ_DELREF(tmp);
560 }
561 Z_OBJ_ADDREF_P(value);
562 obj->parent = value->value.obj;
563 }
564 break;
565
566 case HTTP_MSG_PROPHASH_REQUEST_METHOD:
567 case HTTP_MSG_CHILD_PROPHASH_REQUEST_METHOD:
568 if (HTTP_MSG_TYPE(REQUEST, msg)) {
569 convert_to_string(cpy);
570 STR_SET(msg->http.info.request.method, estrndup(Z_STRVAL_P(cpy), Z_STRLEN_P(cpy)));
571 }
572 break;
573
574 case HTTP_MSG_PROPHASH_REQUEST_URL:
575 case HTTP_MSG_CHILD_PROPHASH_REQUEST_URL:
576 if (HTTP_MSG_TYPE(REQUEST, msg)) {
577 convert_to_string(cpy);
578 STR_SET(msg->http.info.request.url, estrndup(Z_STRVAL_P(cpy), Z_STRLEN_P(cpy)));
579 }
580 break;
581
582 case HTTP_MSG_PROPHASH_RESPONSE_CODE:
583 case HTTP_MSG_CHILD_PROPHASH_RESPONSE_CODE:
584 if (HTTP_MSG_TYPE(RESPONSE, msg)) {
585 convert_to_long(cpy);
586 msg->http.info.response.code = Z_LVAL_P(cpy);
587 }
588 break;
589
590 case HTTP_MSG_PROPHASH_RESPONSE_STATUS:
591 case HTTP_MSG_CHILD_PROPHASH_RESPONSE_STATUS:
592 if (HTTP_MSG_TYPE(RESPONSE, msg)) {
593 convert_to_string(cpy);
594 STR_SET(msg->http.info.response.status, estrndup(Z_STRVAL_P(cpy), Z_STRLEN_P(cpy)));
595 }
596 break;
597
598 default:
599 #ifdef WONKY
600 zend_get_std_object_handlers()->write_property(object, member, value TSRMLS_CC);
601 #endif
602 break;
603 }
604 zval_free(&cpy);
605 }
606
607 static HashTable *_http_message_object_get_props(zval *object TSRMLS_DC)
608 {
609 zval *headers;
610 getObjectEx(http_message_object, obj, object);
611 http_message *msg = obj->message;
612 HashTable *props = OBJ_PROP(obj);
613 zval array, *parent;
614
615 INIT_ZARR(array, props);
616
617 #define ASSOC_PROP(array, ptype, name, val) \
618 { \
619 char *m_prop_name; \
620 int m_prop_len; \
621 zend_mangle_property_name(&m_prop_name, &m_prop_len, "*", 1, name, lenof(name), 0); \
622 add_assoc_ ##ptype## _ex(&array, m_prop_name, sizeof(name)+3, val); \
623 efree(m_prop_name); \
624 }
625 #define ASSOC_STRING(array, name, val) ASSOC_STRINGL(array, name, val, strlen(val))
626 #define ASSOC_STRINGL(array, name, val, len) \
627 { \
628 char *m_prop_name; \
629 int m_prop_len; \
630 zend_mangle_property_name(&m_prop_name, &m_prop_len, "*", 1, name, lenof(name), 0); \
631 add_assoc_stringl_ex(&array, m_prop_name, sizeof(name)+3, val, len, 1); \
632 efree(m_prop_name); \
633 }
634
635 ASSOC_PROP(array, long, "type", msg->type);
636 ASSOC_PROP(array, double, "httpVersion", msg->http.version);
637
638 switch (msg->type) {
639 case HTTP_MSG_REQUEST:
640 ASSOC_PROP(array, long, "responseCode", 0);
641 ASSOC_STRINGL(array, "responseStatus", "", 0);
642 ASSOC_STRING(array, "requestMethod", STR_PTR(msg->http.info.request.method));
643 ASSOC_STRING(array, "requestUrl", STR_PTR(msg->http.info.request.url));
644 break;
645
646 case HTTP_MSG_RESPONSE:
647 ASSOC_PROP(array, long, "responseCode", msg->http.info.response.code);
648 ASSOC_STRING(array, "responseStatus", STR_PTR(msg->http.info.response.status));
649 ASSOC_STRINGL(array, "requestMethod", "", 0);
650 ASSOC_STRINGL(array, "requestUrl", "", 0);
651 break;
652
653 case HTTP_MSG_NONE:
654 default:
655 ASSOC_PROP(array, long, "responseCode", 0);
656 ASSOC_STRINGL(array, "responseStatus", "", 0);
657 ASSOC_STRINGL(array, "requestMethod", "", 0);
658 ASSOC_STRINGL(array, "requestUrl", "", 0);
659 break;
660 }
661
662 MAKE_STD_ZVAL(headers);
663 array_init(headers);
664 zend_hash_copy(Z_ARRVAL_P(headers), &msg->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
665 ASSOC_PROP(array, zval, "headers", headers);
666 ASSOC_STRINGL(array, "body", PHPSTR_VAL(msg), PHPSTR_LEN(msg));
667
668 MAKE_STD_ZVAL(parent);
669 if (msg->parent) {
670 ZVAL_OBJVAL(parent, obj->parent, 1);
671 } else {
672 ZVAL_NULL(parent);
673 }
674 ASSOC_PROP(array, zval, "parentMessage", parent);
675
676 return OBJ_PROP(obj);
677 }
678
679 /* ### USERLAND ### */
680
681 /* {{{ proto void HttpMessage::__construct([string message])
682 Create a new HttpMessage object instance. */
683 PHP_METHOD(HttpMessage, __construct)
684 {
685 int length = 0;
686 char *message = NULL;
687
688 getObject(http_message_object, obj);
689
690 SET_EH_THROW_HTTP();
691 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &message, &length) && message && length) {
692 http_message *msg = obj->message;
693
694 http_message_dtor(msg);
695 if ((obj->message = http_message_parse_ex(msg, message, length))) {
696 if (obj->message->parent) {
697 obj->parent = http_message_object_new_ex(Z_OBJCE_P(getThis()), obj->message->parent, NULL);
698 }
699 } else {
700 obj->message = http_message_init(msg);
701 }
702 }
703 if (!obj->message) {
704 obj->message = http_message_new();
705 }
706 SET_EH_NORMAL();
707 }
708 /* }}} */
709
710 /* {{{ proto static HttpMessage HttpMessage::factory([string raw_message[, string class_name = "HttpMessage"]])
711 Create a new HttpMessage object instance. */
712 PHP_METHOD(HttpMessage, factory)
713 {
714 char *string = NULL, *cn = NULL;
715 int length = 0, cl = 0;
716 http_message *msg = NULL;
717 zend_object_value ov;
718 http_message_object *obj = NULL;
719
720 RETVAL_NULL();
721
722 SET_EH_THROW_HTTP();
723 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ss", &string, &length, &cn, &cl)) {
724 if (length) {
725 msg = http_message_parse(string, length);
726 }
727 if ((msg || !length) && SUCCESS == http_object_new(&ov, cn, cl, _http_message_object_new_ex, http_message_object_ce, msg, &obj)) {
728 RETVAL_OBJVAL(ov, 0);
729 }
730 if (obj && !obj->message) {
731 obj->message = http_message_new();
732 }
733 }
734 SET_EH_NORMAL();
735 }
736 /* }}} */
737
738 /* {{{ proto string HttpMessage::getBody()
739 Get the body of the parsed HttpMessage. */
740 PHP_METHOD(HttpMessage, getBody)
741 {
742 NO_ARGS;
743
744 if (return_value_used) {
745 getObject(http_message_object, obj);
746 RETURN_PHPSTR(&obj->message->body, PHPSTR_FREE_NOT, 1);
747 }
748 }
749 /* }}} */
750
751 /* {{{ proto void HttpMessage::setBody(string body)
752 Set the body of the HttpMessage. NOTE: Don't forget to update any headers accordingly. */
753 PHP_METHOD(HttpMessage, setBody)
754 {
755 char *body;
756 int len;
757 getObject(http_message_object, obj);
758
759 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &body, &len)) {
760 phpstr_dtor(PHPSTR(obj->message));
761 phpstr_from_string_ex(PHPSTR(obj->message), body, len);
762 }
763 }
764 /* }}} */
765
766 /* {{{ proto string HttpMessage::getHeader(string header)
767 Get message header. */
768 PHP_METHOD(HttpMessage, getHeader)
769 {
770 zval *header;
771 char *orig_header, *nice_header;
772 int header_len;
773 getObject(http_message_object, obj);
774
775 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &orig_header, &header_len)) {
776 RETURN_FALSE;
777 }
778
779 nice_header = pretty_key(estrndup(orig_header, header_len), header_len, 1, 1);
780 if ((header = http_message_header_ex(obj->message, nice_header, header_len + 1, 0))) {
781 RETVAL_ZVAL(header, 1, 1);
782 }
783 efree(nice_header);
784 }
785 /* }}} */
786
787 /* {{{ proto array HttpMessage::getHeaders()
788 Get Message Headers. */
789 PHP_METHOD(HttpMessage, getHeaders)
790 {
791 NO_ARGS;
792
793 if (return_value_used) {
794 getObject(http_message_object, obj);
795
796 array_init(return_value);
797 array_copy(&obj->message->hdrs, Z_ARRVAL_P(return_value));
798 }
799 }
800 /* }}} */
801
802 /* {{{ proto void HttpMessage::setHeaders(array headers)
803 Sets new headers. */
804 PHP_METHOD(HttpMessage, setHeaders)
805 {
806 zval *new_headers = NULL;
807 getObject(http_message_object, obj);
808
809 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/!", &new_headers)) {
810 return;
811 }
812
813 zend_hash_clean(&obj->message->hdrs);
814 if (new_headers) {
815 array_copy(Z_ARRVAL_P(new_headers), &obj->message->hdrs);
816 }
817 }
818 /* }}} */
819
820 /* {{{ proto void HttpMessage::addHeaders(array headers[, bool append = false])
821 Add headers. If append is true, headers with the same name will be separated, else overwritten. */
822 PHP_METHOD(HttpMessage, addHeaders)
823 {
824 zval *new_headers;
825 zend_bool append = 0;
826 getObject(http_message_object, obj);
827
828 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|b", &new_headers, &append)) {
829 return;
830 }
831
832 array_join(Z_ARRVAL_P(new_headers), &obj->message->hdrs, append, ARRAY_JOIN_STRONLY|ARRAY_JOIN_PRETTIFY);
833 }
834 /* }}} */
835
836 /* {{{ proto int HttpMessage::getType()
837 Get Message Type. (HTTP_MSG_NONE|HTTP_MSG_REQUEST|HTTP_MSG_RESPONSE) */
838 PHP_METHOD(HttpMessage, getType)
839 {
840 NO_ARGS;
841
842 if (return_value_used) {
843 getObject(http_message_object, obj);
844 RETURN_LONG(obj->message->type);
845 }
846 }
847 /* }}} */
848
849 /* {{{ proto void HttpMessage::setType(int type)
850 Set Message Type. (HTTP_MSG_NONE|HTTP_MSG_REQUEST|HTTP_MSG_RESPONSE) */
851 PHP_METHOD(HttpMessage, setType)
852 {
853 long type;
854 getObject(http_message_object, obj);
855
856 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &type)) {
857 return;
858 }
859 http_message_set_type(obj->message, type);
860 }
861 /* }}} */
862
863 /* {{{ proto int HttpMessage::getResponseCode()
864 Get the Response Code of the Message. */
865 PHP_METHOD(HttpMessage, getResponseCode)
866 {
867 NO_ARGS;
868
869 if (return_value_used) {
870 getObject(http_message_object, obj);
871 HTTP_CHECK_MESSAGE_TYPE_RESPONSE(obj->message, RETURN_FALSE);
872 RETURN_LONG(obj->message->http.info.response.code);
873 }
874 }
875 /* }}} */
876
877 /* {{{ proto bool HttpMessage::setResponseCode(int code)
878 Set the response code of an HTTP Response Message. */
879 PHP_METHOD(HttpMessage, setResponseCode)
880 {
881 long code;
882 getObject(http_message_object, obj);
883
884 HTTP_CHECK_MESSAGE_TYPE_RESPONSE(obj->message, RETURN_FALSE);
885
886 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &code)) {
887 RETURN_FALSE;
888 }
889 if (code < 100 || code > 510) {
890 http_error_ex(HE_WARNING, HTTP_E_INVALID_PARAM, "Invalid response code (100-510): %ld", code);
891 RETURN_FALSE;
892 }
893
894 obj->message->http.info.response.code = code;
895 RETURN_TRUE;
896 }
897 /* }}} */
898
899 /* {{{ proto string HttpMessage::getResponseStatus()
900 Get the Response Status of the message (i.e. the string following the response code). */
901 PHP_METHOD(HttpMessage, getResponseStatus)
902 {
903 NO_ARGS;
904
905 if (return_value_used) {
906 getObject(http_message_object, obj);
907 HTTP_CHECK_MESSAGE_TYPE_RESPONSE(obj->message, RETURN_FALSE);
908 RETURN_STRING(obj->message->http.info.response.status, 1);
909 }
910 }
911 /* }}} */
912
913 /* {{{ proto bool HttpMessage::setResponseStatus(string status)
914 Set the Response Status of the HTTP message (i.e. the string following the response code). */
915 PHP_METHOD(HttpMessage, setResponseStatus)
916 {
917 char *status;
918 int status_len;
919 getObject(http_message_object, obj);
920
921 HTTP_CHECK_MESSAGE_TYPE_RESPONSE(obj->message, RETURN_FALSE);
922
923 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &status, &status_len)) {
924 RETURN_FALSE;
925 }
926 STR_SET(obj->message->http.info.response.status, estrdup(status));
927 RETURN_TRUE;
928 }
929 /* }}} */
930
931 /* {{{ proto string HttpMessage::getRequestMethod()
932 Get the Request Method of the Message. */
933 PHP_METHOD(HttpMessage, getRequestMethod)
934 {
935 NO_ARGS;
936
937 if (return_value_used) {
938 getObject(http_message_object, obj);
939 HTTP_CHECK_MESSAGE_TYPE_REQUEST(obj->message, RETURN_FALSE);
940 RETURN_STRING(obj->message->http.info.request.method, 1);
941 }
942 }
943 /* }}} */
944
945 /* {{{ proto bool HttpMessage::setRequestMethod(string method)
946 Set the Request Method of the HTTP Message. */
947 PHP_METHOD(HttpMessage, setRequestMethod)
948 {
949 char *method;
950 int method_len;
951 getObject(http_message_object, obj);
952
953 HTTP_CHECK_MESSAGE_TYPE_REQUEST(obj->message, RETURN_FALSE);
954
955 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &method, &method_len)) {
956 RETURN_FALSE;
957 }
958 if (method_len < 1) {
959 http_error(HE_WARNING, HTTP_E_INVALID_PARAM, "Cannot set HttpMessage::requestMethod to an empty string");
960 RETURN_FALSE;
961 }
962 if (!http_request_method_exists(1, 0, method)) {
963 http_error_ex(HE_WARNING, HTTP_E_REQUEST_METHOD, "Unknown request method: %s", method);
964 RETURN_FALSE;
965 }
966
967 STR_SET(obj->message->http.info.request.method, estrndup(method, method_len));
968 RETURN_TRUE;
969 }
970 /* }}} */
971
972 /* {{{ proto string HttpMessage::getRequestUrl()
973 Get the Request URL of the Message. */
974 PHP_METHOD(HttpMessage, getRequestUrl)
975 {
976 NO_ARGS;
977
978 if (return_value_used) {
979 getObject(http_message_object, obj);
980 HTTP_CHECK_MESSAGE_TYPE_REQUEST(obj->message, RETURN_FALSE);
981 RETURN_STRING(obj->message->http.info.request.url, 1);
982 }
983 }
984 /* }}} */
985
986 /* {{{ proto bool HttpMessage::setRequestUrl(string url)
987 Set the Request URL of the HTTP Message. */
988 PHP_METHOD(HttpMessage, setRequestUrl)
989 {
990 char *URI;
991 int URIlen;
992 getObject(http_message_object, obj);
993
994 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &URI, &URIlen)) {
995 RETURN_FALSE;
996 }
997 HTTP_CHECK_MESSAGE_TYPE_REQUEST(obj->message, RETURN_FALSE);
998 if (URIlen < 1) {
999 http_error(HE_WARNING, HTTP_E_INVALID_PARAM, "Cannot set HttpMessage::requestUrl to an empty string");
1000 RETURN_FALSE;
1001 }
1002
1003 STR_SET(obj->message->http.info.request.url, estrndup(URI, URIlen));
1004 RETURN_TRUE;
1005 }
1006 /* }}} */
1007
1008 /* {{{ proto string HttpMessage::getHttpVersion()
1009 Get the HTTP Protocol Version of the Message. */
1010 PHP_METHOD(HttpMessage, getHttpVersion)
1011 {
1012 NO_ARGS;
1013
1014 if (return_value_used) {
1015 char ver[4] = {0};
1016 getObject(http_message_object, obj);
1017
1018 sprintf(ver, "%1.1lf", obj->message->http.version);
1019 RETURN_STRINGL(ver, 3, 1);
1020 }
1021 }
1022 /* }}} */
1023
1024 /* {{{ proto bool HttpMessage::setHttpVersion(string version)
1025 Set the HTTP Protocol version of the Message. */
1026 PHP_METHOD(HttpMessage, setHttpVersion)
1027 {
1028 char v[4];
1029 zval *zv;
1030 getObject(http_message_object, obj);
1031
1032 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/", &zv)) {
1033 return;
1034 }
1035
1036 convert_to_double(zv);
1037 sprintf(v, "%1.1lf", Z_DVAL_P(zv));
1038 if (strcmp(v, "1.0") && strcmp(v, "1.1")) {
1039 http_error_ex(HE_WARNING, HTTP_E_INVALID_PARAM, "Invalid HTTP protocol version (1.0 or 1.1): %s", v);
1040 RETURN_FALSE;
1041 }
1042
1043 obj->message->http.version = Z_DVAL_P(zv);
1044 RETURN_TRUE;
1045 }
1046 /* }}} */
1047
1048 /* {{{ proto string HttpMessage::guessContentType(string magic_file[, int magic_mode = MAGIC_MIME])
1049 Attempts to guess the content type of supplied payload through libmagic. */
1050 PHP_METHOD(HttpMessage, guessContentType)
1051 {
1052 #ifdef HTTP_HAVE_MAGIC
1053 char *magic_file, *ct = NULL;
1054 int magic_file_len;
1055 long magic_mode = MAGIC_MIME;
1056
1057 RETVAL_FALSE;
1058 SET_EH_THROW_HTTP();
1059 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &magic_file, &magic_file_len, &magic_mode)) {
1060 getObject(http_message_object, obj);
1061 if ((ct = http_guess_content_type(magic_file, magic_mode, PHPSTR_VAL(&obj->message->body), PHPSTR_LEN(&obj->message->body), SEND_DATA))) {
1062 RETVAL_STRING(ct, 0);
1063 }
1064 }
1065 SET_EH_NORMAL();
1066 #else
1067 http_error(HE_THROW, HTTP_E_RUNTIME, "Cannot guess Content-Type; libmagic not available");
1068 RETURN_FALSE;
1069 #endif
1070 }
1071 /* }}} */
1072
1073 /* {{{ proto HttpMessage HttpMessage::getParentMessage()
1074 Get parent Message. */
1075 PHP_METHOD(HttpMessage, getParentMessage)
1076 {
1077 SET_EH_THROW_HTTP();
1078 NO_ARGS {
1079 getObject(http_message_object, obj);
1080
1081 if (obj->message->parent) {
1082 RETVAL_OBJVAL(obj->parent, 1);
1083 } else {
1084 http_error(HE_WARNING, HTTP_E_RUNTIME, "HttpMessage does not have a parent message");
1085 }
1086 }
1087 SET_EH_NORMAL();
1088 }
1089 /* }}} */
1090
1091 /* {{{ proto bool HttpMessage::send()
1092 Send the Message according to its type as Response or Request. */
1093 PHP_METHOD(HttpMessage, send)
1094 {
1095 getObject(http_message_object, obj);
1096
1097 NO_ARGS;
1098
1099 RETURN_SUCCESS(http_message_send(obj->message));
1100 }
1101 /* }}} */
1102
1103 /* {{{ proto string HttpMessage::toString([bool include_parent = false])
1104 Get the string representation of the Message. */
1105 PHP_METHOD(HttpMessage, toString)
1106 {
1107 if (return_value_used) {
1108 char *string;
1109 size_t length;
1110 zend_bool include_parent = 0;
1111 getObject(http_message_object, obj);
1112
1113 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &include_parent)) {
1114 RETURN_FALSE;
1115 }
1116
1117 if (include_parent) {
1118 http_message_serialize(obj->message, &string, &length);
1119 } else {
1120 http_message_tostring(obj->message, &string, &length);
1121 }
1122 RETURN_STRINGL(string, length, 0);
1123 }
1124 }
1125 /* }}} */
1126
1127 /* {{{ proto HttpRequest|HttpResponse HttpMessage::toMessageTypeObject(void)
1128 Creates an object regarding to the type of the message. Returns either an HttpRequest or HttpResponse object on success, or NULL on failure. */
1129 PHP_METHOD(HttpMessage, toMessageTypeObject)
1130 {
1131 SET_EH_THROW_HTTP();
1132
1133 NO_ARGS;
1134
1135 if (return_value_used) {
1136 getObject(http_message_object, obj);
1137
1138 switch (obj->message->type) {
1139 case HTTP_MSG_REQUEST:
1140 {
1141 #ifdef HTTP_HAVE_CURL
1142 int method;
1143 char *url;
1144 zval body, *array, *headers, *host = http_message_header(obj->message, "Host");
1145 php_url hurl, *purl = php_url_parse(obj->message->http.info.request.url);
1146
1147 MAKE_STD_ZVAL(array);
1148 array_init(array);
1149
1150 memset(&hurl, 0, sizeof(php_url));
1151 hurl.host = host ? Z_STRVAL_P(host) : NULL;
1152 zval_ptr_dtor(&host);
1153 http_build_url(HTTP_URL_REPLACE, purl, &hurl, NULL, &url, NULL);
1154 php_url_free(purl);
1155 add_assoc_string(array, "url", url, 0);
1156
1157 if ( (method = http_request_method_exists(1, 0, obj->message->http.info.request.method)) ||
1158 (method = http_request_method_register(obj->message->http.info.request.method, strlen(obj->message->http.info.request.method)))) {
1159 add_assoc_long(array, "method", method);
1160 }
1161
1162 if (10 == (int) (obj->message->http.version * 10)) {
1163 add_assoc_long(array, "protocol", CURL_HTTP_VERSION_1_0);
1164 }
1165
1166 MAKE_STD_ZVAL(headers);
1167 array_init(headers);
1168 array_copy(&obj->message->hdrs, Z_ARRVAL_P(headers));
1169 add_assoc_zval(array, "headers", headers);
1170
1171 object_init_ex(return_value, http_request_object_ce);
1172 zend_call_method_with_1_params(&return_value, http_request_object_ce, NULL, "setoptions", NULL, array);
1173 zval_ptr_dtor(&array);
1174
1175 INIT_PZVAL(&body);
1176 ZVAL_STRINGL(&body, PHPSTR_VAL(obj->message), PHPSTR_LEN(obj->message), 0);
1177 zend_call_method_with_1_params(&return_value, http_request_object_ce, NULL, "setrawpostdata", NULL, &body);
1178 #else
1179 http_error(HE_WARNING, HTTP_E_RUNTIME, "Cannot transform HttpMessage to HttpRequest (missing curl support)");
1180 #endif
1181 break;
1182 }
1183
1184 case HTTP_MSG_RESPONSE:
1185 {
1186 #ifndef WONKY
1187 HashPosition pos1, pos2;
1188 HashKey key = initHashKey(0);
1189 zval **header, **h, *body;
1190
1191 if (obj->message->http.info.response.code) {
1192 http_send_status(obj->message->http.info.response.code);
1193 }
1194
1195 object_init_ex(return_value, http_response_object_ce);
1196
1197 FOREACH_HASH_KEYVAL(pos1, &obj->message->hdrs, key, header) {
1198 if (key.type == HASH_KEY_IS_STRING) {
1199 zval *zkey;
1200
1201 MAKE_STD_ZVAL(zkey);
1202 ZVAL_STRINGL(zkey, key.str, key.len - 1, 1);
1203
1204 switch (Z_TYPE_PP(header)) {
1205 case IS_ARRAY:
1206 case IS_OBJECT:
1207 FOREACH_HASH_VAL(pos2, HASH_OF(*header), h) {
1208 ZVAL_ADDREF(*h);
1209 zend_call_method_with_2_params(&return_value, http_response_object_ce, NULL, "setheader", NULL, zkey, *h);
1210 zval_ptr_dtor(h);
1211 }
1212 break;
1213
1214 default:
1215 ZVAL_ADDREF(*header);
1216 zend_call_method_with_2_params(&return_value, http_response_object_ce, NULL, "setheader", NULL, zkey, *header);
1217 zval_ptr_dtor(header);
1218 break;
1219 }
1220 zval_ptr_dtor(&zkey);
1221 }
1222 }
1223
1224 MAKE_STD_ZVAL(body);
1225 ZVAL_STRINGL(body, PHPSTR_VAL(obj->message), PHPSTR_LEN(obj->message), 1);
1226 zend_call_method_with_1_params(&return_value, http_response_object_ce, NULL, "setdata", NULL, body);
1227 zval_ptr_dtor(&body);
1228 #else
1229 http_error(HE_WARNING, HTTP_E_RUNTIME, "Cannot transform HttpMessage to HttpResponse (need PHP 5.1+)");
1230 #endif
1231 break;
1232 }
1233
1234 default:
1235 http_error(HE_WARNING, HTTP_E_MESSAGE_TYPE, "HttpMessage is neither of type HttpMessage::TYPE_REQUEST nor HttpMessage::TYPE_RESPONSE");
1236 break;
1237 }
1238 }
1239 SET_EH_NORMAL();
1240 }
1241 /* }}} */
1242
1243 /* {{{ proto int HttpMessage::count()
1244 Implements Countable::count(). Returns the number of parent messages + 1. */
1245 PHP_METHOD(HttpMessage, count)
1246 {
1247 NO_ARGS {
1248 long i;
1249 getObject(http_message_object, obj);
1250
1251 http_message_count(i, obj->message);
1252 RETURN_LONG(i);
1253 }
1254 }
1255 /* }}} */
1256
1257 /* {{{ proto string HttpMessage::serialize()
1258 Implements Serializable::serialize(). Returns the serialized representation of the HttpMessage. */
1259 PHP_METHOD(HttpMessage, serialize)
1260 {
1261 NO_ARGS {
1262 char *string;
1263 size_t length;
1264 getObject(http_message_object, obj);
1265
1266 http_message_serialize(obj->message, &string, &length);
1267 RETURN_STRINGL(string, length, 0);
1268 }
1269 }
1270 /* }}} */
1271
1272 /* {{{ proto void HttpMessage::unserialize(string serialized)
1273 Implements Serializable::unserialize(). Re-constructs the HttpMessage based upon the serialized string. */
1274 PHP_METHOD(HttpMessage, unserialize)
1275 {
1276 int length;
1277 char *serialized;
1278 getObject(http_message_object, obj);
1279
1280 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &serialized, &length)) {
1281 http_message_dtor(obj->message);
1282 if (!http_message_parse_ex(obj->message, serialized, (size_t) length)) {
1283 http_error(HE_ERROR, HTTP_E_RUNTIME, "Could not unserialize HttpMessage");
1284 http_message_init(obj->message);
1285 }
1286 }
1287 }
1288 /* }}} */
1289
1290 /* {{{ proto HttpMessage HttpMessage::detach(void)
1291 Returns a clone of an HttpMessage object detached from any parent messages. */
1292 PHP_METHOD(HttpMessage, detach)
1293 {
1294 http_info info;
1295 http_message *msg;
1296 getObject(http_message_object, obj);
1297
1298 NO_ARGS;
1299
1300 info.type = obj->message->type;
1301 memcpy(&HTTP_INFO(&info), &HTTP_INFO(obj->message), sizeof(struct http_info));
1302
1303 msg = http_message_new();
1304 http_message_set_info(msg, &info);
1305
1306 zend_hash_copy(&msg->hdrs, &obj->message->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
1307 phpstr_append(&msg->body, PHPSTR_VAL(obj->message), PHPSTR_LEN(obj->message));
1308
1309 RETVAL_OBJVAL(http_message_object_new_ex(Z_OBJCE_P(getThis()), msg, NULL), 0);
1310 }
1311 /* }}} */
1312
1313 /* {{{ proto void HttpMessage::prepend(HttpMessage message[, bool top = true])
1314 Prepends message(s) to the HTTP message. Throws HttpInvalidParamException if the message is located within the same message chain. */
1315 PHP_METHOD(HttpMessage, prepend)
1316 {
1317 zval *prepend;
1318 zend_bool top = 1;
1319
1320 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|b", &prepend, http_message_object_ce, &top)) {
1321 http_message *msg[2];
1322 getObject(http_message_object, obj);
1323 getObjectEx(http_message_object, prepend_obj, prepend);
1324
1325 /* safety check */
1326 for (msg[0] = obj->message; msg[0]; msg[0] = msg[0]->parent) {
1327 for (msg[1] = prepend_obj->message; msg[1]; msg[1] = msg[1]->parent) {
1328 if (msg[0] == msg[1]) {
1329 http_error(HE_THROW, HTTP_E_INVALID_PARAM, "Cannot prepend a message located within the same message chain");
1330 return;
1331 }
1332 }
1333 }
1334
1335 http_message_object_prepend_ex(getThis(), prepend, top);
1336 }
1337 }
1338 /* }}} */
1339
1340 /* {{{ proto HttpMessage HttpMessage::reverse()
1341 Reorders the message chain in reverse order. Returns the most parent HttpMessage object. */
1342 PHP_METHOD(HttpMessage, reverse)
1343 {
1344 NO_ARGS {
1345 http_message_object_reverse(getThis(), return_value);
1346 }
1347 }
1348 /* }}} */
1349
1350 /* {{{ proto void HttpMessage::rewind(void)
1351 Implements Iterator::rewind(). */
1352 PHP_METHOD(HttpMessage, rewind)
1353 {
1354 NO_ARGS {
1355 getObject(http_message_object, obj);
1356
1357 if (obj->iterator) {
1358 zval_ptr_dtor(&obj->iterator);
1359 }
1360 ZVAL_ADDREF(getThis());
1361 obj->iterator = getThis();
1362 }
1363 }
1364 /* }}} */
1365
1366 /* {{{ proto bool HttpMessage::valid(void)
1367 Implements Iterator::valid(). */
1368 PHP_METHOD(HttpMessage, valid)
1369 {
1370 NO_ARGS {
1371 getObject(http_message_object, obj);
1372
1373 RETURN_BOOL(obj->iterator != NULL);
1374 }
1375 }
1376 /* }}} */
1377
1378 /* {{{ proto void HttpMessage::next(void)
1379 Implements Iterator::next(). */
1380 PHP_METHOD(HttpMessage, next)
1381 {
1382 NO_ARGS {
1383 getObject(http_message_object, obj);
1384 getObjectEx(http_message_object, itr, obj->iterator);
1385
1386 if (itr && itr->parent.handle) {
1387 zval *old = obj->iterator;
1388 MAKE_STD_ZVAL(obj->iterator);
1389 ZVAL_OBJVAL(obj->iterator, itr->parent, 1);
1390 zval_ptr_dtor(&old);
1391 } else {
1392 zval_ptr_dtor(&obj->iterator);
1393 obj->iterator = NULL;
1394 }
1395 }
1396 }
1397 /* }}} */
1398
1399 /* {{{ proto int HttpMessage::key(void)
1400 Implements Iterator::key(). */
1401 PHP_METHOD(HttpMessage, key)
1402 {
1403 NO_ARGS {
1404 getObject(http_message_object, obj);
1405
1406 RETURN_LONG(obj->iterator ? obj->iterator->value.obj.handle:0);
1407 }
1408 }
1409 /* }}} */
1410
1411 /* {{{ proto HttpMessage HttpMessage::current(void)
1412 Implements Iterator::current(). */
1413 PHP_METHOD(HttpMessage, current)
1414 {
1415 NO_ARGS {
1416 getObject(http_message_object, obj);
1417
1418 if (obj->iterator) {
1419 RETURN_ZVAL(obj->iterator, 1, 0);
1420 }
1421 }
1422 }
1423 /* }}} */
1424
1425 #endif /* ZEND_ENGINE_2 */
1426
1427 /*
1428 * Local variables:
1429 * tab-width: 4
1430 * c-basic-offset: 4
1431 * End:
1432 * vim600: noet sw=4 ts=4 fdm=marker
1433 * vim<600: noet sw=4 ts=4
1434 */
1435