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-2014, 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
, void *value_ptr
, size_t value_len
)
17 if (Z_TYPE_P(options
) == IS_OBJECT
) {
18 if (EXPECTED(value_ptr
)) {
21 zend_update_property_double(Z_OBJCE_P(options
), options
, name_str
, name_len
, *(double *)value_ptr
);
24 zend_update_property_long(Z_OBJCE_P(options
), options
, name_str
, name_len
, *(zend_long
*)value_ptr
);
27 zend_update_property_stringl(Z_OBJCE_P(options
), options
, name_str
, name_len
, value_ptr
, value_len
);
31 zend_update_property(Z_OBJCE_P(options
), options
, name_str
, name_len
, value_ptr
);
35 zend_update_property_null(Z_OBJCE_P(options
), options
, name_str
, name_len
);
38 convert_to_array(options
);
39 if (EXPECTED(value_ptr
)) {
42 add_assoc_double_ex(options
, name_str
, name_len
, *(double *)value_ptr
);
45 add_assoc_long_ex(options
, name_str
, name_len
, *(zend_long
*)value_ptr
);
48 zend_string
*value
= zend_string_init(value_ptr
, value_len
, 0);
49 add_assoc_str_ex(options
, name_str
, name_len
, value
);
53 Z_ADDREF_P(value_ptr
);
54 add_assoc_zval_ex(options
, name_str
, name_len
, value_ptr
);
59 add_assoc_null_ex(options
, name_str
, name_len
);
63 static zval
*get_option(zval
*options
, const char *name_str
, size_t name_len
, zval
*tmp
)
67 if (EXPECTED(Z_TYPE_P(options
) == IS_OBJECT
)) {
68 val
= zend_read_property(Z_OBJCE_P(options
), options
, name_str
, name_len
, 0, tmp
);
69 } else if (EXPECTED(Z_TYPE_P(options
) == IS_ARRAY
)) {
70 val
= zend_symtable_str_find(Z_ARRVAL_P(options
), name_str
, name_len
);
79 static php_http_message_body_t
*get_body(zval
*options
)
81 zval zbody_tmp
, *zbody
;
82 php_http_message_body_t
*body
= NULL
;
84 if (EXPECTED(zbody
= get_option(options
, ZEND_STRL("body"), &zbody_tmp
))) {
85 if ((Z_TYPE_P(zbody
) == IS_OBJECT
) && instanceof_function(Z_OBJCE_P(zbody
), php_http_get_message_body_class_entry())) {
86 php_http_message_body_object_t
*body_obj
= PHP_HTTP_OBJ(NULL
, zbody
);
88 body
= body_obj
->body
;
90 Z_TRY_DELREF_P(zbody
);
95 static php_http_message_t
*get_request(zval
*options
)
97 zval zrequest_tmp
, *zrequest
;
98 php_http_message_t
*request
= NULL
;
100 if (EXPECTED(zrequest
= get_option(options
, ZEND_STRL("request"), &zrequest_tmp
))) {
101 if (UNEXPECTED(Z_TYPE_P(zrequest
) == IS_OBJECT
&& instanceof_function(Z_OBJCE_P(zrequest
), php_http_message_get_class_entry()))) {
102 php_http_message_object_t
*request_obj
= PHP_HTTP_OBJ(NULL
, zrequest
);
104 request
= request_obj
->message
;
106 Z_TRY_DELREF_P(zrequest
);
111 static void set_cookie(zval
*options
, zval
*zcookie_new
)
113 zval tmp
, zcookies_set_tmp
, *zcookies_set
;
114 php_http_arrkey_t key
;
115 php_http_cookie_object_t
*obj
= PHP_HTTP_OBJ(NULL
, zcookie_new
);
118 zcookies_set
= get_option(options
, ZEND_STRL("cookies"), &zcookies_set_tmp
);
119 if (zcookies_set
&& Z_TYPE_P(zcookies_set
) == IS_ARRAY
) {
120 array_copy(Z_ARRVAL_P(zcookies_set
), Z_ARRVAL(tmp
));
121 zval_ptr_dtor(zcookies_set
);
124 ZEND_HASH_FOREACH_KEY(&obj
->list
->cookies
, key
.h
, key
.key
)
126 Z_ADDREF_P(zcookie_new
);
128 add_assoc_zval_ex(&tmp
, key
.key
->val
, key
.key
->len
, zcookie_new
);
130 add_index_zval(&tmp
, key
.h
, zcookie_new
);
133 ZEND_HASH_FOREACH_END();
135 set_option(options
, ZEND_STRL("cookies"), IS_ARRAY
, &tmp
, 0);
139 php_http_cache_status_t
php_http_env_is_response_cached_by_etag(zval
*options
, const char *header_str
, size_t header_len
, php_http_message_t
*request
)
141 php_http_cache_status_t ret
= PHP_HTTP_CACHE_NO
;
142 char *header
= NULL
, *etag
= NULL
;
143 php_http_message_body_t
*body
;
144 zval zetag_tmp
, *zetag
;
147 if (UNEXPECTED(!(body
= get_body(options
)))) {
151 if (EXPECTED(zetag
= get_option(options
, ZEND_STRL("etag"), &zetag_tmp
)) && Z_TYPE_P(zetag
) != IS_NULL
) {
152 zend_string
*zs
= zval_get_string(zetag
);
153 etag
= estrndup(zs
->val
, zs
->len
);
154 zend_string_release(zs
);
155 zval_ptr_dtor(zetag
);
158 if (!etag
&& (etag
= php_http_message_body_etag(body
))) {
159 set_option(options
, ZEND_STRL("etag"), IS_STRING
, etag
, strlen(etag
));
162 if (etag
&& (header
= php_http_env_get_request_header(header_str
, header_len
, NULL
, request
))) {
163 ret
= php_http_match(header
, etag
, PHP_HTTP_MATCH_WORD
) ? PHP_HTTP_CACHE_HIT
: PHP_HTTP_CACHE_MISS
;
172 php_http_cache_status_t
php_http_env_is_response_cached_by_last_modified(zval
*options
, const char *header_str
, size_t header_len
, php_http_message_t
*request
)
174 php_http_cache_status_t ret
= PHP_HTTP_CACHE_NO
;
177 php_http_message_body_t
*body
;
180 if (UNEXPECTED(!(body
= get_body(options
)))) {
184 if (EXPECTED(zlm
= get_option(options
, ZEND_STRL("lastModified"), &zlm_tmp
))) {
185 lm
= zval_get_long(zlm
);
189 if (EXPECTED(lm
<= 0)) {
190 lm
= php_http_message_body_mtime(body
);
191 set_option(options
, ZEND_STRL("lastModified"), IS_LONG
, &lm
, 0);
194 if ((header
= php_http_env_get_request_header(header_str
, header_len
, NULL
, request
))) {
195 ums
= php_parse_date(header
, NULL
);
197 if (ums
> 0 && ums
>= lm
) {
198 ret
= PHP_HTTP_CACHE_HIT
;
200 ret
= PHP_HTTP_CACHE_MISS
;
208 static zend_bool
php_http_env_response_is_cacheable(php_http_env_response_t
*r
, php_http_message_t
*request
)
210 long status
= r
->ops
->get_status(r
);
212 if (status
&& status
/ 100 != 2) {
216 if (php_http_env_got_request_header(ZEND_STRL("Authorization"), request
)) {
220 if (-1 == php_http_select_str(php_http_env_get_request_method(request
), 2, "HEAD", "GET")) {
227 static size_t output(void *context
, char *buf
, size_t len
)
229 php_http_env_response_t
*r
= context
;
231 if (UNEXPECTED(SUCCESS
!= r
->ops
->write(r
, buf
, len
))) {
235 /* we really only need to flush when throttling is enabled,
236 because we push the data as fast as possible anyway if not */
237 if (UNEXPECTED(r
->throttle
.delay
>= PHP_HTTP_DIFFSEC
)) {
239 php_http_sleep(r
->throttle
.delay
);
244 static ZEND_RESULT_CODE
php_http_env_response_send_data(php_http_env_response_t
*r
, const char *buf
, size_t len
)
246 size_t chunks_sent
, chunk
= r
->throttle
.chunk
? r
->throttle
.chunk
: PHP_HTTP_SENDBUF_SIZE
;
248 if (r
->content
.encoder
) {
249 char *enc_str
= NULL
;
253 if (SUCCESS
!= php_http_encoding_stream_update(r
->content
.encoder
, buf
, len
, &enc_str
, &enc_len
)) {
257 if (SUCCESS
!= php_http_encoding_stream_finish(r
->content
.encoder
, &enc_str
, &enc_len
)) {
265 chunks_sent
= php_http_buffer_chunked_output(&r
->buffer
, enc_str
, enc_len
, buf
? chunk
: 0, output
, r
);
268 chunks_sent
= php_http_buffer_chunked_output(&r
->buffer
, buf
, len
, buf
? chunk
: 0, output
, r
);
271 return chunks_sent
!= (size_t) -1 ? SUCCESS
: FAILURE
;
274 static inline ZEND_RESULT_CODE
php_http_env_response_send_done(php_http_env_response_t
*r
)
276 return php_http_env_response_send_data(r
, NULL
, 0);
279 php_http_env_response_t
*php_http_env_response_init(php_http_env_response_t
*r
, zval
*options
, php_http_env_response_ops_t
*ops
, void *init_arg
)
284 r
= emalloc(sizeof(*r
));
286 memset(r
, 0, sizeof(*r
));
291 r
->ops
= php_http_env_response_get_sapi_ops();
294 r
->buffer
= php_http_buffer_init(NULL
);
296 ZVAL_COPY(&r
->options
, options
);
298 if (r
->ops
->init
&& (SUCCESS
!= r
->ops
->init(r
, init_arg
))) {
300 php_http_env_response_free(&r
);
302 php_http_env_response_dtor(r
);
310 void php_http_env_response_dtor(php_http_env_response_t
*r
)
315 php_http_buffer_free(&r
->buffer
);
316 zval_ptr_dtor(&r
->options
);
317 PTR_FREE(r
->content
.type
);
318 PTR_FREE(r
->content
.encoding
);
319 if (r
->content
.encoder
) {
320 php_http_encoding_stream_free(&r
->content
.encoder
);
324 void php_http_env_response_free(php_http_env_response_t
**r
)
327 php_http_env_response_dtor(*r
);
333 static ZEND_RESULT_CODE
php_http_env_response_send_head(php_http_env_response_t
*r
, php_http_message_t
*request
)
335 ZEND_RESULT_CODE ret
= SUCCESS
;
336 zval zoption_tmp
, *zoption
, *options
= &r
->options
;
342 if (EXPECTED(zoption
= get_option(options
, ZEND_STRL("headers"), &zoption_tmp
))) {
343 if (EXPECTED(Z_TYPE_P(zoption
) == IS_ARRAY
)) {
344 php_http_header_to_callback(Z_ARRVAL_P(zoption
), 0, (php_http_pass_format_callback_t
) r
->ops
->set_header
, r
);
346 zval_ptr_dtor(zoption
);
349 if (EXPECTED(zoption
= get_option(options
, ZEND_STRL("responseCode"), &zoption_tmp
))) {
350 zend_long rc
= zval_get_long(zoption
);
352 zval_ptr_dtor(zoption
);
354 ret
= r
->ops
->set_status(r
, rc
);
358 if (ret
!= SUCCESS
) {
362 if (EXPECTED(zoption
= get_option(options
, ZEND_STRL("httpVersion"), &zoption_tmp
))) {
363 php_http_version_t v
;
364 zend_string
*zs
= zval_get_string(zoption
);
366 zval_ptr_dtor(zoption
);
367 if (EXPECTED(zs
->len
&& php_http_version_parse(&v
, zs
->val
))) {
368 ret
= r
->ops
->set_protocol_version(r
, &v
);
369 php_http_version_dtor(&v
);
371 zend_string_release(zs
);
374 if (ret
!= SUCCESS
) {
378 if (EXPECTED(zoption
= get_option(options
, ZEND_STRL("cookies"), &zoption_tmp
))) {
379 if (Z_TYPE_P(zoption
) == IS_ARRAY
) {
382 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(zoption
), zcookie
)
384 if (Z_TYPE_P(zcookie
) == IS_OBJECT
&& instanceof_function(Z_OBJCE_P(zcookie
), php_http_cookie_get_class_entry())) {
385 php_http_cookie_object_t
*obj
= PHP_HTTP_OBJ(NULL
, zcookie
);
389 php_http_cookie_list_to_string(obj
->list
, &str
, &len
);
390 if (SUCCESS
!= (ret
= r
->ops
->add_header(r
, "Set-Cookie: %s", str
))) {
397 ZEND_HASH_FOREACH_END();
399 zval_ptr_dtor(zoption
);
402 if (ret
!= SUCCESS
) {
406 if (EXPECTED(zoption
= get_option(options
, ZEND_STRL("contentType"), &zoption_tmp
))) {
407 zend_string
*zs
= zval_get_string(zoption
);
409 zval_ptr_dtor(zoption
);
410 if (zs
->len
&& strchr(zs
->val
, '/')) {
411 if (SUCCESS
== (ret
= r
->ops
->set_header(r
, "Content-Type: %.*s", zs
->len
, zs
->val
))) {
412 r
->content
.type
= estrndup(zs
->val
, zs
->len
);
415 zend_string_release(zs
);
418 if (ret
!= SUCCESS
) {
422 if (UNEXPECTED(r
->range
.status
== PHP_HTTP_RANGE_OK
)) {
423 if (zend_hash_num_elements(&r
->range
.values
) == 1) {
424 zval
*range
, *begin
, *end
;
426 if (EXPECTED( 1 == php_http_array_list(&r
->range
.values
, 1, &range
)
427 && 2 == php_http_array_list(Z_ARRVAL_P(range
), 2, &begin
, &end
))
429 if (SUCCESS
== (ret
= r
->ops
->set_status(r
, 206))) {
430 ret
= r
->ops
->set_header(r
, "Content-Range: bytes %ld-%ld/%zu", Z_LVAL_P(begin
), Z_LVAL_P(end
), r
->content
.length
);
433 /* this should never happen */
434 zend_hash_destroy(&r
->range
.values
);
438 php_http_boundary(r
->range
.boundary
, sizeof(r
->range
.boundary
));
439 if (SUCCESS
== (ret
= r
->ops
->set_status(r
, 206))) {
440 ret
= r
->ops
->set_header(r
, "Content-Type: multipart/byteranges; boundary=%s", r
->range
.boundary
);
444 if (EXPECTED(zoption
= get_option(options
, ZEND_STRL("cacheControl"), &zoption_tmp
))) {
445 zend_string
*zs
= zval_get_string(zoption
);
447 zval_ptr_dtor(zoption
);
449 ret
= r
->ops
->set_header(r
, "Cache-Control: %.*s", zs
->len
, zs
->val
);
451 zend_string_release(zs
);
454 if (ret
!= SUCCESS
) {
458 if (EXPECTED(zoption
= get_option(options
, ZEND_STRL("contentDisposition"), &zoption_tmp
))) {
460 if (Z_TYPE_P(zoption
) == IS_ARRAY
) {
461 php_http_buffer_t buf
;
463 php_http_buffer_init(&buf
);
464 if (php_http_params_to_string(&buf
, Z_ARRVAL_P(zoption
), ZEND_STRL(","), ZEND_STRL(";"), ZEND_STRL("="), PHP_HTTP_PARAMS_DEFAULT
)) {
466 ret
= r
->ops
->set_header(r
, "Content-Disposition: %.*s", buf
.used
, buf
.data
);
470 php_http_buffer_dtor(&buf
);
472 zval_ptr_dtor(zoption
);
475 if (ret
!= SUCCESS
) {
479 if (EXPECTED(zoption
= get_option(options
, ZEND_STRL("contentEncoding"), &zoption_tmp
))) {
480 zend_long ce
= zval_get_long(zoption
);
482 HashTable
*result
= NULL
;
484 zval_ptr_dtor(zoption
);
486 case PHP_HTTP_CONTENT_ENCODING_GZIP
:
487 array_init(&zsupported
);
488 add_next_index_stringl(&zsupported
, ZEND_STRL("none"));
489 add_next_index_stringl(&zsupported
, ZEND_STRL("gzip"));
490 add_next_index_stringl(&zsupported
, ZEND_STRL("deflate"));
492 if ((result
= php_http_negotiate_encoding(Z_ARRVAL(zsupported
), request
))) {
493 zend_string
*key_str
= NULL
;
494 zend_ulong index
= 0;
496 zend_hash_internal_pointer_reset(result
);
497 if (HASH_KEY_IS_STRING
== zend_hash_get_current_key(result
, &key_str
, &index
)) {
498 if (zend_string_equals_literal(key_str
, "gzip")) {
499 if (!(r
->content
.encoder
= php_http_encoding_stream_init(NULL
, php_http_encoding_stream_get_deflate_ops(), PHP_HTTP_DEFLATE_TYPE_GZIP
))) {
501 } else if (SUCCESS
== (ret
= r
->ops
->set_header(r
, "Content-Encoding: gzip"))) {
502 r
->content
.encoding
= estrndup(key_str
->val
, key_str
->len
);
504 } else if (zend_string_equals_literal(key_str
, "deflate")) {
505 if (!(r
->content
.encoder
= php_http_encoding_stream_init(NULL
, php_http_encoding_stream_get_deflate_ops(), PHP_HTTP_DEFLATE_TYPE_ZLIB
))) {
507 } else if (SUCCESS
== (ret
= r
->ops
->set_header(r
, "Content-Encoding: deflate"))) {
508 r
->content
.encoding
= estrndup(key_str
->val
, key_str
->len
);
511 ret
= r
->ops
->del_header(r
, ZEND_STRL("Content-Encoding"));
514 if (SUCCESS
== ret
) {
515 ret
= r
->ops
->add_header(r
, "Vary: Accept-Encoding");
519 zend_hash_destroy(result
);
520 FREE_HASHTABLE(result
);
523 zval_dtor(&zsupported
);
526 case PHP_HTTP_CONTENT_ENCODING_NONE
:
528 ret
= r
->ops
->del_header(r
, ZEND_STRL("Content-Encoding"));
533 if (SUCCESS
!= ret
) {
537 if (php_http_env_response_is_cacheable(r
, request
)) {
538 switch (php_http_env_is_response_cached_by_etag(options
, ZEND_STRL("If-None-Match"), request
)) {
539 case PHP_HTTP_CACHE_MISS
:
542 case PHP_HTTP_CACHE_NO
:
543 if (PHP_HTTP_CACHE_HIT
!= php_http_env_is_response_cached_by_last_modified(options
, ZEND_STRL("If-Modified-Since"), request
)) {
548 case PHP_HTTP_CACHE_HIT
:
549 ret
= r
->ops
->set_status(r
, 304);
554 if (EXPECTED(zoption
= get_option(options
, ZEND_STRL("etag"), &zoption_tmp
))) {
555 zend_string
*zs
= zval_get_string(zoption
);
557 zval_ptr_dtor(zoption
);
558 if (EXPECTED(*zs
->val
!= '"' && strncmp(zs
->val
, "W/\"", 3))) {
559 ret
= r
->ops
->set_header(r
, "ETag: \"%s\"", zs
->val
);
561 ret
= r
->ops
->set_header(r
, "ETag: %s", zs
->val
);
563 zend_string_release(zs
);
565 if (EXPECTED(zoption
= get_option(options
, ZEND_STRL("lastModified"), &zoption_tmp
))) {
566 zend_long lm
= zval_get_long(zoption
);
568 zval_ptr_dtor(zoption
);
570 zend_string
*date
= php_format_date(ZEND_STRL(PHP_HTTP_DATE_FORMAT
), lm
, 0);
572 ret
= r
->ops
->set_header(r
, "Last-Modified: %s", date
->val
);
573 zend_string_release(date
);
583 static ZEND_RESULT_CODE
php_http_env_response_send_body(php_http_env_response_t
*r
)
585 ZEND_RESULT_CODE ret
= SUCCESS
;
586 zval zoption_tmp
, *zoption
;
587 php_http_message_body_t
*body
;
593 if (EXPECTED(body
= get_body(&r
->options
))) {
594 if (EXPECTED(zoption
= get_option(&r
->options
, ZEND_STRL("throttleDelay"), &zoption_tmp
))) {
595 r
->throttle
.delay
= zval_get_double(zoption
);
596 zval_ptr_dtor(zoption
);
598 if (EXPECTED(zoption
= get_option(&r
->options
, ZEND_STRL("throttleChunk"), &zoption_tmp
))) {
599 r
->throttle
.chunk
= zval_get_long(zoption
);
600 zval_ptr_dtor(zoption
);
603 if (UNEXPECTED(r
->range
.status
== PHP_HTTP_RANGE_OK
)) {
604 if (zend_hash_num_elements(&r
->range
.values
) == 1) {
606 zval
*range
, *begin
, *end
;
608 if ( 1 == php_http_array_list(&r
->range
.values
, 1, &range
)
609 && 2 == php_http_array_list(Z_ARRVAL_P(range
), 2, &begin
, &end
)
612 ret
= php_http_message_body_to_callback(body
, (php_http_pass_callback_t
) php_http_env_response_send_data
, r
, Z_LVAL_P(begin
), Z_LVAL_P(end
) - Z_LVAL_P(begin
) + 1);
613 if (ret
== SUCCESS
) {
614 ret
= php_http_env_response_send_done(r
);
616 zend_hash_destroy(&r
->range
.values
);
618 /* this should never happen */
619 zend_hash_destroy(&r
->range
.values
);
620 r
->ops
->set_status(r
, 500);
625 /* send multipart/byte-ranges message */
628 ZEND_HASH_FOREACH_VAL(&r
->range
.values
, chunk
)
632 if (2 == php_http_array_list(Z_ARRVAL_P(chunk
), 2, &begin
, &end
)) {
633 php_http_buffer_appendf(r
->buffer
,
636 "Content-Type: %s" PHP_HTTP_CRLF
637 "Content-Range: bytes %ld-%ld/%zu" PHP_HTTP_CRLF PHP_HTTP_CRLF
,
640 r
->content
.type
? r
->content
.type
: "application/octet-stream",
645 ret
= php_http_message_body_to_callback(body
, (php_http_pass_callback_t
) php_http_env_response_send_data
, r
, Z_LVAL_P(begin
), Z_LVAL_P(end
) - Z_LVAL_P(begin
) + 1);
648 ZEND_HASH_FOREACH_END();
650 if (ret
== SUCCESS
) {
651 php_http_buffer_appendf(r
->buffer
, PHP_HTTP_CRLF
"--%s--", r
->range
.boundary
);
652 ret
= php_http_env_response_send_done(r
);
654 zend_hash_destroy(&r
->range
.values
);
658 ret
= php_http_message_body_to_callback(body
, (php_http_pass_callback_t
) php_http_env_response_send_data
, r
, 0, 0);
659 if (ret
== SUCCESS
) {
660 ret
= php_http_env_response_send_done(r
);
667 ZEND_RESULT_CODE
php_http_env_response_send(php_http_env_response_t
*r
)
669 php_http_message_t
*request
;
670 php_http_message_body_t
*body
;
672 request
= get_request(&r
->options
);
674 /* check for ranges */
675 if (EXPECTED(body
= get_body(&r
->options
))) {
676 r
->content
.length
= php_http_message_body_size(body
);
678 if (UNEXPECTED(SUCCESS
!= r
->ops
->set_header(r
, "Accept-Ranges: bytes"))) {
681 ZEND_INIT_SYMTABLE_EX(&r
->range
.values
, 0, 0);
682 r
->range
.status
= php_http_env_get_request_ranges(&r
->range
.values
, r
->content
.length
, request
);
684 switch (r
->range
.status
) {
685 case PHP_HTTP_RANGE_NO
:
686 zend_hash_destroy(&r
->range
.values
);
689 case PHP_HTTP_RANGE_ERR
:
690 if (php_http_env_got_request_header(ZEND_STRL("If-Range"), request
)) {
691 r
->range
.status
= PHP_HTTP_RANGE_NO
;
692 zend_hash_destroy(&r
->range
.values
);
695 zend_hash_destroy(&r
->range
.values
);
696 if (SUCCESS
!= r
->ops
->set_status(r
, 416)) {
699 if (SUCCESS
!= r
->ops
->set_header(r
, "Content-Range: bytes */%zu", r
->content
.length
)) {
705 case PHP_HTTP_RANGE_OK
:
706 if (PHP_HTTP_CACHE_MISS
== php_http_env_is_response_cached_by_etag(&r
->options
, ZEND_STRL("If-Range"), request
)
707 || PHP_HTTP_CACHE_MISS
== php_http_env_is_response_cached_by_last_modified(&r
->options
, ZEND_STRL("If-Range"), request
)
709 r
->range
.status
= PHP_HTTP_RANGE_NO
;
710 zend_hash_destroy(&r
->range
.values
);
713 if (PHP_HTTP_CACHE_MISS
== php_http_env_is_response_cached_by_etag(&r
->options
, ZEND_STRL("If-Match"), request
)
714 || PHP_HTTP_CACHE_MISS
== php_http_env_is_response_cached_by_last_modified(&r
->options
, ZEND_STRL("If-Unmodified-Since"), request
)
715 || PHP_HTTP_CACHE_MISS
== php_http_env_is_response_cached_by_last_modified(&r
->options
, ZEND_STRL("Unless-Modified-Since"), request
)
718 zend_hash_destroy(&r
->range
.values
);
719 if (SUCCESS
!= r
->ops
->set_status(r
, 412)) {
730 if (UNEXPECTED(SUCCESS
!= php_http_env_response_send_head(r
, request
))) {
731 php_error_docref(NULL
, E_WARNING
, "Failed to send response headers");
735 if (UNEXPECTED(SUCCESS
!= php_http_env_response_send_body(r
))) {
736 php_error_docref(NULL
, E_WARNING
, "Failed to send response body");
740 if (UNEXPECTED(SUCCESS
!= r
->ops
->finish(r
))) {
741 php_error_docref(NULL
, E_WARNING
, "Failed to finish response");
748 static long php_http_env_response_sapi_get_status(php_http_env_response_t
*r
)
750 return php_http_env_get_response_code();
752 static ZEND_RESULT_CODE
php_http_env_response_sapi_set_status(php_http_env_response_t
*r
, long http_code
)
754 return php_http_env_set_response_code(http_code
);
756 static ZEND_RESULT_CODE
php_http_env_response_sapi_set_protocol_version(php_http_env_response_t
*r
, php_http_version_t
*v
)
759 return php_http_env_set_response_protocol_version(v
);
761 static ZEND_RESULT_CODE
php_http_env_response_sapi_set_header(php_http_env_response_t
*r
, const char *fmt
, ...)
763 ZEND_RESULT_CODE ret
;
767 ret
= php_http_env_set_response_header_va(0, 1, fmt
, args
);
772 static ZEND_RESULT_CODE
php_http_env_response_sapi_add_header(php_http_env_response_t
*r
, const char *fmt
, ...)
774 ZEND_RESULT_CODE ret
;
778 ret
= php_http_env_set_response_header_va(0, 0, fmt
, args
);
783 static ZEND_RESULT_CODE
php_http_env_response_sapi_del_header(php_http_env_response_t
*r
, const char *header_str
, size_t header_len
)
785 return php_http_env_set_response_header_value(0, header_str
, header_len
, NULL
, 1);
787 static ZEND_RESULT_CODE
php_http_env_response_sapi_write(php_http_env_response_t
*r
, const char *data_str
, size_t data_len
)
789 if (0 < PHPWRITE(data_str
, data_len
)) {
794 static ZEND_RESULT_CODE
php_http_env_response_sapi_flush(php_http_env_response_t
*r
)
796 if (php_output_get_level()) {
797 php_output_flush_all();
799 if (!(php_output_get_status() & PHP_OUTPUT_IMPLICITFLUSH
)) {
805 static ZEND_RESULT_CODE
php_http_env_response_sapi_finish(php_http_env_response_t
*r
)
810 static php_http_env_response_ops_t php_http_env_response_sapi_ops
= {
813 php_http_env_response_sapi_get_status
,
814 php_http_env_response_sapi_set_status
,
815 php_http_env_response_sapi_set_protocol_version
,
816 php_http_env_response_sapi_set_header
,
817 php_http_env_response_sapi_add_header
,
818 php_http_env_response_sapi_del_header
,
819 php_http_env_response_sapi_write
,
820 php_http_env_response_sapi_flush
,
821 php_http_env_response_sapi_finish
824 php_http_env_response_ops_t
*php_http_env_response_get_sapi_ops(void)
826 return &php_http_env_response_sapi_ops
;
829 typedef struct php_http_env_response_stream_ctx
{
831 php_http_version_t version
;
835 php_stream_filter
*chunked_filter
;
836 php_http_message_t
*request
;
841 } php_http_env_response_stream_ctx_t
;
843 static ZEND_RESULT_CODE
php_http_env_response_stream_init(php_http_env_response_t
*r
, void *init_arg
)
845 php_http_env_response_stream_ctx_t
*ctx
;
846 size_t buffer_size
= 0x1000;
848 ctx
= ecalloc(1, sizeof(*ctx
));
850 ctx
->stream
= init_arg
;
851 GC_ADDREF(ctx
->stream
->res
);
852 ZEND_INIT_SYMTABLE(&ctx
->header
);
853 php_http_version_init(&ctx
->version
, 1, 1);
854 php_stream_set_option(ctx
->stream
, PHP_STREAM_OPTION_WRITE_BUFFER
, PHP_STREAM_BUFFER_FULL
, &buffer_size
);
855 ctx
->status_code
= 200;
857 ctx
->request
= get_request(&r
->options
);
859 /* there are some limitations regarding TE:chunked, see https://tools.ietf.org/html/rfc7230#section-3.3.1 */
860 if (UNEXPECTED(ctx
->request
&& ctx
->request
->http
.version
.major
== 1 && ctx
->request
->http
.version
.minor
== 0)) {
861 ctx
->version
.minor
= 0;
868 static void php_http_env_response_stream_dtor(php_http_env_response_t
*r
)
870 php_http_env_response_stream_ctx_t
*ctx
= r
->ctx
;
872 if (UNEXPECTED(ctx
->chunked_filter
)) {
873 ctx
->chunked_filter
= php_stream_filter_remove(ctx
->chunked_filter
, 1);
875 zend_hash_destroy(&ctx
->header
);
876 zend_list_delete(ctx
->stream
->res
);
880 static void php_http_env_response_stream_header(php_http_env_response_stream_ctx_t
*ctx
, HashTable
*header
, php_http_buffer_t
*buf
)
884 ZEND_HASH_FOREACH_VAL(header
, val
)
886 if (UNEXPECTED(Z_TYPE_P(val
) == IS_ARRAY
)) {
887 php_http_env_response_stream_header(ctx
, Z_ARRVAL_P(val
), buf
);
889 zend_string
*zs
= zval_get_string(val
);
892 /* disable chunked transfer encoding if we've got an explicit content-length */
893 if (!strncasecmp(zs
->val
, "Content-Length:", lenof("Content-Length:"))) {
897 php_http_buffer_append(buf
, zs
->val
, zs
->len
);
898 php_http_buffer_appends(buf
, PHP_HTTP_CRLF
);
899 zend_string_release(zs
);
902 ZEND_HASH_FOREACH_END();
904 static ZEND_RESULT_CODE
php_http_env_response_stream_start(php_http_env_response_stream_ctx_t
*ctx
)
906 php_http_buffer_t header_buf
;
908 if (ctx
->started
|| ctx
->finished
) {
912 php_http_buffer_init(&header_buf
);
913 php_http_buffer_appendf(&header_buf
, "HTTP/%u.%u %ld %s" PHP_HTTP_CRLF
, ctx
->version
.major
, ctx
->version
.minor
, ctx
->status_code
, php_http_env_get_response_status_for_code(ctx
->status_code
));
915 /* there are some limitations regarding TE:chunked, see https://tools.ietf.org/html/rfc7230#section-3.3.1 */
916 if (UNEXPECTED(ctx
->version
.major
== 1 && ctx
->version
.minor
== 0)) {
918 } else if (UNEXPECTED(ctx
->status_code
== 204 || ctx
->status_code
/100 == 1)) {
920 } else if (UNEXPECTED(ctx
->request
&& ctx
->status_code
/100 == 2 && !strcasecmp(ctx
->request
->http
.info
.request
.method
, "CONNECT"))) {
924 php_http_env_response_stream_header(ctx
, &ctx
->header
, &header_buf
);
926 /* enable chunked transfer encoding */
928 php_http_buffer_appends(&header_buf
, "Transfer-Encoding: chunked" PHP_HTTP_CRLF
);
931 php_http_buffer_appends(&header_buf
, PHP_HTTP_CRLF
);
933 if (header_buf
.used
== php_stream_write(ctx
->stream
, header_buf
.data
, header_buf
.used
)) {
936 php_http_buffer_dtor(&header_buf
);
937 php_stream_flush(ctx
->stream
);
940 ctx
->chunked_filter
= php_stream_filter_create("http.chunked_encode", NULL
, 0);
941 if (ctx
->chunked_filter
) {
942 php_stream_filter_append(&ctx
->stream
->writefilters
, ctx
->chunked_filter
);
946 return ctx
->started
? SUCCESS
: FAILURE
;
948 static long php_http_env_response_stream_get_status(php_http_env_response_t
*r
)
950 php_http_env_response_stream_ctx_t
*ctx
= r
->ctx
;
952 return ctx
->status_code
;
954 static ZEND_RESULT_CODE
php_http_env_response_stream_set_status(php_http_env_response_t
*r
, long http_code
)
956 php_http_env_response_stream_ctx_t
*stream_ctx
= r
->ctx
;
958 if (stream_ctx
->started
|| stream_ctx
->finished
) {
962 stream_ctx
->status_code
= http_code
;
966 static ZEND_RESULT_CODE
php_http_env_response_stream_set_protocol_version(php_http_env_response_t
*r
, php_http_version_t
*v
)
968 php_http_env_response_stream_ctx_t
*stream_ctx
= r
->ctx
;
970 if (stream_ctx
->started
|| stream_ctx
->finished
) {
974 memcpy(&stream_ctx
->version
, v
, sizeof(stream_ctx
->version
));
978 static ZEND_RESULT_CODE
php_http_env_response_stream_set_header_ex(php_http_env_response_t
*r
, zend_bool replace
, const char *fmt
, va_list argv
)
980 php_http_env_response_stream_ctx_t
*stream_ctx
= r
->ctx
;
981 char *header_end
, *header_str
= NULL
;
982 size_t header_len
= 0;
983 zval zheader
, *zheader_ptr
;
984 zend_string
*header_key
;
987 if (UNEXPECTED(stream_ctx
->started
|| stream_ctx
->finished
)) {
991 header_len
= vspprintf(&header_str
, 0, fmt
, argv
);
993 if (UNEXPECTED(!(header_end
= strchr(header_str
, ':')))) {
998 header_key
= zend_string_init(header_str
, header_end
- header_str
, 0);
1000 if (!replace
&& (zheader_ptr
= zend_hash_find(&stream_ctx
->header
, header_key
))) {
1001 convert_to_array(zheader_ptr
);
1002 rv
= add_next_index_str(zheader_ptr
, php_http_cs2zs(header_str
, header_len
));
1004 ZVAL_STR(&zheader
, php_http_cs2zs(header_str
, header_len
));
1006 rv
= zend_hash_update(&stream_ctx
->header
, header_key
, &zheader
)
1007 ? SUCCESS
: FAILURE
;
1010 zend_string_release(header_key
);
1014 static ZEND_RESULT_CODE
php_http_env_response_stream_set_header(php_http_env_response_t
*r
, const char *fmt
, ...)
1016 ZEND_RESULT_CODE ret
;
1019 va_start(argv
, fmt
);
1020 ret
= php_http_env_response_stream_set_header_ex(r
, 1, fmt
, argv
);
1025 static ZEND_RESULT_CODE
php_http_env_response_stream_add_header(php_http_env_response_t
*r
, const char *fmt
, ...)
1027 ZEND_RESULT_CODE ret
;
1030 va_start(argv
, fmt
);
1031 ret
= php_http_env_response_stream_set_header_ex(r
, 0, fmt
, argv
);
1036 static ZEND_RESULT_CODE
php_http_env_response_stream_del_header(php_http_env_response_t
*r
, const char *header_str
, size_t header_len
)
1038 php_http_env_response_stream_ctx_t
*stream_ctx
= r
->ctx
;
1040 if (stream_ctx
->started
|| stream_ctx
->finished
) {
1044 zend_hash_str_del(&stream_ctx
->header
, header_str
, header_len
);
1047 static ZEND_RESULT_CODE
php_http_env_response_stream_write(php_http_env_response_t
*r
, const char *data_str
, size_t data_len
)
1049 php_http_env_response_stream_ctx_t
*stream_ctx
= r
->ctx
;
1051 if (stream_ctx
->finished
) {
1054 if (!stream_ctx
->started
) {
1055 if (SUCCESS
!= php_http_env_response_stream_start(stream_ctx
)) {
1060 if (data_len
!= php_stream_write(stream_ctx
->stream
, data_str
, data_len
)) {
1066 static ZEND_RESULT_CODE
php_http_env_response_stream_flush(php_http_env_response_t
*r
)
1068 php_http_env_response_stream_ctx_t
*stream_ctx
= r
->ctx
;
1070 if (stream_ctx
->finished
) {
1073 if (!stream_ctx
->started
) {
1074 if (SUCCESS
!= php_http_env_response_stream_start(stream_ctx
)) {
1079 return php_stream_flush(stream_ctx
->stream
);
1081 static ZEND_RESULT_CODE
php_http_env_response_stream_finish(php_http_env_response_t
*r
)
1083 php_http_env_response_stream_ctx_t
*ctx
= r
->ctx
;
1085 if (UNEXPECTED(ctx
->finished
)) {
1088 if (UNEXPECTED(!ctx
->started
)) {
1089 if (SUCCESS
!= php_http_env_response_stream_start(ctx
)) {
1094 php_stream_flush(ctx
->stream
);
1095 if (ctx
->chunked
&& ctx
->chunked_filter
) {
1096 php_stream_filter_flush(ctx
->chunked_filter
, 1);
1097 ctx
->chunked_filter
= php_stream_filter_remove(ctx
->chunked_filter
, 1);
1105 static php_http_env_response_ops_t php_http_env_response_stream_ops
= {
1106 php_http_env_response_stream_init
,
1107 php_http_env_response_stream_dtor
,
1108 php_http_env_response_stream_get_status
,
1109 php_http_env_response_stream_set_status
,
1110 php_http_env_response_stream_set_protocol_version
,
1111 php_http_env_response_stream_set_header
,
1112 php_http_env_response_stream_add_header
,
1113 php_http_env_response_stream_del_header
,
1114 php_http_env_response_stream_write
,
1115 php_http_env_response_stream_flush
,
1116 php_http_env_response_stream_finish
1119 php_http_env_response_ops_t
*php_http_env_response_get_stream_ops(void)
1121 return &php_http_env_response_stream_ops
;
1124 #define PHP_HTTP_ENV_RESPONSE_OBJECT_INIT(obj) \
1126 if (!obj->message) { \
1127 obj->message = php_http_message_init_env(NULL, PHP_HTTP_RESPONSE); \
1131 ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse___construct
, 0, 0, 0)
1132 ZEND_END_ARG_INFO();
1133 static PHP_METHOD(HttpEnvResponse
, __construct
)
1135 php_http_message_object_t
*obj
;
1137 php_http_expect(SUCCESS
== zend_parse_parameters_none(), invalid_arg
, return);
1139 obj
= PHP_HTTP_OBJ(NULL
, getThis());
1141 php_http_expect(obj
->message
= php_http_message_init_env(obj
->message
, PHP_HTTP_RESPONSE
), unexpected_val
, return);
1144 ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse___invoke
, 0, 0, 1)
1145 ZEND_ARG_INFO(0, ob_string
)
1146 ZEND_ARG_INFO(0, ob_flags
)
1147 ZEND_END_ARG_INFO();
1148 static PHP_METHOD(HttpEnvResponse
, __invoke
)
1152 zend_long ob_flags
= 0;
1154 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &ob_str
, &ob_len
, &ob_flags
)) {
1155 php_http_message_object_t
*obj
= PHP_HTTP_OBJ(NULL
, getThis());
1157 PHP_HTTP_ENV_RESPONSE_OBJECT_INIT(obj
);
1160 php_http_message_object_init_body_object(obj
);
1163 if (ob_flags
& PHP_OUTPUT_HANDLER_CLEAN
) {
1164 php_stream_truncate_set_size(php_http_message_body_stream(obj
->message
->body
), 0);
1166 php_http_message_body_append(obj
->message
->body
, ob_str
, ob_len
);
1172 ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_setEnvRequest
, 0, 0, 1)
1173 ZEND_ARG_OBJ_INFO(0, env_request
, http
\\Message
, 1)
1174 ZEND_END_ARG_INFO();
1175 static PHP_METHOD(HttpEnvResponse
, setEnvRequest
)
1177 zval
*env_req
= NULL
;
1179 php_http_expect(SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS(), "|O", &env_req
, php_http_message_get_class_entry()), invalid_arg
, return);
1181 set_option(getThis(), ZEND_STRL("request"), IS_OBJECT
, env_req
, 0);
1182 RETVAL_ZVAL(getThis(), 1, 0);
1185 ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_setContentType
, 0, 0, 1)
1186 ZEND_ARG_INFO(0, content_type
)
1187 ZEND_END_ARG_INFO();
1188 static PHP_METHOD(HttpEnvResponse
, setContentType
)
1190 char *ct_str
= NULL
;
1193 php_http_expect(SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS(), "s!", &ct_str
, &ct_len
), invalid_arg
, return);
1195 set_option(getThis(), ZEND_STRL("contentType"), IS_STRING
, ct_str
, ct_len
);
1196 RETVAL_ZVAL(getThis(), 1, 0);
1199 ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_setContentDisposition
, 0, 0, 1)
1200 ZEND_ARG_ARRAY_INFO(0, disposition_params
, 1)
1201 ZEND_END_ARG_INFO();
1202 static PHP_METHOD(HttpEnvResponse
, setContentDisposition
)
1206 php_http_expect(SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS(), "a", &zdisposition
), invalid_arg
, return);
1208 zend_update_property(Z_OBJCE_P(getThis()), getThis(), ZEND_STRL("contentDisposition"), zdisposition
);
1209 RETVAL_ZVAL(getThis(), 1, 0);
1212 ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_setContentEncoding
, 0, 0, 1)
1213 ZEND_ARG_INFO(0, content_encoding
)
1214 ZEND_END_ARG_INFO();
1215 static PHP_METHOD(HttpEnvResponse
, setContentEncoding
)
1219 php_http_expect(SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS(), "l", &ce
), invalid_arg
, return);
1221 set_option(getThis(), ZEND_STRL("contentEncoding"), IS_LONG
, &ce
, 0);
1222 RETVAL_ZVAL(getThis(), 1, 0);
1225 ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_setCacheControl
, 0, 0, 1)
1226 ZEND_ARG_INFO(0, cache_control
)
1227 ZEND_END_ARG_INFO();
1228 static PHP_METHOD(HttpEnvResponse
, setCacheControl
)
1230 char *cc_str
= NULL
;
1233 php_http_expect(SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS(), "s!", &cc_str
, &cc_len
), invalid_arg
, return);
1235 set_option(getThis(), ZEND_STRL("cacheControl"), IS_STRING
, cc_str
, cc_len
);
1236 RETVAL_ZVAL(getThis(), 1, 0);
1239 ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_setLastModified
, 0, 0, 1)
1240 ZEND_ARG_INFO(0, last_modified
)
1241 ZEND_END_ARG_INFO();
1242 static PHP_METHOD(HttpEnvResponse
, setLastModified
)
1244 zend_long last_modified
;
1246 php_http_expect(SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS(), "l", &last_modified
), invalid_arg
, return);
1248 set_option(getThis(), ZEND_STRL("lastModified"), IS_LONG
, &last_modified
, 0);
1249 RETVAL_ZVAL(getThis(), 1, 0);
1252 ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_isCachedByLastModified
, 0, 0, 0)
1253 ZEND_ARG_INFO(0, header_name
)
1254 ZEND_END_ARG_INFO();
1255 static PHP_METHOD(HttpEnvResponse
, isCachedByLastModified
)
1257 char *header_name_str
= NULL
;
1258 size_t header_name_len
= 0;
1260 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS(), "|s!", &header_name_str
, &header_name_len
)) {
1261 if (!header_name_str
|| !header_name_len
) {
1262 header_name_str
= "If-Modified-Since";
1263 header_name_len
= lenof("If-Modified-Since");
1266 RETURN_LONG(php_http_env_is_response_cached_by_last_modified(getThis(), header_name_str
, header_name_len
, get_request(getThis())));
1270 ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_setEtag
, 0, 0, 1)
1271 ZEND_ARG_INFO(0, etag
)
1272 ZEND_END_ARG_INFO();
1273 static PHP_METHOD(HttpEnvResponse
, setEtag
)
1275 char *etag_str
= NULL
;
1276 size_t etag_len
= 0;
1278 php_http_expect(SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS(), "s!", &etag_str
, &etag_len
), invalid_arg
, return);
1280 set_option(getThis(), ZEND_STRL("etag"), IS_STRING
, etag_str
, etag_len
);
1281 RETVAL_ZVAL(getThis(), 1, 0);
1284 ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_isCachedByEtag
, 0, 0, 0)
1285 ZEND_ARG_INFO(0, header_name
)
1286 ZEND_END_ARG_INFO();
1287 static PHP_METHOD(HttpEnvResponse
, isCachedByEtag
)
1289 char *header_name_str
= NULL
;
1290 size_t header_name_len
= 0;
1292 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS(), "|s!", &header_name_str
, &header_name_len
)) {
1293 if (!header_name_str
|| !header_name_len
) {
1294 header_name_str
= "If-None-Match";
1295 header_name_len
= lenof("If-None-Match");
1297 RETURN_LONG(php_http_env_is_response_cached_by_etag(getThis(), header_name_str
, header_name_len
, get_request(getThis())));
1301 ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_setThrottleRate
, 0, 0, 1)
1302 ZEND_ARG_INFO(0, chunk_size
)
1303 ZEND_ARG_INFO(0, delay
)
1304 ZEND_END_ARG_INFO();
1305 static PHP_METHOD(HttpEnvResponse
, setThrottleRate
)
1307 zend_long chunk_size
;
1310 php_http_expect(SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS(), "l|d", &chunk_size
, &delay
), invalid_arg
, return);
1312 set_option(getThis(), ZEND_STRL("throttleDelay"), IS_DOUBLE
, &delay
, 0);
1313 set_option(getThis(), ZEND_STRL("throttleChunk"), IS_LONG
, &chunk_size
, 0);
1314 RETVAL_ZVAL(getThis(), 1, 0);
1317 ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_setCookie
, 0, 0, 1)
1318 ZEND_ARG_INFO(0, cookie
)
1319 ZEND_END_ARG_INFO();
1320 static PHP_METHOD(HttpEnvResponse
, setCookie
)
1322 zval
*zcookie_new
, tmp
;
1324 zend_error_handling zeh
;
1325 php_http_cookie_list_t
*list
= NULL
;
1327 php_http_expect(SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS(), "z", &zcookie_new
), invalid_arg
, return);
1329 zend_replace_error_handling(EH_THROW
, php_http_get_exception_unexpected_val_class_entry(), &zeh
);
1330 switch (Z_TYPE_P(zcookie_new
)) {
1332 if (instanceof_function(Z_OBJCE_P(zcookie_new
), php_http_cookie_get_class_entry())) {
1333 Z_ADDREF_P(zcookie_new
);
1338 list
= php_http_cookie_list_from_struct(NULL
, zcookie_new
);
1340 ZVAL_OBJECT(zcookie_new
, &php_http_cookie_object_new_ex(php_http_cookie_get_class_entry(), list
)->zo
, 0);
1344 zs
= zval_get_string(zcookie_new
);
1345 list
= php_http_cookie_list_parse(NULL
, zs
->val
, zs
->len
, 0, NULL
);
1346 zend_string_release(zs
);
1348 ZVAL_OBJECT(zcookie_new
, &php_http_cookie_object_new_ex(php_http_cookie_get_class_entry(), list
)->zo
, 0);
1350 zend_restore_error_handling(&zeh
);
1352 set_cookie(getThis(), zcookie_new
);
1353 zval_ptr_dtor(zcookie_new
);
1355 RETVAL_ZVAL(getThis(), 1, 0);
1358 ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_send
, 0, 0, 0)
1359 ZEND_ARG_INFO(0, stream
)
1360 ZEND_END_ARG_INFO();
1361 static PHP_METHOD(HttpEnvResponse
, send
)
1363 zval
*zstream
= NULL
;
1364 php_stream
*s
= NULL
;
1366 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS(), "|r", &zstream
)) {
1367 /* first flush the output layer to avoid conflicting headers and output;
1368 * also, ob_start($thisEnvResponse) might have been called */
1369 php_output_end_all();
1372 php_http_env_response_t
*r
;
1374 php_stream_from_zval(s
, zstream
);
1375 r
= php_http_env_response_init(NULL
, getThis(), php_http_env_response_get_stream_ops(), s
);
1380 RETVAL_BOOL(SUCCESS
== php_http_env_response_send(r
));
1381 php_http_env_response_free(&r
);
1383 php_http_env_response_t r
;
1385 if (!php_http_env_response_init(&r
, getThis(), NULL
, NULL
)) {
1389 RETVAL_BOOL(SUCCESS
== php_http_env_response_send(&r
));
1390 php_http_env_response_dtor(&r
);
1395 static zend_function_entry php_http_env_response_methods
[] = {
1396 PHP_ME(HttpEnvResponse
, __construct
, ai_HttpEnvResponse___construct
, ZEND_ACC_PUBLIC
)
1397 PHP_ME(HttpEnvResponse
, __invoke
, ai_HttpEnvResponse___invoke
, ZEND_ACC_PUBLIC
)
1398 PHP_ME(HttpEnvResponse
, setEnvRequest
, ai_HttpEnvResponse_setEnvRequest
, ZEND_ACC_PUBLIC
)
1399 PHP_ME(HttpEnvResponse
, setCookie
, ai_HttpEnvResponse_setCookie
, ZEND_ACC_PUBLIC
)
1400 PHP_ME(HttpEnvResponse
, setContentType
, ai_HttpEnvResponse_setContentType
, ZEND_ACC_PUBLIC
)
1401 PHP_ME(HttpEnvResponse
, setContentDisposition
, ai_HttpEnvResponse_setContentDisposition
, ZEND_ACC_PUBLIC
)
1402 PHP_ME(HttpEnvResponse
, setContentEncoding
, ai_HttpEnvResponse_setContentEncoding
, ZEND_ACC_PUBLIC
)
1403 PHP_ME(HttpEnvResponse
, setCacheControl
, ai_HttpEnvResponse_setCacheControl
, ZEND_ACC_PUBLIC
)
1404 PHP_ME(HttpEnvResponse
, setLastModified
, ai_HttpEnvResponse_setLastModified
, ZEND_ACC_PUBLIC
)
1405 PHP_ME(HttpEnvResponse
, isCachedByLastModified
, ai_HttpEnvResponse_isCachedByLastModified
, ZEND_ACC_PUBLIC
)
1406 PHP_ME(HttpEnvResponse
, setEtag
, ai_HttpEnvResponse_setEtag
, ZEND_ACC_PUBLIC
)
1407 PHP_ME(HttpEnvResponse
, isCachedByEtag
, ai_HttpEnvResponse_isCachedByEtag
, ZEND_ACC_PUBLIC
)
1408 PHP_ME(HttpEnvResponse
, setThrottleRate
, ai_HttpEnvResponse_setThrottleRate
, ZEND_ACC_PUBLIC
)
1409 PHP_ME(HttpEnvResponse
, send
, ai_HttpEnvResponse_send
, ZEND_ACC_PUBLIC
)
1410 EMPTY_FUNCTION_ENTRY
1413 static zend_class_entry
*php_http_env_response_class_entry
;
1414 zend_class_entry
*php_http_get_env_response_class_entry(void)
1416 return php_http_env_response_class_entry
;
1419 PHP_MINIT_FUNCTION(http_env_response
)
1421 zend_class_entry ce
= {0};
1423 INIT_NS_CLASS_ENTRY(ce
, "http\\Env", "Response", php_http_env_response_methods
);
1424 php_http_env_response_class_entry
= zend_register_internal_class_ex(&ce
, php_http_message_get_class_entry());
1426 zend_declare_class_constant_long(php_http_env_response_class_entry
, ZEND_STRL("CONTENT_ENCODING_NONE"), PHP_HTTP_CONTENT_ENCODING_NONE
);
1427 zend_declare_class_constant_long(php_http_env_response_class_entry
, ZEND_STRL("CONTENT_ENCODING_GZIP"), PHP_HTTP_CONTENT_ENCODING_GZIP
);
1429 zend_declare_class_constant_long(php_http_env_response_class_entry
, ZEND_STRL("CACHE_NO"), PHP_HTTP_CACHE_NO
);
1430 zend_declare_class_constant_long(php_http_env_response_class_entry
, ZEND_STRL("CACHE_HIT"), PHP_HTTP_CACHE_HIT
);
1431 zend_declare_class_constant_long(php_http_env_response_class_entry
, ZEND_STRL("CACHE_MISS"), PHP_HTTP_CACHE_MISS
);
1433 zend_declare_property_null(php_http_env_response_class_entry
, ZEND_STRL("request"), ZEND_ACC_PROTECTED
);
1434 zend_declare_property_null(php_http_env_response_class_entry
, ZEND_STRL("cookies"), ZEND_ACC_PROTECTED
);
1435 zend_declare_property_null(php_http_env_response_class_entry
, ZEND_STRL("contentType"), ZEND_ACC_PROTECTED
);
1436 zend_declare_property_null(php_http_env_response_class_entry
, ZEND_STRL("contentDisposition"), ZEND_ACC_PROTECTED
);
1437 zend_declare_property_null(php_http_env_response_class_entry
, ZEND_STRL("contentEncoding"), ZEND_ACC_PROTECTED
);
1438 zend_declare_property_null(php_http_env_response_class_entry
, ZEND_STRL("cacheControl"), ZEND_ACC_PROTECTED
);
1439 zend_declare_property_null(php_http_env_response_class_entry
, ZEND_STRL("etag"), ZEND_ACC_PROTECTED
);
1440 zend_declare_property_null(php_http_env_response_class_entry
, ZEND_STRL("lastModified"), ZEND_ACC_PROTECTED
);
1441 zend_declare_property_null(php_http_env_response_class_entry
, ZEND_STRL("throttleDelay"), ZEND_ACC_PROTECTED
);
1442 zend_declare_property_null(php_http_env_response_class_entry
, ZEND_STRL("throttleChunk"), ZEND_ACC_PROTECTED
);
1453 * vim600: noet sw=4 ts=4 fdm=marker
1454 * vim<600: noet sw=4 ts=4