ensure the merged header IS_STRING
[m6w6/ext-http] / php_http_env.c
1 /*
2 +--------------------------------------------------------------------+
3 | PECL :: http |
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted provided that the conditions mentioned |
7 | in the accompanying LICENSE file are met. |
8 +--------------------------------------------------------------------+
9 | Copyright (c) 2004-2010, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
11 */
12
13 /* $Id $ */
14
15 #include "php_http.h"
16
17 #include <main/SAPI.h>
18 #include <ext/date/php_date.h>
19 #include <ext/standard/php_string.h>
20
21 PHP_RINIT_FUNCTION(http_env)
22 {
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);
27
28 return SUCCESS;
29 }
30
31 PHP_RSHUTDOWN_FUNCTION(http_env)
32 {
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;
37 }
38 if (PHP_HTTP_G->env.request.body) {
39 php_http_message_body_free(&PHP_HTTP_G->env.request.body);
40 }
41 if (PHP_HTTP_G->env.response.body) {
42 php_http_message_body_free(&PHP_HTTP_G->env.response.body);
43 }
44 STR_SET(PHP_HTTP_G->env.response.content_type, NULL);
45 STR_SET(PHP_HTTP_G->env.response.etag, NULL);
46
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;
50 }
51
52 return SUCCESS;
53 }
54
55 PHP_HTTP_API void php_http_env_get_request_headers(HashTable *headers TSRMLS_DC)
56 {
57 php_http_array_hashkey_t key = php_http_array_hashkey_init(0);
58 zval **hsv, **header;
59 HashPosition pos;
60
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);
64
65 zend_is_auto_global("_SERVER", lenof("_SERVER") TSRMLS_CC);
66
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)) {
70 key.len -= 5;
71 key.str = php_http_pretty_key(estrndup(key.str + 5, key.len - 1), key.len - 1, 1, 1);
72
73 zend_hash_get_current_data_ex(Z_ARRVAL_PP(hsv), (void *) &header, &pos);
74 Z_ADDREF_P(*header);
75 zend_hash_add(PHP_HTTP_G->env.request.headers, key.str, key.len, (void *) header, sizeof(zval *), NULL);
76
77 efree(key.str);
78 }
79 }
80 }
81 }
82
83 if (headers) {
84 zend_hash_copy(headers, PHP_HTTP_G->env.request.headers, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
85 }
86 }
87
88 PHP_HTTP_API char *php_http_env_get_request_header(const char *name_str, size_t name_len TSRMLS_DC)
89 {
90 zval **zvalue;
91 char *val = NULL, *key = php_http_pretty_key(estrndup(name_str, name_len), name_len, 1, 1);
92
93 php_http_env_get_request_headers(NULL TSRMLS_CC);
94
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);
97
98 val = estrndup(Z_STRVAL_P(zcopy), Z_STRLEN_P(zcopy));
99 zval_ptr_dtor(&zcopy);
100 }
101
102 efree(key);
103
104 return val;
105 }
106
107 PHP_HTTP_API int php_http_env_got_request_header(const char *name_str, size_t name_len TSRMLS_DC)
108 {
109 char *key = php_http_pretty_key(estrndup(name_str, name_len), name_len, 1, 1);
110 int got;
111
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);
114 efree(key);
115
116 return got;
117 }
118
119 PHP_HTTP_API zval *php_http_env_get_server_var(const char *key, size_t key_len, zend_bool check TSRMLS_DC)
120 {
121 zval **hsv, **var;
122 char *env;
123
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)) {
127 return NULL;
128 }
129 if (PHP_HTTP_G->env.server_var) {
130 zval_ptr_dtor(&PHP_HTTP_G->env.server_var);
131 }
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;
135 }
136
137 zend_is_auto_global(ZEND_STRL("_SERVER") TSRMLS_CC);
138
139 if ((SUCCESS != zend_hash_find(&EG(symbol_table), ZEND_STRS("_SERVER"), (void *) &hsv)) || (Z_TYPE_PP(hsv) != IS_ARRAY)) {
140 return NULL;
141 }
142 if ((SUCCESS != zend_hash_find(Z_ARRVAL_PP(hsv), key, key_len + 1, (void *) &var))) {
143 return NULL;
144 }
145 if (check && !((Z_TYPE_PP(var) == IS_STRING) && Z_STRVAL_PP(var) && Z_STRLEN_PP(var))) {
146 return NULL;
147 }
148 return *var;
149 }
150
151 PHP_HTTP_API php_http_message_body_t *php_http_env_get_request_body(TSRMLS_D)
152 {
153 if (!PHP_HTTP_G->env.request.body) {
154 php_stream *s = NULL;
155
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);
161 } else {
162 php_stream_write(s, SG(request_info).post_data, SG(request_info).post_data_length);
163 }
164 php_stream_rewind(s);
165 }
166 } else if (sapi_module.read_post) {
167 if ((s = php_stream_temp_new())) {
168 char *buf = emalloc(4096);
169 int len;
170
171 while (0 < (len = sapi_module.read_post(buf, 4096 TSRMLS_CC))) {
172 php_stream_write(s, buf, len);
173
174 if (len < 4096) {
175 break;
176 }
177 }
178 efree(buf);
179
180 php_stream_rewind(s);
181 }
182 }
183 PHP_HTTP_G->env.request.body = php_http_message_body_init(NULL, s TSRMLS_CC);
184 }
185
186 return PHP_HTTP_G->env.request.body;
187 }
188
189 PHP_HTTP_API php_http_range_status_t php_http_env_get_request_ranges(HashTable *ranges, size_t length TSRMLS_DC)
190 {
191 zval *zentry;
192 char *range, *rp, c;
193 long begin = -1, end = -1, *ptr;
194
195 if (!(range = php_http_env_get_request_header(ZEND_STRL("Range") TSRMLS_CC))) {
196 return PHP_HTTP_RANGE_NO;
197 }
198 if (strncmp(range, "bytes=", lenof("bytes="))) {
199 STR_FREE(range);
200 return PHP_HTTP_RANGE_NO;
201 }
202
203 rp = range + lenof("bytes=");
204 ptr = &begin;
205
206 do {
207 switch (c = *(rp++)) {
208 case '0':
209 /* allow 000... - shall we? */
210 if (*ptr != -10) {
211 *ptr *= 10;
212 }
213 break;
214
215 case '1': case '2': case '3':
216 case '4': case '5': case '6':
217 case '7': case '8': case '9':
218 /*
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
222 * --
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".
228 */
229 if (*ptr > 0) {
230 *ptr *= 10;
231 *ptr += c - '0';
232 } else {
233 *ptr = c - '0';
234 }
235 break;
236
237 case '-':
238 ptr = &end;
239 break;
240
241 case ' ':
242 break;
243
244 case 0:
245 case ',':
246
247 if (length) {
248 /* validate ranges */
249 switch (begin) {
250 /* "0-12345" */
251 case -10:
252 switch (end) {
253 /* "0-" */
254 case -1:
255 STR_FREE(range);
256 return PHP_HTTP_RANGE_NO;
257
258 /* "0-0" */
259 case -10:
260 end = 0;
261 break;
262
263 default:
264 if (length <= (size_t) end) {
265 end = length - 1;
266 }
267 break;
268 }
269 begin = 0;
270 break;
271
272 /* "-12345" */
273 case -1:
274 /* "-", "-0" */
275 if (end == -1 || end == -10) {
276 STR_FREE(range);
277 return PHP_HTTP_RANGE_ERR;
278 }
279 begin = length - end;
280 end = length - 1;
281 break;
282
283 /* "12345-(NNN)" */
284 default:
285 if (length <= (size_t) begin) {
286 STR_FREE(range);
287 return PHP_HTTP_RANGE_ERR;
288 }
289 switch (end) {
290 /* "12345-0" */
291 case -10:
292 STR_FREE(range);
293 return PHP_HTTP_RANGE_ERR;
294
295 /* "12345-" */
296 case -1:
297 end = length - 1;
298 break;
299
300 /* "12345-67890" */
301 default:
302 if (length <= (size_t) end) {
303 end = length - 1;
304 } else if (end < begin) {
305 STR_FREE(range);
306 return PHP_HTTP_RANGE_ERR;
307 }
308 break;
309 }
310 break;
311 }
312 }
313
314 MAKE_STD_ZVAL(zentry);
315 array_init(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);
319
320 begin = -1;
321 end = -1;
322 ptr = &begin;
323
324 break;
325
326 default:
327 STR_FREE(range);
328 return PHP_HTTP_RANGE_NO;
329 }
330 } while (c != 0);
331
332 STR_FREE(range);
333 return PHP_HTTP_RANGE_OK;
334 }
335
336 static void grab_headers(void *data, void *arg TSRMLS_DC)
337 {
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);
340 }
341
342 PHP_HTTP_API STATUS php_http_env_get_response_headers(HashTable *headers_ht TSRMLS_DC)
343 {
344 STATUS status;
345 php_http_buffer_t headers;
346
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);
350
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);
353
354 return status;
355 }
356
357 PHP_HTTP_API char *php_http_env_get_response_header(const char *name_str, size_t name_len TSRMLS_DC)
358 {
359 char *val = NULL;
360 HashTable headers;
361
362 zend_hash_init(&headers, 0, NULL, NULL, 0);
363 if (SUCCESS == php_http_env_get_response_headers(&headers TSRMLS_CC)) {
364 zval **zvalue;
365 char *key = php_http_pretty_key(estrndup(name_str, name_len), name_len, 1, 1);
366
367 if (SUCCESS == zend_hash_find(&headers, key, name_len + 1, (void *) &zvalue)) {
368 zval *zcopy = php_http_zsep(IS_STRING, *zvalue);
369
370 val = estrndup(Z_STRVAL_P(zcopy), Z_STRLEN_P(zcopy));
371 zval_ptr_dtor(&zcopy);
372 }
373
374 efree(key);
375 }
376 zend_hash_destroy(&headers);
377
378 return val;
379 }
380
381 PHP_HTTP_API long php_http_env_get_response_code(TSRMLS_D)
382 {
383 long code = SG(sapi_headers).http_response_code;
384 return code ? code : 200;
385 }
386
387 PHP_HTTP_API STATUS php_http_env_set_response_code(long http_code TSRMLS_DC)
388 {
389 return sapi_header_op(SAPI_HEADER_SET_STATUS, (void *) http_code TSRMLS_CC);
390 }
391
392 PHP_HTTP_API STATUS php_http_env_set_response_status_line(long code, php_http_version_t *v TSRMLS_DC)
393 {
394 sapi_header_line h = {0};
395 STATUS ret;
396
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);
399 efree(h.line);
400
401 return ret;
402 }
403
404 PHP_HTTP_API STATUS php_http_env_set_response_protocol_version(php_http_version_t *v TSRMLS_DC)
405 {
406 return php_http_env_set_response_status_line(php_http_env_get_response_code(TSRMLS_C), v TSRMLS_CC);
407 }
408
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)
410 {
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);
413 efree(h.line);
414 return ret;
415 }
416
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)
418 {
419 if (!value) {
420 sapi_header_line h = {(char *) name_str, name_len, http_code};
421
422 return sapi_header_op(SAPI_HEADER_DELETE, (void *) &h TSRMLS_CC);
423 }
424
425 if(Z_TYPE_P(value) == IS_ARRAY || Z_TYPE_P(value) == IS_OBJECT) {
426 HashPosition pos;
427 int first = replace;
428 zval **data_ptr;
429
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)) {
432 return FAILURE;
433 }
434 first = 0;
435 }
436
437 return SUCCESS;
438 } else {
439 zval *data = php_http_zsep(IS_STRING, value);
440
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);
444 } else {
445 sapi_header_line h;
446 STATUS ret;
447
448 if (name_len > INT_MAX) {
449 name_len = INT_MAX;
450 }
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));
453
454 ret = sapi_header_op(replace ? SAPI_HEADER_REPLACE : SAPI_HEADER_ADD, (void *) &h TSRMLS_CC);
455
456 zval_ptr_dtor(&data);
457 STR_FREE(h.line);
458
459 return ret;
460 }
461 }
462 }
463
464 PHP_HTTP_API void php_http_env_set_response_throttle_rate(zval *container, size_t chunk_size, double delay TSRMLS_CC)
465 {
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);
469 } else {
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);
473 }
474 }
475
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)
477 {
478 if (Z_TYPE_P(container) == IS_OBJECT) {
479 /* stupid non-const api */
480 char *name = estrndup(name_str, name_len);
481 switch (type) {
482 case IS_LONG:
483 zend_update_property_long(Z_OBJCE_P(container), container, name, name_len, *(long *)value_ptr TSRMLS_CC);
484 break;
485 case IS_STRING:
486 zend_update_property_stringl(Z_OBJCE_P(container), container, name, name_len, value_ptr, value_len TSRMLS_CC);
487 break;
488 }
489 efree(name);
490 } else {
491 convert_to_array(container);
492 switch (type) {
493 case IS_LONG:
494 add_assoc_long_ex(container, name_str, name_len + 1, *(long *)value_ptr);
495 break;
496 case IS_STRING: {
497 char *value = estrndup(value_ptr, value_len);
498 add_assoc_stringl_ex(container, name_str, name_len + 1, value, value_len, 0);
499 break;
500 }
501 }
502 }
503 }
504
505 PHP_HTTP_API STATUS php_http_env_set_response_last_modified(zval *container, time_t t, char **sent_header TSRMLS_DC)
506 {
507 STATUS ret;
508 char *lm_header_str, *date;
509 size_t lm_header_len;
510
511 if (t) {
512 if (!(date = php_format_date(ZEND_STRL(PHP_HTTP_DATE_FORMAT), t, 0 TSRMLS_CC))) {
513 return FAILURE;
514 }
515
516 lm_header_len = spprintf(&lm_header_str, 0, "Last-Modified: %s", date);
517 STR_FREE(date);
518 } else {
519 lm_header_str = "Last-Modified:";
520 lm_header_len = lenof("Last-Modified:");
521 }
522
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);
525 }
526
527 if (sent_header) {
528 *sent_header = lm_header_str;
529 } else if (t) {
530 STR_FREE(lm_header_str);
531 }
532
533 return ret;
534 }
535
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)
537 {
538 STATUS ret;
539 char *etag = NULL, *etag_header_str;
540 size_t etag_header_len;
541
542 if (etag_len){
543 etag_header_len = spprintf(&etag_header_str, 0, "ETag: \"%s\"", etag_str);
544 } else {
545 etag_header_str = "ETag:";
546 etag_header_len = lenof("ETag:");
547 }
548
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);
551 }
552
553 if (sent_header) {
554 *sent_header = etag_header_str;
555 } else if (etag_len) {
556 STR_FREE(etag_header_str);
557 }
558
559 return ret;
560 }
561
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)
563 {
564 STATUS ret;
565 char *ct_header_str;
566 size_t ct_header_len;
567
568 if (ct_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);
571 } else {
572 ct_header_str = "Content-Type:";
573 ct_header_len = lenof("Content-Type:");
574 }
575
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);
578 }
579
580 if (sent_header) {
581 *sent_header = ct_header_str;
582 } else if (ct_len) {
583 STR_FREE(ct_header_str);
584 }
585
586 return ret;
587 }
588
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)
590 {
591 STATUS ret;
592 char *tmp, *cd_header_str, *new_f_str;
593 int new_f_len;
594 size_t cd_header_len;
595
596 switch (d) {
597 case PHP_HTTP_CONTENT_DISPOSITION_NONE:
598 break;
599 case PHP_HTTP_CONTENT_DISPOSITION_INLINE:
600 tmp = "inline";
601 break;
602 case PHP_HTTP_CONTENT_DISPOSITION_ATTACHMENT:
603 tmp = "attachment";
604 break;
605 default:
606 php_http_error(HE_WARNING, PHP_HTTP_E_INVALID_PARAM, "Unknown content disposition (%d)", (int) d);
607 return FAILURE;
608 }
609
610 if (f_len) {
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);
613 STR_FREE(new_f_str);
614 } else if (d) {
615 cd_header_len = spprintf(&cd_header_str, 0, "Content-Disposition: %s", tmp);
616 } else {
617 cd_header_str = "Content-Disposition:";
618 cd_header_len = lenof("Content-Disposition:");
619 }
620
621 ret = php_http_env_set_response_header(0, cd_header_str, cd_header_len, 1 TSRMLS_CC);
622
623 if (sent_header) {
624 *sent_header = cd_header_str;
625 } else if (f_len || d){
626 STR_FREE(cd_header_str);
627 }
628
629 return ret;
630 }
631
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)
633 {
634 STATUS ret;
635 char *cc_header_str;
636 size_t cc_header_len;
637
638 if (cc_len) {
639 cc_header_len = spprintf(&cc_header_str, 0, "Cache-Control: %s", cc_str);
640 } else {
641 cc_header_str = "Content-Disposition:";
642 cc_header_len = lenof("Content-Disposition:");
643 }
644
645 ret = php_http_env_set_response_header(0, cc_header_str, cc_header_len, 1 TSRMLS_CC);
646
647 if (sent_header) {
648 *sent_header = cc_header_str;
649 } else if (cc_len) {
650 STR_FREE(cc_header_str);
651 }
652
653 return ret;
654 }
655
656 static zval *get_container_value(zval *container, const char *name_str, size_t name_len TSRMLS_CC)
657 {
658 zval *val, **valptr;
659
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);
663 efree(name);
664 } else {
665 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(container), name_str, name_len + 1, (void *) &valptr)) {
666 val = *valptr;
667 } else {
668 val = NULL;
669 }
670 }
671 if (val) {
672 Z_ADDREF_P(val);
673 }
674 return val;
675 }
676
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)
678 {
679 int ret, free_etag = 0;
680 char *header, *etag;
681 zval *zetag, *zbody = NULL;
682
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)
687 ) {
688 STR_FREE(header);
689 if (zbody) {
690 zval_ptr_dtor(&zbody);
691 }
692 return PHP_HTTP_CACHE_NO;
693 }
694
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);
698 zetag = zetag_copy;
699 }
700
701 if (zetag && Z_STRLEN_P(zetag)) {
702 etag = Z_STRVAL_P(zetag);
703 } else {
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);
706 free_etag = 1;
707 }
708
709 if (zetag) {
710 zval_ptr_dtor(&zetag);
711 }
712
713 ret = php_http_match(header, etag, PHP_HTTP_MATCH_WORD);
714
715 if (free_etag) {
716 efree(etag);
717 }
718 efree(header);
719
720 return ret ? PHP_HTTP_CACHE_HIT : PHP_HTTP_CACHE_MISS;
721 }
722
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)
724 {
725 char *header;
726 time_t ums, lm = 0;
727 zval *zbody = NULL, *zlm;
728
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)
733 ) {
734 STR_FREE(header);
735 if (zbody) {
736 zval_ptr_dtor(&zbody);
737 }
738 return PHP_HTTP_CACHE_NO;
739 }
740
741 if ((zlm = get_container_value(container, ZEND_STRL("lastModified") TSRMLS_CC))) {
742 zval *zlm_copy = php_http_zsep(IS_LONG, zlm);
743 zval_ptr_dtor(&zlm);
744 zlm = zlm_copy;
745 }
746
747 if (zlm && Z_LVAL_P(zlm) > 0) {
748 lm = Z_LVAL_P(zlm);
749 } else {
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);
752 }
753
754 if (zlm) {
755 zval_ptr_dtor(&zlm);
756 }
757
758 ums = php_parse_date(header, NULL TSRMLS_CC);
759 efree(header);
760
761 if (ums > 0 && ums <= lm) {
762 return PHP_HTTP_CACHE_HIT;
763 } else {
764 return PHP_HTTP_CACHE_MISS;
765 }
766 }
767
768 PHP_HTTP_API void php_http_env_set_response_body(zval *container, php_http_message_body_t *body)
769 {
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);
772
773 set_container_value(container, ZEND_STRL("body"), IS_OBJECT, &ov, 0 TSRMLS_CC);
774 }
775
776 struct output_ctx {
777 php_http_buffer_t *buf;
778 zval *container;
779 };
780
781 static size_t output(void *context, const char *buf, size_t len TSRMLS_DC)
782 {
783 struct output_ctx *ctx = context;
784
785 if (ctx->buf) {
786 zval *zcs;
787 size_t chunk_size = PHP_HTTP_SENDBUF_SIZE;
788
789 if ((zcs = get_container_value(ctx->container, ZEND_STRL("throttleChunk") TSRMLS_CC))) {
790 zval *zcs_copy = php_http_zsep(IS_LONG, zcs);
791
792 zval_ptr_dtor(&zcs);
793 chunk_size = Z_LVAL_P(zcs_copy);
794 zval_ptr_dtor(&zcs_copy);
795 }
796 php_http_buffer_chunked_output(&ctx->buf, buf, len, buf ? chunk_size : 0, output, NULL TSRMLS_CC);
797 } else {
798 zval *ztd;
799
800
801 PHPWRITE(buf, len);
802
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))) {
806 double delay;
807 zval *ztd_copy = php_http_zsep(IS_DOUBLE, ztd);
808
809 zval_ptr_dtor(&ztd);
810 delay = Z_DVAL_P(ztd_copy);
811 zval_ptr_dtor(&ztd_copy);
812
813 if (delay >= PHP_HTTP_DIFFSEC) {
814 if (php_output_get_level(TSRMLS_C)) {
815 php_output_flush_all(TSRMLS_C);
816 }
817 if (!(php_output_get_status(TSRMLS_C) & PHP_OUTPUT_IMPLICITFLUSH)) {
818 sapi_flush(TSRMLS_C);
819 }
820 php_http_sleep(delay);
821 }
822 }
823 }
824 return len;
825 }
826
827 PHP_HTTP_API STATUS php_http_env_send_response(zval *container TSRMLS_DC)
828 {
829 struct output_ctx ctx = {NULL, container};
830 zval *zbody, *zheader, *zrcode, *zversion;
831 HashTable ranges;
832 php_http_range_status_t range_status;
833 php_http_message_body_t *body;
834 size_t body_size;
835
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)
839 ) {
840 if (zbody) {
841 zval_ptr_dtor(&zbody);
842 }
843 return FAILURE;
844 }
845
846 if ((zrcode = get_container_value(container, ZEND_STRL("responseCode") TSRMLS_CC))) {
847 zval *zrcode_copy = php_http_zsep(IS_LONG, zrcode);
848
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);
852 }
853 zval_ptr_dtor(&zrcode_copy);
854 }
855
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);
859
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);
864 }
865 zval_ptr_dtor(&zversion_copy);
866 }
867
868 if ((zheader = get_container_value(container, ZEND_STRL("headers") TSRMLS_CC))) {
869 if (Z_TYPE_P(zheader) == IS_ARRAY) {
870 zval **val;
871 HashPosition pos;
872 php_http_array_hashkey_t key = php_http_array_hashkey_init(0);
873
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);
877 }
878 }
879 }
880 zval_ptr_dtor(&zheader);
881 }
882
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);
888
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)) {
893 char *cr_header_str;
894 size_t cr_header_len;
895
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);
899 if (zbody) {
900 zval_ptr_dtor(&zbody);
901 }
902 return SUCCESS;
903 }
904 break;
905
906 case PHP_HTTP_RANGE_NO:
907 /* send full entity */
908 zend_hash_destroy(&ranges);
909 break;
910
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)
915 ) {
916 /* send full entity */
917 zend_hash_destroy(&ranges);
918 break;
919 }
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)
923 ) {
924 zend_hash_destroy(&ranges);
925 php_http_env_set_response_code(412 TSRMLS_CC);
926 if (zbody) {
927 zval_ptr_dtor(&zbody);
928 }
929 return SUCCESS;
930 }
931 if (zend_hash_num_elements(&ranges) == 1) {
932 /* single range */
933 zval **range, **begin, **end;
934
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)
938 ) {
939 /* this should never happen */
940 zend_hash_destroy(&ranges);
941 php_http_env_set_response_code(500 TSRMLS_CC);
942 if (zbody) {
943 zval_ptr_dtor(&zbody);
944 }
945 return FAILURE;
946 } else {
947 char *cr_header_str;
948 size_t cr_header_len;
949
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);
953
954 /* send chunk */
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);
957 if (zbody) {
958 zval_ptr_dtor(&zbody);
959 }
960 return SUCCESS;
961 }
962 } else {
963 /* send multipart/byte-ranges message */
964 HashPosition pos;
965 zval **chunk, *zct;
966 php_http_buffer_t preface;
967 int free_ct = 0;
968 char *content_type = "application/octet-stream";
969 char boundary[32], *ct_header_str = "Content-Type: multipart/byteranges; boundary= ";
970
971 if ((zct = get_container_value(container, ZEND_STRL("contentType") TSRMLS_CC))) {
972 zval *zct_copy = php_http_zsep(IS_STRING, zct);
973
974 zval_ptr_dtor(&zct);
975 if (Z_STRLEN_P(zct_copy)) {
976 content_type = estrndup(Z_STRVAL_P(zct_copy), Z_STRLEN_P(zct_copy));
977 free_ct = 1;
978 }
979
980 zval_ptr_dtor(&zct);
981 }
982
983 php_http_boundary(boundary, sizeof(boundary));
984 strlcpy(&ct_header_str[45], boundary, 32);
985
986 php_http_env_set_response_header(206, ct_header_str, strlen(ct_header_str), 1 TSRMLS_CC);
987
988 php_http_buffer_init(&preface);
989 FOREACH_HASH_VAL(pos, &ranges, chunk) {
990 zval **begin, **end;
991
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)
997 ) {
998 php_http_buffer_appendf(&preface,
999 PHP_HTTP_CRLF
1000 "--%s" PHP_HTTP_CRLF
1001 "Content-Type: %s" PHP_HTTP_CRLF
1002 "Content-Range: bytes %ld-%ld/%zu" PHP_HTTP_CRLF,
1003 /* - */
1004 boundary,
1005 content_type,
1006 Z_LVAL_PP(begin),
1007 Z_LVAL_PP(end),
1008 body_size
1009 );
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);
1013
1014 php_http_message_body_to_callback(body, output, &ctx, Z_LVAL_PP(begin), Z_LVAL_PP(end) - Z_LVAL_PP(begin) + 1);
1015 }
1016 }
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);
1022 if (zbody) {
1023 zval_ptr_dtor(&zbody);
1024 }
1025 return SUCCESS;
1026 }
1027 break;
1028 }
1029
1030 switch (php_http_env_is_response_cached_by_etag(container, ZEND_STRL("If-None-Match"))) {
1031 case PHP_HTTP_CACHE_MISS:
1032 break;
1033
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"))) {
1036 break;
1037 }
1038
1039 case PHP_HTTP_CACHE_HIT:
1040 php_http_env_set_response_code(304 TSRMLS_CC);
1041 if (zbody) {
1042 zval_ptr_dtor(&zbody);
1043 }
1044 return SUCCESS;
1045 }
1046
1047 php_http_message_body_to_callback(body, output, &ctx, 0, 0);
1048 output(&ctx, NULL, 0 TSRMLS_CC);
1049
1050 if (zbody) {
1051 zval_ptr_dtor(&zbody);
1052 }
1053 return SUCCESS;
1054 }
1055
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
1103 ;
1104
1105 PHP_HTTP_API const char *php_http_env_get_response_status_for_code(unsigned code)
1106 {
1107 return php_http_strlist_find(php_http_env_response_status, 100, code);
1108 }
1109
1110 zend_class_entry *php_http_env_class_entry;
1111
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)
1115
1116 PHP_HTTP_BEGIN_ARGS(getRequestHeader, 0)
1117 PHP_HTTP_ARG_VAL(header_name, 0)
1118 PHP_HTTP_END_ARGS;
1119
1120 PHP_HTTP_BEGIN_ARGS(getRequestBody, 0)
1121 PHP_HTTP_ARG_VAL(body_class_name, 0)
1122 PHP_HTTP_END_ARGS;
1123
1124 PHP_HTTP_BEGIN_ARGS(getResponseStatusForCode, 1)
1125 PHP_HTTP_ARG_VAL(code, 0)
1126 PHP_HTTP_END_ARGS;
1127
1128 PHP_HTTP_BEGIN_ARGS(getResponseHeader, 0)
1129 PHP_HTTP_ARG_VAL(header_name, 0)
1130 PHP_HTTP_END_ARGS;
1131
1132 PHP_HTTP_EMPTY_ARGS(getResponseCode);
1133
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)
1139 PHP_HTTP_END_ARGS;
1140
1141 PHP_HTTP_BEGIN_ARGS(setResponseCode, 1)
1142 PHP_HTTP_ARG_VAL(code, 0)
1143 PHP_HTTP_END_ARGS;
1144
1145 PHP_HTTP_BEGIN_ARGS(negotiateLanguage, 0)
1146 PHP_HTTP_ARG_VAL(supported, 0)
1147 PHP_HTTP_ARG_VAL(result_array, 1)
1148 PHP_HTTP_END_ARGS;
1149
1150 PHP_HTTP_BEGIN_ARGS(negotiateContentType, 0)
1151 PHP_HTTP_ARG_VAL(supported, 0)
1152 PHP_HTTP_ARG_VAL(result_array, 1)
1153 PHP_HTTP_END_ARGS;
1154
1155 PHP_HTTP_BEGIN_ARGS(negotiateCharset, 0)
1156 PHP_HTTP_ARG_VAL(supported, 0)
1157 PHP_HTTP_ARG_VAL(result_array, 1)
1158 PHP_HTTP_END_ARGS;
1159
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)
1164 PHP_HTTP_END_ARGS;
1165
1166 PHP_HTTP_EMPTY_ARGS(persistentHandlesStat);
1167
1168 PHP_HTTP_BEGIN_ARGS(persistentHandlesClean, 0)
1169 PHP_HTTP_ARG_VAL(name, 0)
1170 PHP_HTTP_END_ARGS;
1171
1172 PHP_HTTP_BEGIN_ARGS(persistentHandlesIdent, 0)
1173 PHP_HTTP_ARG_VAL(name, 0)
1174 PHP_HTTP_END_ARGS;
1175
1176 zend_function_entry php_http_env_method_entry[] = {
1177 PHP_HTTP_ENV_ME(getRequestHeader)
1178 PHP_HTTP_ENV_ME(getRequestBody)
1179
1180 PHP_HTTP_ENV_ME(getResponseStatusForCode)
1181
1182 PHP_HTTP_ENV_ME(getResponseHeader)
1183 PHP_HTTP_ENV_ME(getResponseCode)
1184 PHP_HTTP_ENV_ME(setResponseHeader)
1185 PHP_HTTP_ENV_ME(setResponseCode)
1186
1187 PHP_HTTP_ENV_ME(negotiateLanguage)
1188 PHP_HTTP_ENV_ME(negotiateContentType)
1189 PHP_HTTP_ENV_ME(negotiateCharset)
1190 PHP_HTTP_ENV_ME(negotiate)
1191
1192 PHP_HTTP_ENV_ME(persistentHandlesStat)
1193 PHP_HTTP_ENV_ME(persistentHandlesClean)
1194 PHP_HTTP_ENV_ME(persistentHandlesIdent)
1195
1196 EMPTY_FUNCTION_ENTRY
1197 };
1198
1199 PHP_METHOD(HttpEnv, getRequestHeader)
1200 {
1201 char *header_name_str;
1202 int header_name_len;
1203
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);
1207
1208 if (header_value) {
1209 RETURN_STRING(header_value, 0);
1210 }
1211 RETURN_NULL();
1212 } else {
1213 array_init(return_value);
1214 php_http_env_get_request_headers(Z_ARRVAL_P(return_value) TSRMLS_CC);
1215 return;
1216 }
1217 }
1218 RETURN_FALSE;
1219 }
1220
1221 PHP_METHOD(HttpEnv, getRequestBody)
1222 {
1223 with_error_handling(EH_THROW, PHP_HTTP_EX_CE(runtime)) {
1224 zend_class_entry *class_entry = php_http_message_body_class_entry;
1225
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);
1229
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);
1232 }
1233 }
1234 } end_error_handling();
1235 }
1236
1237 PHP_METHOD(HttpEnv, getResponseStatusForCode)
1238 {
1239 long code;
1240
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);
1243 }
1244 RETURN_FALSE;
1245 }
1246
1247 PHP_METHOD(HttpEnv, getResponseHeader)
1248 {
1249 char *header_name_str;
1250 int header_name_len;
1251
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);
1255
1256 if (header_value) {
1257 RETURN_STRING(header_value, 0);
1258 }
1259 RETURN_NULL();
1260 } else {
1261 array_init(return_value);
1262 php_http_env_get_response_headers(Z_ARRVAL_P(return_value) TSRMLS_CC);
1263 return;
1264 }
1265 }
1266 RETURN_FALSE;
1267 }
1268
1269 PHP_METHOD(HttpEnv, getResponseCode)
1270 {
1271 if (SUCCESS == zend_parse_parameters_none()) {
1272 RETURN_LONG(php_http_env_get_response_code(TSRMLS_C));
1273 }
1274 RETURN_FALSE;
1275 }
1276
1277 PHP_METHOD(HttpEnv, setResponseHeader)
1278 {
1279 char *header_name_str;
1280 int header_name_len;
1281 zval *header_value;
1282 long code = 0;
1283 zend_bool replace_header = 1;
1284
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));
1287 }
1288 RETURN_FALSE;
1289 }
1290
1291 PHP_METHOD(HttpEnv, setResponseCode)
1292 {
1293 long code;
1294
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));
1297 }
1298 RETURN_FALSE;
1299 }
1300
1301
1302 #define PHP_HTTP_DO_NEGOTIATE_DEFAULT(supported) \
1303 { \
1304 zval **value; \
1305 \
1306 zend_hash_internal_pointer_reset((supported)); \
1307 if (SUCCESS == zend_hash_get_current_data((supported), (void *) &value)) { \
1308 RETVAL_ZVAL(*value, 1, 0); \
1309 } else { \
1310 RETVAL_NULL(); \
1311 } \
1312 }
1313
1314 #define PHP_HTTP_DO_NEGOTIATE_HANDLE_DEFAULT(supported, rs_array) \
1315 PHP_HTTP_DO_NEGOTIATE_DEFAULT(supported); \
1316 if (rs_array) { \
1317 HashPosition pos; \
1318 zval **value_ptr; \
1319 \
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); \
1324 } \
1325 }
1326
1327 #define PHP_HTTP_DO_NEGOTIATE_HANDLE_RESULT(result, supported, rs_array) \
1328 { \
1329 char *key; \
1330 uint key_len; \
1331 ulong idx; \
1332 \
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); \
1335 } else { \
1336 PHP_HTTP_DO_NEGOTIATE_DEFAULT(supported); \
1337 } \
1338 \
1339 if (rs_array) { \
1340 zend_hash_copy(Z_ARRVAL_P(rs_array), result, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); \
1341 } \
1342 \
1343 zend_hash_destroy(result); \
1344 FREE_HASHTABLE(result); \
1345 }
1346
1347 #define PHP_HTTP_DO_NEGOTIATE(type, supported, rs_array) \
1348 { \
1349 HashTable *result; \
1350 if ((result = php_http_negotiate_ ##type(supported))) { \
1351 PHP_HTTP_DO_NEGOTIATE_HANDLE_RESULT(result, supported, rs_array); \
1352 } else { \
1353 PHP_HTTP_DO_NEGOTIATE_HANDLE_DEFAULT(supported, rs_array); \
1354 } \
1355 }
1356
1357 PHP_METHOD(HttpEnv, negotiateLanguage)
1358 {
1359 HashTable *supported;
1360 zval *rs_array = NULL;
1361
1362 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "H|z", &supported, &rs_array)) {
1363 if (rs_array) {
1364 zval_dtor(rs_array);
1365 array_init(rs_array);
1366 }
1367
1368 PHP_HTTP_DO_NEGOTIATE(language, supported, rs_array);
1369 }
1370 RETURN_FALSE;
1371 }
1372
1373 PHP_METHOD(HttpEnv, negotiateCharset)
1374 {
1375 HashTable *supported;
1376 zval *rs_array = NULL;
1377
1378 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "H|z", &supported, &rs_array)) {
1379 if (rs_array) {
1380 zval_dtor(rs_array);
1381 array_init(rs_array);
1382 }
1383 PHP_HTTP_DO_NEGOTIATE(charset, supported, rs_array);
1384 }
1385 RETURN_FALSE;
1386 }
1387
1388 PHP_METHOD(HttpEnv, negotiateContentType)
1389 {
1390 HashTable *supported;
1391 zval *rs_array = NULL;
1392
1393 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "H|z", &supported, &rs_array)) {
1394 if (rs_array) {
1395 zval_dtor(rs_array);
1396 array_init(rs_array);
1397 }
1398 PHP_HTTP_DO_NEGOTIATE(content_type, supported, rs_array);
1399 }
1400 RETURN_FALSE;
1401 }
1402
1403 PHP_METHOD(HttpEnv, negotiate)
1404 {
1405 HashTable *supported;
1406 zval *rs_array = NULL;
1407 char *value_str;
1408 int value_len;
1409
1410 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sH|z", &value_str, &value_len, &supported, &rs_array)) {
1411 HashTable *rs;
1412
1413 if (rs_array) {
1414 zval_dtor(rs_array);
1415 array_init(rs_array);
1416 }
1417
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);
1420 } else {
1421 PHP_HTTP_DO_NEGOTIATE_HANDLE_DEFAULT(supported, rs_array);
1422 }
1423 }
1424 RETURN_FALSE;
1425 }
1426
1427 PHP_METHOD(HttpEnv, persistentHandlesStat)
1428 {
1429 if (SUCCESS == zend_parse_parameters_none()) {
1430 object_init(return_value);
1431 if (php_http_persistent_handle_statall(HASH_OF(return_value))) {
1432 return;
1433 }
1434 zval_dtor(return_value);
1435 }
1436 RETURN_FALSE;
1437 }
1438
1439 PHP_METHOD(HttpEnv, persistentHandlesClean)
1440 {
1441 char *name_str = NULL;
1442 int name_len = 0;
1443
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);
1446 }
1447 }
1448
1449 PHP_METHOD(HttpEnv, persistentHandlesIdent)
1450 {
1451 char *ident_str = NULL;
1452 int ident_len = 0;
1453
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);
1458 }
1459 return;
1460 }
1461 RETURN_FALSE;
1462 }
1463
1464 zend_class_entry *php_http_env_request_class_entry;
1465
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)
1471
1472 PHP_HTTP_EMPTY_ARGS(__construct);
1473
1474 zend_function_entry php_http_env_request_method_entry[] = {
1475 PHP_HTTP_ENV_REQUEST_ME(__construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
1476
1477 EMPTY_FUNCTION_ENTRY
1478 };
1479
1480 PHP_METHOD(HttpEnvRequest, __construct)
1481 {
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);
1485
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();
1489 }
1490 } end_error_handling();
1491 }
1492
1493
1494 zend_class_entry *php_http_env_response_class_entry;
1495
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)
1501
1502 PHP_HTTP_EMPTY_ARGS(__construct);
1503
1504 PHP_HTTP_BEGIN_ARGS(setContentType, 1)
1505 PHP_HTTP_ARG_VAL(content_type, 0)
1506 PHP_HTTP_END_ARGS;
1507
1508 PHP_HTTP_BEGIN_ARGS(setContentDisposition, 1)
1509 PHP_HTTP_ARG_VAL(content_disposition, 0)
1510 PHP_HTTP_ARG_VAL(filename, 0)
1511 PHP_HTTP_END_ARGS;
1512
1513 PHP_HTTP_BEGIN_ARGS(setCacheControl, 1)
1514 PHP_HTTP_ARG_VAL(cache_control, 0)
1515 PHP_HTTP_END_ARGS;
1516
1517 PHP_HTTP_BEGIN_ARGS(setLastModified, 1)
1518 PHP_HTTP_ARG_VAL(last_modified, 0)
1519 PHP_HTTP_END_ARGS;
1520
1521 PHP_HTTP_BEGIN_ARGS(isCachedByLastModified, 0)
1522 PHP_HTTP_ARG_VAL(header_name, 0)
1523 PHP_HTTP_END_ARGS;
1524
1525 PHP_HTTP_BEGIN_ARGS(setEtag, 1)
1526 PHP_HTTP_ARG_VAL(etag, 0)
1527 PHP_HTTP_END_ARGS;
1528
1529 PHP_HTTP_BEGIN_ARGS(isCachedByEtag, 0)
1530 PHP_HTTP_ARG_VAL(header_name, 0)
1531 PHP_HTTP_END_ARGS;
1532
1533 PHP_HTTP_BEGIN_ARGS(setThrottleRate, 1)
1534 PHP_HTTP_ARG_VAL(chunk_size, 0)
1535 PHP_HTTP_ARG_VAL(delay, 0)
1536 PHP_HTTP_END_ARGS;
1537
1538 PHP_HTTP_EMPTY_ARGS(send);
1539
1540
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)
1551
1552 PHP_HTTP_ENV_RESPONSE_ME(send, ZEND_ACC_PUBLIC)
1553
1554 EMPTY_FUNCTION_ENTRY
1555 };
1556
1557
1558 PHP_METHOD(HttpEnvResponse, __construct)
1559 {
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);
1563
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();
1567 }
1568 } end_error_handling();
1569
1570 }
1571
1572 PHP_METHOD(HttpEnvResponse, setContentType)
1573 {
1574 char *ct_str;
1575 int ct_len;
1576
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));
1579 }
1580 RETURN_FALSE;
1581 }
1582
1583 PHP_METHOD(HttpEnvResponse, setContentDisposition)
1584 {
1585 long cd;
1586 char *file_str = NULL;
1587 int file_len = 0;
1588
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));
1591 }
1592 RETURN_FALSE;
1593 }
1594
1595 PHP_METHOD(HttpEnvResponse, setCacheControl)
1596 {
1597 char *cc_str;
1598 int cc_len;
1599
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));
1602 }
1603 RETURN_FALSE;
1604 }
1605
1606 PHP_METHOD(HttpEnvResponse, setLastModified)
1607 {
1608 long last_modified;
1609
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));
1612 }
1613 RETURN_FALSE;
1614 }
1615
1616 PHP_METHOD(HttpEnvResponse, isCachedByLastModified)
1617 {
1618 char *header_name_str = NULL;
1619 int header_name_len = 0;
1620
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");
1625 }
1626 RETURN_LONG(php_http_env_is_response_cached_by_last_modified(getThis(), header_name_str, header_name_len TSRMLS_CC));
1627 }
1628 RETURN_FALSE;
1629 }
1630
1631 PHP_METHOD(HttpEnvResponse, setEtag)
1632 {
1633 char *etag_str;
1634 int etag_len;
1635
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));
1638 }
1639 RETURN_FALSE;
1640 }
1641
1642 PHP_METHOD(HttpEnvResponse, isCachedByEtag)
1643 {
1644 char *header_name_str = NULL;
1645 int header_name_len = 0;
1646
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");
1651 }
1652 RETURN_LONG(php_http_env_is_response_cached_by_etag(getThis(), header_name_str, header_name_len TSRMLS_CC));
1653 }
1654 RETURN_FALSE;
1655 }
1656
1657 PHP_METHOD(HttpEnvResponse, setThrottleRate)
1658 {
1659 long chunk_size;
1660 double delay = 1;
1661
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);
1664 RETURN_TRUE;
1665 }
1666 RETURN_FALSE;
1667 }
1668
1669 PHP_METHOD(HttpEnvResponse, send)
1670 {
1671 if (SUCCESS == zend_parse_parameters_none()) {
1672 RETURN_SUCCESS(php_http_env_send_response(getThis() TSRMLS_CC));
1673 }
1674 RETURN_FALSE;
1675 }
1676
1677
1678 PHP_MINIT_FUNCTION(http_env)
1679 {
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);
1683
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);
1686
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);
1690
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);
1696
1697 return SUCCESS;
1698 }
1699
1700
1701 /*
1702 * Local variables:
1703 * tab-width: 4
1704 * c-basic-offset: 4
1705 * End:
1706 * vim600: noet sw=4 ts=4 fdm=marker
1707 * vim<600: noet sw=4 ts=4
1708 */