Added postredir request options constants
[m6w6/ext-http] / http_response_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-2007, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
11 */
12
13 /* $Id$ */
14
15 #define HTTP_WANT_SAPI
16 #define HTTP_WANT_MAGIC
17 #include "php_http.h"
18
19 /* broken static properties in PHP 5.0 */
20 #if defined(ZEND_ENGINE_2) && !defined(WONKY)
21
22 #include "php_ini.h"
23
24 #include "php_http_api.h"
25 #include "php_http_cache_api.h"
26 #include "php_http_exception_object.h"
27 #include "php_http_headers_api.h"
28 #include "php_http_response_object.h"
29 #include "php_http_send_api.h"
30
31 #define HTTP_BEGIN_ARGS(method, req_args) HTTP_BEGIN_ARGS_EX(HttpResponse, method, 0, req_args)
32 #define HTTP_EMPTY_ARGS(method) HTTP_EMPTY_ARGS_EX(HttpResponse, method, 0)
33 #define HTTP_RESPONSE_ME(method, visibility) PHP_ME(HttpResponse, method, HTTP_ARGS(HttpResponse, method), visibility|ZEND_ACC_STATIC)
34 #define HTTP_RESPONSE_ALIAS(method, func) HTTP_STATIC_ME_ALIAS(method, func, HTTP_ARGS(HttpResponse, method))
35
36 HTTP_BEGIN_ARGS(setHeader, 1)
37 HTTP_ARG_VAL(name, 0)
38 HTTP_ARG_VAL(value, 0)
39 HTTP_ARG_VAL(replace, 0)
40 HTTP_END_ARGS;
41
42 HTTP_BEGIN_ARGS(getHeader, 0)
43 HTTP_ARG_VAL(name, 0)
44 HTTP_END_ARGS;
45
46 HTTP_EMPTY_ARGS(getETag);
47 HTTP_BEGIN_ARGS(setETag, 1)
48 HTTP_ARG_VAL(etag, 0)
49 HTTP_END_ARGS;
50
51 HTTP_EMPTY_ARGS(getLastModified);
52 HTTP_BEGIN_ARGS(setLastModified, 1)
53 HTTP_ARG_VAL(timestamp, 0)
54 HTTP_END_ARGS;
55
56 HTTP_EMPTY_ARGS(getCache);
57 HTTP_BEGIN_ARGS(setCache, 1)
58 HTTP_ARG_VAL(cache, 0)
59 HTTP_END_ARGS;
60
61 HTTP_EMPTY_ARGS(getGzip);
62 HTTP_BEGIN_ARGS(setGzip, 1)
63 HTTP_ARG_VAL(gzip, 0)
64 HTTP_END_ARGS;
65
66 HTTP_EMPTY_ARGS(getCacheControl);
67 HTTP_BEGIN_ARGS(setCacheControl, 1)
68 HTTP_ARG_VAL(cache_control, 0)
69 HTTP_ARG_VAL(max_age, 0)
70 HTTP_ARG_VAL(must_revalidate, 0)
71 HTTP_END_ARGS;
72
73 HTTP_EMPTY_ARGS(getContentType);
74 HTTP_BEGIN_ARGS(setContentType, 1)
75 HTTP_ARG_VAL(content_type, 0)
76 HTTP_END_ARGS;
77
78 HTTP_BEGIN_ARGS(guessContentType, 1)
79 HTTP_ARG_VAL(magic_file, 0)
80 HTTP_ARG_VAL(magic_mode, 0)
81 HTTP_END_ARGS;
82
83 HTTP_EMPTY_ARGS(getContentDisposition);
84 HTTP_BEGIN_ARGS(setContentDisposition, 1)
85 HTTP_ARG_VAL(filename, 0)
86 HTTP_ARG_VAL(send_inline, 0)
87 HTTP_END_ARGS;
88
89 HTTP_EMPTY_ARGS(getThrottleDelay);
90 HTTP_BEGIN_ARGS(setThrottleDelay, 1)
91 HTTP_ARG_VAL(seconds, 0)
92 HTTP_END_ARGS;
93
94 HTTP_EMPTY_ARGS(getBufferSize);
95 HTTP_BEGIN_ARGS(setBufferSize, 1)
96 HTTP_ARG_VAL(bytes, 0)
97 HTTP_END_ARGS;
98
99 HTTP_EMPTY_ARGS(getData);
100 HTTP_BEGIN_ARGS(setData, 1)
101 HTTP_ARG_VAL(data, 0)
102 HTTP_END_ARGS;
103
104 HTTP_EMPTY_ARGS(getStream);
105 HTTP_BEGIN_ARGS(setStream, 1)
106 HTTP_ARG_VAL(stream, 0)
107 HTTP_END_ARGS;
108
109 HTTP_EMPTY_ARGS(getFile);
110 HTTP_BEGIN_ARGS(setFile, 1)
111 HTTP_ARG_VAL(filepath, 0)
112 HTTP_END_ARGS;
113
114 HTTP_BEGIN_ARGS(send, 0)
115 HTTP_ARG_VAL(clean_ob, 0)
116 HTTP_END_ARGS;
117
118 HTTP_EMPTY_ARGS(capture);
119
120 HTTP_BEGIN_ARGS(redirect, 0)
121 HTTP_ARG_VAL(url, 0)
122 HTTP_ARG_VAL(params, 0)
123 HTTP_ARG_VAL(session, 0)
124 HTTP_ARG_VAL(permanent, 0)
125 HTTP_END_ARGS;
126
127 HTTP_BEGIN_ARGS(status, 1)
128 HTTP_ARG_VAL(code, 0)
129 HTTP_END_ARGS;
130
131 HTTP_EMPTY_ARGS(getRequestHeaders);
132 HTTP_EMPTY_ARGS(getRequestBody);
133 HTTP_EMPTY_ARGS(getRequestBodyStream);
134
135 #define THIS_CE http_response_object_ce
136 zend_class_entry *http_response_object_ce;
137 zend_function_entry http_response_object_fe[] = {
138
139 HTTP_RESPONSE_ME(setHeader, ZEND_ACC_PUBLIC)
140 HTTP_RESPONSE_ME(getHeader, ZEND_ACC_PUBLIC)
141
142 HTTP_RESPONSE_ME(setETag, ZEND_ACC_PUBLIC)
143 HTTP_RESPONSE_ME(getETag, ZEND_ACC_PUBLIC)
144
145 HTTP_RESPONSE_ME(setLastModified, ZEND_ACC_PUBLIC)
146 HTTP_RESPONSE_ME(getLastModified, ZEND_ACC_PUBLIC)
147
148 HTTP_RESPONSE_ME(setContentDisposition, ZEND_ACC_PUBLIC)
149 HTTP_RESPONSE_ME(getContentDisposition, ZEND_ACC_PUBLIC)
150
151 HTTP_RESPONSE_ME(setContentType, ZEND_ACC_PUBLIC)
152 HTTP_RESPONSE_ME(getContentType, ZEND_ACC_PUBLIC)
153
154 HTTP_RESPONSE_ME(guessContentType, ZEND_ACC_PUBLIC)
155
156 HTTP_RESPONSE_ME(setCache, ZEND_ACC_PUBLIC)
157 HTTP_RESPONSE_ME(getCache, ZEND_ACC_PUBLIC)
158
159 HTTP_RESPONSE_ME(setCacheControl, ZEND_ACC_PUBLIC)
160 HTTP_RESPONSE_ME(getCacheControl, ZEND_ACC_PUBLIC)
161
162 HTTP_RESPONSE_ME(setGzip, ZEND_ACC_PUBLIC)
163 HTTP_RESPONSE_ME(getGzip, ZEND_ACC_PUBLIC)
164
165 HTTP_RESPONSE_ME(setThrottleDelay, ZEND_ACC_PUBLIC)
166 HTTP_RESPONSE_ME(getThrottleDelay, ZEND_ACC_PUBLIC)
167
168 HTTP_RESPONSE_ME(setBufferSize, ZEND_ACC_PUBLIC)
169 HTTP_RESPONSE_ME(getBufferSize, ZEND_ACC_PUBLIC)
170
171 HTTP_RESPONSE_ME(setData, ZEND_ACC_PUBLIC)
172 HTTP_RESPONSE_ME(getData, ZEND_ACC_PUBLIC)
173
174 HTTP_RESPONSE_ME(setFile, ZEND_ACC_PUBLIC)
175 HTTP_RESPONSE_ME(getFile, ZEND_ACC_PUBLIC)
176
177 HTTP_RESPONSE_ME(setStream, ZEND_ACC_PUBLIC)
178 HTTP_RESPONSE_ME(getStream, ZEND_ACC_PUBLIC)
179
180 HTTP_RESPONSE_ME(send, ZEND_ACC_PUBLIC)
181 HTTP_RESPONSE_ME(capture, ZEND_ACC_PUBLIC)
182
183 HTTP_RESPONSE_ALIAS(redirect, http_redirect)
184 HTTP_RESPONSE_ALIAS(status, http_send_status)
185 HTTP_RESPONSE_ALIAS(getRequestHeaders, http_get_request_headers)
186 HTTP_RESPONSE_ALIAS(getRequestBody, http_get_request_body)
187 HTTP_RESPONSE_ALIAS(getRequestBodyStream, http_get_request_body_stream)
188
189 EMPTY_FUNCTION_ENTRY
190 };
191
192 PHP_MINIT_FUNCTION(http_response_object)
193 {
194 HTTP_REGISTER_CLASS(HttpResponse, http_response_object, NULL, 0);
195
196 zend_declare_property_bool(THIS_CE, ZEND_STRS("sent")-1, 0, (ZEND_ACC_STATIC|ZEND_ACC_PRIVATE) TSRMLS_CC);
197 zend_declare_property_bool(THIS_CE, ZEND_STRS("catch")-1, 0, (ZEND_ACC_STATIC|ZEND_ACC_PRIVATE) TSRMLS_CC);
198 zend_declare_property_long(THIS_CE, ZEND_STRS("mode")-1, -1, (ZEND_ACC_STATIC|ZEND_ACC_PRIVATE) TSRMLS_CC);
199 zend_declare_property_long(THIS_CE, ZEND_STRS("stream")-1, 0, (ZEND_ACC_STATIC|ZEND_ACC_PRIVATE) TSRMLS_CC);
200 zend_declare_property_null(THIS_CE, ZEND_STRS("file")-1, (ZEND_ACC_STATIC|ZEND_ACC_PRIVATE) TSRMLS_CC);
201 zend_declare_property_null(THIS_CE, ZEND_STRS("data")-1, (ZEND_ACC_STATIC|ZEND_ACC_PRIVATE) TSRMLS_CC);
202 zend_declare_property_bool(THIS_CE, ZEND_STRS("cache")-1, 0, (ZEND_ACC_STATIC|ZEND_ACC_PROTECTED) TSRMLS_CC);
203 zend_declare_property_bool(THIS_CE, ZEND_STRS("gzip")-1, 0, (ZEND_ACC_STATIC|ZEND_ACC_PROTECTED) TSRMLS_CC);
204 zend_declare_property_null(THIS_CE, ZEND_STRS("eTag")-1, (ZEND_ACC_STATIC|ZEND_ACC_PROTECTED) TSRMLS_CC);
205 zend_declare_property_long(THIS_CE, ZEND_STRS("lastModified")-1, 0, (ZEND_ACC_STATIC|ZEND_ACC_PROTECTED) TSRMLS_CC);
206 zend_declare_property_null(THIS_CE, ZEND_STRS("cacheControl")-1, (ZEND_ACC_STATIC|ZEND_ACC_PROTECTED) TSRMLS_CC);
207 zend_declare_property_null(THIS_CE, ZEND_STRS("contentType")-1, (ZEND_ACC_STATIC|ZEND_ACC_PROTECTED) TSRMLS_CC);
208 zend_declare_property_null(THIS_CE, ZEND_STRS("contentDisposition")-1, (ZEND_ACC_STATIC|ZEND_ACC_PROTECTED) TSRMLS_CC);
209 zend_declare_property_long(THIS_CE, ZEND_STRS("bufferSize")-1, 0, (ZEND_ACC_STATIC|ZEND_ACC_PROTECTED) TSRMLS_CC);
210 zend_declare_property_double(THIS_CE, ZEND_STRS("throttleDelay")-1, 0.0, (ZEND_ACC_STATIC|ZEND_ACC_PROTECTED) TSRMLS_CC);
211
212 #ifndef WONKY
213 zend_declare_class_constant_long(THIS_CE, ZEND_STRS("REDIRECT")-1, HTTP_REDIRECT TSRMLS_CC);
214 zend_declare_class_constant_long(THIS_CE, ZEND_STRS("REDIRECT_PERM")-1, HTTP_REDIRECT_PERM TSRMLS_CC);
215 zend_declare_class_constant_long(THIS_CE, ZEND_STRS("REDIRECT_FOUND")-1, HTTP_REDIRECT_FOUND TSRMLS_CC);
216 zend_declare_class_constant_long(THIS_CE, ZEND_STRS("REDIRECT_POST")-1, HTTP_REDIRECT_POST TSRMLS_CC);
217 zend_declare_class_constant_long(THIS_CE, ZEND_STRS("REDIRECT_PROXY")-1, HTTP_REDIRECT_PROXY TSRMLS_CC);
218 zend_declare_class_constant_long(THIS_CE, ZEND_STRS("REDIRECT_TEMP")-1, HTTP_REDIRECT_TEMP TSRMLS_CC);
219 #endif /* WONKY */
220
221 return SUCCESS;
222 }
223
224 /* ### USERLAND ### */
225
226 /* {{{ proto static bool HttpResponse::setHeader(string name[, mixed value[, bool replace = true]])
227 Send an HTTP header. */
228 PHP_METHOD(HttpResponse, setHeader)
229 {
230 zend_bool replace = 1;
231 char *name;
232 int name_len = 0;
233 zval *value = NULL;
234
235 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z/!b", &name, &name_len, &value, &replace)) {
236 RETURN_FALSE;
237 }
238 if (SG(headers_sent)) {
239 http_error(HE_WARNING, HTTP_E_HEADER, "Cannot add another header when headers have already been sent");
240 RETURN_FALSE;
241 }
242 if (!name_len) {
243 http_error(HE_WARNING, HTTP_E_HEADER, "Cannot send anonymous headers");
244 RETURN_FALSE;
245 }
246 http_send_header_zval_ex(name, name_len, &value, replace);
247 RETURN_TRUE;
248 }
249 /* }}} */
250
251 /* {{{ proto static mixed HttpResponse::getHeader([string name])
252 Get header(s) about to be sent. */
253 PHP_METHOD(HttpResponse, getHeader)
254 {
255 char *name = NULL;
256 int name_len = 0;
257
258 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &name, &name_len)) {
259 RETURN_FALSE;
260 }
261
262 if (name && name_len) {
263 zval **header;
264 HashTable headers_ht;
265
266 zend_hash_init(&headers_ht, sizeof(zval *), NULL, ZVAL_PTR_DTOR, 0);
267 if ( (SUCCESS == http_get_response_headers(&headers_ht)) &&
268 (SUCCESS == zend_hash_find(&headers_ht, name, name_len + 1, (void *) &header))) {
269 RETVAL_ZVAL(*header, 1, 0);
270 } else {
271 RETVAL_NULL();
272 }
273 zend_hash_destroy(&headers_ht);
274 } else {
275 array_init(return_value);
276 http_get_response_headers(Z_ARRVAL_P(return_value));
277 }
278 }
279 /* }}} */
280
281 /* {{{ proto static bool HttpResponse::setCache(bool cache)
282 Whether it should be attempted to cache the entity. */
283 PHP_METHOD(HttpResponse, setCache)
284 {
285 zend_bool do_cache = 0;
286
287 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "b", &do_cache)) {
288 RETURN_FALSE;
289 }
290
291 RETURN_SUCCESS(zend_update_static_property_bool(THIS_CE, ZEND_STRS("cache")-1, do_cache TSRMLS_CC));
292 }
293 /* }}} */
294
295 /* {{{ proto static bool HttpResponse::getCache()
296 Get current caching setting. */
297 PHP_METHOD(HttpResponse, getCache)
298 {
299 NO_ARGS;
300
301 if (return_value_used) {
302 zval *cache = http_zsep(IS_BOOL, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("cache")-1, 0 TSRMLS_CC)));
303 RETVAL_ZVAL(cache, 1, 1);
304 }
305 }
306 /* }}}*/
307
308 /* {{{ proto static bool HttpResponse::setGzip(bool gzip)
309 Enable on-thy-fly gzipping of the sent entity. */
310 PHP_METHOD(HttpResponse, setGzip)
311 {
312 zend_bool do_gzip = 0;
313
314 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "b", &do_gzip)) {
315 RETURN_FALSE;
316 }
317
318 RETURN_SUCCESS(zend_update_static_property_bool(THIS_CE, ZEND_STRS("gzip")-1, do_gzip TSRMLS_CC));
319 }
320 /* }}} */
321
322 /* {{{ proto static bool HttpResponse::getGzip()
323 Get current gzipping setting. */
324 PHP_METHOD(HttpResponse, getGzip)
325 {
326 NO_ARGS;
327
328 if (return_value_used) {
329 zval *gzip = http_zsep(IS_BOOL, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("gzip")-1, 0 TSRMLS_CC)));
330 RETVAL_ZVAL(gzip, 1, 1);
331 }
332 }
333 /* }}} */
334
335 /* {{{ proto static bool HttpResponse::setCacheControl(string control[, int max_age = 0[, bool must_revalidate = true]])
336 Set a custom cache-control header, usually being "private" or "public"; The max_age parameter controls how long the cache entry is valid on the client side. */
337 PHP_METHOD(HttpResponse, setCacheControl)
338 {
339 char *ccontrol, *cctl;
340 int cc_len;
341 long max_age = 0;
342 zend_bool must_revalidate = 1;
343
344 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lb", &ccontrol, &cc_len, &max_age, &must_revalidate)) {
345 RETURN_FALSE;
346 }
347
348 if (strcmp(ccontrol, "public") && strcmp(ccontrol, "private") && strcmp(ccontrol, "no-cache")) {
349 http_error_ex(HE_WARNING, HTTP_E_INVALID_PARAM, "Cache-Control '%s' doesn't match public, private or no-cache", ccontrol);
350 RETURN_FALSE;
351 } else {
352 size_t cctl_len = spprintf(&cctl, 0, "%s,%s max-age=%ld", ccontrol, must_revalidate?" must-revalidate,":"", max_age);
353 RETVAL_SUCCESS(zend_update_static_property_stringl(THIS_CE, ZEND_STRS("cacheControl")-1, cctl, cctl_len TSRMLS_CC));
354 efree(cctl);
355 }
356 }
357 /* }}} */
358
359 /* {{{ proto static string HttpResponse::getCacheControl()
360 Get current Cache-Control header setting. */
361 PHP_METHOD(HttpResponse, getCacheControl)
362 {
363 NO_ARGS;
364
365 if (return_value_used) {
366 zval *cctl = http_zsep(IS_STRING, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("cacheControl")-1, 0 TSRMLS_CC)));
367 RETVAL_ZVAL(cctl, 1, 1);
368 }
369 }
370 /* }}} */
371
372 /* {{{ proto static bool HttpResponse::setContentType(string content_type)
373 Set the content-type of the sent entity. */
374 PHP_METHOD(HttpResponse, setContentType)
375 {
376 char *ctype;
377 int ctype_len;
378
379 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &ctype, &ctype_len)) {
380 RETURN_FALSE;
381 }
382
383 HTTP_CHECK_CONTENT_TYPE(ctype, RETURN_FALSE);
384 RETURN_SUCCESS(zend_update_static_property_stringl(THIS_CE, ZEND_STRS("contentType")-1, ctype, ctype_len TSRMLS_CC));
385 }
386 /* }}} */
387
388 /* {{{ proto static string HttpResponse::getContentType()
389 Get current Content-Type header setting. */
390 PHP_METHOD(HttpResponse, getContentType)
391 {
392 NO_ARGS;
393
394 if (return_value_used) {
395 zval *ctype = http_zsep(IS_STRING, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("contentType")-1, 0 TSRMLS_CC)));
396 RETVAL_ZVAL(ctype, 1, 1);
397 }
398 }
399 /* }}} */
400
401 /* {{{ proto static string HttpResponse::guessContentType(string magic_file[, int magic_mode = MAGIC_MIME])
402 Attempts to guess the content type of supplied payload through libmagic. */
403 PHP_METHOD(HttpResponse, guessContentType)
404 {
405 #ifdef HTTP_HAVE_MAGIC
406 char *magic_file, *ct = NULL;
407 int magic_file_len;
408 long magic_mode = MAGIC_MIME;
409
410 RETVAL_FALSE;
411 SET_EH_THROW_HTTP();
412 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &magic_file, &magic_file_len, &magic_mode)) {
413 switch (Z_LVAL_P(*zend_std_get_static_property(THIS_CE, ZEND_STRS("mode")-1, 0 TSRMLS_CC))) {
414 case SEND_DATA:
415 {
416 zval *data = *zend_std_get_static_property(THIS_CE, ZEND_STRS("data")-1, 0 TSRMLS_CC);
417 ct = http_guess_content_type(magic_file, magic_mode, Z_STRVAL_P(data), Z_STRLEN_P(data), SEND_DATA);
418 break;
419 }
420
421 case SEND_RSRC:
422 {
423 php_stream *s;
424 zval *z = *zend_std_get_static_property(THIS_CE, ZEND_STRS("stream")-1, 0 TSRMLS_CC);
425 z->type = IS_RESOURCE;
426 php_stream_from_zval(s, &z);
427 ct = http_guess_content_type(magic_file, magic_mode, s, 0, SEND_RSRC);
428 break;
429 }
430
431 default:
432 ct = http_guess_content_type(magic_file, magic_mode, Z_STRVAL_P(*zend_std_get_static_property(THIS_CE, ZEND_STRS("file")-1, 0 TSRMLS_CC)), 0, -1);
433 break;
434 }
435 if (ct) {
436 zend_update_static_property_string(THIS_CE, ZEND_STRS("contentType")-1, ct TSRMLS_CC);
437 RETVAL_STRING(ct, 0);
438 }
439 }
440 SET_EH_NORMAL();
441 #else
442 http_error(HE_THROW, HTTP_E_RUNTIME, "Cannot guess Content-Type; libmagic not available");
443 RETURN_FALSE;
444 #endif
445 }
446 /* }}} */
447
448 /* {{{ proto static bool HttpResponse::setContentDisposition(string filename[, bool inline = false])
449 Set the Content-Disposition. */
450 PHP_METHOD(HttpResponse, setContentDisposition)
451 {
452 char *file, *cd;
453 int file_len;
454 size_t cd_len;
455 zend_bool send_inline = 0;
456
457 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &file, &file_len, &send_inline)) {
458 RETURN_FALSE;
459 }
460
461 cd_len = spprintf(&cd, 0, "%s; filename=\"%s\"", send_inline ? "inline" : "attachment", file);
462 RETVAL_SUCCESS(zend_update_static_property_stringl(THIS_CE, ZEND_STRS("contentDisposition")-1, cd, cd_len TSRMLS_CC));
463 efree(cd);
464 }
465 /* }}} */
466
467 /* {{{ proto static string HttpResponse::getContentDisposition()
468 Get current Content-Disposition setting. */
469 PHP_METHOD(HttpResponse, getContentDisposition)
470 {
471 NO_ARGS;
472
473 if (return_value_used) {
474 zval *cdisp = http_zsep(IS_STRING, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("contentDisposition")-1, 0 TSRMLS_CC)));
475 RETVAL_ZVAL(cdisp, 1, 1);
476 }
477 }
478 /* }}} */
479
480 /* {{{ proto static bool HttpResponse::setETag(string etag)
481 Set a custom ETag. Use this only if you know what you're doing. */
482 PHP_METHOD(HttpResponse, setETag)
483 {
484 char *etag;
485 int etag_len;
486
487 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &etag, &etag_len)) {
488 RETURN_FALSE;
489 }
490
491 RETURN_SUCCESS(zend_update_static_property_stringl(THIS_CE, ZEND_STRS("eTag")-1, etag, etag_len TSRMLS_CC));
492 }
493 /* }}} */
494
495 /* {{{ proto static string HttpResponse::getETag()
496 Get calculated or previously set custom ETag. */
497 PHP_METHOD(HttpResponse, getETag)
498 {
499 NO_ARGS;
500
501 if (return_value_used) {
502 zval *etag = http_zsep(IS_STRING, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("eTag")-1, 0 TSRMLS_CC)));
503 RETVAL_ZVAL(etag, 1, 1);
504 }
505 }
506 /* }}} */
507
508 /* {{{ proto static bool HttpResponse::setLastModified(int timestamp)
509 Set a custom Last-Modified date. */
510 PHP_METHOD(HttpResponse, setLastModified)
511 {
512 long lm;
513
514 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &lm)) {
515 RETURN_FALSE;
516 }
517
518 RETURN_SUCCESS(zend_update_static_property_long(THIS_CE, ZEND_STRS("lastModified")-1, lm TSRMLS_CC));
519 }
520 /* }}} */
521
522 /* {{{ proto static int HttpResponse::getLastModified()
523 Get calculated or previously set custom Last-Modified date. */
524 PHP_METHOD(HttpResponse, getLastModified)
525 {
526 NO_ARGS;
527
528 if (return_value_used) {
529 zval *lmod = http_zsep(IS_LONG, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("lastModified")-1, 0 TSRMLS_CC)));
530 RETVAL_ZVAL(lmod, 1, 1);
531 }
532 }
533 /* }}} */
534
535 /* {{{ proto static bool HttpResponse::setThrottleDelay(double seconds)
536 Sets the throttle delay for use with HttpResponse::setBufferSize(). */
537 PHP_METHOD(HttpResponse, setThrottleDelay)
538 {
539 double seconds;
540
541 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &seconds)) {
542 RETURN_FALSE;
543 }
544 RETURN_SUCCESS(zend_update_static_property_double(THIS_CE, ZEND_STRS("throttleDelay")-1, seconds TSRMLS_CC));
545 }
546 /* }}} */
547
548 /* {{{ proto static double HttpResponse::getThrottleDelay()
549 Get the current throttle delay. */
550 PHP_METHOD(HttpResponse, getThrottleDelay)
551 {
552 NO_ARGS;
553
554 if (return_value_used) {
555 zval *tdel = http_zsep(IS_DOUBLE, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("throttleDelay")-1, 0 TSRMLS_CC)));
556 RETVAL_ZVAL(tdel, 1, 1);
557 }
558 }
559 /* }}} */
560
561 /* {{{ proto static bool HttpResponse::setBufferSize(int bytes)
562 Sets the send buffer size for use with HttpResponse::setThrottleDelay(). */
563 PHP_METHOD(HttpResponse, setBufferSize)
564 {
565 long bytes;
566
567 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &bytes)) {
568 RETURN_FALSE;
569 }
570 RETURN_SUCCESS(zend_update_static_property_long(THIS_CE, ZEND_STRS("bufferSize")-1, bytes TSRMLS_CC));
571 }
572 /* }}} */
573
574 /* {{{ proto static int HttpResponse::getBufferSize()
575 Get current buffer size. */
576 PHP_METHOD(HttpResponse, getBufferSize)
577 {
578 NO_ARGS;
579
580 if (return_value_used) {
581 zval *bsize = http_zsep(IS_LONG, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("bufferSize")-1, 0 TSRMLS_CC)));
582 RETVAL_ZVAL(bsize, 1, 1);
583 }
584 }
585 /* }}} */
586
587 /* {{{ proto static bool HttpResponse::setData(mixed data)
588 Set the data to be sent. */
589 PHP_METHOD(HttpResponse, setData)
590 {
591 char *etag;
592 zval *the_data;
593
594 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/", &the_data)) {
595 RETURN_FALSE;
596 }
597 if (Z_TYPE_P(the_data) != IS_STRING) {
598 convert_to_string(the_data);
599 }
600
601 if ( (SUCCESS != zend_update_static_property(THIS_CE, ZEND_STRS("data")-1, the_data TSRMLS_CC)) ||
602 (SUCCESS != zend_update_static_property_long(THIS_CE, ZEND_STRS("mode")-1, SEND_DATA TSRMLS_CC))) {
603 RETURN_FALSE;
604 }
605
606 zend_update_static_property_long(THIS_CE, ZEND_STRS("lastModified")-1, http_last_modified(the_data, SEND_DATA) TSRMLS_CC);
607 if ((etag = http_etag(Z_STRVAL_P(the_data), Z_STRLEN_P(the_data), SEND_DATA))) {
608 zend_update_static_property_string(THIS_CE, ZEND_STRS("eTag")-1, etag TSRMLS_CC);
609 efree(etag);
610 }
611
612 RETURN_TRUE;
613 }
614 /* }}} */
615
616 /* {{{ proto static string HttpResponse::getData()
617 Get the previously set data to be sent. */
618 PHP_METHOD(HttpResponse, getData)
619 {
620 NO_ARGS;
621
622 if (return_value_used) {
623 zval *the_data = *zend_std_get_static_property(THIS_CE, ZEND_STRS("data")-1, 0 TSRMLS_CC);
624
625 RETURN_ZVAL(the_data, 1, 0);
626 }
627 }
628 /* }}} */
629
630 /* {{{ proto static bool HttpResponse::setStream(resource stream)
631 Set the resource to be sent. */
632 PHP_METHOD(HttpResponse, setStream)
633 {
634 char *etag;
635 zval *the_stream;
636 php_stream *the_real_stream;
637 php_stream_statbuf ssb;
638
639 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &the_stream)) {
640 RETURN_FALSE;
641 }
642
643 php_stream_from_zval(the_real_stream, &the_stream);
644 if (php_stream_stat(the_real_stream, &ssb)) {
645 RETURN_FALSE;
646 }
647
648 if ( (SUCCESS != zend_update_static_property_long(THIS_CE, ZEND_STRS("stream")-1, Z_LVAL_P(the_stream) TSRMLS_CC)) ||
649 (SUCCESS != zend_update_static_property_long(THIS_CE, ZEND_STRS("mode")-1, SEND_RSRC TSRMLS_CC))) {
650 RETURN_FALSE;
651 }
652 zend_list_addref(Z_LVAL_P(the_stream));
653
654 zend_update_static_property_long(THIS_CE, ZEND_STRS("lastModified")-1, http_last_modified(the_real_stream, SEND_RSRC) TSRMLS_CC);
655 if ((etag = http_etag(the_real_stream, 0, SEND_RSRC))) {
656 zend_update_static_property_string(THIS_CE, ZEND_STRS("eTag")-1, etag TSRMLS_CC);
657 efree(etag);
658 }
659
660 RETURN_TRUE;
661 }
662 /* }}} */
663
664 /* {{{ proto static resource HttpResponse::getStream()
665 Get the previously set resource to be sent. */
666 PHP_METHOD(HttpResponse, getStream)
667 {
668 NO_ARGS;
669
670 if (return_value_used) {
671 zval *stream = http_zsep(IS_LONG, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("stream")-1, 0 TSRMLS_CC)));
672 RETVAL_RESOURCE(Z_LVAL_P(stream));
673 }
674 }
675 /* }}} */
676
677 /* {{{ proto static bool HttpResponse::setFile(string file)
678 Set the file to be sent. */
679 PHP_METHOD(HttpResponse, setFile)
680 {
681 char *the_file, *etag;
682 int file_len;
683 php_stream_statbuf ssb;
684
685 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &the_file, &file_len)) {
686 RETURN_FALSE;
687 }
688
689 if (php_stream_stat_path(the_file, &ssb)) {
690 RETURN_FALSE;
691 }
692
693 if ( (SUCCESS != zend_update_static_property_stringl(THIS_CE, ZEND_STRS("file")-1, the_file, file_len TSRMLS_CC)) ||
694 (SUCCESS != zend_update_static_property_long(THIS_CE, ZEND_STRS("mode")-1, -1 TSRMLS_CC))) {
695 RETURN_FALSE;
696 }
697
698 zend_update_static_property_long(THIS_CE, ZEND_STRS("lastModified")-1, http_last_modified(the_file, -1) TSRMLS_CC);
699 if ((etag = http_etag(the_file, 0, -1))) {
700 zend_update_static_property_string(THIS_CE, ZEND_STRS("eTag")-1, etag TSRMLS_CC);
701 efree(etag);
702 }
703
704 RETURN_TRUE;
705 }
706 /* }}} */
707
708 /* {{{ proto static string HttpResponse::getFile()
709 Get the previously set file to be sent. */
710 PHP_METHOD(HttpResponse, getFile)
711 {
712 NO_ARGS;
713
714 if (return_value_used) {
715 zval *file = http_zsep(IS_STRING, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("file")-1, 0 TSRMLS_CC)));
716 RETVAL_ZVAL(file, 1, 1);
717 }
718 }
719 /* }}} */
720
721 /* {{{ proto static bool HttpResponse::send([bool clean_ob = true])
722 Finally send the entity. */
723 PHP_METHOD(HttpResponse, send)
724 {
725 zval *sent;
726 zend_bool clean_ob = 1;
727
728 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &clean_ob)) {
729 RETURN_FALSE;
730 }
731
732 HTTP_CHECK_HEADERS_SENT(RETURN_FALSE);
733
734 sent = *zend_std_get_static_property(THIS_CE, ZEND_STRS("sent")-1, 0 TSRMLS_CC);
735 if (Z_LVAL_P(sent)) {
736 http_error(HE_WARNING, HTTP_E_RESPONSE, "Cannot send HttpResponse, response has already been sent");
737 RETURN_FALSE;
738 } else {
739 Z_LVAL_P(sent) = 1;
740 }
741
742 /* capture mode */
743 if (i_zend_is_true(*zend_std_get_static_property(THIS_CE, ZEND_STRS("catch")-1, 0 TSRMLS_CC))) {
744 zval *zetag, *the_data;
745
746 MAKE_STD_ZVAL(the_data);
747 php_ob_get_buffer(the_data TSRMLS_CC);
748 zend_update_static_property(THIS_CE, ZEND_STRS("data")-1, the_data TSRMLS_CC);
749 ZVAL_LONG(*zend_std_get_static_property(THIS_CE, ZEND_STRS("mode")-1, 0 TSRMLS_CC), SEND_DATA);
750
751 zetag = http_zsep(IS_STRING, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("eTag")-1, 0 TSRMLS_CC)));
752 if (!Z_STRLEN_P(zetag)) {
753 char *etag = http_etag(Z_STRVAL_P(the_data), Z_STRLEN_P(the_data), SEND_DATA);
754 if (etag) {
755 zend_update_static_property_string(THIS_CE, ZEND_STRS("eTag")-1, etag TSRMLS_CC);
756 efree(etag);
757 }
758 }
759 zval_ptr_dtor(&the_data);
760 zval_ptr_dtor(&zetag);
761
762 clean_ob = 1;
763 }
764
765 if (clean_ob) {
766 /* interrupt on-the-fly etag generation */
767 HTTP_G->etag.started = 0;
768 /* discard previous output buffers */
769 php_end_ob_buffers(0 TSRMLS_CC);
770 }
771
772 /* caching */
773 if (i_zend_is_true(*zend_std_get_static_property(THIS_CE, ZEND_STRS("cache")-1, 0 TSRMLS_CC))) {
774 zval *cctl, *etag, *lmod;
775
776 lmod = http_zsep(IS_LONG, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("lastModified")-1, 0 TSRMLS_CC)));
777 etag = http_zsep(IS_STRING, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("eTag")-1, 0 TSRMLS_CC)));
778 cctl = http_zsep(IS_STRING, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("cacheControl")-1, 0 TSRMLS_CC)));
779
780 if (Z_LVAL_P(lmod) || Z_STRLEN_P(etag)) {
781 if (Z_STRLEN_P(cctl)) {
782 http_send_cache_control(Z_STRVAL_P(cctl), Z_STRLEN_P(cctl));
783 } else {
784 http_send_cache_control(HTTP_DEFAULT_CACHECONTROL, lenof(HTTP_DEFAULT_CACHECONTROL));
785 }
786 if (Z_STRLEN_P(etag)) {
787 http_send_etag(Z_STRVAL_P(etag), Z_STRLEN_P(etag));
788 }
789 if (Z_LVAL_P(lmod)) {
790 http_send_last_modified(Z_LVAL_P(lmod));
791 }
792 }
793
794 zval_ptr_dtor(&etag);
795 zval_ptr_dtor(&lmod);
796 zval_ptr_dtor(&cctl);
797 }
798
799 /* content type */
800 {
801 zval *ctype = http_zsep(IS_STRING, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("contentType")-1, 0 TSRMLS_CC)));
802 if (Z_STRLEN_P(ctype)) {
803 http_send_content_type(Z_STRVAL_P(ctype), Z_STRLEN_P(ctype));
804 } else {
805 char *ctypes = INI_STR("default_mimetype");
806 size_t ctlen = ctypes ? strlen(ctypes) : 0;
807
808 if (ctlen) {
809 http_send_content_type(ctypes, ctlen);
810 } else {
811 http_send_content_type("application/x-octetstream", lenof("application/x-octetstream"));
812 }
813 }
814 zval_ptr_dtor(&ctype);
815 }
816
817 /* content disposition */
818 {
819 zval *cd = http_zsep(IS_STRING, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("contentDisposition")-1, 0 TSRMLS_CC)));
820 if (Z_STRLEN_P(cd)) {
821 http_send_header_ex("Content-Disposition", lenof("Content-Disposition"), Z_STRVAL_P(cd), Z_STRLEN_P(cd), 1, NULL);
822 }
823 zval_ptr_dtor(&cd);
824 }
825
826 /* throttling */
827 {
828 zval *bsize = http_zsep(IS_LONG, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("bufferSize")-1, 0 TSRMLS_CC)));
829 zval *delay = http_zsep(IS_DOUBLE, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("throttleDelay")-1, 0 TSRMLS_CC)));
830 HTTP_G->send.buffer_size = Z_LVAL_P(bsize);
831 HTTP_G->send.throttle_delay = Z_DVAL_P(delay);
832 zval_ptr_dtor(&bsize);
833 zval_ptr_dtor(&delay);
834 }
835
836 /* gzip */
837 HTTP_G->send.deflate.response = i_zend_is_true(*zend_std_get_static_property(THIS_CE, ZEND_STRS("gzip")-1, 0 TSRMLS_CC));
838
839 /* send */
840 switch (Z_LVAL_P(*zend_std_get_static_property(THIS_CE, ZEND_STRS("mode")-1, 0 TSRMLS_CC))) {
841 case SEND_DATA:
842 {
843 zval *zdata = http_zsep(IS_STRING, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("data")-1, 0 TSRMLS_CC)));
844 RETVAL_SUCCESS(http_send_data(Z_STRVAL_P(zdata), Z_STRLEN_P(zdata)));
845 zval_ptr_dtor(&zdata);
846 return;
847 }
848
849 case SEND_RSRC:
850 {
851 php_stream *the_real_stream;
852 zval *the_stream = http_zsep(IS_LONG, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("stream")-1, 0 TSRMLS_CC)));
853 the_stream->type = IS_RESOURCE;
854 php_stream_from_zval(the_real_stream, &the_stream);
855 RETVAL_SUCCESS(http_send_stream(the_real_stream));
856 zval_ptr_dtor(&the_stream);
857 return;
858 }
859
860 default:
861 {
862 zval *file = http_zsep(IS_STRING, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("file")-1, 0 TSRMLS_CC)));
863 RETVAL_SUCCESS(http_send_file(Z_STRVAL_P(file)));
864 zval_ptr_dtor(&file);
865 return;
866 }
867 }
868 }
869 /* }}} */
870
871 /* {{{ proto static void HttpResponse::capture()
872 Capture script output.
873 */
874 PHP_METHOD(HttpResponse, capture)
875 {
876 NO_ARGS;
877
878 HTTP_CHECK_HEADERS_SENT(RETURN_FALSE);
879
880 zend_update_static_property_long(THIS_CE, ZEND_STRS("catch")-1, 1 TSRMLS_CC);
881
882 php_end_ob_buffers(0 TSRMLS_CC);
883 php_start_ob_buffer(NULL, 0, 0 TSRMLS_CC);
884
885 /* register shutdown function */
886 {
887 zval func, retval, arg, *argp[1];
888
889 INIT_PZVAL(&arg);
890 INIT_PZVAL(&func);
891 INIT_PZVAL(&retval);
892 ZVAL_STRINGL(&func, "register_shutdown_function", lenof("register_shutdown_function"), 0);
893
894 array_init(&arg);
895 add_next_index_stringl(&arg, "HttpResponse", lenof("HttpResponse"), 1);
896 add_next_index_stringl(&arg, "send", lenof("send"), 1);
897 argp[0] = &arg;
898 call_user_function(EG(function_table), NULL, &func, &retval, 1, argp TSRMLS_CC);
899 zval_dtor(&arg);
900 }
901 }
902 /* }}} */
903
904 #endif /* ZEND_ENGINE_2 && !WONKY */
905
906 /*
907 * Local variables:
908 * tab-width: 4
909 * c-basic-offset: 4
910 * End:
911 * vim600: noet sw=4 ts=4 fdm=marker
912 * vim<600: noet sw=4 ts=4
913 */
914