2 +--------------------------------------------------------------------+
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-2011, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
13 #include "php_http_api.h"
15 static void set_option(zval
*options
, const char *name_str
, size_t name_len
, int type
, const void *value_ptr
, size_t value_len TSRMLS_DC
)
17 if (Z_TYPE_P(options
) == IS_OBJECT
) {
18 /* stupid non-const api */
19 char *name
= estrndup(name_str
, name_len
);
23 zend_update_property_double(Z_OBJCE_P(options
), options
, name
, name_len
, *(double *)value_ptr TSRMLS_CC
);
26 zend_update_property_long(Z_OBJCE_P(options
), options
, name
, name_len
, *(long *)value_ptr TSRMLS_CC
);
29 zend_update_property_stringl(Z_OBJCE_P(options
), options
, name
, name_len
, value_ptr
, value_len TSRMLS_CC
);
33 zend_update_property_null(Z_OBJCE_P(options
), options
, name
, name_len TSRMLS_CC
);
37 convert_to_array(options
);
41 add_assoc_double_ex(options
, name_str
, name_len
+ 1, *(double *)value_ptr
);
44 add_assoc_long_ex(options
, name_str
, name_len
+ 1, *(long *)value_ptr
);
47 char *value
= estrndup(value_ptr
, value_len
);
48 add_assoc_stringl_ex(options
, name_str
, name_len
+ 1, value
, value_len
, 0);
53 add_assoc_null_ex(options
, name_str
, name_len
+ 1);
57 static zval
*get_option(zval
*options
, const char *name_str
, size_t name_len TSRMLS_DC
)
61 if (Z_TYPE_P(options
) == IS_OBJECT
) {
62 char *name
= estrndup(name_str
, name_len
);
63 val
= zend_read_property(Z_OBJCE_P(options
), options
, name
, name_len
, 0 TSRMLS_CC
);
66 if (SUCCESS
== zend_symtable_find(Z_ARRVAL_P(options
), name_str
, name_len
+ 1, (void *) &valptr
)) {
78 PHP_HTTP_API php_http_cache_status_t
php_http_env_is_response_cached_by_etag(zval
*options
, const char *header_str
, size_t header_len TSRMLS_DC
)
80 php_http_cache_status_t ret
= PHP_HTTP_CACHE_NO
;
82 char *header
= NULL
, *etag
;
83 zval
*zetag
, *zbody
= NULL
;
85 if ( !(zbody
= get_option(options
, ZEND_STRL("body") TSRMLS_CC
))
86 || !(Z_TYPE_P(zbody
) == IS_OBJECT
)
87 || !instanceof_function(Z_OBJCE_P(zbody
), php_http_message_body_class_entry TSRMLS_CC
)
90 zval_ptr_dtor(&zbody
);
95 if ((zetag
= get_option(options
, ZEND_STRL("etag") TSRMLS_CC
))) {
96 zval
*zetag_copy
= php_http_ztyp(IS_STRING
, zetag
);
97 zval_ptr_dtor(&zetag
);
101 if (zetag
&& Z_STRLEN_P(zetag
)) {
102 etag
= Z_STRVAL_P(zetag
);
103 } else if ((etag
= php_http_message_body_etag(((php_http_message_body_object_t
*) zend_object_store_get_object(zbody TSRMLS_CC
))->body
))) {
104 set_option(options
, ZEND_STRL("etag"), IS_STRING
, etag
, strlen(etag
) TSRMLS_CC
);
109 zval_ptr_dtor(&zbody
);
113 zval_ptr_dtor(&zetag
);
116 if (etag
&& (header
= php_http_env_get_request_header(header_str
, header_len
, NULL TSRMLS_CC
))) {
117 ret
= php_http_match(header
, etag
, PHP_HTTP_MATCH_WORD
) ? PHP_HTTP_CACHE_HIT
: PHP_HTTP_CACHE_MISS
;
128 PHP_HTTP_API php_http_cache_status_t
php_http_env_is_response_cached_by_last_modified(zval
*options
, const char *header_str
, size_t header_len TSRMLS_DC
)
132 zval
*zbody
= NULL
, *zlm
;
134 if ( !(zbody
= get_option(options
, ZEND_STRL("body") TSRMLS_CC
))
135 || !(Z_TYPE_P(zbody
) == IS_OBJECT
)
136 || !instanceof_function(Z_OBJCE_P(zbody
), php_http_message_body_class_entry TSRMLS_CC
)
139 zval_ptr_dtor(&zbody
);
141 return PHP_HTTP_CACHE_NO
;
144 if ((zlm
= get_option(options
, ZEND_STRL("lastModified") TSRMLS_CC
))) {
145 zval
*zlm_copy
= php_http_ztyp(IS_LONG
, zlm
);
150 if (zlm
&& Z_LVAL_P(zlm
) > 0) {
153 lm
= php_http_message_body_mtime(((php_http_message_body_object_t
*) zend_object_store_get_object(zbody TSRMLS_CC
))->body
);
154 set_option(options
, ZEND_STRL("lastModified"), IS_LONG
, &lm
, 0 TSRMLS_CC
);
157 zval_ptr_dtor(&zbody
);
162 if (!(header
= php_http_env_get_request_header(header_str
, header_len
, NULL TSRMLS_CC
))) {
163 return PHP_HTTP_CACHE_NO
;
166 ums
= php_parse_date(header
, NULL
);
169 if (ums
> 0 && ums
<= lm
) {
170 return PHP_HTTP_CACHE_HIT
;
172 return PHP_HTTP_CACHE_MISS
;
176 static size_t output(void *context
, char *buf
, size_t len TSRMLS_DC
)
178 php_http_env_response_t
*r
= context
;
182 /* we really only need to flush when throttling is enabled,
183 because we push the data as fast as possible anyway if not */
184 if (r
->throttle
.delay
>= PHP_HTTP_DIFFSEC
) {
185 if (php_output_get_level(TSRMLS_C
)) {
186 php_output_flush_all(TSRMLS_C
);
188 if (!(php_output_get_status(TSRMLS_C
) & PHP_OUTPUT_IMPLICITFLUSH
)) {
189 sapi_flush(TSRMLS_C
);
191 php_http_sleep(r
->throttle
.delay
);
196 #define php_http_env_response_send_done(r) php_http_env_response_send_data((r), NULL, 0)
197 static STATUS
php_http_env_response_send_data(php_http_env_response_t
*r
, const char *buf
, size_t len
)
199 TSRMLS_FETCH_FROM_CTX(r
->ts
);
200 size_t chunk
= r
->throttle
.chunk
? r
->throttle
.chunk
: PHP_HTTP_SENDBUF_SIZE
;
202 if (r
->content
.encoder
) {
203 char *enc_str
= NULL
;
207 if (SUCCESS
!= php_http_encoding_stream_update(r
->content
.encoder
, buf
, len
, &enc_str
, &enc_len
)) {
211 if (SUCCESS
!= php_http_encoding_stream_finish(r
->content
.encoder
, &enc_str
, &enc_len
)) {
217 php_http_buffer_chunked_output(&r
->buffer
, enc_str
, enc_len
, buf
? chunk
: 0, output
, r TSRMLS_CC
);
221 php_http_buffer_chunked_output(&r
->buffer
, buf
, len
, buf
? chunk
: 0, output
, r TSRMLS_CC
);
227 PHP_HTTP_API php_http_env_response_t
*php_http_env_response_init(php_http_env_response_t
*r
, zval
*options TSRMLS_DC
)
229 php_http_env_response_t
*free_r
= NULL
;
232 r
= free_r
= emalloc(sizeof(*r
));
234 memset(r
, 0, sizeof(*r
));
236 r
->buffer
= php_http_buffer_init(NULL
);
239 r
->options
= options
;
241 TSRMLS_SET_CTX(r
->ts
);
246 PHP_HTTP_API
void php_http_env_response_dtor(php_http_env_response_t
*r
)
248 php_http_buffer_free(&r
->buffer
);
249 zval_ptr_dtor(&r
->options
);
250 STR_FREE(r
->content
.type
);
251 STR_FREE(r
->content
.encoding
);
252 if (r
->content
.encoder
) {
253 php_http_encoding_stream_free(&r
->content
.encoder
);
257 PHP_HTTP_API
void php_http_env_response_free(php_http_env_response_t
**r
)
260 php_http_env_response_dtor(*r
);
266 static STATUS
php_http_env_response_send_head(php_http_env_response_t
*r
)
268 STATUS ret
= SUCCESS
;
269 zval
*zoption
, *options
= r
->options
;
270 TSRMLS_FETCH_FROM_CTX(r
->ts
);
276 if ((zoption
= get_option(options
, ZEND_STRL("responseCode") TSRMLS_CC
))) {
277 zval
*zoption_copy
= php_http_ztyp(IS_LONG
, zoption
);
279 zval_ptr_dtor(&zoption
);
280 if (Z_LVAL_P(zoption_copy
) > 0) {
281 ret
= php_http_env_set_response_code(Z_LVAL_P(zoption_copy
) TSRMLS_CC
);
283 zval_ptr_dtor(&zoption_copy
);
286 if (ret
!= SUCCESS
) {
290 if ((zoption
= get_option(options
, ZEND_STRL("httpVersion") TSRMLS_CC
))) {
291 php_http_version_t v
;
292 zval
*zoption_copy
= php_http_ztyp(IS_STRING
, zoption
);
294 zval_ptr_dtor(&zoption
);
295 if (Z_STRLEN_P(zoption_copy
) && php_http_version_parse(&v
, Z_STRVAL_P(zoption_copy
) TSRMLS_CC
)) {
296 ret
= php_http_env_set_response_protocol_version(&v TSRMLS_CC
);
297 php_http_version_dtor(&v
);
299 zval_ptr_dtor(&zoption_copy
);
302 if (ret
!= SUCCESS
) {
306 if ((zoption
= get_option(options
, ZEND_STRL("headers") TSRMLS_CC
))) {
307 if (Z_TYPE_P(zoption
) == IS_ARRAY
) {
310 php_http_array_hashkey_t key
= php_http_array_hashkey_init(0);
312 FOREACH_KEYVAL(pos
, zoption
, key
, val
) {
313 if (key
.type
== HASH_KEY_IS_STRING
) {
314 if (SUCCESS
!= (ret
= php_http_env_set_response_header_value(0, key
.str
, key
.len
- 1, *val
, 1 TSRMLS_CC
))) {
320 zval_ptr_dtor(&zoption
);
323 if (ret
!= SUCCESS
) {
327 if ((zoption
= get_option(options
, ZEND_STRL("contentType") TSRMLS_CC
))) {
328 zval
*zoption_copy
= php_http_ztyp(IS_STRING
, zoption
);
330 zval_ptr_dtor(&zoption
);
331 if (Z_STRLEN_P(zoption_copy
)) {
332 PHP_HTTP_CHECK_CONTENT_TYPE(Z_STRVAL_P(zoption_copy
), ret
= FAILURE
) else {
333 if (SUCCESS
== (ret
= php_http_env_set_response_header_format(0, 1 TSRMLS_CC
, "Content-Type: %.*s", Z_STRLEN_P(zoption_copy
), Z_STRVAL_P(zoption_copy
)))) {
334 r
->content
.type
= estrndup(Z_STRVAL_P(zoption_copy
), Z_STRLEN_P(zoption_copy
));
338 zval_ptr_dtor(&zoption_copy
);
341 if (ret
!= SUCCESS
) {
345 if (r
->range
.status
== PHP_HTTP_RANGE_OK
) {
346 if (zend_hash_num_elements(&r
->range
.values
) == 1) {
347 zval
**range
, **begin
, **end
;
349 if (SUCCESS
!= zend_hash_index_find(&r
->range
.values
, 0, (void *) &range
)
350 || SUCCESS
!= zend_hash_index_find(Z_ARRVAL_PP(range
), 0, (void *) &begin
)
351 || SUCCESS
!= zend_hash_index_find(Z_ARRVAL_PP(range
), 1, (void *) &end
)
353 /* this should never happen */
354 zend_hash_destroy(&r
->range
.values
);
355 php_http_env_set_response_code(500 TSRMLS_CC
);
358 ret
= php_http_env_set_response_header_format(206, 1 TSRMLS_CC
, "Content-Range: bytes %ld-%ld/%zu", Z_LVAL_PP(begin
), Z_LVAL_PP(end
), r
->content
.length
);
361 php_http_boundary(r
->range
.boundary
, sizeof(r
->range
.boundary
) TSRMLS_CC
);
362 ret
= php_http_env_set_response_header_format(206, 1 TSRMLS_CC
, "Content-Type: multipart/byteranges; boundary=%s", r
->range
.boundary
);
365 if ((zoption
= get_option(options
, ZEND_STRL("cacheControl") TSRMLS_CC
))) {
366 zval
*zoption_copy
= php_http_ztyp(IS_STRING
, zoption
);
368 zval_ptr_dtor(&zoption
);
369 if (Z_STRLEN_P(zoption_copy
)) {
370 ret
= php_http_env_set_response_header_format(0, 1 TSRMLS_CC
, "Cache-Control: %.*s", Z_STRLEN_P(zoption_copy
), Z_STRVAL_P(zoption_copy
) TSRMLS_CC
);
372 zval_ptr_dtor(&zoption_copy
);
375 if (ret
!= SUCCESS
) {
379 if ((zoption
= get_option(options
, ZEND_STRL("contentDisposition") TSRMLS_CC
))) {
380 zval
*zoption_copy
= php_http_ztyp(IS_ARRAY
, zoption
);
381 zval
**zdisposition
, **zfilename
= NULL
;
383 zval_ptr_dtor(&zoption
);
384 if (SUCCESS
== zend_hash_find(Z_ARRVAL_P(zoption_copy
), ZEND_STRS("disposition"), (void *) &zdisposition
)) {
385 zval
*zdisposition_copy
= php_http_ztyp(IS_LONG
, *zdisposition
);
388 switch (Z_LVAL_P(zdisposition_copy
)) {
389 case PHP_HTTP_CONTENT_DISPOSITION_NONE
:
390 ret
= php_http_env_set_response_header_value(0, ZEND_STRL("Content-Disposition"), NULL
, 1 TSRMLS_CC
);
392 case PHP_HTTP_CONTENT_DISPOSITION_INLINE
:
395 case PHP_HTTP_CONTENT_DISPOSITION_ATTACHMENT
:
401 if (SUCCESS
!= zend_hash_find(Z_ARRVAL_P(zoption_copy
), ZEND_STRS("filename"), (void *) &zfilename
)) {
402 ret
= php_http_env_set_response_header_format(0, 1 TSRMLS_CC
, "Content-Disposition: %s", tmp
);
404 zval
*zfilename_copy
= php_http_ztyp(IS_STRING
, *zfilename
);
406 if (!Z_STRLEN_P(zfilename_copy
)) {
407 ret
= php_http_env_set_response_header_format(0, 1 TSRMLS_CC
, "Content-Disposition: %s", tmp
);
410 char *new_f_str
= php_addslashes(estrndup(Z_STRVAL_P(zfilename_copy
), Z_STRLEN_P(zfilename_copy
)), Z_STRLEN_P(zfilename_copy
), &new_f_len
, 1 TSRMLS_CC
);
412 ret
= php_http_env_set_response_header_format(0, 1 TSRMLS_CC
, "Content-Disposition: %s; filename=\"%.*s\"", tmp
, new_f_len
, new_f_str
);
416 zval_ptr_dtor(&zfilename_copy
);
419 zval_ptr_dtor(&zdisposition_copy
);
421 zval_ptr_dtor(&zoption_copy
);
424 if (ret
!= SUCCESS
) {
428 if ((zoption
= get_option(options
, ZEND_STRL("contentEncoding") TSRMLS_CC
))) {
429 zval
*zoption_copy
= php_http_ztyp(IS_LONG
, zoption
);
431 HashTable
*result
= NULL
;
433 zval_ptr_dtor(&zoption
);
434 switch (Z_LVAL_P(zoption_copy
)) {
435 case PHP_HTTP_CONTENT_ENCODING_GZIP
:
436 INIT_PZVAL(&zsupported
);
437 array_init(&zsupported
);
438 add_next_index_stringl(&zsupported
, ZEND_STRL("none"), 1);
439 add_next_index_stringl(&zsupported
, ZEND_STRL("gzip"), 1);
440 add_next_index_stringl(&zsupported
, ZEND_STRL("deflate"), 1);
442 if ((result
= php_http_negotiate_encoding(Z_ARRVAL(zsupported
) TSRMLS_CC
))) {
443 char *key_str
= NULL
;
446 zend_hash_internal_pointer_reset(result
);
447 if (HASH_KEY_IS_STRING
== zend_hash_get_current_key_ex(result
, &key_str
, &key_len
, NULL
, 0, NULL
)) {
448 if (!strcmp(key_str
, "gzip")) {
449 if (!(r
->content
.encoder
= php_http_encoding_stream_init(NULL
, php_http_encoding_stream_get_deflate_ops(), PHP_HTTP_DEFLATE_TYPE_GZIP TSRMLS_CC
))) {
451 } else if (SUCCESS
== (ret
= php_http_env_set_response_header(0, ZEND_STRL("Content-Encoding: gzip"), 1 TSRMLS_CC
))) {
452 r
->content
.encoding
= estrndup(key_str
, key_len
- 1);
454 } else if (!strcmp(key_str
, "deflate")) {
455 if (!(r
->content
.encoder
= php_http_encoding_stream_init(NULL
, php_http_encoding_stream_get_deflate_ops(), PHP_HTTP_DEFLATE_TYPE_ZLIB TSRMLS_CC
))) {
457 } else if (SUCCESS
== (ret
= php_http_env_set_response_header(0, ZEND_STRL("Content-Encoding: deflate"), 1 TSRMLS_CC
))) {
458 r
->content
.encoding
= estrndup(key_str
, key_len
- 1);
461 ret
= php_http_env_set_response_header_value(0, ZEND_STRL("Content-Encoding"), NULL
, 0 TSRMLS_CC
);
464 if (SUCCESS
== ret
) {
465 ret
= php_http_env_set_response_header(0, ZEND_STRL("Vary: Accept-Encoding"), 0 TSRMLS_CC
);
469 zend_hash_destroy(result
);
470 FREE_HASHTABLE(result
);
473 zval_dtor(&zsupported
);
476 case PHP_HTTP_CONTENT_ENCODING_NONE
:
478 ret
= php_http_env_set_response_header_value(0, ZEND_STRL("Content-Encoding"), NULL
, 0 TSRMLS_CC
);
481 zval_ptr_dtor(&zoption_copy
);
484 if (SUCCESS
!= ret
) {
488 if (php_http_env_get_response_code(TSRMLS_C
) < 400 && !php_http_env_got_request_header(ZEND_STRL("Authorization") TSRMLS_CC
)
489 && ( !SG(request_info
).request_method
490 || !strcasecmp(SG(request_info
).request_method
, "GET")
491 || !strcasecmp(SG(request_info
).request_method
, "HEAD")
494 switch (php_http_env_is_response_cached_by_etag(options
, ZEND_STRL("If-None-Match") TSRMLS_CC
)) {
495 case PHP_HTTP_CACHE_MISS
:
498 case PHP_HTTP_CACHE_NO
:
499 if (PHP_HTTP_CACHE_HIT
!= php_http_env_is_response_cached_by_last_modified(options
, ZEND_STRL("If-Modified-Since") TSRMLS_CC
)) {
504 case PHP_HTTP_CACHE_HIT
:
505 ret
= php_http_env_set_response_code(304 TSRMLS_CC
);
510 if ((zoption
= get_option(options
, ZEND_STRL("etag") TSRMLS_CC
))) {
511 zval
*zoption_copy
= php_http_ztyp(IS_STRING
, zoption
);
513 zval_ptr_dtor(&zoption
);
514 if (*Z_STRVAL_P(zoption_copy
) != '"' && strncmp(Z_STRVAL_P(zoption_copy
), "W/\"", 3)) {
515 ret
= php_http_env_set_response_header_format(0, 1 TSRMLS_CC
, "ETag: \"%s\"", Z_STRVAL_P(zoption_copy
));
517 ret
= php_http_env_set_response_header_value(0, ZEND_STRL("ETag"), zoption_copy
, 1 TSRMLS_CC
);
519 zval_ptr_dtor(&zoption_copy
);
521 if ((zoption
= get_option(options
, ZEND_STRL("lastModified") TSRMLS_CC
))) {
522 zval
*zoption_copy
= php_http_ztyp(IS_LONG
, zoption
);
524 zval_ptr_dtor(&zoption
);
525 if (Z_LVAL_P(zoption_copy
)) {
526 char *date
= php_format_date(ZEND_STRL(PHP_HTTP_DATE_FORMAT
), Z_LVAL_P(zoption_copy
), 0 TSRMLS_CC
);
528 ret
= php_http_env_set_response_header_format(0, 1 TSRMLS_CC
, "Last-Modified: %s", date
);
532 zval_ptr_dtor(&zoption_copy
);
540 static STATUS
php_http_env_response_send_body(php_http_env_response_t
*r
)
542 STATUS ret
= SUCCESS
;
544 TSRMLS_FETCH_FROM_CTX(r
->ts
);
550 if ( (zbody
= get_option(r
->options
, ZEND_STRL("body") TSRMLS_CC
))
551 && (Z_TYPE_P(zbody
) == IS_OBJECT
)
552 && instanceof_function(Z_OBJCE_P(zbody
), php_http_message_body_class_entry TSRMLS_CC
)
554 php_http_message_body_object_t
*obj
= zend_object_store_get_object(zbody TSRMLS_CC
);
556 if (r
->range
.status
== PHP_HTTP_RANGE_OK
) {
557 if (zend_hash_num_elements(&r
->range
.values
) == 1) {
559 zval
**range
, **begin
, **end
;
561 if (SUCCESS
!= zend_hash_index_find(&r
->range
.values
, 0, (void *) &range
)
562 || SUCCESS
!= zend_hash_index_find(Z_ARRVAL_PP(range
), 0, (void *) &begin
)
563 || SUCCESS
!= zend_hash_index_find(Z_ARRVAL_PP(range
), 1, (void *) &end
)
565 /* this should never happen */
566 zend_hash_destroy(&r
->range
.values
);
567 php_http_env_set_response_code(500 TSRMLS_CC
);
571 php_http_message_body_to_callback(obj
->body
, (php_http_pass_callback_t
) php_http_env_response_send_data
, r
, Z_LVAL_PP(begin
), Z_LVAL_PP(end
) - Z_LVAL_PP(begin
) + 1);
572 php_http_env_response_send_done(r
);
573 zend_hash_destroy(&r
->range
.values
);
577 /* send multipart/byte-ranges message */
581 FOREACH_HASH_VAL(pos
, &r
->range
.values
, chunk
) {
584 if (IS_ARRAY
== Z_TYPE_PP(chunk
)
585 && SUCCESS
== zend_hash_index_find(Z_ARRVAL_PP(chunk
), 0, (void *) &begin
)
586 && IS_LONG
== Z_TYPE_PP(begin
)
587 && SUCCESS
== zend_hash_index_find(Z_ARRVAL_PP(chunk
), 1, (void *) &end
)
588 && IS_LONG
== Z_TYPE_PP(end
)
590 php_http_buffer_appendf(r
->buffer
,
593 "Content-Type: %s" PHP_HTTP_CRLF
594 "Content-Range: bytes %ld-%ld/%zu" PHP_HTTP_CRLF PHP_HTTP_CRLF
,
597 r
->content
.type
? r
->content
.type
: "application/octet-stream",
602 php_http_message_body_to_callback(obj
->body
, (php_http_pass_callback_t
) php_http_env_response_send_data
, r
, Z_LVAL_PP(begin
), Z_LVAL_PP(end
) - Z_LVAL_PP(begin
) + 1);
605 php_http_buffer_appendf(r
->buffer
, PHP_HTTP_CRLF
"--%s--", r
->range
.boundary
);
606 php_http_env_response_send_done(r
);
607 zend_hash_destroy(&r
->range
.values
);
611 php_http_message_body_to_callback(obj
->body
, (php_http_pass_callback_t
) php_http_env_response_send_data
, r
, 0, 0);
612 php_http_env_response_send_done(r
);
616 zval_ptr_dtor(&zbody
);
621 PHP_HTTP_API STATUS
php_http_env_response_send(php_http_env_response_t
*r
)
624 TSRMLS_FETCH_FROM_CTX(r
->ts
);
626 /* check for ranges */
627 if ( (zbody
= get_option(r
->options
, ZEND_STRL("body") TSRMLS_CC
))
628 && (Z_TYPE_P(zbody
) == IS_OBJECT
)
629 && instanceof_function(Z_OBJCE_P(zbody
), php_http_message_body_class_entry TSRMLS_CC
)
631 php_http_message_body_object_t
*obj
= zend_object_store_get_object(zbody TSRMLS_CC
);
633 r
->content
.length
= php_http_message_body_size(obj
->body
);
634 zval_ptr_dtor(&zbody
);
636 if (SUCCESS
!= php_http_env_set_response_header(0, ZEND_STRL("Accept-Ranges: bytes"), 1 TSRMLS_CC
)) {
639 zend_hash_init(&r
->range
.values
, 0, NULL
, ZVAL_PTR_DTOR
, 0);
640 r
->range
.status
= php_http_env_get_request_ranges(&r
->range
.values
, r
->content
.length TSRMLS_CC
);
642 switch (r
->range
.status
) {
643 case PHP_HTTP_RANGE_NO
:
644 zend_hash_destroy(&r
->range
.values
);
647 case PHP_HTTP_RANGE_ERR
:
648 if (php_http_env_got_request_header(ZEND_STRL("If-Range") TSRMLS_CC
)) {
649 r
->range
.status
= PHP_HTTP_RANGE_NO
;
650 zend_hash_destroy(&r
->range
.values
);
653 zend_hash_destroy(&r
->range
.values
);
654 if (SUCCESS
!= php_http_env_set_response_header_format(416, 1 TSRMLS_CC
, "Content-Range: bytes */%zu", r
->content
.length
)) {
660 case PHP_HTTP_RANGE_OK
:
661 if (PHP_HTTP_CACHE_MISS
== php_http_env_is_response_cached_by_etag(r
->options
, ZEND_STRL("If-Range") TSRMLS_CC
)
662 || PHP_HTTP_CACHE_MISS
== php_http_env_is_response_cached_by_last_modified(r
->options
, ZEND_STRL("If-Range") TSRMLS_CC
)
664 r
->range
.status
= PHP_HTTP_RANGE_NO
;
665 zend_hash_destroy(&r
->range
.values
);
668 if (PHP_HTTP_CACHE_MISS
== php_http_env_is_response_cached_by_etag(r
->options
, ZEND_STRL("If-Match") TSRMLS_CC
)
669 || PHP_HTTP_CACHE_MISS
== php_http_env_is_response_cached_by_last_modified(r
->options
, ZEND_STRL("If-Unmodified-Since") TSRMLS_CC
)
670 || PHP_HTTP_CACHE_MISS
== php_http_env_is_response_cached_by_last_modified(r
->options
, ZEND_STRL("Unless-Modified-Since") TSRMLS_CC
)
673 zend_hash_destroy(&r
->range
.values
);
674 if (SUCCESS
!= php_http_env_set_response_code(412 TSRMLS_CC
)) {
684 zval_ptr_dtor(&zbody
);
687 if (SUCCESS
!= php_http_env_response_send_head(r
)) {
691 if (SUCCESS
!= php_http_env_response_send_body(r
)) {
697 zend_class_entry
*php_http_env_response_class_entry
;
699 #undef PHP_HTTP_BEGIN_ARGS
700 #undef PHP_HTTP_EMPTY_ARGS
701 #define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpEnvResponse, method, 0, req_args)
702 #define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpEnvResponse, method, 0)
703 #define PHP_HTTP_ENV_RESPONSE_ME(method, visibility) PHP_ME(HttpEnvResponse, method, PHP_HTTP_ARGS(HttpEnvResponse, method), visibility)
705 PHP_HTTP_EMPTY_ARGS(__construct
);
707 PHP_HTTP_BEGIN_ARGS(__invoke
, 1)
708 PHP_HTTP_ARG_VAL(ob_string
, 0)
709 PHP_HTTP_ARG_VAL(ob_flags
, 0)
712 PHP_HTTP_BEGIN_ARGS(setContentType
, 1)
713 PHP_HTTP_ARG_VAL(content_type
, 0)
716 PHP_HTTP_BEGIN_ARGS(setContentEncoding
, 1)
717 PHP_HTTP_ARG_VAL(content_encoding
, 0)
720 PHP_HTTP_BEGIN_ARGS(setContentDisposition
, 1)
721 PHP_HTTP_ARG_VAL(content_disposition
, 0)
722 PHP_HTTP_ARG_VAL(filename
, 0)
725 PHP_HTTP_BEGIN_ARGS(setCacheControl
, 1)
726 PHP_HTTP_ARG_VAL(cache_control
, 0)
729 PHP_HTTP_BEGIN_ARGS(setLastModified
, 1)
730 PHP_HTTP_ARG_VAL(last_modified
, 0)
733 PHP_HTTP_BEGIN_ARGS(isCachedByLastModified
, 0)
734 PHP_HTTP_ARG_VAL(header_name
, 0)
737 PHP_HTTP_BEGIN_ARGS(setEtag
, 1)
738 PHP_HTTP_ARG_VAL(etag
, 0)
741 PHP_HTTP_BEGIN_ARGS(isCachedByEtag
, 0)
742 PHP_HTTP_ARG_VAL(header_name
, 0)
745 PHP_HTTP_BEGIN_ARGS(setThrottleRate
, 1)
746 PHP_HTTP_ARG_VAL(chunk_size
, 0)
747 PHP_HTTP_ARG_VAL(delay
, 0)
750 PHP_HTTP_EMPTY_ARGS(send
);
753 zend_function_entry php_http_env_response_method_entry
[] = {
754 PHP_HTTP_ENV_RESPONSE_ME(__construct
, ZEND_ACC_PUBLIC
|ZEND_ACC_CTOR
)
755 PHP_HTTP_ENV_RESPONSE_ME(__invoke
, ZEND_ACC_PUBLIC
)
756 PHP_HTTP_ENV_RESPONSE_ME(setContentType
, ZEND_ACC_PUBLIC
)
757 PHP_HTTP_ENV_RESPONSE_ME(setContentDisposition
, ZEND_ACC_PUBLIC
)
758 PHP_HTTP_ENV_RESPONSE_ME(setContentEncoding
, ZEND_ACC_PUBLIC
)
759 PHP_HTTP_ENV_RESPONSE_ME(setCacheControl
, ZEND_ACC_PUBLIC
)
760 PHP_HTTP_ENV_RESPONSE_ME(setLastModified
, ZEND_ACC_PUBLIC
)
761 PHP_HTTP_ENV_RESPONSE_ME(isCachedByLastModified
, ZEND_ACC_PUBLIC
)
762 PHP_HTTP_ENV_RESPONSE_ME(setEtag
, ZEND_ACC_PUBLIC
)
763 PHP_HTTP_ENV_RESPONSE_ME(isCachedByEtag
, ZEND_ACC_PUBLIC
)
764 PHP_HTTP_ENV_RESPONSE_ME(setThrottleRate
, ZEND_ACC_PUBLIC
)
766 PHP_HTTP_ENV_RESPONSE_ME(send
, ZEND_ACC_PUBLIC
)
772 PHP_METHOD(HttpEnvResponse
, __construct
)
774 with_error_handling(EH_THROW
, php_http_exception_class_entry
) {
775 if (SUCCESS
== zend_parse_parameters_none()) {
776 php_http_message_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
778 with_error_handling(EH_THROW
, php_http_exception_class_entry
) {
779 obj
->message
= php_http_message_init_env(obj
->message
, PHP_HTTP_RESPONSE TSRMLS_CC
);
780 } end_error_handling();
782 } end_error_handling();
786 PHP_METHOD(HttpEnvResponse
, __invoke
)
792 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s|l", &ob_str
, &ob_len
, &ob_flags
)) {
793 php_http_message_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
795 if (obj
->body
.handle
|| SUCCESS
== php_http_new(&obj
->body
, php_http_message_body_class_entry
, (php_http_new_t
) php_http_message_body_object_new_ex
, NULL
, (void *) php_http_message_body_copy(&obj
->message
->body
, NULL
, 0), NULL TSRMLS_CC
)) {
796 php_http_message_body_append(&obj
->message
->body
, ob_str
, ob_len
);
803 PHP_METHOD(HttpEnvResponse
, setContentType
)
808 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s!", &ct_str
, &ct_len
)) {
809 set_option(getThis(), ZEND_STRL("contentType"), IS_STRING
, ct_str
, ct_len TSRMLS_CC
);
813 PHP_METHOD(HttpEnvResponse
, setContentDisposition
)
816 char *file_str
= NULL
;
819 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "l|s!", &cd
, &file_str
, &file_len
)) {
824 add_assoc_long_ex(arr
, ZEND_STRS("disposition"), cd
);
826 add_assoc_stringl_ex(arr
, ZEND_STRS("filename"), file_str
, file_len
, 1);
828 zend_update_property(Z_OBJCE_P(getThis()), getThis(), ZEND_STRL("contentDisposition"), arr TSRMLS_CC
);
833 PHP_METHOD(HttpEnvResponse
, setContentEncoding
)
837 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "l", &ce
)) {
838 set_option(getThis(), ZEND_STRL("contentEncoding"), IS_LONG
, &ce
, 0 TSRMLS_CC
);
842 PHP_METHOD(HttpEnvResponse
, setCacheControl
)
847 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s!", &cc_str
, &cc_len
)) {
848 set_option(getThis(), ZEND_STRL("cacheControl"), IS_STRING
, cc_str
, cc_len TSRMLS_CC
);
852 PHP_METHOD(HttpEnvResponse
, setLastModified
)
856 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "l", &last_modified
)) {
857 set_option(getThis(), ZEND_STRL("lastModified"), IS_LONG
, &last_modified
, 0 TSRMLS_CC
);
861 PHP_METHOD(HttpEnvResponse
, isCachedByLastModified
)
863 char *header_name_str
= NULL
;
864 int header_name_len
= 0;
866 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|s!", &header_name_str
, &header_name_len
)) {
867 if (!header_name_str
|| !header_name_len
) {
868 header_name_str
= "If-Modified-Since";
869 header_name_len
= lenof("If-Modified-Since");
871 RETURN_LONG(php_http_env_is_response_cached_by_last_modified(getThis(), header_name_str
, header_name_len TSRMLS_CC
));
876 PHP_METHOD(HttpEnvResponse
, setEtag
)
878 char *etag_str
= NULL
;
881 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s!", &etag_str
, &etag_len
)) {
882 set_option(getThis(), ZEND_STRL("etag"), IS_STRING
, etag_str
, etag_len TSRMLS_CC
);
886 PHP_METHOD(HttpEnvResponse
, isCachedByEtag
)
888 char *header_name_str
= NULL
;
889 int header_name_len
= 0;
891 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|s!", &header_name_str
, &header_name_len
)) {
892 if (!header_name_str
|| !header_name_len
) {
893 header_name_str
= "If-None-Match";
894 header_name_len
= lenof("If-None-Match");
896 RETURN_LONG(php_http_env_is_response_cached_by_etag(getThis(), header_name_str
, header_name_len TSRMLS_CC
));
901 PHP_METHOD(HttpEnvResponse
, setThrottleRate
)
906 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "l|d", &chunk_size
, &delay
)) {
907 long chunk_size_long
= (long) chunk_size
;
909 set_option(getThis(), ZEND_STRL("throttleDelay"), IS_DOUBLE
, &delay
, 0 TSRMLS_CC
);
910 set_option(getThis(), ZEND_STRL("throttleChunk"), IS_LONG
, &chunk_size_long
, 0 TSRMLS_CC
);
916 PHP_METHOD(HttpEnvResponse
, send
)
920 if (SUCCESS
== zend_parse_parameters_none()) {
921 php_http_env_response_t
*r
= php_http_env_response_init(NULL
, getThis() TSRMLS_CC
);
924 RETVAL_SUCCESS(php_http_env_response_send(r
));
927 php_http_env_response_free(&r
);
931 PHP_MINIT_FUNCTION(http_env_response
)
933 PHP_HTTP_REGISTER_CLASS(http
\\Env
, Response
, http_env_response
, php_http_message_class_entry
, 0);
935 zend_declare_class_constant_long(php_http_env_response_class_entry
, ZEND_STRL("CONTENT_DISPOSITION_NONE"), PHP_HTTP_CONTENT_DISPOSITION_NONE TSRMLS_CC
);
936 zend_declare_class_constant_long(php_http_env_response_class_entry
, ZEND_STRL("CONTENT_DISPOSITION_INLINE"), PHP_HTTP_CONTENT_DISPOSITION_INLINE TSRMLS_CC
);
937 zend_declare_class_constant_long(php_http_env_response_class_entry
, ZEND_STRL("CONTENT_DISPOSITION_ATTACHMENT"), PHP_HTTP_CONTENT_DISPOSITION_ATTACHMENT TSRMLS_CC
);
939 zend_declare_class_constant_long(php_http_env_response_class_entry
, ZEND_STRL("CONTENT_ENCODING_NONE"), PHP_HTTP_CONTENT_ENCODING_NONE TSRMLS_CC
);
940 zend_declare_class_constant_long(php_http_env_response_class_entry
, ZEND_STRL("CONTENT_ENCODING_GZIP"), PHP_HTTP_CONTENT_ENCODING_GZIP TSRMLS_CC
);
942 zend_declare_class_constant_long(php_http_env_response_class_entry
, ZEND_STRL("CACHE_NO"), PHP_HTTP_CACHE_NO TSRMLS_CC
);
943 zend_declare_class_constant_long(php_http_env_response_class_entry
, ZEND_STRL("CACHE_HIT"), PHP_HTTP_CACHE_HIT TSRMLS_CC
);
944 zend_declare_class_constant_long(php_http_env_response_class_entry
, ZEND_STRL("CACHE_MISS"), PHP_HTTP_CACHE_MISS TSRMLS_CC
);
946 zend_declare_property_null(php_http_env_response_class_entry
, ZEND_STRL("contentType"), ZEND_ACC_PROTECTED TSRMLS_CC
);
947 zend_declare_property_null(php_http_env_response_class_entry
, ZEND_STRL("contentDisposition"), ZEND_ACC_PROTECTED TSRMLS_CC
);
948 zend_declare_property_null(php_http_env_response_class_entry
, ZEND_STRL("contentEncoding"), ZEND_ACC_PROTECTED TSRMLS_CC
);
949 zend_declare_property_null(php_http_env_response_class_entry
, ZEND_STRL("cacheControl"), ZEND_ACC_PROTECTED TSRMLS_CC
);
950 zend_declare_property_null(php_http_env_response_class_entry
, ZEND_STRL("etag"), ZEND_ACC_PROTECTED TSRMLS_CC
);
951 zend_declare_property_null(php_http_env_response_class_entry
, ZEND_STRL("lastModified"), ZEND_ACC_PROTECTED TSRMLS_CC
);
952 zend_declare_property_null(php_http_env_response_class_entry
, ZEND_STRL("throttleDelay"), ZEND_ACC_PROTECTED TSRMLS_CC
);
953 zend_declare_property_null(php_http_env_response_class_entry
, ZEND_STRL("throttleChunk"), ZEND_ACC_PROTECTED TSRMLS_CC
);
964 * vim600: noet sw=4 ts=4 fdm=marker
965 * vim<600: noet sw=4 ts=4