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