9f5d3c14befa4e6608e8c2a6458405fb4343ce1d
[m6w6/ext-http] / http_response_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 #include "php.h"
23
24 #ifdef ZEND_ENGINE_2
25
26 #include "php_http.h"
27 #include "php_http_api.h"
28 #include "php_http_std_defs.h"
29 #include "php_http_response_object.h"
30 #include "php_http_send_api.h"
31 #include "php_http_cache_api.h"
32
33 #include "missing.h"
34
35 ZEND_EXTERN_MODULE_GLOBALS(http);
36
37 #define HTTP_BEGIN_ARGS(method, req_args) HTTP_BEGIN_ARGS_EX(HttpResponse, method, 0, req_args)
38 #define HTTP_EMPTY_ARGS(method, ret_ref) HTTP_EMPTY_ARGS_EX(HttpResponse, method, ret_ref)
39 #define HTTP_RESPONSE_ME(method, visibility) PHP_ME(HttpResponse, method, HTTP_ARGS(HttpResponse, method), visibility)
40
41 HTTP_EMPTY_ARGS(__destruct, 0);
42 HTTP_BEGIN_ARGS(__construct, 0)
43 HTTP_ARG_VAL(cache, 0)
44 HTTP_ARG_VAL(gzip, 0)
45 HTTP_END_ARGS;
46
47 HTTP_EMPTY_ARGS(getETag, 0);
48 HTTP_BEGIN_ARGS(setETag, 1)
49 HTTP_ARG_VAL(etag, 0)
50 HTTP_END_ARGS;
51
52 HTTP_EMPTY_ARGS(getCache, 0);
53 HTTP_BEGIN_ARGS(setCache, 1)
54 HTTP_ARG_VAL(cache, 0)
55 HTTP_END_ARGS;
56
57 HTTP_EMPTY_ARGS(getGzip, 0);
58 HTTP_BEGIN_ARGS(setGzip, 1)
59 HTTP_ARG_VAL(gzip, 0)
60 HTTP_END_ARGS;
61
62 HTTP_EMPTY_ARGS(getCacheControl, 0);
63 HTTP_BEGIN_ARGS(setCacheControl, 1)
64 HTTP_ARG_VAL(cache_control, 0)
65 HTTP_ARG_VAL(raw, 0)
66 HTTP_END_ARGS;
67
68 HTTP_EMPTY_ARGS(getContentType, 0);
69 HTTP_BEGIN_ARGS(setContentType, 1)
70 HTTP_ARG_VAL(content_type, 0)
71 HTTP_END_ARGS;
72
73 HTTP_EMPTY_ARGS(getContentDisposition, 0);
74 HTTP_BEGIN_ARGS(setContentDisposition, 1)
75 HTTP_ARG_VAL(filename, 0)
76 HTTP_ARG_VAL(send_inline, 0)
77 HTTP_END_ARGS;
78
79 HTTP_EMPTY_ARGS(getThrottleDelay, 0);
80 HTTP_BEGIN_ARGS(setThrottleDelay, 1)
81 HTTP_ARG_VAL(seconds, 0)
82 HTTP_END_ARGS;
83
84 HTTP_EMPTY_ARGS(getSendBuffersize, 0);
85 HTTP_BEGIN_ARGS(setSendBuffersize, 1)
86 HTTP_ARG_VAL(bytes, 0)
87 HTTP_END_ARGS;
88
89 HTTP_EMPTY_ARGS(getData, 0);
90 HTTP_BEGIN_ARGS(setData, 1)
91 HTTP_ARG_VAL(data, 0)
92 HTTP_END_ARGS;
93
94 HTTP_EMPTY_ARGS(getStream, 0);
95 HTTP_BEGIN_ARGS(setStream, 1)
96 HTTP_ARG_VAL(stream, 0)
97 HTTP_END_ARGS;
98
99 HTTP_EMPTY_ARGS(getFile, 0);
100 HTTP_BEGIN_ARGS(setFile, 1)
101 HTTP_ARG_VAL(filepath, 0)
102 HTTP_END_ARGS;
103
104 HTTP_BEGIN_ARGS(send, 0)
105 HTTP_ARG_VAL(clean_ob, 0)
106 HTTP_END_ARGS;
107
108 HTTP_BEGIN_ARGS(catchOutput, 0)
109 HTTP_ARG_VAL(clean_ob, 0)
110 HTTP_END_ARGS;
111
112 #define http_response_object_declare_default_properties() _http_response_object_declare_default_properties(TSRMLS_C)
113 static inline void _http_response_object_declare_default_properties(TSRMLS_D);
114
115 zend_class_entry *http_response_object_ce;
116 zend_function_entry http_response_object_fe[] = {
117 HTTP_RESPONSE_ME(__construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
118 HTTP_RESPONSE_ME(__destruct, ZEND_ACC_PUBLIC|ZEND_ACC_DTOR)
119
120 HTTP_RESPONSE_ME(setETag, ZEND_ACC_PUBLIC)
121 HTTP_RESPONSE_ME(getETag, ZEND_ACC_PUBLIC)
122
123 HTTP_RESPONSE_ME(setContentDisposition, ZEND_ACC_PUBLIC)
124 HTTP_RESPONSE_ME(getContentDisposition, ZEND_ACC_PUBLIC)
125
126 HTTP_RESPONSE_ME(setContentType, ZEND_ACC_PUBLIC)
127 HTTP_RESPONSE_ME(getContentType, ZEND_ACC_PUBLIC)
128
129 HTTP_RESPONSE_ME(setCache, ZEND_ACC_PUBLIC)
130 HTTP_RESPONSE_ME(getCache, ZEND_ACC_PUBLIC)
131
132 HTTP_RESPONSE_ME(setCacheControl, ZEND_ACC_PUBLIC)
133 HTTP_RESPONSE_ME(getCacheControl, ZEND_ACC_PUBLIC)
134
135 HTTP_RESPONSE_ME(setGzip, ZEND_ACC_PUBLIC)
136 HTTP_RESPONSE_ME(getGzip, ZEND_ACC_PUBLIC)
137
138 HTTP_RESPONSE_ME(setThrottleDelay, ZEND_ACC_PUBLIC)
139 HTTP_RESPONSE_ME(getThrottleDelay, ZEND_ACC_PUBLIC)
140
141 HTTP_RESPONSE_ME(setSendBuffersize, ZEND_ACC_PUBLIC)
142 HTTP_RESPONSE_ME(getSendBuffersize, ZEND_ACC_PUBLIC)
143
144 HTTP_RESPONSE_ME(setData, ZEND_ACC_PUBLIC)
145 HTTP_RESPONSE_ME(getData, ZEND_ACC_PUBLIC)
146
147 HTTP_RESPONSE_ME(setFile, ZEND_ACC_PUBLIC)
148 HTTP_RESPONSE_ME(getFile, ZEND_ACC_PUBLIC)
149
150 HTTP_RESPONSE_ME(setStream, ZEND_ACC_PUBLIC)
151 HTTP_RESPONSE_ME(getStream, ZEND_ACC_PUBLIC)
152
153 HTTP_RESPONSE_ME(send, ZEND_ACC_PUBLIC)
154 HTTP_RESPONSE_ME(catchOutput, ZEND_ACC_PUBLIC)
155
156 {NULL, NULL, NULL}
157 };
158 static zend_object_handlers http_response_object_handlers;
159
160 void _http_response_object_init(INIT_FUNC_ARGS)
161 {
162 HTTP_REGISTER_CLASS_EX(HttpResponse, http_response_object, NULL, 0);
163 }
164
165 zend_object_value _http_response_object_new(zend_class_entry *ce TSRMLS_DC)
166 {
167 zend_object_value ov;
168 http_response_object *o;
169
170 o = ecalloc(1, sizeof(http_response_object));
171 o->zo.ce = ce;
172
173 ALLOC_HASHTABLE(OBJ_PROP(o));
174 zend_hash_init(OBJ_PROP(o), 0, NULL, ZVAL_PTR_DTOR, 0);
175 zend_hash_copy(OBJ_PROP(o), &ce->default_properties, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
176
177 ov.handle = zend_objects_store_put(o, (zend_objects_store_dtor_t) zend_objects_destroy_object, http_response_object_free, NULL TSRMLS_CC);
178 ov.handlers = &http_response_object_handlers;
179
180 return ov;
181 }
182
183 static inline void _http_response_object_declare_default_properties(TSRMLS_D)
184 {
185 zend_class_entry *ce = http_response_object_ce;
186
187 DCL_PROP(PROTECTED, string, contentType, "application/x-octetstream");
188 DCL_PROP(PROTECTED, string, eTag, "");
189 DCL_PROP(PROTECTED, string, dispoFile, "");
190 DCL_PROP(PROTECTED, string, cacheControl, "public");
191 DCL_PROP(PROTECTED, string, data, "");
192 DCL_PROP(PROTECTED, string, file, "");
193 DCL_PROP(PROTECTED, long, stream, 0);
194 DCL_PROP(PROTECTED, long, lastModified, 0);
195 DCL_PROP(PROTECTED, long, dispoInline, 0);
196 DCL_PROP(PROTECTED, long, cache, 0);
197 DCL_PROP(PROTECTED, long, gzip, 0);
198 DCL_PROP(PROTECTED, long, sendBuffersize, HTTP_SENDBUF_SIZE);
199 DCL_PROP(PROTECTED, double, throttleDelay, 0.0);
200
201 DCL_PROP(PRIVATE, long, raw_cache_header, 0);
202 DCL_PROP(PRIVATE, long, send_mode, -1);
203 DCL_PROP(PRIVATE, long, sent, 0);
204 DCL_PROP(PRIVATE, long, catch_ob, 0);
205 }
206
207 void _http_response_object_free(zend_object *object TSRMLS_DC)
208 {
209 http_response_object *o = (http_response_object *) object;
210
211 if (OBJ_PROP(o)) {
212 zend_hash_destroy(OBJ_PROP(o));
213 FREE_HASHTABLE(OBJ_PROP(o));
214 }
215 efree(o);
216 }
217
218 void _http_response_object_sendhandler(zval *this_ptr, http_response_object *obj, zend_bool clean_ob, zval *return_value TSRMLS_DC)
219 {
220 zval *do_cache, *do_gzip;
221
222 if (!obj) {
223 getObject(http_response_object, o);
224 obj = o;
225 }
226
227 do_cache = GET_PROP(obj, cache);
228 do_gzip = GET_PROP(obj, gzip);
229
230 if (clean_ob) {
231 /* interrupt on-the-fly etag generation */
232 HTTP_G(etag).started = 0;
233 /* discard previous output buffers */
234 php_end_ob_buffers(0 TSRMLS_CC);
235 }
236
237 /* gzip */
238 if (Z_LVAL_P(do_gzip)) {
239 php_start_ob_buffer_named("ob_gzhandler", 0, 1 TSRMLS_CC);
240 }
241
242 /* caching */
243 if (Z_LVAL_P(do_cache)) {
244 char *cc_hdr;
245 int cc_len;
246 zval *cctrl, *etag, *lmod, *ccraw;
247
248 etag = GET_PROP(obj, eTag);
249 lmod = GET_PROP(obj, lastModified);
250 cctrl = GET_PROP(obj, cacheControl);
251 ccraw = GET_PROP(obj, raw_cache_header);
252
253 if (Z_LVAL_P(ccraw)) {
254 cc_hdr = Z_STRVAL_P(cctrl);
255 cc_len = Z_STRLEN_P(cctrl);
256 } else {
257 char cc_header[42] = {0};
258 sprintf(cc_header, "%s, must-revalidate, max-age=0", Z_STRVAL_P(cctrl));
259 cc_hdr = cc_header;
260 cc_len = Z_STRLEN_P(cctrl) + lenof(", must-revalidate, max-age=0");
261 }
262
263 http_cache_etag(Z_STRVAL_P(etag), Z_STRLEN_P(etag), cc_hdr, cc_len);
264 http_cache_last_modified(Z_LVAL_P(lmod), Z_LVAL_P(lmod) ? Z_LVAL_P(lmod) : time(NULL), cc_hdr, cc_len);
265 }
266
267 /* content type */
268 {
269 zval *ctype = GET_PROP(obj, contentType);
270 if (Z_STRLEN_P(ctype)) {
271 http_send_content_type(Z_STRVAL_P(ctype), Z_STRLEN_P(ctype));
272 } else {
273 http_send_content_type("application/x-octetstream", lenof("application/x-octetstream"));
274 }
275 }
276
277 /* content disposition */
278 {
279 zval *dispo_file = GET_PROP(obj, dispoFile);
280 if (Z_STRLEN_P(dispo_file)) {
281 zval *dispo_inline = GET_PROP(obj, dispoInline);
282 http_send_content_disposition(Z_STRVAL_P(dispo_file), Z_STRLEN_P(dispo_file), (zend_bool) Z_LVAL_P(dispo_inline));
283 }
284 }
285
286 /* throttling */
287 {
288 zval *send_buffersize, *throttle_delay;
289 send_buffersize = GET_PROP(obj, sendBuffersize);
290 throttle_delay = GET_PROP(obj, throttleDelay);
291 HTTP_G(send).buffer_size = Z_LVAL_P(send_buffersize);
292 HTTP_G(send).throttle_delay = Z_DVAL_P(throttle_delay);
293 }
294
295 /* send */
296 {
297 zval *send_mode = GET_PROP(obj, send_mode);
298 switch (Z_LVAL_P(send_mode))
299 {
300 case SEND_DATA:
301 {
302 zval *zdata = GET_PROP(obj, data);
303 RETURN_SUCCESS(http_send_data(Z_STRVAL_P(zdata), Z_STRLEN_P(zdata)));
304 }
305
306 case SEND_RSRC:
307 {
308 php_stream *the_real_stream;
309 zval *the_stream = GET_PROP(obj, stream);
310 php_stream_from_zval(the_real_stream, &the_stream);
311 RETURN_SUCCESS(http_send_stream(the_real_stream));
312 }
313
314 default:
315 {
316 zval *zfile = GET_PROP(obj, file);
317 RETURN_SUCCESS(http_send_file(Z_STRVAL_P(zfile)));
318 }
319 }
320 }
321 }
322
323 #endif /* ZEND_ENGINE_2 */
324
325 /*
326 * Local variables:
327 * tab-width: 4
328 * c-basic-offset: 4
329 * End:
330 * vim600: noet sw=4 ts=4 fdm=marker
331 * vim<600: noet sw=4 ts=4
332 */
333