- add HttpMessage::setRaw(), ::getBody(), ::getHeaders()
[m6w6/ext-http] / http_message_object.c
1 /*
2 +----------------------------------------------------------------------+
3 | PECL :: http |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.0 of the PHP license, that |
6 | is bundled with this package in the file LICENSE, and is available |
7 | through the world-wide-web at http://www.php.net/license/3_0.txt. |
8 | If you did not receive a copy of the PHP license and are unable to |
9 | obtain it through the world-wide-web, please send a note to |
10 | license@php.net so we can mail you a copy immediately. |
11 +----------------------------------------------------------------------+
12 | Copyright (c) 2004-2005 Michael Wallner <mike@php.net> |
13 +----------------------------------------------------------------------+
14 */
15
16 /* $Id$ */
17
18
19 #ifdef HAVE_CONFIG_H
20 # include "config.h"
21 #endif
22
23 #include "php.h"
24
25 #include "php_http.h"
26 #include "php_http_std_defs.h"
27 #include "php_http_message_object.h"
28
29 #ifdef ZEND_ENGINE_2
30
31 ZEND_EXTERN_MODULE_GLOBALS(http);
32
33 #define http_message_object_declare_default_properties() _http_message_object_declare_default_properties(TSRMLS_C)
34 static inline void _http_message_object_declare_default_properties(TSRMLS_D);
35 #define http_message_object_read_prop _http_message_object_read_prop
36 static zval *_http_message_object_read_prop(zval *object, zval *member, int type TSRMLS_DC);
37 #define http_message_object_write_prop _http_message_object_write_prop
38 static void _http_message_object_write_prop(zval *object, zval *member, zval *value TSRMLS_DC);
39 #define http_message_object_get_props _http_message_object_get_props
40 static HashTable *_http_message_object_get_props(zval *object TSRMLS_DC);
41
42 zend_class_entry *http_message_object_ce;
43 zend_function_entry http_message_object_fe[] = {
44 PHP_ME(HttpMessage, __construct, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
45 PHP_ME(HttpMessage, setRaw, NULL, ZEND_ACC_PUBLIC)
46 PHP_ME(HttpMessage, getBody, NULL, ZEND_ACC_PUBLIC)
47 PHP_ME(HttpMessage, getHeaders, NULL, ZEND_ACC_PUBLIC)
48 {NULL, NULL, NULL}
49 };
50 static zend_object_handlers http_message_object_handlers;
51
52 void _http_message_object_init(INIT_FUNC_ARGS)
53 {
54 HTTP_REGISTER_CLASS_EX(HttpMessage, http_message_object, NULL, 0);
55
56 http_message_object_handlers.read_property = http_message_object_read_prop;
57 http_message_object_handlers.write_property = http_message_object_write_prop;
58 http_message_object_handlers.get_properties = http_message_object_get_props;
59 }
60
61 zend_object_value _http_message_object_new(zend_class_entry *ce TSRMLS_DC)
62 {
63 zend_object_value ov;
64 http_message_object *o;
65
66 o = ecalloc(1, sizeof(http_message_object));
67 o->zo.ce = ce;
68 o->message = http_message_new();
69
70 ALLOC_HASHTABLE(OBJ_PROP(o));
71 zend_hash_init(OBJ_PROP(o), 0, NULL, ZVAL_PTR_DTOR, 0);
72
73 ov.handle = zend_objects_store_put(o, (zend_objects_store_dtor_t) zend_objects_destroy_object, http_message_object_free, NULL TSRMLS_CC);
74 ov.handlers = &http_message_object_handlers;
75
76 return ov;
77 }
78
79 static inline void _http_message_object_declare_default_properties(TSRMLS_D)
80 {
81 zend_class_entry *ce = http_message_object_ce;
82
83 DCL_PROP(PROTECTED, long, type, HTTP_MSG_NONE);
84
85 DCL_PROP(PROTECTED, string, raw, "");
86 DCL_PROP(PROTECTED, string, body, "");
87
88 DCL_PROP(PROTECTED, string, requestMethod, "");
89 DCL_PROP(PROTECTED, string, requestUri, "");
90 DCL_PROP(PROTECTED, long, responseStatus, 0);
91
92 DCL_PROP_N(PROTECTED, httpVersion);
93 DCL_PROP_N(PROTECTED, headers);
94 DCL_PROP_N(PROTECTED, nestedMessage);
95 }
96
97 static void _http_message_object_free(zend_object *object TSRMLS_DC)
98 {
99 http_message_object *o = (http_message_object *) object;
100
101 if (OBJ_PROP(o)) {
102 zend_hash_destroy(OBJ_PROP(o));
103 FREE_HASHTABLE(OBJ_PROP(o));
104 }
105 if (o->message) {
106 http_message_free(o->message);
107 }
108 efree(o);
109 }
110
111 static zval *_http_message_object_read_prop(zval *object, zval *member, int type TSRMLS_DC)
112 {
113 getObjectEx(http_message_object, obj, object);
114 http_message *msg = obj->message;
115 zval *return_value = &HTTP_G(message_object_tmp_property);
116
117 if (!EG(scope) || !instanceof_function(EG(scope), obj->zo.ce TSRMLS_CC)) {
118 zend_error(E_WARNING, "Cannot access protected property %s::$%s", obj->zo.ce->name, Z_STRVAL_P(member));
119 return EG(uninitialized_zval_ptr);
120 }
121
122 zval_dtor(return_value);
123
124 #if 0
125 fprintf(stderr, "Reading property: %s(%d==%d) (%lu)\n", Z_STRVAL_P(member), Z_STRLEN_P(member), strlen(Z_STRVAL_P(member)),
126 zend_get_hash_value(Z_STRVAL_P(member), strlen(Z_STRVAL_P(member)) + 1)
127 );
128 #endif
129
130 switch (zend_get_hash_value(Z_STRVAL_P(member), strlen(Z_STRVAL_P(member)) + 1))
131 {
132 case HTTP_MSG_PROPHASH_TYPE:
133 RETVAL_LONG(msg->type);
134 break;
135
136 case HTTP_MSG_PROPHASH_HTTP_VERSION:
137 switch (msg->type)
138 {
139 case HTTP_MSG_NONE:
140 RETVAL_NULL();
141 break;
142
143 case HTTP_MSG_REQUEST:
144 RETVAL_DOUBLE(msg->info.request.http_version);
145 break;
146
147 case HTTP_MSG_RESPONSE:
148 RETVAL_DOUBLE(msg->info.response.http_version);
149 break;
150 }
151 break;
152
153 case HTTP_MSG_PROPHASH_RAW:
154 if (msg->raw) {
155 if (msg->len) {
156 RETVAL_STRINGL(msg->raw, msg->len, 1);
157 } else {
158 RETVAL_STRINGL(empty_string, 0, 1);
159 }
160 } else {
161 RETVAL_NULL();
162 }
163 break;
164
165 case HTTP_MSG_PROPHASH_BODY:
166 phpstr_fix(PHPSTR(msg));
167 RETVAL_PHPSTR(PHPSTR(msg), 0, 1);
168 break;
169
170 case HTTP_MSG_PROPHASH_HEADERS:
171 array_init(return_value);
172 zend_hash_copy(Z_ARRVAL_P(return_value), &msg->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
173 break;
174
175 case HTTP_MSG_PROPHASH_NESTED_MESSAGE:
176 RETVAL_NULL();
177 break;
178
179 case HTTP_MSG_PROPHASH_REQUEST_METHOD:
180 if (msg->type == HTTP_MSG_REQUEST && msg->info.request.method) {
181 RETVAL_STRING(msg->info.request.method, 1);
182 } else {
183 RETVAL_NULL();
184 }
185 break;
186
187 case HTTP_MSG_PROPHASH_REQUEST_URI:
188 if (msg->type == HTTP_MSG_REQUEST && msg->info.request.URI) {
189 RETVAL_STRING(msg->info.request.URI, 1);
190 } else {
191 RETVAL_NULL();
192 }
193 break;
194
195 case HTTP_MSG_PROPHASH_RESPONSE_STATUS:
196 if (msg->type == HTTP_MSG_RESPONSE) {
197 RETVAL_LONG(msg->info.response.status);
198 } else {
199 RETVAL_NULL();
200 }
201 break;
202
203 default:
204 RETVAL_NULL();
205 break;
206 }
207
208 return return_value;
209 }
210
211 static void _http_message_object_write_prop(zval *object, zval *member, zval *value TSRMLS_DC)
212 {
213 getObjectEx(http_message_object, obj, object);
214 http_message *msg = obj->message;
215
216 if (!EG(scope) || !instanceof_function(EG(scope), obj->zo.ce TSRMLS_CC)) {
217 zend_error(E_WARNING, "Cannot access protected property %s::$%s", obj->zo.ce->name, Z_STRVAL_P(member));
218 }
219
220 #if 0
221 fprintf(stderr, "Writing property: %s(%d==%d) (%lu)\n", Z_STRVAL_P(member), Z_STRLEN_P(member), strlen(Z_STRVAL_P(member)),
222 zend_get_hash_value(Z_STRVAL_P(member), strlen(Z_STRVAL_P(member)) + 1)
223 );
224 #endif
225
226 switch (zend_get_hash_value(Z_STRVAL_P(member), strlen(Z_STRVAL_P(member)) + 1))
227 {
228 case HTTP_MSG_PROPHASH_TYPE:
229 msg->type = Z_LVAL_P(value);
230 break;
231
232 case HTTP_MSG_PROPHASH_HTTP_VERSION:
233 switch (msg->type)
234 {
235 case HTTP_MSG_REQUEST:
236 msg->info.request.http_version = (float) Z_DVAL_P(value);
237 break;
238
239 case HTTP_MSG_RESPONSE:
240 msg->info.response.http_version = (float) Z_DVAL_P(value);
241 break;
242 }
243 break;
244
245 case HTTP_MSG_PROPHASH_RAW:
246 http_message_dtor(msg);
247 http_message_parse_ex(msg, Z_STRVAL_P(value), Z_STRLEN_P(value), 1);
248 break;
249
250 case HTTP_MSG_PROPHASH_BODY:
251 phpstr_dtor(PHPSTR(msg));
252 phpstr_from_string_ex(PHPSTR(msg), Z_STRVAL_P(value), Z_STRLEN_P(value));
253 break;
254
255 case HTTP_MSG_PROPHASH_HEADERS:
256 zend_hash_clean(&msg->hdrs);
257 zend_hash_copy(&msg->hdrs, Z_ARRVAL_P(value), (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
258 break;
259
260 case HTTP_MSG_PROPHASH_NESTED_MESSAGE:
261 break;
262
263 case HTTP_MSG_PROPHASH_REQUEST_METHOD:
264 if (msg->type == HTTP_MSG_REQUEST) {
265 if (msg->info.request.method) {
266 efree(msg->info.request.method);
267 }
268 msg->info.request.method = estrndup(Z_STRVAL_P(value), Z_STRLEN_P(value));
269 }
270 break;
271
272 case HTTP_MSG_PROPHASH_REQUEST_URI:
273 if (msg->type == HTTP_MSG_REQUEST) {
274 if (msg->info.request.URI) {
275 efree(msg->info.request.URI);
276 }
277 msg->info.request.URI = estrndup(Z_STRVAL_P(value), Z_STRLEN_P(value));
278 }
279 break;
280
281 case HTTP_MSG_PROPHASH_RESPONSE_STATUS:
282 if (msg->type == HTTP_MSG_RESPONSE) {
283 msg->info.response.status = Z_LVAL_P(value);
284 }
285 break;
286 }
287 }
288
289 static HashTable *_http_message_object_get_props(zval *object TSRMLS_DC)
290 {
291 zval *headers;
292 getObjectEx(http_message_object, obj, object);
293 http_message *msg = obj->message;
294
295 #define ASSOC_PROP(obj, ptype, name, val) \
296 { \
297 zval array; \
298 char *m_prop_name; \
299 int m_prop_len; \
300 Z_ARRVAL(array) = OBJ_PROP(obj); \
301 zend_mangle_property_name(&m_prop_name, &m_prop_len, "*", 1, name, lenof(name), 1); \
302 add_assoc_ ##ptype## _ex(&array, m_prop_name, sizeof(name)+4, val); \
303 }
304 #define ASSOC_STRING(obj, name, val) ASSOC_STRINGL(obj, name, val, strlen(val))
305 #define ASSOC_STRINGL(obj, name, val, len) \
306 { \
307 zval array; \
308 char *m_prop_name; \
309 int m_prop_len; \
310 Z_ARRVAL(array) = OBJ_PROP(obj); \
311 zend_mangle_property_name(&m_prop_name, &m_prop_len, "*", 1, name, lenof(name), 1); \
312 add_assoc_stringl_ex(&array, m_prop_name, sizeof(name)+4, val, len, val != empty_string); \
313 }
314
315 zend_hash_clean(OBJ_PROP(obj));
316
317 ASSOC_PROP(obj, long, "type", msg->type);
318 ASSOC_STRINGL(obj, "raw", msg->raw, msg->len)
319 ASSOC_STRINGL(obj, "body", PHPSTR_VAL(msg), PHPSTR_LEN(msg));
320
321 MAKE_STD_ZVAL(headers);
322 array_init(headers);
323
324 zend_hash_copy(Z_ARRVAL_P(headers), &msg->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
325 ASSOC_PROP(obj, zval, "headers", headers);
326
327 switch (msg->type)
328 {
329 case HTTP_MSG_REQUEST:
330 ASSOC_PROP(obj, double, "httpVersion", msg->info.request.http_version);
331 ASSOC_PROP(obj, long, "responseStatus", 0);
332 ASSOC_STRING(obj, "requestMethod", msg->info.request.method);
333 ASSOC_STRING(obj, "requestUri", msg->info.request.URI);
334 break;
335
336 case HTTP_MSG_RESPONSE:
337 ASSOC_PROP(obj, double, "httpVersion", msg->info.response.http_version);
338 ASSOC_PROP(obj, long, "responseStatus", msg->info.response.status);
339 ASSOC_STRING(obj, "requestMethod", empty_string);
340 ASSOC_STRING(obj, "requestUri", empty_string);
341 break;
342
343 case HTTP_MSG_NONE:
344 default:
345 ASSOC_PROP(obj, double, "httpVersion", 0.0);
346 ASSOC_PROP(obj, long, "responseStatus", 0);
347 ASSOC_STRING(obj, "requestMethod", empty_string);
348 ASSOC_STRING(obj, "requestUri", empty_string);
349 break;
350 }
351
352 return OBJ_PROP(obj);
353 }
354
355 #endif /* ZEND_ENGINE_2 */
356
357 /*
358 * Local variables:
359 * tab-width: 4
360 * c-basic-offset: 4
361 * End:
362 * vim600: noet sw=4 ts=4 fdm=marker
363 * vim<600: noet sw=4 ts=4
364 */
365