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