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