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-2010, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
17 #include <main/SAPI.h>
18 #include <ext/date/php_date.h>
19 #include <ext/standard/php_string.h>
21 PHP_RINIT_FUNCTION(http_env
)
23 PHP_HTTP_G
->env
.response
.last_modified
= 0;
24 PHP_HTTP_G
->env
.response
.throttle_chunk
= 0;
25 PHP_HTTP_G
->env
.response
.throttle_delay
= 0;
26 PHP_HTTP_G
->env
.request
.time
= sapi_get_request_time(TSRMLS_C
);
31 PHP_RSHUTDOWN_FUNCTION(http_env
)
33 if (PHP_HTTP_G
->env
.request
.headers
) {
34 zend_hash_destroy(PHP_HTTP_G
->env
.request
.headers
);
35 FREE_HASHTABLE(PHP_HTTP_G
->env
.request
.headers
);
36 PHP_HTTP_G
->env
.request
.headers
= NULL
;
38 if (PHP_HTTP_G
->env
.request
.body
) {
39 php_http_message_body_free(&PHP_HTTP_G
->env
.request
.body
);
41 if (PHP_HTTP_G
->env
.response
.body
) {
42 php_http_message_body_free(&PHP_HTTP_G
->env
.response
.body
);
44 STR_SET(PHP_HTTP_G
->env
.response
.content_type
, NULL
);
45 STR_SET(PHP_HTTP_G
->env
.response
.etag
, NULL
);
47 if (PHP_HTTP_G
->env
.server_var
) {
48 zval_ptr_dtor(&PHP_HTTP_G
->env
.server_var
);
49 PHP_HTTP_G
->env
.server_var
= NULL
;
55 PHP_HTTP_API
void php_http_env_get_request_headers(HashTable
*headers TSRMLS_DC
)
57 php_http_array_hashkey_t key
= php_http_array_hashkey_init(0);
61 if (!PHP_HTTP_G
->env
.request
.headers
) {
62 ALLOC_HASHTABLE(PHP_HTTP_G
->env
.request
.headers
);
63 zend_hash_init(PHP_HTTP_G
->env
.request
.headers
, 0, NULL
, ZVAL_PTR_DTOR
, 0);
65 zend_is_auto_global("_SERVER", lenof("_SERVER") TSRMLS_CC
);
67 if (SUCCESS
== zend_hash_find(&EG(symbol_table
), "_SERVER", sizeof("_SERVER"), (void *) &hsv
) && Z_TYPE_PP(hsv
) == IS_ARRAY
) {
68 FOREACH_KEY(pos
, *hsv
, key
) {
69 if (key
.type
== HASH_KEY_IS_STRING
&& key
.len
> 6 && !strncmp(key
.str
, "HTTP_", 5)) {
71 key
.str
= php_http_pretty_key(estrndup(key
.str
+ 5, key
.len
- 1), key
.len
- 1, 1, 1);
73 zend_hash_get_current_data_ex(Z_ARRVAL_PP(hsv
), (void *) &header
, &pos
);
75 zend_hash_add(PHP_HTTP_G
->env
.request
.headers
, key
.str
, key
.len
, (void *) header
, sizeof(zval
*), NULL
);
84 zend_hash_copy(headers
, PHP_HTTP_G
->env
.request
.headers
, (copy_ctor_func_t
) zval_add_ref
, NULL
, sizeof(zval
*));
88 PHP_HTTP_API
char *php_http_env_get_request_header(const char *name_str
, size_t name_len TSRMLS_DC
)
91 char *val
= NULL
, *key
= php_http_pretty_key(estrndup(name_str
, name_len
), name_len
, 1, 1);
93 php_http_env_get_request_headers(NULL TSRMLS_CC
);
95 if (SUCCESS
== zend_hash_find(PHP_HTTP_G
->env
.request
.headers
, key
, name_len
+ 1, (void *) &zvalue
)) {
96 zval
*zcopy
= php_http_zsep(IS_STRING
, *zvalue
);
98 val
= estrndup(Z_STRVAL_P(zcopy
), Z_STRLEN_P(zcopy
));
99 zval_ptr_dtor(&zcopy
);
107 PHP_HTTP_API
int php_http_env_got_request_header(const char *name_str
, size_t name_len TSRMLS_DC
)
109 char *key
= php_http_pretty_key(estrndup(name_str
, name_len
), name_len
, 1, 1);
112 php_http_env_get_request_headers(NULL TSRMLS_CC
);
113 got
= zend_hash_exists(PHP_HTTP_G
->env
.request
.headers
, key
, name_len
+ 1);
119 PHP_HTTP_API zval
*php_http_env_get_server_var(const char *key
, size_t key_len
, zend_bool check TSRMLS_DC
)
124 /* if available, this is a lot faster than accessing $_SERVER */
125 if (sapi_module
.getenv
) {
126 if ((!(env
= sapi_module
.getenv((char *) key
, key_len TSRMLS_CC
))) || (check
&& !*env
)) {
129 if (PHP_HTTP_G
->env
.server_var
) {
130 zval_ptr_dtor(&PHP_HTTP_G
->env
.server_var
);
132 MAKE_STD_ZVAL(PHP_HTTP_G
->env
.server_var
);
133 ZVAL_STRING(PHP_HTTP_G
->env
.server_var
, env
, 1);
134 return PHP_HTTP_G
->env
.server_var
;
137 zend_is_auto_global(ZEND_STRL("_SERVER") TSRMLS_CC
);
139 if ((SUCCESS
!= zend_hash_find(&EG(symbol_table
), ZEND_STRS("_SERVER"), (void *) &hsv
)) || (Z_TYPE_PP(hsv
) != IS_ARRAY
)) {
142 if ((SUCCESS
!= zend_hash_find(Z_ARRVAL_PP(hsv
), key
, key_len
+ 1, (void *) &var
))) {
145 if (check
&& !((Z_TYPE_PP(var
) == IS_STRING
) && Z_STRVAL_PP(var
) && Z_STRLEN_PP(var
))) {
151 PHP_HTTP_API php_http_message_body_t
*php_http_env_get_request_body(TSRMLS_D
)
153 if (!PHP_HTTP_G
->env
.request
.body
) {
154 php_stream
*s
= NULL
;
156 if (SG(request_info
).post_data
|| SG(request_info
).raw_post_data
) {
157 if ((s
= php_stream_temp_new())) {
158 /* php://input does not support seek() */
159 if (SG(request_info
).raw_post_data
) {
160 php_stream_write(s
, SG(request_info
).raw_post_data
, SG(request_info
).raw_post_data_length
);
162 php_stream_write(s
, SG(request_info
).post_data
, SG(request_info
).post_data_length
);
164 php_stream_rewind(s
);
166 } else if (sapi_module
.read_post
) {
167 if ((s
= php_stream_temp_new())) {
168 char *buf
= emalloc(4096);
171 while (0 < (len
= sapi_module
.read_post(buf
, 4096 TSRMLS_CC
))) {
172 php_stream_write(s
, buf
, len
);
180 php_stream_rewind(s
);
183 PHP_HTTP_G
->env
.request
.body
= php_http_message_body_init(NULL
, s TSRMLS_CC
);
186 return PHP_HTTP_G
->env
.request
.body
;
189 PHP_HTTP_API php_http_range_status_t
php_http_env_get_request_ranges(HashTable
*ranges
, size_t length TSRMLS_DC
)
193 long begin
= -1, end
= -1, *ptr
;
195 if (!(range
= php_http_env_get_request_header(ZEND_STRL("Range") TSRMLS_CC
))) {
196 return PHP_HTTP_RANGE_NO
;
198 if (strncmp(range
, "bytes=", lenof("bytes="))) {
200 return PHP_HTTP_RANGE_NO
;
203 rp
= range
+ lenof("bytes=");
207 switch (c
= *(rp
++)) {
209 /* allow 000... - shall we? */
215 case '1': case '2': case '3':
216 case '4': case '5': case '6':
217 case '7': case '8': case '9':
219 * If the value of the pointer is already set (non-negative)
220 * then multiply its value by ten and add the current value,
221 * else initialise the pointers value with the current value
223 * This let us recognize empty fields when validating the
224 * ranges, i.e. a "-10" for begin and "12345" for the end
225 * was the following range request: "Range: bytes=0-12345";
226 * While a "-1" for begin and "12345" for the end would
227 * have been: "Range: bytes=-12345".
248 /* validate ranges */
256 return PHP_HTTP_RANGE_NO
;
264 if (length
<= (size_t) end
) {
275 if (end
== -1 || end
== -10) {
277 return PHP_HTTP_RANGE_ERR
;
279 begin
= length
- end
;
285 if (length
<= (size_t) begin
) {
287 return PHP_HTTP_RANGE_ERR
;
293 return PHP_HTTP_RANGE_ERR
;
302 if (length
<= (size_t) end
) {
304 } else if (end
< begin
) {
306 return PHP_HTTP_RANGE_ERR
;
314 MAKE_STD_ZVAL(zentry
);
316 add_index_long(zentry
, 0, begin
);
317 add_index_long(zentry
, 1, end
);
318 zend_hash_next_index_insert(ranges
, &zentry
, sizeof(zval
*), NULL
);
328 return PHP_HTTP_RANGE_NO
;
333 return PHP_HTTP_RANGE_OK
;
336 static void grab_headers(void *data
, void *arg TSRMLS_DC
)
338 php_http_buffer_appendl(PHP_HTTP_BUFFER(arg
), ((sapi_header_struct
*)data
)->header
);
339 php_http_buffer_appends(PHP_HTTP_BUFFER(arg
), PHP_HTTP_CRLF
);
342 PHP_HTTP_API STATUS
php_http_env_get_response_headers(HashTable
*headers_ht TSRMLS_DC
)
345 php_http_buffer_t headers
;
347 php_http_buffer_init(&headers
);
348 zend_llist_apply_with_argument(&SG(sapi_headers
).headers
, grab_headers
, &headers TSRMLS_CC
);
349 php_http_buffer_fix(&headers
);
351 status
= php_http_headers_parse(PHP_HTTP_BUFFER_VAL(&headers
), PHP_HTTP_BUFFER_LEN(&headers
), headers_ht
, NULL
, NULL TSRMLS_CC
);
352 php_http_buffer_dtor(&headers
);
357 PHP_HTTP_API
char *php_http_env_get_response_header(const char *name_str
, size_t name_len TSRMLS_DC
)
362 zend_hash_init(&headers
, 0, NULL
, NULL
, 0);
363 if (SUCCESS
== php_http_env_get_response_headers(&headers TSRMLS_CC
)) {
365 char *key
= php_http_pretty_key(estrndup(name_str
, name_len
), name_len
, 1, 1);
367 if (SUCCESS
== zend_hash_find(&headers
, key
, name_len
+ 1, (void *) &zvalue
)) {
368 zval
*zcopy
= php_http_zsep(IS_STRING
, *zvalue
);
370 val
= estrndup(Z_STRVAL_P(zcopy
), Z_STRLEN_P(zcopy
));
371 zval_ptr_dtor(&zcopy
);
376 zend_hash_destroy(&headers
);
381 PHP_HTTP_API
long php_http_env_get_response_code(TSRMLS_D
)
383 long code
= SG(sapi_headers
).http_response_code
;
384 return code
? code
: 200;
387 PHP_HTTP_API STATUS
php_http_env_set_response_code(long http_code TSRMLS_DC
)
389 return sapi_header_op(SAPI_HEADER_SET_STATUS
, (void *) http_code TSRMLS_CC
);
392 PHP_HTTP_API STATUS
php_http_env_set_response_status_line(long code
, php_http_version_t
*v TSRMLS_DC
)
394 sapi_header_line h
= {0};
397 h
.line_len
= spprintf(&h
.line
, 0, "HTTP/%u.%u %ld %s", v
->major
, v
->minor
, code
, php_http_env_get_response_status_for_code(code
));
398 ret
= sapi_header_op(SAPI_HEADER_REPLACE
, (void *) &h TSRMLS_CC
);
404 PHP_HTTP_API STATUS
php_http_env_set_response_protocol_version(php_http_version_t
*v TSRMLS_DC
)
406 return php_http_env_set_response_status_line(php_http_env_get_response_code(TSRMLS_C
), v TSRMLS_CC
);
409 PHP_HTTP_API STATUS
php_http_env_set_response_header(long http_code
, const char *header_str
, size_t header_len
, zend_bool replace TSRMLS_DC
)
411 sapi_header_line h
= {estrndup(header_str
, header_len
), header_len
, http_code
};
412 STATUS ret
= sapi_header_op(replace
? SAPI_HEADER_REPLACE
: SAPI_HEADER_ADD
, (void *) &h TSRMLS_CC
);
417 PHP_HTTP_API STATUS
php_http_env_set_response_header_value(long http_code
, const char *name_str
, size_t name_len
, zval
*value
, zend_bool replace TSRMLS_DC
)
420 sapi_header_line h
= {(char *) name_str
, name_len
, http_code
};
422 return sapi_header_op(SAPI_HEADER_DELETE
, (void *) &h TSRMLS_CC
);
425 if(Z_TYPE_P(value
) == IS_ARRAY
|| Z_TYPE_P(value
) == IS_OBJECT
) {
430 FOREACH_HASH_VAL(pos
, HASH_OF(value
), data_ptr
) {
431 if (SUCCESS
!= php_http_env_set_response_header_value(http_code
, name_str
, name_len
, *data_ptr
, first TSRMLS_CC
)) {
439 zval
*data
= php_http_zsep(IS_STRING
, value
);
441 if (!Z_STRLEN_P(data
)) {
442 zval_ptr_dtor(&data
);
443 return php_http_env_set_response_header_value(http_code
, name_str
, name_len
, NULL
, replace TSRMLS_CC
);
448 if (name_len
> INT_MAX
) {
451 h
.response_code
= http_code
;
452 h
.line_len
= spprintf(&h
.line
, 0, "%.*s: %.*s", (int) name_len
, name_str
, Z_STRLEN_P(data
), Z_STRVAL_P(data
));
454 ret
= sapi_header_op(replace
? SAPI_HEADER_REPLACE
: SAPI_HEADER_ADD
, (void *) &h TSRMLS_CC
);
456 zval_ptr_dtor(&data
);
464 PHP_HTTP_API
void php_http_env_set_response_throttle_rate(zval
*container
, size_t chunk_size
, double delay TSRMLS_CC
)
466 if (Z_TYPE_P(container
) == IS_OBJECT
) {
467 zend_update_property_double(Z_OBJCE_P(container
), container
, ZEND_STRL("throttleDelay"), delay TSRMLS_CC
);
468 zend_update_property_long(Z_OBJCE_P(container
), container
, ZEND_STRL("throttleChunk"), chunk_size TSRMLS_CC
);
470 convert_to_array(container
);
471 add_assoc_double_ex(container
, ZEND_STRS("throttleDelay"), delay
);
472 add_assoc_long_ex(container
, ZEND_STRS("throttleChunk"), chunk_size
);
476 static void set_container_value(zval
*container
, const char *name_str
, size_t name_len
, int type
, const void *value_ptr
, size_t value_len TSRMLS_DC
)
478 if (Z_TYPE_P(container
) == IS_OBJECT
) {
479 /* stupid non-const api */
480 char *name
= estrndup(name_str
, name_len
);
483 zend_update_property_long(Z_OBJCE_P(container
), container
, name
, name_len
, *(long *)value_ptr TSRMLS_CC
);
486 zend_update_property_stringl(Z_OBJCE_P(container
), container
, name
, name_len
, value_ptr
, value_len TSRMLS_CC
);
491 convert_to_array(container
);
494 add_assoc_long_ex(container
, name_str
, name_len
+ 1, *(long *)value_ptr
);
497 char *value
= estrndup(value_ptr
, value_len
);
498 add_assoc_stringl_ex(container
, name_str
, name_len
+ 1, value
, value_len
, 0);
505 PHP_HTTP_API STATUS
php_http_env_set_response_last_modified(zval
*container
, time_t t
, char **sent_header TSRMLS_DC
)
508 char *lm_header_str
, *date
;
509 size_t lm_header_len
;
512 if (!(date
= php_format_date(ZEND_STRL(PHP_HTTP_DATE_FORMAT
), t
, 0 TSRMLS_CC
))) {
516 lm_header_len
= spprintf(&lm_header_str
, 0, "Last-Modified: %s", date
);
519 lm_header_str
= "Last-Modified:";
520 lm_header_len
= lenof("Last-Modified:");
523 if (SUCCESS
== (ret
= php_http_env_set_response_header(0, lm_header_str
, lm_header_len
, 1 TSRMLS_CC
))) {
524 set_container_value(container
, ZEND_STRL("lastModified"), IS_LONG
, &t
, 0 TSRMLS_CC
);
528 *sent_header
= lm_header_str
;
530 STR_FREE(lm_header_str
);
536 PHP_HTTP_API STATUS
php_http_env_set_response_etag(zval
*container
, const char *etag_str
, size_t etag_len
, char **sent_header TSRMLS_DC
)
539 char *etag
= NULL
, *etag_header_str
;
540 size_t etag_header_len
;
543 etag_header_len
= spprintf(&etag_header_str
, 0, "ETag: \"%s\"", etag_str
);
545 etag_header_str
= "ETag:";
546 etag_header_len
= lenof("ETag:");
549 if (SUCCESS
== (ret
= php_http_env_set_response_header(0, etag_header_str
, etag_header_len
, 1 TSRMLS_CC
))) {
550 set_container_value(container
, ZEND_STRL(etag
), IS_STRING
, etag_str
, etag_len TSRMLS_CC
);
554 *sent_header
= etag_header_str
;
555 } else if (etag_len
) {
556 STR_FREE(etag_header_str
);
562 PHP_HTTP_API STATUS
php_http_env_set_response_content_type(zval
*container
, const char *ct_str
, size_t ct_len
, char **sent_header TSRMLS_DC
)
566 size_t ct_header_len
;
569 PHP_HTTP_CHECK_CONTENT_TYPE(ct_str
, return FAILURE
);
570 ct_header_len
= spprintf(&ct_header_str
, 0, "Content-Type: %s", ct_str
);
572 ct_header_str
= "Content-Type:";
573 ct_header_len
= lenof("Content-Type:");
576 if (SUCCESS
== (ret
= php_http_env_set_response_header(0, ct_header_str
, ct_header_len
, 1 TSRMLS_CC
))) {
577 set_container_value(container
, ZEND_STRL("contentType"), IS_STRING
, ct_str
, ct_len TSRMLS_CC
);
581 *sent_header
= ct_header_str
;
583 STR_FREE(ct_header_str
);
589 PHP_HTTP_API STATUS
php_http_env_set_response_content_disposition(zval
*container
, php_http_content_disposition_t d
, const char *f_str
, size_t f_len
, char **sent_header TSRMLS_DC
)
592 char *tmp
, *cd_header_str
, *new_f_str
;
594 size_t cd_header_len
;
597 case PHP_HTTP_CONTENT_DISPOSITION_NONE
:
599 case PHP_HTTP_CONTENT_DISPOSITION_INLINE
:
602 case PHP_HTTP_CONTENT_DISPOSITION_ATTACHMENT
:
606 php_http_error(HE_WARNING
, PHP_HTTP_E_INVALID_PARAM
, "Unknown content disposition (%d)", (int) d
);
611 new_f_str
= php_addslashes(estrndup(f_str
, f_len
), f_len
, &new_f_len
, 0 TSRMLS_CC
);
612 cd_header_len
= spprintf(&cd_header_str
, 0, "Content-Disposition: %s; filename=\"%.*s\"", tmp
, new_f_len
, new_f_str
);
615 cd_header_len
= spprintf(&cd_header_str
, 0, "Content-Disposition: %s", tmp
);
617 cd_header_str
= "Content-Disposition:";
618 cd_header_len
= lenof("Content-Disposition:");
621 ret
= php_http_env_set_response_header(0, cd_header_str
, cd_header_len
, 1 TSRMLS_CC
);
624 *sent_header
= cd_header_str
;
625 } else if (f_len
|| d
){
626 STR_FREE(cd_header_str
);
632 PHP_HTTP_API STATUS
php_http_env_set_response_cache_control(zval
*container
, const char *cc_str
, size_t cc_len
, char **sent_header TSRMLS_DC
)
636 size_t cc_header_len
;
639 cc_header_len
= spprintf(&cc_header_str
, 0, "Cache-Control: %s", cc_str
);
641 cc_header_str
= "Content-Disposition:";
642 cc_header_len
= lenof("Content-Disposition:");
645 ret
= php_http_env_set_response_header(0, cc_header_str
, cc_header_len
, 1 TSRMLS_CC
);
648 *sent_header
= cc_header_str
;
650 STR_FREE(cc_header_str
);
656 static zval
*get_container_value(zval
*container
, const char *name_str
, size_t name_len TSRMLS_CC
)
660 if (Z_TYPE_P(container
) == IS_OBJECT
) {
661 char *name
= estrndup(name_str
, name_len
);
662 val
= zend_read_property(Z_OBJCE_P(container
), container
, name
, name_len
, 0 TSRMLS_CC
);
665 if (SUCCESS
== zend_hash_find(Z_ARRVAL_P(container
), name_str
, name_len
+ 1, (void *) &valptr
)) {
677 PHP_HTTP_API php_http_cache_status_t
php_http_env_is_response_cached_by_etag(zval
*container
, const char *header_str
, size_t header_len TSRMLS_DC
)
679 int ret
, free_etag
= 0;
681 zval
*zetag
, *zbody
= NULL
;
683 if ( !(header
= php_http_env_get_request_header(header_str
, header_len TSRMLS_CC
))
684 || !(zbody
= get_container_value(container
, ZEND_STRL("body") TSRMLS_CC
))
685 || !(Z_TYPE_P(zbody
) == IS_OBJECT
)
686 || !instanceof_function(Z_OBJCE_P(zbody
), php_http_message_body_class_entry TSRMLS_CC
)
690 zval_ptr_dtor(&zbody
);
692 return PHP_HTTP_CACHE_NO
;
695 if ((zetag
= get_container_value(container
, ZEND_STRL("etag") TSRMLS_CC
))) {
696 zval
*zetag_copy
= php_http_zsep(IS_STRING
, zetag
);
697 zval_ptr_dtor(&zetag
);
701 if (zetag
&& Z_STRLEN_P(zetag
)) {
702 etag
= Z_STRVAL_P(zetag
);
704 etag
= php_http_message_body_etag(((php_http_message_body_object_t
*) zend_object_store_get_object(zbody TSRMLS_CC
))->body
);
705 php_http_env_set_response_etag(container
, etag
, strlen(etag
), NULL TSRMLS_CC
);
710 zval_ptr_dtor(&zetag
);
713 ret
= php_http_match(header
, etag
, PHP_HTTP_MATCH_WORD
);
720 return ret
? PHP_HTTP_CACHE_HIT
: PHP_HTTP_CACHE_MISS
;
723 PHP_HTTP_API php_http_cache_status_t
php_http_env_is_response_cached_by_last_modified(zval
*container
, const char *header_str
, size_t header_len TSRMLS_DC
)
727 zval
*zbody
= NULL
, *zlm
;
729 if ( !(header
= php_http_env_get_request_header(header_str
, header_len TSRMLS_CC
))
730 || !(zbody
= get_container_value(container
, ZEND_STRL("body") TSRMLS_CC
))
731 || !(Z_TYPE_P(zbody
) == IS_OBJECT
)
732 || !instanceof_function(Z_OBJCE_P(zbody
), php_http_message_body_class_entry TSRMLS_CC
)
736 zval_ptr_dtor(&zbody
);
738 return PHP_HTTP_CACHE_NO
;
741 if ((zlm
= get_container_value(container
, ZEND_STRL("lastModified") TSRMLS_CC
))) {
742 zval
*zlm_copy
= php_http_zsep(IS_LONG
, zlm
);
747 if (zlm
&& Z_LVAL_P(zlm
) > 0) {
750 lm
= php_http_message_body_mtime(((php_http_message_body_object_t
*) zend_object_store_get_object(zbody TSRMLS_CC
))->body
);
751 php_http_env_set_response_last_modified(container
, lm
, NULL TSRMLS_CC
);
758 ums
= php_parse_date(header
, NULL TSRMLS_CC
);
761 if (ums
> 0 && ums
<= lm
) {
762 return PHP_HTTP_CACHE_HIT
;
764 return PHP_HTTP_CACHE_MISS
;
768 PHP_HTTP_API
void php_http_env_set_response_body(zval
*container
, php_http_message_body_t
*body
)
770 TSRMLS_FETCH_FROM_CTX(body
->ts
);
771 zend_object_value ov
= php_http_message_body_object_new_ex(php_http_message_body_class_entry
, php_http_message_body_copy(body
, NULL
, 0), NULL TSRMLS_CC
);
773 set_container_value(container
, ZEND_STRL("body"), IS_OBJECT
, &ov
, 0 TSRMLS_CC
);
777 php_http_buffer_t
*buf
;
781 static size_t output(void *context
, const char *buf
, size_t len TSRMLS_DC
)
783 struct output_ctx
*ctx
= context
;
787 size_t chunk_size
= PHP_HTTP_SENDBUF_SIZE
;
789 if ((zcs
= get_container_value(ctx
->container
, ZEND_STRL("throttleChunk") TSRMLS_CC
))) {
790 zval
*zcs_copy
= php_http_zsep(IS_LONG
, zcs
);
793 chunk_size
= Z_LVAL_P(zcs_copy
);
794 zval_ptr_dtor(&zcs_copy
);
796 php_http_buffer_chunked_output(&ctx
->buf
, buf
, len
, buf
? chunk_size
: 0, output
, NULL TSRMLS_CC
);
803 /* we really only need to flush when throttling is enabled,
804 because we push the data as fast as possible anyway if not */
805 if ((ztd
= get_container_value(ctx
->container
, ZEND_STRL("throttleDelay") TSRMLS_CC
))) {
807 zval
*ztd_copy
= php_http_zsep(IS_DOUBLE
, ztd
);
810 delay
= Z_DVAL_P(ztd_copy
);
811 zval_ptr_dtor(&ztd_copy
);
813 if (delay
>= PHP_HTTP_DIFFSEC
) {
814 if (php_output_get_level(TSRMLS_C
)) {
815 php_output_flush_all(TSRMLS_C
);
817 if (!(php_output_get_status(TSRMLS_C
) & PHP_OUTPUT_IMPLICITFLUSH
)) {
818 sapi_flush(TSRMLS_C
);
820 php_http_sleep(delay
);
827 PHP_HTTP_API STATUS
php_http_env_send_response(zval
*container TSRMLS_DC
)
829 struct output_ctx ctx
= {NULL
, container
};
830 zval
*zbody
, *zheader
, *zrcode
, *zversion
;
832 php_http_range_status_t range_status
;
833 php_http_message_body_t
*body
;
836 if ( !(zbody
= get_container_value(container
, ZEND_STRL("body") TSRMLS_CC
))
837 || !(Z_TYPE_P(zbody
) == IS_OBJECT
)
838 || !instanceof_function(Z_OBJCE_P(zbody
), php_http_message_body_class_entry TSRMLS_CC
)
841 zval_ptr_dtor(&zbody
);
846 if ((zrcode
= get_container_value(container
, ZEND_STRL("responseCode") TSRMLS_CC
))) {
847 zval
*zrcode_copy
= php_http_zsep(IS_LONG
, zrcode
);
849 zval_ptr_dtor(&zrcode
);
850 if (Z_LVAL_P(zrcode_copy
) > 0) {
851 php_http_env_set_response_code(Z_LVAL_P(zrcode_copy
) TSRMLS_CC
);
853 zval_ptr_dtor(&zrcode_copy
);
856 if ((zversion
= get_container_value(container
, ZEND_STRL("httpVersion") TSRMLS_CC
))) {
857 php_http_version_t v
;
858 zval
*zversion_copy
= php_http_zsep(IS_STRING
, zversion
);
860 zval_ptr_dtor(&zversion
);
861 if (Z_STRLEN_P(zversion_copy
) && php_http_version_parse(&v
, Z_STRVAL_P(zversion_copy
) TSRMLS_CC
)) {
862 php_http_env_set_response_protocol_version(&v TSRMLS_CC
);
863 php_http_version_dtor(&v
);
865 zval_ptr_dtor(&zversion_copy
);
868 if ((zheader
= get_container_value(container
, ZEND_STRL("headers") TSRMLS_CC
))) {
869 if (Z_TYPE_P(zheader
) == IS_ARRAY
) {
872 php_http_array_hashkey_t key
= php_http_array_hashkey_init(0);
874 FOREACH_KEYVAL(pos
, zheader
, key
, val
) {
875 if (key
.type
== HASH_KEY_IS_STRING
) {
876 php_http_env_set_response_header_value(0, key
.str
, key
.len
- 1, *val
, 1 TSRMLS_CC
);
880 zval_ptr_dtor(&zheader
);
883 body
= ((php_http_message_body_object_t
*) zend_object_store_get_object(zbody TSRMLS_CC
))->body
;
884 body_size
= php_http_message_body_size(body
);
885 php_http_env_set_response_header(0, ZEND_STRL("Accept-Ranges: bytes"), 1 TSRMLS_CC
);
886 zend_hash_init(&ranges
, 0, NULL
, ZVAL_PTR_DTOR
, 0);
887 range_status
= php_http_env_get_request_ranges(&ranges
, body_size TSRMLS_CC
);
889 switch (range_status
) {
890 case PHP_HTTP_RANGE_ERR
:
891 zend_hash_destroy(&ranges
);
892 if (!php_http_env_got_request_header(ZEND_STRL("If-Range") TSRMLS_CC
)) {
894 size_t cr_header_len
;
896 cr_header_len
= spprintf(&cr_header_str
, 0, "Content-Range: bytes */%zu", body_size
);
897 php_http_env_set_response_header(416, cr_header_str
, cr_header_len
, 1 TSRMLS_CC
);
898 efree(cr_header_str
);
900 zval_ptr_dtor(&zbody
);
906 case PHP_HTTP_RANGE_NO
:
907 /* send full entity */
908 zend_hash_destroy(&ranges
);
911 case PHP_HTTP_RANGE_OK
:
912 /* send content-range response */
913 if (PHP_HTTP_CACHE_MISS
== php_http_env_is_response_cached_by_etag(container
, ZEND_STRL("If-Range") TSRMLS_CC
)
914 || PHP_HTTP_CACHE_MISS
== php_http_env_is_response_cached_by_last_modified(container
, ZEND_STRL("If-Range") TSRMLS_CC
)
916 /* send full entity */
917 zend_hash_destroy(&ranges
);
920 if (PHP_HTTP_CACHE_MISS
== php_http_env_is_response_cached_by_etag(container
, ZEND_STRL("If-Match") TSRMLS_CC
)
921 || PHP_HTTP_CACHE_MISS
== php_http_env_is_response_cached_by_last_modified(container
, ZEND_STRL("If-Unmodified-Since") TSRMLS_CC
)
922 || PHP_HTTP_CACHE_MISS
== php_http_env_is_response_cached_by_last_modified(container
, ZEND_STRL("Unless-Modified-Since") TSRMLS_CC
)
924 zend_hash_destroy(&ranges
);
925 php_http_env_set_response_code(412 TSRMLS_CC
);
927 zval_ptr_dtor(&zbody
);
931 if (zend_hash_num_elements(&ranges
) == 1) {
933 zval
**range
, **begin
, **end
;
935 if (SUCCESS
!= zend_hash_index_find(&ranges
, 0, (void *) &range
)
936 || SUCCESS
!= zend_hash_index_find(Z_ARRVAL_PP(range
), 0, (void *) &begin
)
937 || SUCCESS
!= zend_hash_index_find(Z_ARRVAL_PP(range
), 1, (void *) &end
)
939 /* this should never happen */
940 zend_hash_destroy(&ranges
);
941 php_http_env_set_response_code(500 TSRMLS_CC
);
943 zval_ptr_dtor(&zbody
);
948 size_t cr_header_len
;
950 cr_header_len
= spprintf(&cr_header_str
, 0, "Content-Range: bytes %ld-%ld/%zu", Z_LVAL_PP(begin
), Z_LVAL_PP(end
), body_size
);
951 php_http_env_set_response_header(206, cr_header_str
, cr_header_len
, 1 TSRMLS_CC
);
952 efree(cr_header_str
);
955 php_http_message_body_to_callback(body
, output
, &ctx
, Z_LVAL_PP(begin
), Z_LVAL_PP(end
) - Z_LVAL_PP(begin
) + 1);
956 output(&ctx
, NULL
, 0 TSRMLS_CC
);
958 zval_ptr_dtor(&zbody
);
963 /* send multipart/byte-ranges message */
966 php_http_buffer_t preface
;
968 char *content_type
= "application/octet-stream";
969 char boundary
[32], *ct_header_str
= "Content-Type: multipart/byteranges; boundary= ";
971 if ((zct
= get_container_value(container
, ZEND_STRL("contentType") TSRMLS_CC
))) {
972 zval
*zct_copy
= php_http_zsep(IS_STRING
, zct
);
975 if (Z_STRLEN_P(zct_copy
)) {
976 content_type
= estrndup(Z_STRVAL_P(zct_copy
), Z_STRLEN_P(zct_copy
));
983 php_http_boundary(boundary
, sizeof(boundary
));
984 strlcpy(&ct_header_str
[45], boundary
, 32);
986 php_http_env_set_response_header(206, ct_header_str
, strlen(ct_header_str
), 1 TSRMLS_CC
);
988 php_http_buffer_init(&preface
);
989 FOREACH_HASH_VAL(pos
, &ranges
, chunk
) {
992 if (IS_ARRAY
== Z_TYPE_PP(chunk
)
993 && SUCCESS
== zend_hash_index_find(Z_ARRVAL_PP(chunk
), 0, (void *) &begin
)
994 && IS_LONG
== Z_TYPE_PP(begin
)
995 && SUCCESS
== zend_hash_index_find(Z_ARRVAL_PP(chunk
), 1, (void *) &end
)
996 && IS_LONG
== Z_TYPE_PP(end
)
998 php_http_buffer_appendf(&preface
,
1000 "--%s" PHP_HTTP_CRLF
1001 "Content-Type: %s" PHP_HTTP_CRLF
1002 "Content-Range: bytes %ld-%ld/%zu" PHP_HTTP_CRLF
,
1010 php_http_buffer_fix(&preface
);
1011 output(&ctx
, PHP_HTTP_BUFFER_VAL(&preface
), PHP_HTTP_BUFFER_LEN(&preface
) TSRMLS_CC
);
1012 php_http_buffer_reset(&preface
);
1014 php_http_message_body_to_callback(body
, output
, &ctx
, Z_LVAL_PP(begin
), Z_LVAL_PP(end
) - Z_LVAL_PP(begin
) + 1);
1017 php_http_buffer_appendf(&preface
, PHP_HTTP_CRLF
"--%s--", boundary
);
1018 php_http_buffer_fix(&preface
);
1019 output(&ctx
, PHP_HTTP_BUFFER_VAL(&preface
), PHP_HTTP_BUFFER_LEN(&preface
) TSRMLS_CC
);
1020 php_http_buffer_dtor(&preface
);
1021 output(&ctx
, NULL
, 0 TSRMLS_CC
);
1023 zval_ptr_dtor(&zbody
);
1030 switch (php_http_env_is_response_cached_by_etag(container
, ZEND_STRL("If-None-Match"))) {
1031 case PHP_HTTP_CACHE_MISS
:
1034 case PHP_HTTP_CACHE_NO
:
1035 if (PHP_HTTP_CACHE_HIT
!= php_http_env_is_response_cached_by_last_modified(container
, ZEND_STRL("If-Modified-Since"))) {
1039 case PHP_HTTP_CACHE_HIT
:
1040 php_http_env_set_response_code(304 TSRMLS_CC
);
1042 zval_ptr_dtor(&zbody
);
1047 php_http_message_body_to_callback(body
, output
, &ctx
, 0, 0);
1048 output(&ctx
, NULL
, 0 TSRMLS_CC
);
1051 zval_ptr_dtor(&zbody
);
1056 static PHP_HTTP_STRLIST(php_http_env_response_status
) =
1057 PHP_HTTP_STRLIST_ITEM("Continue")
1058 PHP_HTTP_STRLIST_ITEM("Switching Protocols")
1059 PHP_HTTP_STRLIST_NEXT
1060 PHP_HTTP_STRLIST_ITEM("OK")
1061 PHP_HTTP_STRLIST_ITEM("Created")
1062 PHP_HTTP_STRLIST_ITEM("Accepted")
1063 PHP_HTTP_STRLIST_ITEM("Non-Authoritative Information")
1064 PHP_HTTP_STRLIST_ITEM("No Content")
1065 PHP_HTTP_STRLIST_ITEM("Reset Content")
1066 PHP_HTTP_STRLIST_ITEM("Partial Content")
1067 PHP_HTTP_STRLIST_NEXT
1068 PHP_HTTP_STRLIST_ITEM("Multiple Choices")
1069 PHP_HTTP_STRLIST_ITEM("Moved Permanently")
1070 PHP_HTTP_STRLIST_ITEM("Found")
1071 PHP_HTTP_STRLIST_ITEM("See Other")
1072 PHP_HTTP_STRLIST_ITEM("Not Modified")
1073 PHP_HTTP_STRLIST_ITEM("Use Proxy")
1074 PHP_HTTP_STRLIST_ITEM("(Unused)")
1075 PHP_HTTP_STRLIST_ITEM("Temporary Redirect")
1076 PHP_HTTP_STRLIST_NEXT
1077 PHP_HTTP_STRLIST_ITEM("Bad Request")
1078 PHP_HTTP_STRLIST_ITEM("Unauthorized")
1079 PHP_HTTP_STRLIST_ITEM("Payment Required")
1080 PHP_HTTP_STRLIST_ITEM("Forbidden")
1081 PHP_HTTP_STRLIST_ITEM("Not Found")
1082 PHP_HTTP_STRLIST_ITEM("Method Not Allowed")
1083 PHP_HTTP_STRLIST_ITEM("Not Acceptable")
1084 PHP_HTTP_STRLIST_ITEM("Proxy Authentication Required")
1085 PHP_HTTP_STRLIST_ITEM("Request Timeout")
1086 PHP_HTTP_STRLIST_ITEM("Conflict")
1087 PHP_HTTP_STRLIST_ITEM("Gone")
1088 PHP_HTTP_STRLIST_ITEM("Length Required")
1089 PHP_HTTP_STRLIST_ITEM("Precondition Failed")
1090 PHP_HTTP_STRLIST_ITEM("Request Entity Too Large")
1091 PHP_HTTP_STRLIST_ITEM("Request URI Too Long")
1092 PHP_HTTP_STRLIST_ITEM("Unsupported Media Type")
1093 PHP_HTTP_STRLIST_ITEM("Requested Range Not Satisfiable")
1094 PHP_HTTP_STRLIST_ITEM("Expectation Failed")
1095 PHP_HTTP_STRLIST_NEXT
1096 PHP_HTTP_STRLIST_ITEM("Internal Server Error")
1097 PHP_HTTP_STRLIST_ITEM("Not Implemented")
1098 PHP_HTTP_STRLIST_ITEM("Bad Gateway")
1099 PHP_HTTP_STRLIST_ITEM("Service Unavailable")
1100 PHP_HTTP_STRLIST_ITEM("Gateway Timeout")
1101 PHP_HTTP_STRLIST_ITEM("HTTP Version Not Supported")
1102 PHP_HTTP_STRLIST_STOP
1105 PHP_HTTP_API
const char *php_http_env_get_response_status_for_code(unsigned code
)
1107 return php_http_strlist_find(php_http_env_response_status
, 100, code
);
1110 zend_class_entry
*php_http_env_class_entry
;
1112 #define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpEnv, method, 0, req_args)
1113 #define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpEnv, method, 0)
1114 #define PHP_HTTP_ENV_ME(method) PHP_ME(HttpEnv, method, PHP_HTTP_ARGS(HttpEnv, method), ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
1116 PHP_HTTP_BEGIN_ARGS(getRequestHeader
, 0)
1117 PHP_HTTP_ARG_VAL(header_name
, 0)
1120 PHP_HTTP_BEGIN_ARGS(getRequestBody
, 0)
1121 PHP_HTTP_ARG_VAL(body_class_name
, 0)
1124 PHP_HTTP_BEGIN_ARGS(getResponseStatusForCode
, 1)
1125 PHP_HTTP_ARG_VAL(code
, 0)
1128 PHP_HTTP_BEGIN_ARGS(getResponseHeader
, 0)
1129 PHP_HTTP_ARG_VAL(header_name
, 0)
1132 PHP_HTTP_EMPTY_ARGS(getResponseCode
);
1134 PHP_HTTP_BEGIN_ARGS(setResponseHeader
, 1)
1135 PHP_HTTP_ARG_VAL(header_name
, 0)
1136 PHP_HTTP_ARG_VAL(header_value
, 0)
1137 PHP_HTTP_ARG_VAL(response_code
, 0)
1138 PHP_HTTP_ARG_VAL(replace_header
, 0)
1141 PHP_HTTP_BEGIN_ARGS(setResponseCode
, 1)
1142 PHP_HTTP_ARG_VAL(code
, 0)
1145 PHP_HTTP_BEGIN_ARGS(negotiateLanguage
, 0)
1146 PHP_HTTP_ARG_VAL(supported
, 0)
1147 PHP_HTTP_ARG_VAL(result_array
, 1)
1150 PHP_HTTP_BEGIN_ARGS(negotiateContentType
, 0)
1151 PHP_HTTP_ARG_VAL(supported
, 0)
1152 PHP_HTTP_ARG_VAL(result_array
, 1)
1155 PHP_HTTP_BEGIN_ARGS(negotiateCharset
, 0)
1156 PHP_HTTP_ARG_VAL(supported
, 0)
1157 PHP_HTTP_ARG_VAL(result_array
, 1)
1160 PHP_HTTP_BEGIN_ARGS(negotiate
, 0)
1161 PHP_HTTP_ARG_VAL(value
, 0)
1162 PHP_HTTP_ARG_VAL(supported
, 0)
1163 PHP_HTTP_ARG_VAL(result_array
, 1)
1166 PHP_HTTP_EMPTY_ARGS(persistentHandlesStat
);
1168 PHP_HTTP_BEGIN_ARGS(persistentHandlesClean
, 0)
1169 PHP_HTTP_ARG_VAL(name
, 0)
1172 PHP_HTTP_BEGIN_ARGS(persistentHandlesIdent
, 0)
1173 PHP_HTTP_ARG_VAL(name
, 0)
1176 zend_function_entry php_http_env_method_entry
[] = {
1177 PHP_HTTP_ENV_ME(getRequestHeader
)
1178 PHP_HTTP_ENV_ME(getRequestBody
)
1180 PHP_HTTP_ENV_ME(getResponseStatusForCode
)
1182 PHP_HTTP_ENV_ME(getResponseHeader
)
1183 PHP_HTTP_ENV_ME(getResponseCode
)
1184 PHP_HTTP_ENV_ME(setResponseHeader
)
1185 PHP_HTTP_ENV_ME(setResponseCode
)
1187 PHP_HTTP_ENV_ME(negotiateLanguage
)
1188 PHP_HTTP_ENV_ME(negotiateContentType
)
1189 PHP_HTTP_ENV_ME(negotiateCharset
)
1190 PHP_HTTP_ENV_ME(negotiate
)
1192 PHP_HTTP_ENV_ME(persistentHandlesStat
)
1193 PHP_HTTP_ENV_ME(persistentHandlesClean
)
1194 PHP_HTTP_ENV_ME(persistentHandlesIdent
)
1196 EMPTY_FUNCTION_ENTRY
1199 PHP_METHOD(HttpEnv
, getRequestHeader
)
1201 char *header_name_str
;
1202 int header_name_len
;
1204 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|s!", &header_name_str
, &header_name_len
)) {
1205 if (header_name_str
&& header_name_len
) {
1206 char *header_value
= php_http_env_get_request_header(header_name_str
, header_name_len TSRMLS_CC
);
1209 RETURN_STRING(header_value
, 0);
1213 array_init(return_value
);
1214 php_http_env_get_request_headers(Z_ARRVAL_P(return_value
) TSRMLS_CC
);
1221 PHP_METHOD(HttpEnv
, getRequestBody
)
1223 with_error_handling(EH_THROW
, PHP_HTTP_EX_CE(runtime
)) {
1224 zend_class_entry
*class_entry
= php_http_message_body_class_entry
;
1226 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|C", &class_entry
)) {
1227 zend_object_value ov
;
1228 php_http_message_body_t
*body
= php_http_env_get_request_body(TSRMLS_C
);
1230 if (SUCCESS
== php_http_new(&ov
, class_entry
, (php_http_new_t
) php_http_message_body_object_new_ex
, php_http_message_body_class_entry
, body
, NULL TSRMLS_CC
)) {
1231 RETURN_OBJVAL(ov
, 0);
1234 } end_error_handling();
1237 PHP_METHOD(HttpEnv
, getResponseStatusForCode
)
1241 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "l", &code
)) {
1242 RETURN_STRING(php_http_env_get_response_status_for_code(code
), 1);
1247 PHP_METHOD(HttpEnv
, getResponseHeader
)
1249 char *header_name_str
;
1250 int header_name_len
;
1252 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|s!", &header_name_str
, &header_name_len
)) {
1253 if (header_name_str
&& header_name_len
) {
1254 char *header_value
= php_http_env_get_response_header(header_name_str
, header_name_len TSRMLS_CC
);
1257 RETURN_STRING(header_value
, 0);
1261 array_init(return_value
);
1262 php_http_env_get_response_headers(Z_ARRVAL_P(return_value
) TSRMLS_CC
);
1269 PHP_METHOD(HttpEnv
, getResponseCode
)
1271 if (SUCCESS
== zend_parse_parameters_none()) {
1272 RETURN_LONG(php_http_env_get_response_code(TSRMLS_C
));
1277 PHP_METHOD(HttpEnv
, setResponseHeader
)
1279 char *header_name_str
;
1280 int header_name_len
;
1283 zend_bool replace_header
= 1;
1285 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s|z!lb", &header_name_str
, &header_name_len
, &header_value
, &code
, &replace_header
)) {
1286 RETURN_SUCCESS(php_http_env_set_response_header_value(code
, header_name_str
, header_name_len
, header_value
, replace_header TSRMLS_CC
));
1291 PHP_METHOD(HttpEnv
, setResponseCode
)
1295 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "l", &code
)) {
1296 RETURN_SUCCESS(php_http_env_set_response_code(code TSRMLS_CC
));
1302 #define PHP_HTTP_DO_NEGOTIATE_DEFAULT(supported) \
1306 zend_hash_internal_pointer_reset((supported)); \
1307 if (SUCCESS == zend_hash_get_current_data((supported), (void *) &value)) { \
1308 RETVAL_ZVAL(*value, 1, 0); \
1314 #define PHP_HTTP_DO_NEGOTIATE_HANDLE_DEFAULT(supported, rs_array) \
1315 PHP_HTTP_DO_NEGOTIATE_DEFAULT(supported); \
1320 FOREACH_HASH_VAL(pos, supported, value_ptr) { \
1321 zval *value = php_http_zsep(IS_STRING, *value_ptr); \
1322 add_assoc_double(rs_array, Z_STRVAL_P(value), 1.0); \
1323 zval_ptr_dtor(&value); \
1327 #define PHP_HTTP_DO_NEGOTIATE_HANDLE_RESULT(result, supported, rs_array) \
1333 if (zend_hash_num_elements(result) && HASH_KEY_IS_STRING == zend_hash_get_current_key_ex(result, &key, &key_len, &idx, 1, NULL)) { \
1334 RETVAL_STRINGL(key, key_len-1, 0); \
1336 PHP_HTTP_DO_NEGOTIATE_DEFAULT(supported); \
1340 zend_hash_copy(Z_ARRVAL_P(rs_array), result, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); \
1343 zend_hash_destroy(result); \
1344 FREE_HASHTABLE(result); \
1347 #define PHP_HTTP_DO_NEGOTIATE(type, supported, rs_array) \
1349 HashTable *result; \
1350 if ((result = php_http_negotiate_ ##type(supported))) { \
1351 PHP_HTTP_DO_NEGOTIATE_HANDLE_RESULT(result, supported, rs_array); \
1353 PHP_HTTP_DO_NEGOTIATE_HANDLE_DEFAULT(supported, rs_array); \
1357 PHP_METHOD(HttpEnv
, negotiateLanguage
)
1359 HashTable
*supported
;
1360 zval
*rs_array
= NULL
;
1362 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "H|z", &supported
, &rs_array
)) {
1364 zval_dtor(rs_array
);
1365 array_init(rs_array
);
1368 PHP_HTTP_DO_NEGOTIATE(language
, supported
, rs_array
);
1373 PHP_METHOD(HttpEnv
, negotiateCharset
)
1375 HashTable
*supported
;
1376 zval
*rs_array
= NULL
;
1378 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "H|z", &supported
, &rs_array
)) {
1380 zval_dtor(rs_array
);
1381 array_init(rs_array
);
1383 PHP_HTTP_DO_NEGOTIATE(charset
, supported
, rs_array
);
1388 PHP_METHOD(HttpEnv
, negotiateContentType
)
1390 HashTable
*supported
;
1391 zval
*rs_array
= NULL
;
1393 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "H|z", &supported
, &rs_array
)) {
1395 zval_dtor(rs_array
);
1396 array_init(rs_array
);
1398 PHP_HTTP_DO_NEGOTIATE(content_type
, supported
, rs_array
);
1403 PHP_METHOD(HttpEnv
, negotiate
)
1405 HashTable
*supported
;
1406 zval
*rs_array
= NULL
;
1410 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "sH|z", &value_str
, &value_len
, &supported
, &rs_array
)) {
1414 zval_dtor(rs_array
);
1415 array_init(rs_array
);
1418 if ((rs
= php_http_negotiate(value_str
, supported
, php_http_negotiate_default_func
))) {
1419 PHP_HTTP_DO_NEGOTIATE_HANDLE_RESULT(rs
, supported
, rs_array
);
1421 PHP_HTTP_DO_NEGOTIATE_HANDLE_DEFAULT(supported
, rs_array
);
1427 PHP_METHOD(HttpEnv
, persistentHandlesStat
)
1429 if (SUCCESS
== zend_parse_parameters_none()) {
1430 object_init(return_value
);
1431 if (php_http_persistent_handle_statall(HASH_OF(return_value
))) {
1434 zval_dtor(return_value
);
1439 PHP_METHOD(HttpEnv
, persistentHandlesClean
)
1441 char *name_str
= NULL
;
1444 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|s", &name_str
, &name_len
)) {
1445 php_http_persistent_handle_cleanup(name_str
, name_len
, 1 TSRMLS_CC
);
1449 PHP_METHOD(HttpEnv
, persistentHandlesIdent
)
1451 char *ident_str
= NULL
;
1454 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|s", &ident_str
, &ident_len
)) {
1455 RETVAL_STRING(zend_ini_string(ZEND_STRS("http.persistent.handles.ident"), 0), 1);
1456 if (ident_str
&& ident_len
) {
1457 zend_alter_ini_entry(ZEND_STRS("http.persistent.handles.ident"), ident_str
, ident_len
, ZEND_INI_USER
, PHP_INI_STAGE_RUNTIME
);
1464 zend_class_entry
*php_http_env_request_class_entry
;
1466 #undef PHP_HTTP_BEGIN_ARGS
1467 #undef PHP_HTTP_EMPTY_ARGS
1468 #define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpEnvRequest, method, 0, req_args)
1469 #define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpEnvRequest, method, 0)
1470 #define PHP_HTTP_ENV_REQUEST_ME(method, visibility) PHP_ME(HttpEnvRequest, method, PHP_HTTP_ARGS(HttpEnvRequest, method), visibility)
1472 PHP_HTTP_EMPTY_ARGS(__construct
);
1474 zend_function_entry php_http_env_request_method_entry
[] = {
1475 PHP_HTTP_ENV_REQUEST_ME(__construct
, ZEND_ACC_PUBLIC
|ZEND_ACC_CTOR
)
1477 EMPTY_FUNCTION_ENTRY
1480 PHP_METHOD(HttpEnvRequest
, __construct
)
1482 with_error_handling(EH_THROW
, PHP_HTTP_EX_CE(runtime
)) {
1483 if (SUCCESS
== zend_parse_parameters_none()) {
1484 php_http_message_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
1486 with_error_handling(EH_THROW
, PHP_HTTP_EX_CE(message
)) {
1487 obj
->message
= php_http_message_init_env(obj
->message
, PHP_HTTP_REQUEST TSRMLS_CC
);
1488 } end_error_handling();
1490 } end_error_handling();
1494 zend_class_entry
*php_http_env_response_class_entry
;
1496 #undef PHP_HTTP_BEGIN_ARGS
1497 #undef PHP_HTTP_EMPTY_ARGS
1498 #define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpEnvResponse, method, 0, req_args)
1499 #define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpEnvResponse, method, 0)
1500 #define PHP_HTTP_ENV_RESPONSE_ME(method, visibility) PHP_ME(HttpEnvResponse, method, PHP_HTTP_ARGS(HttpEnvResponse, method), visibility)
1502 PHP_HTTP_EMPTY_ARGS(__construct
);
1504 PHP_HTTP_BEGIN_ARGS(setContentType
, 1)
1505 PHP_HTTP_ARG_VAL(content_type
, 0)
1508 PHP_HTTP_BEGIN_ARGS(setContentDisposition
, 1)
1509 PHP_HTTP_ARG_VAL(content_disposition
, 0)
1510 PHP_HTTP_ARG_VAL(filename
, 0)
1513 PHP_HTTP_BEGIN_ARGS(setCacheControl
, 1)
1514 PHP_HTTP_ARG_VAL(cache_control
, 0)
1517 PHP_HTTP_BEGIN_ARGS(setLastModified
, 1)
1518 PHP_HTTP_ARG_VAL(last_modified
, 0)
1521 PHP_HTTP_BEGIN_ARGS(isCachedByLastModified
, 0)
1522 PHP_HTTP_ARG_VAL(header_name
, 0)
1525 PHP_HTTP_BEGIN_ARGS(setEtag
, 1)
1526 PHP_HTTP_ARG_VAL(etag
, 0)
1529 PHP_HTTP_BEGIN_ARGS(isCachedByEtag
, 0)
1530 PHP_HTTP_ARG_VAL(header_name
, 0)
1533 PHP_HTTP_BEGIN_ARGS(setThrottleRate
, 1)
1534 PHP_HTTP_ARG_VAL(chunk_size
, 0)
1535 PHP_HTTP_ARG_VAL(delay
, 0)
1538 PHP_HTTP_EMPTY_ARGS(send
);
1541 zend_function_entry php_http_env_response_method_entry
[] = {
1542 PHP_HTTP_ENV_RESPONSE_ME(__construct
, ZEND_ACC_PUBLIC
|ZEND_ACC_CTOR
)
1543 PHP_HTTP_ENV_RESPONSE_ME(setContentType
, ZEND_ACC_PUBLIC
)
1544 PHP_HTTP_ENV_RESPONSE_ME(setContentDisposition
, ZEND_ACC_PUBLIC
)
1545 PHP_HTTP_ENV_RESPONSE_ME(setCacheControl
, ZEND_ACC_PUBLIC
)
1546 PHP_HTTP_ENV_RESPONSE_ME(setLastModified
, ZEND_ACC_PUBLIC
)
1547 PHP_HTTP_ENV_RESPONSE_ME(isCachedByLastModified
, ZEND_ACC_PUBLIC
)
1548 PHP_HTTP_ENV_RESPONSE_ME(setEtag
, ZEND_ACC_PUBLIC
)
1549 PHP_HTTP_ENV_RESPONSE_ME(isCachedByEtag
, ZEND_ACC_PUBLIC
)
1550 PHP_HTTP_ENV_RESPONSE_ME(setThrottleRate
, ZEND_ACC_PUBLIC
)
1552 PHP_HTTP_ENV_RESPONSE_ME(send
, ZEND_ACC_PUBLIC
)
1554 EMPTY_FUNCTION_ENTRY
1558 PHP_METHOD(HttpEnvResponse
, __construct
)
1560 with_error_handling(EH_THROW
, PHP_HTTP_EX_CE(runtime
)) {
1561 if (SUCCESS
== zend_parse_parameters_none()) {
1562 php_http_message_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
1564 with_error_handling(EH_THROW
, PHP_HTTP_EX_CE(message
)) {
1565 obj
->message
= php_http_message_init_env(obj
->message
, PHP_HTTP_RESPONSE TSRMLS_CC
);
1566 } end_error_handling();
1568 } end_error_handling();
1572 PHP_METHOD(HttpEnvResponse
, setContentType
)
1577 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s", &ct_str
, &ct_len
)) {
1578 RETURN_SUCCESS(php_http_env_set_response_content_type(getThis(), ct_str
, ct_len
, NULL TSRMLS_CC
));
1583 PHP_METHOD(HttpEnvResponse
, setContentDisposition
)
1586 char *file_str
= NULL
;
1589 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "l|s!", &cd
, &file_str
, &file_len
)) {
1590 RETURN_SUCCESS(php_http_env_set_response_content_disposition(getThis(), cd
, file_str
, file_len
, NULL TSRMLS_CC
));
1595 PHP_METHOD(HttpEnvResponse
, setCacheControl
)
1600 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s", &cc_str
, &cc_len
)) {
1601 RETURN_SUCCESS(php_http_env_set_response_cache_control(getThis(), cc_str
, cc_len
, NULL TSRMLS_CC
));
1606 PHP_METHOD(HttpEnvResponse
, setLastModified
)
1610 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "l", &last_modified
)) {
1611 RETURN_SUCCESS(php_http_env_set_response_last_modified(getThis(), last_modified
, NULL TSRMLS_CC
));
1616 PHP_METHOD(HttpEnvResponse
, isCachedByLastModified
)
1618 char *header_name_str
= NULL
;
1619 int header_name_len
= 0;
1621 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|s!", &header_name_str
, &header_name_len
)) {
1622 if (!header_name_str
|| !header_name_len
) {
1623 header_name_str
= "If-Modified-Since";
1624 header_name_len
= lenof("If-Modified-Since");
1626 RETURN_LONG(php_http_env_is_response_cached_by_last_modified(getThis(), header_name_str
, header_name_len TSRMLS_CC
));
1631 PHP_METHOD(HttpEnvResponse
, setEtag
)
1636 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s!", &etag_str
, &etag_len
)) {
1637 RETURN_SUCCESS(php_http_env_set_response_etag(getThis(), etag_str
, etag_len
, NULL TSRMLS_CC
));
1642 PHP_METHOD(HttpEnvResponse
, isCachedByEtag
)
1644 char *header_name_str
= NULL
;
1645 int header_name_len
= 0;
1647 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s", &header_name_str
, &header_name_len
)) {
1648 if (!header_name_str
|| !header_name_len
) {
1649 header_name_str
= "If-None-Match";
1650 header_name_len
= lenof("If-None-Match");
1652 RETURN_LONG(php_http_env_is_response_cached_by_etag(getThis(), header_name_str
, header_name_len TSRMLS_CC
));
1657 PHP_METHOD(HttpEnvResponse
, setThrottleRate
)
1662 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "l|d", &chunk_size
, &delay
)) {
1663 php_http_env_set_response_throttle_rate(getThis(), chunk_size
, delay TSRMLS_CC
);
1669 PHP_METHOD(HttpEnvResponse
, send
)
1671 if (SUCCESS
== zend_parse_parameters_none()) {
1672 RETURN_SUCCESS(php_http_env_send_response(getThis() TSRMLS_CC
));
1678 PHP_MINIT_FUNCTION(http_env
)
1680 PHP_HTTP_REGISTER_CLASS(http
, Env
, http_env
, NULL
, 0);
1681 PHP_HTTP_REGISTER_CLASS(http
\\env
, Request
, http_env_request
, php_http_message_class_entry
, 0);
1682 PHP_HTTP_REGISTER_CLASS(http
\\env
, Response
, http_env_response
, php_http_message_class_entry
, 0);
1684 zend_declare_class_constant_long(php_http_env_response_class_entry
, ZEND_STRL("CONTENT_DISPOSITION_INLINE"), PHP_HTTP_CONTENT_DISPOSITION_INLINE TSRMLS_CC
);
1685 zend_declare_class_constant_long(php_http_env_response_class_entry
, ZEND_STRL("CONTENT_DISPOSITION_ATTACHMENT"), PHP_HTTP_CONTENT_DISPOSITION_ATTACHMENT TSRMLS_CC
);
1687 zend_declare_class_constant_long(php_http_env_response_class_entry
, ZEND_STRL("CACHE_NO"), PHP_HTTP_CACHE_NO TSRMLS_CC
);
1688 zend_declare_class_constant_long(php_http_env_response_class_entry
, ZEND_STRL("CACHE_HIT"), PHP_HTTP_CACHE_HIT TSRMLS_CC
);
1689 zend_declare_class_constant_long(php_http_env_response_class_entry
, ZEND_STRL("CACHE_MISS"), PHP_HTTP_CACHE_MISS TSRMLS_CC
);
1691 zend_declare_property_null(php_http_env_response_class_entry
, ZEND_STRL("contentType"), ZEND_ACC_PROTECTED TSRMLS_CC
);
1692 zend_declare_property_null(php_http_env_response_class_entry
, ZEND_STRL("etag"), ZEND_ACC_PROTECTED TSRMLS_CC
);
1693 zend_declare_property_null(php_http_env_response_class_entry
, ZEND_STRL("lastModified"), ZEND_ACC_PROTECTED TSRMLS_CC
);
1694 zend_declare_property_null(php_http_env_response_class_entry
, ZEND_STRL("throttleDelay"), ZEND_ACC_PROTECTED TSRMLS_CC
);
1695 zend_declare_property_null(php_http_env_response_class_entry
, ZEND_STRL("throttleChunk"), ZEND_ACC_PROTECTED TSRMLS_CC
);
1706 * vim600: noet sw=4 ts=4 fdm=marker
1707 * vim<600: noet sw=4 ts=4