Line data Source code
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-2014, Michael Wallner <mike@php.net> |
10 : +--------------------------------------------------------------------+
11 : */
12 :
13 : #include "php_http_api.h"
14 :
15 52 : static void set_option(zval *options, const char *name_str, size_t name_len, int type, void *value_ptr, size_t value_len TSRMLS_DC)
16 : {
17 52 : if (Z_TYPE_P(options) == IS_OBJECT) {
18 52 : if (value_ptr) {
19 52 : switch (type) {
20 : case IS_DOUBLE:
21 1 : zend_update_property_double(Z_OBJCE_P(options), options, name_str, name_len, *(double *)value_ptr TSRMLS_CC);
22 1 : break;
23 : case IS_LONG:
24 22 : zend_update_property_long(Z_OBJCE_P(options), options, name_str, name_len, *(long *)value_ptr TSRMLS_CC);
25 22 : break;
26 : case IS_STRING:
27 21 : zend_update_property_stringl(Z_OBJCE_P(options), options, name_str, name_len, value_ptr, value_len TSRMLS_CC);
28 21 : break;
29 : case IS_ARRAY:
30 : case IS_OBJECT:
31 8 : zend_update_property(Z_OBJCE_P(options), options, name_str, name_len, value_ptr TSRMLS_CC);
32 8 : break;
33 : }
34 : } else {
35 0 : zend_update_property_null(Z_OBJCE_P(options), options, name_str, name_len TSRMLS_CC);
36 : }
37 : } else {
38 0 : convert_to_array(options);
39 0 : if (value_ptr) {
40 0 : switch (type) {
41 : case IS_DOUBLE:
42 0 : add_assoc_double_ex(options, name_str, name_len + 1, *(double *)value_ptr);
43 0 : break;
44 : case IS_LONG:
45 0 : add_assoc_long_ex(options, name_str, name_len + 1, *(long *)value_ptr);
46 0 : break;
47 : case IS_STRING: {
48 0 : char *value = estrndup(value_ptr, value_len);
49 0 : add_assoc_stringl_ex(options, name_str, name_len + 1, value, value_len, 0);
50 0 : break;
51 : case IS_ARRAY:
52 : case IS_OBJECT:
53 0 : Z_ADDREF_P(value_ptr);
54 0 : add_assoc_zval_ex(options, name_str, name_len + 1, value_ptr);
55 0 : break;
56 : }
57 : }
58 : } else {
59 0 : add_assoc_null_ex(options, name_str, name_len + 1);
60 : }
61 : }
62 52 : }
63 380 : static zval *get_option(zval *options, const char *name_str, size_t name_len TSRMLS_DC)
64 : {
65 : zval *val, **valptr;
66 :
67 380 : if (Z_TYPE_P(options) == IS_OBJECT) {
68 380 : val = zend_read_property(Z_OBJCE_P(options), options, name_str, name_len, 0 TSRMLS_CC);
69 : } else {
70 0 : if (SUCCESS == zend_symtable_find(Z_ARRVAL_P(options), name_str, name_len + 1, (void *) &valptr)) {
71 0 : val = *valptr;
72 : } else {
73 0 : val = NULL;
74 : }
75 : }
76 380 : if (val) {
77 380 : Z_ADDREF_P(val);
78 : }
79 380 : return val;
80 : }
81 89 : static php_http_message_body_t *get_body(zval *options TSRMLS_DC)
82 : {
83 : zval *zbody;
84 89 : php_http_message_body_t *body = NULL;
85 :
86 89 : if ((zbody = get_option(options, ZEND_STRL("body") TSRMLS_CC))) {
87 89 : if ((Z_TYPE_P(zbody) == IS_OBJECT) && instanceof_function(Z_OBJCE_P(zbody), php_http_message_body_class_entry TSRMLS_CC)) {
88 79 : php_http_message_body_object_t *body_obj = zend_object_store_get_object(zbody TSRMLS_CC);
89 :
90 79 : body = body_obj->body;
91 : }
92 89 : zval_ptr_dtor(&zbody);
93 : }
94 :
95 89 : return body;
96 : }
97 36 : static php_http_message_t *get_request(zval *options TSRMLS_DC)
98 : {
99 : zval *zrequest;
100 36 : php_http_message_t *request = NULL;
101 :
102 36 : if ((zrequest = get_option(options, ZEND_STRL("request") TSRMLS_CC))) {
103 36 : if (Z_TYPE_P(zrequest) == IS_OBJECT && instanceof_function(Z_OBJCE_P(zrequest), php_http_message_class_entry TSRMLS_CC)) {
104 10 : php_http_message_object_t *request_obj = zend_object_store_get_object(zrequest TSRMLS_CC);
105 :
106 10 : request = request_obj->message;
107 : }
108 36 : zval_ptr_dtor(&zrequest);
109 : }
110 :
111 36 : return request;
112 : }
113 3 : static void set_cookie(zval *options, zval *zcookie_new TSRMLS_DC)
114 : {
115 : HashPosition pos;
116 : zval *zcookies_set;
117 3 : php_http_array_hashkey_t key = php_http_array_hashkey_init(0);
118 3 : php_http_cookie_object_t *obj = zend_object_store_get_object(zcookie_new TSRMLS_CC);
119 :
120 3 : zcookies_set = get_option(options, ZEND_STRL("cookies") TSRMLS_CC);
121 3 : if (!zcookies_set || Z_TYPE_P(zcookies_set) != IS_ARRAY) {
122 1 : if (zcookies_set) {
123 1 : zval_ptr_dtor(&zcookies_set);
124 : }
125 1 : MAKE_STD_ZVAL(zcookies_set);
126 1 : array_init_size(zcookies_set, zend_hash_num_elements(&obj->list->cookies));
127 : } else {
128 2 : SEPARATE_ZVAL(&zcookies_set);
129 : }
130 :
131 6 : FOREACH_HASH_KEY(pos, &obj->list->cookies, key) {
132 3 : Z_ADDREF_P(zcookie_new);
133 3 : if (key.type == HASH_KEY_IS_STRING) {
134 2 : add_assoc_zval_ex(zcookies_set, key.str, key.len, zcookie_new);
135 : } else {
136 1 : add_index_zval(zcookies_set, key.num, zcookie_new);
137 : }
138 : }
139 :
140 3 : set_option(options, ZEND_STRL("cookies"), IS_ARRAY, zcookies_set, 0 TSRMLS_CC);
141 3 : zval_ptr_dtor(&zcookies_set);
142 3 : }
143 :
144 24 : php_http_cache_status_t php_http_env_is_response_cached_by_etag(zval *options, const char *header_str, size_t header_len, php_http_message_t *request TSRMLS_DC)
145 : {
146 24 : php_http_cache_status_t ret = PHP_HTTP_CACHE_NO;
147 24 : int free_etag = 0;
148 24 : char *header = NULL, *etag;
149 : php_http_message_body_t *body;
150 : zval *zetag;
151 :
152 :
153 24 : if (!(body = get_body(options TSRMLS_CC))) {
154 2 : return ret;
155 : }
156 :
157 22 : if ((zetag = get_option(options, ZEND_STRL("etag") TSRMLS_CC))) {
158 22 : zval *zetag_copy = php_http_ztyp(IS_STRING, zetag);
159 22 : zval_ptr_dtor(&zetag);
160 22 : zetag = zetag_copy;
161 : }
162 :
163 22 : if (zetag && Z_STRLEN_P(zetag)) {
164 10 : etag = Z_STRVAL_P(zetag);
165 12 : } else if ((etag = php_http_message_body_etag(body))) {
166 12 : set_option(options, ZEND_STRL("etag"), IS_STRING, etag, strlen(etag) TSRMLS_CC);
167 12 : free_etag = 1;
168 : }
169 :
170 22 : if (zetag) {
171 22 : zval_ptr_dtor(&zetag);
172 : }
173 :
174 22 : if (etag && (header = php_http_env_get_request_header(header_str, header_len, NULL, request TSRMLS_CC))) {
175 2 : ret = php_http_match(header, etag, PHP_HTTP_MATCH_WORD) ? PHP_HTTP_CACHE_HIT : PHP_HTTP_CACHE_MISS;
176 : }
177 :
178 22 : if (free_etag) {
179 12 : efree(etag);
180 : }
181 :
182 22 : PTR_FREE(header);
183 22 : return ret;
184 : }
185 :
186 26 : php_http_cache_status_t php_http_env_is_response_cached_by_last_modified(zval *options, const char *header_str, size_t header_len, php_http_message_t *request TSRMLS_DC)
187 : {
188 26 : php_http_cache_status_t ret = PHP_HTTP_CACHE_NO;
189 : char *header;
190 26 : time_t ums, lm = 0;
191 : php_http_message_body_t *body;
192 : zval *zlm;
193 :
194 26 : if (!(body = get_body(options TSRMLS_CC))) {
195 2 : return ret;
196 : }
197 :
198 24 : if ((zlm = get_option(options, ZEND_STRL("lastModified") TSRMLS_CC))) {
199 24 : zval *zlm_copy = php_http_ztyp(IS_LONG, zlm);
200 24 : zval_ptr_dtor(&zlm);
201 24 : zlm = zlm_copy;
202 : }
203 :
204 24 : if (zlm && Z_LVAL_P(zlm) > 0) {
205 10 : lm = Z_LVAL_P(zlm);
206 : } else {
207 14 : lm = php_http_message_body_mtime(body);
208 14 : set_option(options, ZEND_STRL("lastModified"), IS_LONG, &lm, 0 TSRMLS_CC);
209 : }
210 :
211 24 : if (zlm) {
212 24 : zval_ptr_dtor(&zlm);
213 : }
214 :
215 24 : if ((header = php_http_env_get_request_header(header_str, header_len, NULL, request TSRMLS_CC))) {
216 4 : ums = php_parse_date(header, NULL);
217 :
218 4 : if (ums > 0 && ums >= lm) {
219 4 : ret = PHP_HTTP_CACHE_HIT;
220 : } else {
221 0 : ret = PHP_HTTP_CACHE_MISS;
222 : }
223 : }
224 :
225 24 : PTR_FREE(header);
226 24 : return ret;
227 : }
228 :
229 16 : static zend_bool php_http_env_response_is_cacheable(php_http_env_response_t *r, php_http_message_t *request)
230 : {
231 : TSRMLS_FETCH_FROM_CTX(r->ts);
232 :
233 16 : if (r->ops->get_status(r) >= 400) {
234 0 : return 0;
235 : }
236 :
237 16 : if (php_http_env_got_request_header(ZEND_STRL("Authorization"), request TSRMLS_CC)) {
238 0 : return 0;
239 : }
240 :
241 16 : if (-1 == php_http_select_str(php_http_env_get_request_method(request TSRMLS_CC), 2, "HEAD", "GET")) {
242 2 : return 0;
243 : }
244 :
245 14 : return 1;
246 : }
247 :
248 3296 : static size_t output(void *context, char *buf, size_t len TSRMLS_DC)
249 : {
250 3296 : php_http_env_response_t *r = context;
251 :
252 3296 : if (SUCCESS != r->ops->write(r, buf, len)) {
253 0 : return (size_t) -1;
254 : }
255 :
256 : /* we really only need to flush when throttling is enabled,
257 : because we push the data as fast as possible anyway if not */
258 3296 : if (r->throttle.delay >= PHP_HTTP_DIFFSEC) {
259 6 : r->ops->flush(r);
260 6 : php_http_sleep(r->throttle.delay);
261 : }
262 3296 : return len;
263 : }
264 :
265 : #define php_http_env_response_send_done(r) php_http_env_response_send_data((r), NULL, 0)
266 32802 : static STATUS php_http_env_response_send_data(php_http_env_response_t *r, const char *buf, size_t len)
267 : {
268 32802 : size_t chunks_sent, chunk = r->throttle.chunk ? r->throttle.chunk : PHP_HTTP_SENDBUF_SIZE;
269 : TSRMLS_FETCH_FROM_CTX(r->ts);
270 :
271 32802 : if (r->content.encoder) {
272 6 : char *enc_str = NULL;
273 6 : size_t enc_len = 0;
274 :
275 6 : if (buf) {
276 3 : if (SUCCESS != php_http_encoding_stream_update(r->content.encoder, buf, len, &enc_str, &enc_len)) {
277 0 : return FAILURE;
278 : }
279 : } else {
280 3 : if (SUCCESS != php_http_encoding_stream_finish(r->content.encoder, &enc_str, &enc_len)) {
281 0 : return FAILURE;
282 : }
283 : }
284 :
285 6 : if (!enc_str) {
286 0 : return SUCCESS;
287 : }
288 6 : chunks_sent = php_http_buffer_chunked_output(&r->buffer, enc_str, enc_len, buf ? chunk : 0, output, r TSRMLS_CC);
289 6 : PTR_FREE(enc_str);
290 : } else {
291 32796 : chunks_sent = php_http_buffer_chunked_output(&r->buffer, buf, len, buf ? chunk : 0, output, r TSRMLS_CC);
292 : }
293 :
294 32802 : return chunks_sent != (size_t) -1 ? SUCCESS : FAILURE;
295 : }
296 :
297 21 : php_http_env_response_t *php_http_env_response_init(php_http_env_response_t *r, zval *options, php_http_env_response_ops_t *ops, void *init_arg TSRMLS_DC)
298 : {
299 : zend_bool free_r;
300 :
301 21 : if ((free_r = !r)) {
302 11 : r = emalloc(sizeof(*r));
303 : }
304 21 : memset(r, 0, sizeof(*r));
305 :
306 21 : if (ops) {
307 11 : r->ops = ops;
308 : } else {
309 10 : r->ops = php_http_env_response_get_sapi_ops();
310 : }
311 :
312 21 : r->buffer = php_http_buffer_init(NULL);
313 :
314 21 : Z_ADDREF_P(options);
315 21 : r->options = options;
316 :
317 : TSRMLS_SET_CTX(r->ts);
318 :
319 21 : if (r->ops->init && (SUCCESS != r->ops->init(r, init_arg))) {
320 0 : if (free_r) {
321 0 : php_http_env_response_free(&r);
322 : } else {
323 0 : php_http_env_response_dtor(r);
324 0 : r = NULL;
325 : }
326 : }
327 :
328 21 : return r;
329 : }
330 :
331 21 : void php_http_env_response_dtor(php_http_env_response_t *r)
332 : {
333 21 : if (r->ops->dtor) {
334 11 : r->ops->dtor(r);
335 : }
336 21 : php_http_buffer_free(&r->buffer);
337 21 : zval_ptr_dtor(&r->options);
338 21 : PTR_FREE(r->content.type);
339 21 : PTR_FREE(r->content.encoding);
340 21 : if (r->content.encoder) {
341 3 : php_http_encoding_stream_free(&r->content.encoder);
342 : }
343 21 : }
344 :
345 11 : void php_http_env_response_free(php_http_env_response_t **r)
346 : {
347 11 : if (*r) {
348 11 : php_http_env_response_dtor(*r);
349 11 : efree(*r);
350 11 : *r = NULL;
351 : }
352 11 : }
353 :
354 21 : static STATUS php_http_env_response_send_head(php_http_env_response_t *r, php_http_message_t *request)
355 : {
356 21 : STATUS ret = SUCCESS;
357 21 : zval *zoption, *options = r->options;
358 : TSRMLS_FETCH_FROM_CTX(r->ts);
359 :
360 21 : if (r->done) {
361 1 : return ret;
362 : }
363 :
364 20 : if ((zoption = get_option(options, ZEND_STRL("headers") TSRMLS_CC))) {
365 20 : if (Z_TYPE_P(zoption) == IS_ARRAY) {
366 20 : php_http_header_to_callback(Z_ARRVAL_P(zoption), 0, (php_http_pass_format_callback_t) r->ops->set_header, r TSRMLS_CC);
367 : }
368 20 : zval_ptr_dtor(&zoption);
369 : }
370 :
371 20 : if (ret != SUCCESS) {
372 0 : return ret;
373 : }
374 :
375 20 : if ((zoption = get_option(options, ZEND_STRL("responseCode") TSRMLS_CC))) {
376 20 : zval *zoption_copy = php_http_ztyp(IS_LONG, zoption);
377 :
378 20 : zval_ptr_dtor(&zoption);
379 20 : if (Z_LVAL_P(zoption_copy) > 0) {
380 20 : ret = r->ops->set_status(r, Z_LVAL_P(zoption_copy));
381 : }
382 20 : zval_ptr_dtor(&zoption_copy);
383 : }
384 :
385 20 : if (ret != SUCCESS) {
386 0 : return ret;
387 : }
388 :
389 20 : if ((zoption = get_option(options, ZEND_STRL("httpVersion") TSRMLS_CC))) {
390 : php_http_version_t v;
391 20 : zval *zoption_copy = php_http_ztyp(IS_STRING, zoption);
392 :
393 20 : zval_ptr_dtor(&zoption);
394 20 : if (Z_STRLEN_P(zoption_copy) && php_http_version_parse(&v, Z_STRVAL_P(zoption_copy) TSRMLS_CC)) {
395 20 : ret = r->ops->set_protocol_version(r, &v);
396 20 : php_http_version_dtor(&v);
397 : }
398 20 : zval_ptr_dtor(&zoption_copy);
399 : }
400 :
401 20 : if (ret != SUCCESS) {
402 0 : return ret;
403 : }
404 :
405 20 : if ((zoption = get_option(options, ZEND_STRL("cookies") TSRMLS_CC))) {
406 20 : if (Z_TYPE_P(zoption) == IS_ARRAY) {
407 : HashPosition pos;
408 : zval **zcookie;
409 :
410 4 : FOREACH_VAL(pos, zoption, zcookie) {
411 3 : if (Z_TYPE_PP(zcookie) == IS_OBJECT && instanceof_function(Z_OBJCE_PP(zcookie), php_http_cookie_class_entry TSRMLS_CC)) {
412 3 : php_http_cookie_object_t *obj = zend_object_store_get_object(*zcookie TSRMLS_CC);
413 : char *str;
414 : size_t len;
415 :
416 3 : php_http_cookie_list_to_string(obj->list, &str, &len);
417 3 : if (SUCCESS != (ret = r->ops->add_header(r, "Set-Cookie: %s", str))) {
418 0 : efree(str);
419 0 : break;
420 : }
421 3 : efree(str);
422 : }
423 : }
424 : }
425 20 : zval_ptr_dtor(&zoption);
426 : }
427 :
428 20 : if (ret != SUCCESS) {
429 0 : return ret;
430 : }
431 :
432 20 : if ((zoption = get_option(options, ZEND_STRL("contentType") TSRMLS_CC))) {
433 20 : zval *zoption_copy = php_http_ztyp(IS_STRING, zoption);
434 :
435 20 : zval_ptr_dtor(&zoption);
436 20 : if (Z_STRLEN_P(zoption_copy) && strchr(Z_STRVAL_P(zoption_copy), '/')) {
437 3 : if (SUCCESS == (ret = r->ops->set_header(r, "Content-Type: %.*s", Z_STRLEN_P(zoption_copy), Z_STRVAL_P(zoption_copy)))) {
438 3 : r->content.type = estrndup(Z_STRVAL_P(zoption_copy), Z_STRLEN_P(zoption_copy));
439 : }
440 : }
441 20 : zval_ptr_dtor(&zoption_copy);
442 : }
443 :
444 20 : if (ret != SUCCESS) {
445 0 : return ret;
446 : }
447 :
448 20 : if (r->range.status == PHP_HTTP_RANGE_OK) {
449 4 : if (zend_hash_num_elements(&r->range.values) == 1) {
450 : zval **range, **begin, **end;
451 :
452 3 : if ( 1 == php_http_array_list(&r->range.values TSRMLS_CC, 1, &range)
453 3 : && 2 == php_http_array_list(Z_ARRVAL_PP(range) TSRMLS_CC, 2, &begin, &end)
454 : ) {
455 6 : if (SUCCESS == (ret = r->ops->set_status(r, 206))) {
456 3 : ret = r->ops->set_header(r, "Content-Range: bytes %ld-%ld/%zu", Z_LVAL_PP(begin), Z_LVAL_PP(end), r->content.length);
457 : }
458 : } else {
459 : /* this should never happen */
460 0 : zend_hash_destroy(&r->range.values);
461 0 : ret = FAILURE;
462 : }
463 : } else {
464 1 : php_http_boundary(r->range.boundary, sizeof(r->range.boundary) TSRMLS_CC);
465 1 : if (SUCCESS == (ret = r->ops->set_status(r, 206))) {
466 1 : ret = r->ops->set_header(r, "Content-Type: multipart/byteranges; boundary=%s", r->range.boundary);
467 : }
468 : }
469 : } else {
470 16 : if ((zoption = get_option(options, ZEND_STRL("cacheControl") TSRMLS_CC))) {
471 16 : zval *zoption_copy = php_http_ztyp(IS_STRING, zoption);
472 :
473 16 : zval_ptr_dtor(&zoption);
474 16 : if (Z_STRLEN_P(zoption_copy)) {
475 2 : ret = r->ops->set_header(r, "Cache-Control: %.*s", Z_STRLEN_P(zoption_copy), Z_STRVAL_P(zoption_copy));
476 : }
477 16 : zval_ptr_dtor(&zoption_copy);
478 : }
479 :
480 16 : if (ret != SUCCESS) {
481 0 : return ret;
482 : }
483 :
484 16 : if ((zoption = get_option(options, ZEND_STRL("contentDisposition") TSRMLS_CC))) {
485 16 : zval *zoption_copy = php_http_ztyp(IS_ARRAY, zoption);
486 : php_http_buffer_t buf;
487 :
488 16 : php_http_buffer_init(&buf);
489 16 : if (php_http_params_to_string(&buf, Z_ARRVAL_P(zoption_copy), ZEND_STRL(","), ZEND_STRL(";"), ZEND_STRL("="), PHP_HTTP_PARAMS_DEFAULT TSRMLS_CC)) {
490 16 : if (buf.used) {
491 1 : ret = r->ops->set_header(r, "Content-Disposition: %.*s", buf.used, buf.data);
492 : }
493 : }
494 :
495 16 : php_http_buffer_dtor(&buf);
496 16 : zval_ptr_dtor(&zoption_copy);
497 16 : zval_ptr_dtor(&zoption);
498 : }
499 :
500 16 : if (ret != SUCCESS) {
501 0 : return ret;
502 : }
503 :
504 16 : if ((zoption = get_option(options, ZEND_STRL("contentEncoding") TSRMLS_CC))) {
505 16 : zval *zoption_copy = php_http_ztyp(IS_LONG, zoption);
506 : zval zsupported;
507 16 : HashTable *result = NULL;
508 :
509 16 : zval_ptr_dtor(&zoption);
510 16 : switch (Z_LVAL_P(zoption_copy)) {
511 : case PHP_HTTP_CONTENT_ENCODING_GZIP:
512 3 : INIT_PZVAL(&zsupported);
513 3 : array_init(&zsupported);
514 3 : add_next_index_stringl(&zsupported, ZEND_STRL("none"), 1);
515 3 : add_next_index_stringl(&zsupported, ZEND_STRL("gzip"), 1);
516 3 : add_next_index_stringl(&zsupported, ZEND_STRL("deflate"), 1);
517 :
518 3 : if ((result = php_http_negotiate_encoding(Z_ARRVAL(zsupported), request TSRMLS_CC))) {
519 3 : char *key_str = NULL;
520 3 : uint key_len = 0;
521 :
522 3 : zend_hash_internal_pointer_reset(result);
523 3 : if (HASH_KEY_IS_STRING == zend_hash_get_current_key_ex(result, &key_str, &key_len, NULL, 0, NULL)) {
524 3 : if (!strcmp(key_str, "gzip")) {
525 2 : if (!(r->content.encoder = php_http_encoding_stream_init(NULL, php_http_encoding_stream_get_deflate_ops(), PHP_HTTP_DEFLATE_TYPE_GZIP TSRMLS_CC))) {
526 0 : ret = FAILURE;
527 2 : } else if (SUCCESS == (ret = r->ops->set_header(r, "Content-Encoding: gzip"))) {
528 2 : r->content.encoding = estrndup(key_str, key_len - 1);
529 : }
530 1 : } else if (!strcmp(key_str, "deflate")) {
531 1 : if (!(r->content.encoder = php_http_encoding_stream_init(NULL, php_http_encoding_stream_get_deflate_ops(), PHP_HTTP_DEFLATE_TYPE_ZLIB TSRMLS_CC))) {
532 0 : ret = FAILURE;
533 1 : } else if (SUCCESS == (ret = r->ops->set_header(r, "Content-Encoding: deflate"))) {
534 1 : r->content.encoding = estrndup(key_str, key_len - 1);
535 : }
536 : } else {
537 0 : ret = r->ops->del_header(r, ZEND_STRL("Content-Encoding"));
538 : }
539 :
540 3 : if (SUCCESS == ret) {
541 3 : ret = r->ops->add_header(r, "Vary: Accept-Encoding");
542 : }
543 : }
544 :
545 3 : zend_hash_destroy(result);
546 3 : FREE_HASHTABLE(result);
547 : }
548 :
549 3 : zval_dtor(&zsupported);
550 3 : break;
551 :
552 : case PHP_HTTP_CONTENT_ENCODING_NONE:
553 : default:
554 13 : ret = r->ops->del_header(r, ZEND_STRL("Content-Encoding"));
555 13 : break;
556 : }
557 16 : zval_ptr_dtor(&zoption_copy);
558 : }
559 :
560 16 : if (SUCCESS != ret) {
561 0 : return ret;
562 : }
563 :
564 16 : if (php_http_env_response_is_cacheable(r, request)) {
565 14 : switch (php_http_env_is_response_cached_by_etag(options, ZEND_STRL("If-None-Match"), request TSRMLS_CC)) {
566 : case PHP_HTTP_CACHE_MISS:
567 2 : break;
568 :
569 : case PHP_HTTP_CACHE_NO:
570 12 : if (PHP_HTTP_CACHE_HIT != php_http_env_is_response_cached_by_last_modified(options, ZEND_STRL("If-Modified-Since"), request TSRMLS_CC)) {
571 10 : break;
572 : }
573 : /* no break */
574 :
575 : case PHP_HTTP_CACHE_HIT:
576 2 : ret = r->ops->set_status(r, 304);
577 2 : r->done = 1;
578 2 : break;
579 : }
580 :
581 14 : if ((zoption = get_option(options, ZEND_STRL("etag") TSRMLS_CC))) {
582 14 : zval *zoption_copy = php_http_ztyp(IS_STRING, zoption);
583 :
584 14 : zval_ptr_dtor(&zoption);
585 14 : if (*Z_STRVAL_P(zoption_copy) != '"' && strncmp(Z_STRVAL_P(zoption_copy), "W/\"", 3)) {
586 14 : ret = r->ops->set_header(r, "ETag: \"%s\"", Z_STRVAL_P(zoption_copy));
587 : } else {
588 0 : ret = r->ops->set_header(r, "ETag: %s", Z_STRVAL_P(zoption_copy));
589 : }
590 14 : zval_ptr_dtor(&zoption_copy);
591 : }
592 14 : if ((zoption = get_option(options, ZEND_STRL("lastModified") TSRMLS_CC))) {
593 14 : zval *zoption_copy = php_http_ztyp(IS_LONG, zoption);
594 :
595 14 : zval_ptr_dtor(&zoption);
596 14 : if (Z_LVAL_P(zoption_copy)) {
597 8 : char *date = php_format_date(ZEND_STRL(PHP_HTTP_DATE_FORMAT), Z_LVAL_P(zoption_copy), 0 TSRMLS_CC);
598 8 : if (date) {
599 8 : ret = r->ops->set_header(r, "Last-Modified: %s", date);
600 8 : efree(date);
601 : }
602 : }
603 14 : zval_ptr_dtor(&zoption_copy);
604 : }
605 : }
606 : }
607 :
608 20 : return ret;
609 : }
610 :
611 21 : static STATUS php_http_env_response_send_body(php_http_env_response_t *r)
612 : {
613 21 : STATUS ret = SUCCESS;
614 : zval *zoption;
615 : php_http_message_body_t *body;
616 : TSRMLS_FETCH_FROM_CTX(r->ts);
617 :
618 21 : if (r->done) {
619 3 : return ret;
620 : }
621 :
622 18 : if ((body = get_body(r->options TSRMLS_CC))) {
623 15 : if ((zoption = get_option(r->options, ZEND_STRL("throttleDelay") TSRMLS_CC))) {
624 15 : if (Z_TYPE_P(zoption) == IS_DOUBLE) {
625 1 : r->throttle.delay = Z_DVAL_P(zoption);
626 : }
627 15 : zval_ptr_dtor(&zoption);
628 : }
629 15 : if ((zoption = get_option(r->options, ZEND_STRL("throttleChunk") TSRMLS_CC))) {
630 15 : if (Z_TYPE_P(zoption) == IS_LONG) {
631 1 : r->throttle.chunk = Z_LVAL_P(zoption);
632 : }
633 15 : zval_ptr_dtor(&zoption);
634 : }
635 :
636 15 : if (r->range.status == PHP_HTTP_RANGE_OK) {
637 4 : if (zend_hash_num_elements(&r->range.values) == 1) {
638 : /* single range */
639 : zval **range, **begin, **end;
640 :
641 3 : if ( 1 == php_http_array_list(&r->range.values TSRMLS_CC, 1, &range)
642 3 : && 2 == php_http_array_list(Z_ARRVAL_PP(range) TSRMLS_CC, 2, &begin, &end)
643 : ) {
644 : /* send chunk */
645 3 : ret = php_http_message_body_to_callback(body, (php_http_pass_callback_t) php_http_env_response_send_data, r, Z_LVAL_PP(begin), Z_LVAL_PP(end) - Z_LVAL_PP(begin) + 1);
646 3 : if (ret == SUCCESS) {
647 3 : ret = php_http_env_response_send_done(r);
648 : }
649 3 : zend_hash_destroy(&r->range.values);
650 : } else {
651 : /* this should never happen */
652 0 : zend_hash_destroy(&r->range.values);
653 0 : r->ops->set_status(r, 500);
654 0 : ret = FAILURE;
655 : }
656 :
657 : } else {
658 : /* send multipart/byte-ranges message */
659 : HashPosition pos;
660 : zval **chunk;
661 :
662 6 : FOREACH_HASH_VAL(pos, &r->range.values, chunk) {
663 : zval **begin, **end;
664 :
665 5 : if (2 == php_http_array_list(Z_ARRVAL_PP(chunk) TSRMLS_CC, 2, &begin, &end)) {
666 25 : php_http_buffer_appendf(r->buffer,
667 : PHP_HTTP_CRLF
668 : "--%s" PHP_HTTP_CRLF
669 : "Content-Type: %s" PHP_HTTP_CRLF
670 : "Content-Range: bytes %ld-%ld/%zu" PHP_HTTP_CRLF PHP_HTTP_CRLF,
671 : /* - */
672 5 : r->range.boundary,
673 5 : r->content.type ? r->content.type : "application/octet-stream",
674 5 : Z_LVAL_PP(begin),
675 5 : Z_LVAL_PP(end),
676 : r->content.length
677 : );
678 5 : ret = php_http_message_body_to_callback(body, (php_http_pass_callback_t) php_http_env_response_send_data, r, Z_LVAL_PP(begin), Z_LVAL_PP(end) - Z_LVAL_PP(begin) + 1);
679 : }
680 : }
681 :
682 1 : if (ret == SUCCESS) {
683 1 : php_http_buffer_appendf(r->buffer, PHP_HTTP_CRLF "--%s--", r->range.boundary);
684 1 : ret = php_http_env_response_send_done(r);
685 : }
686 1 : zend_hash_destroy(&r->range.values);
687 : }
688 :
689 : } else {
690 11 : ret = php_http_message_body_to_callback(body, (php_http_pass_callback_t) php_http_env_response_send_data, r, 0, 0);
691 11 : if (ret == SUCCESS) {
692 11 : ret = php_http_env_response_send_done(r);
693 : }
694 : }
695 : }
696 18 : return ret;
697 : }
698 :
699 21 : STATUS php_http_env_response_send(php_http_env_response_t *r)
700 : {
701 : php_http_message_t *request;
702 : php_http_message_body_t *body;
703 : TSRMLS_FETCH_FROM_CTX(r->ts);
704 :
705 21 : request = get_request(r->options TSRMLS_CC);
706 :
707 : /* check for ranges */
708 21 : if ((body = get_body(r->options TSRMLS_CC))) {
709 18 : r->content.length = php_http_message_body_size(body);
710 :
711 18 : if (SUCCESS != r->ops->set_header(r, "Accept-Ranges: bytes")) {
712 0 : return FAILURE;
713 : } else {
714 18 : zend_hash_init(&r->range.values, 0, NULL, ZVAL_PTR_DTOR, 0);
715 18 : r->range.status = php_http_env_get_request_ranges(&r->range.values, r->content.length, request TSRMLS_CC);
716 :
717 18 : switch (r->range.status) {
718 : case PHP_HTTP_RANGE_NO:
719 13 : zend_hash_destroy(&r->range.values);
720 13 : break;
721 :
722 : case PHP_HTTP_RANGE_ERR:
723 1 : if (php_http_env_got_request_header(ZEND_STRL("If-Range"), request TSRMLS_CC)) {
724 0 : r->range.status = PHP_HTTP_RANGE_NO;
725 0 : zend_hash_destroy(&r->range.values);
726 : } else {
727 1 : r->done = 1;
728 1 : zend_hash_destroy(&r->range.values);
729 1 : if (SUCCESS != r->ops->set_status(r, 416)) {
730 0 : return FAILURE;
731 : }
732 1 : if (SUCCESS != r->ops->set_header(r, "Content-Range: bytes */%zu", r->content.length)) {
733 0 : return FAILURE;
734 : }
735 : }
736 1 : break;
737 :
738 : case PHP_HTTP_RANGE_OK:
739 4 : if (PHP_HTTP_CACHE_MISS == php_http_env_is_response_cached_by_etag(r->options, ZEND_STRL("If-Range"), request TSRMLS_CC)
740 4 : || PHP_HTTP_CACHE_MISS == php_http_env_is_response_cached_by_last_modified(r->options, ZEND_STRL("If-Range"), request TSRMLS_CC)
741 : ) {
742 0 : r->range.status = PHP_HTTP_RANGE_NO;
743 0 : zend_hash_destroy(&r->range.values);
744 0 : break;
745 : }
746 4 : if (PHP_HTTP_CACHE_MISS == php_http_env_is_response_cached_by_etag(r->options, ZEND_STRL("If-Match"), request TSRMLS_CC)
747 4 : || PHP_HTTP_CACHE_MISS == php_http_env_is_response_cached_by_last_modified(r->options, ZEND_STRL("If-Unmodified-Since"), request TSRMLS_CC)
748 4 : || PHP_HTTP_CACHE_MISS == php_http_env_is_response_cached_by_last_modified(r->options, ZEND_STRL("Unless-Modified-Since"), request TSRMLS_CC)
749 : ) {
750 0 : r->done = 1;
751 0 : zend_hash_destroy(&r->range.values);
752 0 : if (SUCCESS != r->ops->set_status(r, 412)) {
753 0 : return FAILURE;
754 : }
755 0 : break;
756 : }
757 :
758 4 : break;
759 : }
760 : }
761 : }
762 :
763 21 : if (SUCCESS != php_http_env_response_send_head(r, request)) {
764 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to send response headers");
765 0 : return FAILURE;
766 : }
767 :
768 21 : if (SUCCESS != php_http_env_response_send_body(r)) {
769 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to send response body");
770 0 : return FAILURE;
771 : }
772 :
773 21 : if (SUCCESS != r->ops->finish(r)) {
774 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to finish response");
775 0 : return FAILURE;
776 : }
777 :
778 21 : return SUCCESS;
779 : }
780 :
781 8 : static long php_http_env_response_sapi_get_status(php_http_env_response_t *r)
782 : {
783 : TSRMLS_FETCH_FROM_CTX(r->ts);
784 :
785 8 : return php_http_env_get_response_code(TSRMLS_C);
786 : }
787 14 : static STATUS php_http_env_response_sapi_set_status(php_http_env_response_t *r, long http_code)
788 : {
789 : TSRMLS_FETCH_FROM_CTX(r->ts);
790 :
791 14 : return php_http_env_set_response_code(http_code TSRMLS_CC);
792 : }
793 10 : static STATUS php_http_env_response_sapi_set_protocol_version(php_http_env_response_t *r, php_http_version_t *v)
794 : {
795 : TSRMLS_FETCH_FROM_CTX(r->ts);
796 :
797 10 : return php_http_env_set_response_protocol_version(v TSRMLS_CC);
798 : }
799 40 : static STATUS php_http_env_response_sapi_set_header(php_http_env_response_t *r, const char *fmt, ...)
800 : {
801 : STATUS ret;
802 : va_list args;
803 : TSRMLS_FETCH_FROM_CTX(r->ts);
804 :
805 40 : va_start(args, fmt);
806 40 : ret = php_http_env_set_response_header_va(0, 1, fmt, args TSRMLS_CC);
807 40 : va_end(args);
808 :
809 40 : return ret;
810 : }
811 2 : static STATUS php_http_env_response_sapi_add_header(php_http_env_response_t *r, const char *fmt, ...)
812 : {
813 : STATUS ret;
814 : va_list args;
815 : TSRMLS_FETCH_FROM_CTX(r->ts);
816 :
817 2 : va_start(args, fmt);
818 2 : ret = php_http_env_set_response_header_va(0, 0, fmt, args TSRMLS_CC);
819 2 : va_end(args);
820 :
821 2 : return ret;
822 : }
823 6 : static STATUS php_http_env_response_sapi_del_header(php_http_env_response_t *r, const char *header_str, size_t header_len)
824 : {
825 : TSRMLS_FETCH_FROM_CTX(r->ts);
826 :
827 6 : return php_http_env_set_response_header_value(0, header_str, header_len, NULL, 1 TSRMLS_CC);
828 : }
829 12 : static STATUS php_http_env_response_sapi_write(php_http_env_response_t *r, const char *data_str, size_t data_len)
830 : {
831 : TSRMLS_FETCH_FROM_CTX(r->ts);
832 :
833 12 : if (0 < PHPWRITE(data_str, data_len)) {
834 12 : return SUCCESS;
835 : }
836 0 : return FAILURE;
837 : }
838 6 : static STATUS php_http_env_response_sapi_flush(php_http_env_response_t *r)
839 : {
840 : TSRMLS_FETCH_FROM_CTX(r->ts);
841 :
842 : #if PHP_VERSION_ID >= 50400
843 6 : if (php_output_get_level(TSRMLS_C)) {
844 0 : php_output_flush_all(TSRMLS_C);
845 : }
846 6 : if (!(php_output_get_status(TSRMLS_C) & PHP_OUTPUT_IMPLICITFLUSH)) {
847 6 : sapi_flush(TSRMLS_C);
848 : }
849 : #else
850 : php_end_ob_buffer(1, 1 TSRMLS_CC);
851 : sapi_flush(TSRMLS_C);
852 : #endif
853 :
854 6 : return SUCCESS;
855 : }
856 10 : static STATUS php_http_env_response_sapi_finish(php_http_env_response_t *r)
857 : {
858 10 : return SUCCESS;
859 : }
860 :
861 : static php_http_env_response_ops_t php_http_env_response_sapi_ops = {
862 : NULL,
863 : NULL,
864 : php_http_env_response_sapi_get_status,
865 : php_http_env_response_sapi_set_status,
866 : php_http_env_response_sapi_set_protocol_version,
867 : php_http_env_response_sapi_set_header,
868 : php_http_env_response_sapi_add_header,
869 : php_http_env_response_sapi_del_header,
870 : php_http_env_response_sapi_write,
871 : php_http_env_response_sapi_flush,
872 : php_http_env_response_sapi_finish
873 : };
874 :
875 10 : php_http_env_response_ops_t *php_http_env_response_get_sapi_ops(void)
876 : {
877 10 : return &php_http_env_response_sapi_ops;
878 : }
879 :
880 : typedef struct php_http_env_response_stream_ctx {
881 : HashTable header;
882 : php_http_version_t version;
883 : long status_code;
884 :
885 : php_stream *stream;
886 : php_stream_filter *chunked_filter;
887 : php_http_message_t *request;
888 :
889 : unsigned started:1;
890 : unsigned finished:1;
891 : unsigned chunked:1;
892 : } php_http_env_response_stream_ctx_t;
893 :
894 11 : static STATUS php_http_env_response_stream_init(php_http_env_response_t *r, void *init_arg)
895 : {
896 : php_http_env_response_stream_ctx_t *ctx;
897 11 : size_t buffer_size = 0x1000;
898 : TSRMLS_FETCH_FROM_CTX(r->ts);
899 :
900 11 : ctx = ecalloc(1, sizeof(*ctx));
901 :
902 11 : ctx->stream = init_arg;
903 11 : if (!ctx->stream || SUCCESS != zend_list_addref(ctx->stream->rsrc_id)) {
904 0 : efree(ctx);
905 0 : return FAILURE;
906 : }
907 11 : php_stream_set_option(ctx->stream, PHP_STREAM_OPTION_WRITE_BUFFER, PHP_STREAM_BUFFER_FULL, &buffer_size);
908 11 : zend_hash_init(&ctx->header, 0, NULL, ZVAL_PTR_DTOR, 0);
909 11 : php_http_version_init(&ctx->version, 1, 1 TSRMLS_CC);
910 11 : ctx->status_code = 200;
911 11 : ctx->chunked = 1;
912 11 : ctx->request = get_request(r->options TSRMLS_CC);
913 :
914 : /* there are some limitations regarding TE:chunked, see https://tools.ietf.org/html/rfc7230#section-3.3.1 */
915 11 : if (ctx->request && ctx->request->http.version.major == 1 && ctx->request->http.version.minor == 0) {
916 0 : ctx->version.minor = 0;
917 : }
918 :
919 11 : r->ctx = ctx;
920 :
921 11 : return SUCCESS;
922 : }
923 11 : static void php_http_env_response_stream_dtor(php_http_env_response_t *r)
924 : {
925 11 : php_http_env_response_stream_ctx_t *ctx = r->ctx;
926 : TSRMLS_FETCH_FROM_CTX(r->ts);
927 :
928 11 : if (ctx->chunked_filter) {
929 0 : php_stream_filter_free(ctx->chunked_filter TSRMLS_CC);
930 : }
931 11 : zend_hash_destroy(&ctx->header);
932 11 : zend_list_delete(ctx->stream->rsrc_id);
933 11 : efree(ctx);
934 11 : r->ctx = NULL;
935 11 : }
936 12 : static void php_http_env_response_stream_header(php_http_env_response_stream_ctx_t *ctx, HashTable *header, php_http_buffer_t *buf TSRMLS_DC)
937 : {
938 : HashPosition pos;
939 : zval **val;
940 :
941 48 : FOREACH_HASH_VAL(pos, header, val) {
942 36 : if (Z_TYPE_PP(val) == IS_ARRAY) {
943 1 : php_http_env_response_stream_header(ctx, Z_ARRVAL_PP(val), buf TSRMLS_CC);
944 : } else {
945 35 : zval *tmp = php_http_ztyp(IS_STRING, *val);
946 :
947 35 : if (ctx->chunked) {
948 : /* disable chunked transfer encoding if we've got an explicit content-length */
949 35 : if (!strncasecmp(Z_STRVAL_P(tmp), "Content-Length:", lenof("Content-Length:"))) {
950 0 : ctx->chunked = 0;
951 : }
952 : }
953 35 : php_http_buffer_append(buf, Z_STRVAL_P(tmp), Z_STRLEN_P(tmp));
954 35 : php_http_buffer_appends(buf, PHP_HTTP_CRLF);
955 35 : zval_ptr_dtor(&tmp);
956 : }
957 : }
958 12 : }
959 11 : static STATUS php_http_env_response_stream_start(php_http_env_response_stream_ctx_t *ctx TSRMLS_DC)
960 : {
961 : php_http_buffer_t header_buf;
962 :
963 11 : if (ctx->started || ctx->finished) {
964 0 : return FAILURE;
965 : }
966 :
967 11 : php_http_buffer_init(&header_buf);
968 11 : php_http_buffer_appendf(&header_buf, "HTTP/%u.%u %ld %s" PHP_HTTP_CRLF, ctx->version.major, ctx->version.minor, ctx->status_code, php_http_env_get_response_status_for_code(ctx->status_code));
969 :
970 : /* there are some limitations regarding TE:chunked, see https://tools.ietf.org/html/rfc7230#section-3.3.1 */
971 11 : if (ctx->version.major == 1 && ctx->version.minor == 0) {
972 0 : ctx->chunked = 0;
973 11 : } else if (ctx->status_code == 204 || ctx->status_code/100 == 1) {
974 0 : ctx->chunked = 0;
975 11 : } else if (ctx->request && ctx->status_code/100 == 2 && !strcasecmp(ctx->request->http.info.request.method, "CONNECT")) {
976 1 : ctx->chunked = 0;
977 : }
978 :
979 11 : php_http_env_response_stream_header(ctx, &ctx->header, &header_buf TSRMLS_CC);
980 :
981 : /* enable chunked transfer encoding */
982 11 : if (ctx->chunked) {
983 10 : php_http_buffer_appends(&header_buf, "Transfer-Encoding: chunked" PHP_HTTP_CRLF);
984 : }
985 11 : php_http_buffer_appends(&header_buf, PHP_HTTP_CRLF);
986 :
987 11 : if (header_buf.used == php_stream_write(ctx->stream, header_buf.data, header_buf.used)) {
988 11 : ctx->started = 1;
989 : }
990 11 : php_http_buffer_dtor(&header_buf);
991 11 : php_stream_flush(ctx->stream);
992 :
993 11 : if (ctx->chunked) {
994 10 : ctx->chunked_filter = php_stream_filter_create("http.chunked_encode", NULL, 0 TSRMLS_CC);
995 10 : php_stream_filter_append(&ctx->stream->writefilters, ctx->chunked_filter);
996 : }
997 :
998 11 : return ctx->started ? SUCCESS : FAILURE;
999 : }
1000 8 : static long php_http_env_response_stream_get_status(php_http_env_response_t *r)
1001 : {
1002 8 : php_http_env_response_stream_ctx_t *ctx = r->ctx;
1003 :
1004 8 : return ctx->status_code;
1005 : }
1006 13 : static STATUS php_http_env_response_stream_set_status(php_http_env_response_t *r, long http_code)
1007 : {
1008 13 : php_http_env_response_stream_ctx_t *stream_ctx = r->ctx;
1009 :
1010 13 : if (stream_ctx->started || stream_ctx->finished) {
1011 0 : return FAILURE;
1012 : }
1013 :
1014 13 : stream_ctx->status_code = http_code;
1015 :
1016 13 : return SUCCESS;
1017 : }
1018 10 : static STATUS php_http_env_response_stream_set_protocol_version(php_http_env_response_t *r, php_http_version_t *v)
1019 : {
1020 10 : php_http_env_response_stream_ctx_t *stream_ctx = r->ctx;
1021 :
1022 10 : if (stream_ctx->started || stream_ctx->finished) {
1023 0 : return FAILURE;
1024 : }
1025 :
1026 10 : memcpy(&stream_ctx->version, v, sizeof(stream_ctx->version));
1027 :
1028 10 : return SUCCESS;
1029 : }
1030 36 : static STATUS php_http_env_response_stream_set_header_ex(php_http_env_response_t *r, zend_bool replace, const char *fmt, va_list argv)
1031 : {
1032 36 : php_http_env_response_stream_ctx_t *stream_ctx = r->ctx;
1033 36 : char *header_end, *header_str = NULL;
1034 36 : size_t header_len = 0;
1035 : zval *zheader, **zheader_ptr;
1036 :
1037 36 : if (stream_ctx->started || stream_ctx->finished) {
1038 0 : return FAILURE;
1039 : }
1040 :
1041 36 : header_len = vspprintf(&header_str, 0, fmt, argv);
1042 :
1043 36 : if (!(header_end = strchr(header_str, ':'))) {
1044 0 : efree(header_str);
1045 0 : return FAILURE;
1046 : }
1047 :
1048 36 : *header_end = '\0';
1049 :
1050 36 : if (!replace && (SUCCESS == zend_hash_find(&stream_ctx->header, header_str, header_end - header_str + 1, (void *) &zheader_ptr))) {
1051 2 : convert_to_array(*zheader_ptr);
1052 2 : *header_end = ':';
1053 2 : return add_next_index_stringl(*zheader_ptr, header_str, header_len, 0);
1054 : } else {
1055 34 : MAKE_STD_ZVAL(zheader);
1056 34 : ZVAL_STRINGL(zheader, header_str, header_len, 0);
1057 :
1058 34 : if (SUCCESS != zend_hash_update(&stream_ctx->header, header_str, header_end - header_str + 1, (void *) &zheader, sizeof(zval *), NULL)) {
1059 0 : zval_ptr_dtor(&zheader);
1060 0 : return FAILURE;
1061 : }
1062 :
1063 34 : *header_end = ':';
1064 34 : return SUCCESS;
1065 : }
1066 : }
1067 32 : static STATUS php_http_env_response_stream_set_header(php_http_env_response_t *r, const char *fmt, ...)
1068 : {
1069 : STATUS ret;
1070 : va_list argv;
1071 :
1072 32 : va_start(argv, fmt);
1073 32 : ret = php_http_env_response_stream_set_header_ex(r, 1, fmt, argv);
1074 32 : va_end(argv);
1075 :
1076 32 : return ret;
1077 : }
1078 4 : static STATUS php_http_env_response_stream_add_header(php_http_env_response_t *r, const char *fmt, ...)
1079 : {
1080 : STATUS ret;
1081 : va_list argv;
1082 :
1083 4 : va_start(argv, fmt);
1084 4 : ret = php_http_env_response_stream_set_header_ex(r, 0, fmt, argv);
1085 4 : va_end(argv);
1086 :
1087 4 : return ret;
1088 : }
1089 7 : static STATUS php_http_env_response_stream_del_header(php_http_env_response_t *r, const char *header_str, size_t header_len)
1090 : {
1091 7 : php_http_env_response_stream_ctx_t *stream_ctx = r->ctx;
1092 :
1093 7 : if (stream_ctx->started || stream_ctx->finished) {
1094 0 : return FAILURE;
1095 : }
1096 :
1097 7 : zend_hash_del(&stream_ctx->header, header_str, header_len + 1);
1098 7 : return SUCCESS;
1099 : }
1100 3284 : static STATUS php_http_env_response_stream_write(php_http_env_response_t *r, const char *data_str, size_t data_len)
1101 : {
1102 3284 : php_http_env_response_stream_ctx_t *stream_ctx = r->ctx;
1103 : TSRMLS_FETCH_FROM_CTX(r->ts);
1104 :
1105 3284 : if (stream_ctx->finished) {
1106 0 : return FAILURE;
1107 : }
1108 3284 : if (!stream_ctx->started) {
1109 8 : if (SUCCESS != php_http_env_response_stream_start(stream_ctx TSRMLS_CC)) {
1110 0 : return FAILURE;
1111 : }
1112 : }
1113 :
1114 3284 : if (data_len != php_stream_write(stream_ctx->stream, data_str, data_len)) {
1115 0 : return FAILURE;
1116 : }
1117 :
1118 3284 : return SUCCESS;
1119 : }
1120 0 : static STATUS php_http_env_response_stream_flush(php_http_env_response_t *r)
1121 : {
1122 0 : php_http_env_response_stream_ctx_t *stream_ctx = r->ctx;
1123 : TSRMLS_FETCH_FROM_CTX(r->ts);
1124 :
1125 0 : if (stream_ctx->finished) {
1126 0 : return FAILURE;
1127 : }
1128 0 : if (!stream_ctx->started) {
1129 0 : if (SUCCESS != php_http_env_response_stream_start(stream_ctx TSRMLS_CC)) {
1130 0 : return FAILURE;
1131 : }
1132 : }
1133 :
1134 0 : return php_stream_flush(stream_ctx->stream);
1135 : }
1136 11 : static STATUS php_http_env_response_stream_finish(php_http_env_response_t *r)
1137 : {
1138 11 : php_http_env_response_stream_ctx_t *ctx = r->ctx;
1139 : TSRMLS_FETCH_FROM_CTX(r->ts);
1140 :
1141 11 : if (ctx->finished) {
1142 0 : return FAILURE;
1143 : }
1144 11 : if (!ctx->started) {
1145 3 : if (SUCCESS != php_http_env_response_stream_start(ctx TSRMLS_CC)) {
1146 0 : return FAILURE;
1147 : }
1148 : }
1149 :
1150 11 : php_stream_flush(ctx->stream);
1151 11 : if (ctx->chunked && ctx->chunked_filter) {
1152 10 : php_stream_filter_flush(ctx->chunked_filter, 1);
1153 10 : ctx->chunked_filter = php_stream_filter_remove(ctx->chunked_filter, 1 TSRMLS_CC);
1154 : }
1155 :
1156 11 : ctx->finished = 1;
1157 :
1158 11 : return SUCCESS;
1159 : }
1160 :
1161 : static php_http_env_response_ops_t php_http_env_response_stream_ops = {
1162 : php_http_env_response_stream_init,
1163 : php_http_env_response_stream_dtor,
1164 : php_http_env_response_stream_get_status,
1165 : php_http_env_response_stream_set_status,
1166 : php_http_env_response_stream_set_protocol_version,
1167 : php_http_env_response_stream_set_header,
1168 : php_http_env_response_stream_add_header,
1169 : php_http_env_response_stream_del_header,
1170 : php_http_env_response_stream_write,
1171 : php_http_env_response_stream_flush,
1172 : php_http_env_response_stream_finish
1173 : };
1174 :
1175 11 : php_http_env_response_ops_t *php_http_env_response_get_stream_ops(void)
1176 : {
1177 11 : return &php_http_env_response_stream_ops;
1178 : }
1179 :
1180 : #define PHP_HTTP_ENV_RESPONSE_OBJECT_INIT(obj) \
1181 : do { \
1182 : if (!obj->message) { \
1183 : obj->message = php_http_message_init_env(NULL, PHP_HTTP_RESPONSE TSRMLS_CC); \
1184 : } \
1185 : } while (0)
1186 :
1187 : ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse___construct, 0, 0, 0)
1188 : ZEND_END_ARG_INFO();
1189 24 : static PHP_METHOD(HttpEnvResponse, __construct)
1190 : {
1191 : php_http_message_object_t *obj;
1192 :
1193 24 : php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return);
1194 :
1195 24 : obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1196 :
1197 24 : php_http_expect(obj->message = php_http_message_init_env(obj->message, PHP_HTTP_RESPONSE TSRMLS_CC), unexpected_val, return);
1198 : }
1199 :
1200 : ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse___invoke, 0, 0, 1)
1201 : ZEND_ARG_INFO(0, ob_string)
1202 : ZEND_ARG_INFO(0, ob_flags)
1203 : ZEND_END_ARG_INFO();
1204 3 : static PHP_METHOD(HttpEnvResponse, __invoke)
1205 : {
1206 : char *ob_str;
1207 : int ob_len;
1208 3 : long ob_flags = 0;
1209 :
1210 3 : if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &ob_str, &ob_len, &ob_flags)) {
1211 3 : php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1212 :
1213 3 : PHP_HTTP_ENV_RESPONSE_OBJECT_INIT(obj);
1214 :
1215 3 : php_http_message_object_init_body_object(obj);
1216 3 : php_http_message_body_append(obj->message->body, ob_str, ob_len);
1217 : #if PHP_VERSION_ID >= 50400
1218 3 : RETURN_TRUE;
1219 : #else
1220 : RETURN_EMPTY_STRING();
1221 : #endif
1222 : }
1223 : }
1224 :
1225 : ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_setEnvRequest, 0, 0, 1)
1226 : ZEND_ARG_OBJ_INFO(0, env_request, http\\Message, 1)
1227 : ZEND_END_ARG_INFO();
1228 5 : static PHP_METHOD(HttpEnvResponse, setEnvRequest)
1229 : {
1230 5 : zval *env_req = NULL;
1231 :
1232 10 : php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|O", &env_req, php_http_message_class_entry), invalid_arg, return);
1233 :
1234 5 : set_option(getThis(), ZEND_STRL("request"), IS_OBJECT, env_req, 0 TSRMLS_CC);
1235 5 : RETVAL_ZVAL(getThis(), 1, 0);
1236 : }
1237 :
1238 : ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_setContentType, 0, 0, 1)
1239 : ZEND_ARG_INFO(0, content_type)
1240 : ZEND_END_ARG_INFO();
1241 3 : static PHP_METHOD(HttpEnvResponse, setContentType)
1242 : {
1243 3 : char *ct_str = NULL;
1244 3 : int ct_len = 0;
1245 :
1246 6 : php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s!", &ct_str, &ct_len), invalid_arg, return);
1247 :
1248 3 : set_option(getThis(), ZEND_STRL("contentType"), IS_STRING, ct_str, ct_len TSRMLS_CC);
1249 3 : RETVAL_ZVAL(getThis(), 1, 0);
1250 : }
1251 :
1252 : ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_setContentDisposition, 0, 0, 1)
1253 : ZEND_ARG_ARRAY_INFO(0, disposition_params, 1)
1254 : ZEND_END_ARG_INFO();
1255 3 : static PHP_METHOD(HttpEnvResponse, setContentDisposition)
1256 : {
1257 : zval *zdisposition;
1258 :
1259 6 : php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &zdisposition), invalid_arg, return);
1260 :
1261 3 : zend_update_property(Z_OBJCE_P(getThis()), getThis(), ZEND_STRL("contentDisposition"), zdisposition TSRMLS_CC);
1262 3 : RETVAL_ZVAL(getThis(), 1, 0);
1263 : }
1264 :
1265 : ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_setContentEncoding, 0, 0, 1)
1266 : ZEND_ARG_INFO(0, content_encoding)
1267 : ZEND_END_ARG_INFO();
1268 3 : static PHP_METHOD(HttpEnvResponse, setContentEncoding)
1269 : {
1270 : long ce;
1271 :
1272 6 : php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &ce), invalid_arg, return);
1273 :
1274 3 : set_option(getThis(), ZEND_STRL("contentEncoding"), IS_LONG, &ce, 0 TSRMLS_CC);
1275 3 : RETVAL_ZVAL(getThis(), 1, 0);
1276 : }
1277 :
1278 : ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_setCacheControl, 0, 0, 1)
1279 : ZEND_ARG_INFO(0, cache_control)
1280 : ZEND_END_ARG_INFO();
1281 2 : static PHP_METHOD(HttpEnvResponse, setCacheControl)
1282 : {
1283 2 : char *cc_str = NULL;
1284 2 : int cc_len = 0;
1285 :
1286 4 : php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s!", &cc_str, &cc_len), invalid_arg, return);
1287 :
1288 2 : set_option(getThis(), ZEND_STRL("cacheControl"), IS_STRING, cc_str, cc_len TSRMLS_CC);
1289 2 : RETVAL_ZVAL(getThis(), 1, 0);
1290 : }
1291 :
1292 : ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_setLastModified, 0, 0, 1)
1293 : ZEND_ARG_INFO(0, last_modified)
1294 : ZEND_END_ARG_INFO();
1295 4 : static PHP_METHOD(HttpEnvResponse, setLastModified)
1296 : {
1297 : long last_modified;
1298 :
1299 8 : php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &last_modified), invalid_arg, return);
1300 :
1301 4 : set_option(getThis(), ZEND_STRL("lastModified"), IS_LONG, &last_modified, 0 TSRMLS_CC);
1302 4 : RETVAL_ZVAL(getThis(), 1, 0);
1303 : }
1304 :
1305 : ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_isCachedByLastModified, 0, 0, 0)
1306 : ZEND_ARG_INFO(0, header_name)
1307 : ZEND_END_ARG_INFO();
1308 2 : static PHP_METHOD(HttpEnvResponse, isCachedByLastModified)
1309 : {
1310 2 : char *header_name_str = NULL;
1311 2 : int header_name_len = 0;
1312 :
1313 2 : if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!", &header_name_str, &header_name_len)) {
1314 2 : if (!header_name_str || !header_name_len) {
1315 0 : header_name_str = "If-Modified-Since";
1316 0 : header_name_len = lenof("If-Modified-Since");
1317 : }
1318 :
1319 2 : RETURN_LONG(php_http_env_is_response_cached_by_last_modified(getThis(), header_name_str, header_name_len, get_request(getThis() TSRMLS_CC) TSRMLS_CC));
1320 : }
1321 : }
1322 :
1323 : ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_setEtag, 0, 0, 1)
1324 : ZEND_ARG_INFO(0, etag)
1325 : ZEND_END_ARG_INFO();
1326 4 : static PHP_METHOD(HttpEnvResponse, setEtag)
1327 : {
1328 4 : char *etag_str = NULL;
1329 4 : int etag_len = 0;
1330 :
1331 8 : php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s!", &etag_str, &etag_len), invalid_arg, return);
1332 :
1333 4 : set_option(getThis(), ZEND_STRL("etag"), IS_STRING, etag_str, etag_len TSRMLS_CC);
1334 4 : RETVAL_ZVAL(getThis(), 1, 0);
1335 : }
1336 :
1337 : ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_isCachedByEtag, 0, 0, 0)
1338 : ZEND_ARG_INFO(0, header_name)
1339 : ZEND_END_ARG_INFO();
1340 2 : static PHP_METHOD(HttpEnvResponse, isCachedByEtag)
1341 : {
1342 2 : char *header_name_str = NULL;
1343 2 : int header_name_len = 0;
1344 :
1345 2 : if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!", &header_name_str, &header_name_len)) {
1346 2 : if (!header_name_str || !header_name_len) {
1347 0 : header_name_str = "If-None-Match";
1348 0 : header_name_len = lenof("If-None-Match");
1349 : }
1350 2 : RETURN_LONG(php_http_env_is_response_cached_by_etag(getThis(), header_name_str, header_name_len, get_request(getThis() TSRMLS_CC) TSRMLS_CC));
1351 : }
1352 : }
1353 :
1354 : ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_setThrottleRate, 0, 0, 1)
1355 : ZEND_ARG_INFO(0, chunk_size)
1356 : ZEND_ARG_INFO(0, delay)
1357 : ZEND_END_ARG_INFO();
1358 1 : static PHP_METHOD(HttpEnvResponse, setThrottleRate)
1359 : {
1360 : long chunk_size;
1361 1 : double delay = 1;
1362 :
1363 2 : php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|d", &chunk_size, &delay), invalid_arg, return);
1364 :
1365 1 : set_option(getThis(), ZEND_STRL("throttleDelay"), IS_DOUBLE, &delay, 0 TSRMLS_CC);
1366 1 : set_option(getThis(), ZEND_STRL("throttleChunk"), IS_LONG, &chunk_size, 0 TSRMLS_CC);
1367 1 : RETVAL_ZVAL(getThis(), 1, 0);
1368 : }
1369 :
1370 : ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_setCookie, 0, 0, 1)
1371 : ZEND_ARG_INFO(0, cookie)
1372 : ZEND_END_ARG_INFO();
1373 3 : static PHP_METHOD(HttpEnvResponse, setCookie)
1374 : {
1375 : zval *zcookie_new;
1376 : zend_error_handling zeh;
1377 3 : php_http_cookie_list_t *list = NULL;
1378 :
1379 6 : php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zcookie_new), invalid_arg, return);
1380 :
1381 3 : zend_replace_error_handling(EH_THROW, php_http_exception_unexpected_val_class_entry, &zeh TSRMLS_CC);
1382 3 : switch (Z_TYPE_P(zcookie_new)) {
1383 : case IS_OBJECT:
1384 1 : if (instanceof_function(Z_OBJCE_P(zcookie_new), php_http_cookie_class_entry TSRMLS_CC)) {
1385 1 : Z_ADDREF_P(zcookie_new);
1386 1 : break;
1387 : }
1388 : /* no break */
1389 : case IS_ARRAY:
1390 0 : list = php_http_cookie_list_from_struct(NULL, zcookie_new TSRMLS_CC);
1391 0 : MAKE_STD_ZVAL(zcookie_new);
1392 0 : ZVAL_OBJVAL(zcookie_new, php_http_cookie_object_new_ex(php_http_cookie_class_entry, list, NULL TSRMLS_CC), 0);
1393 0 : break;
1394 :
1395 : default:
1396 2 : zcookie_new = php_http_ztyp(IS_STRING, zcookie_new);
1397 2 : list = php_http_cookie_list_parse(NULL, Z_STRVAL_P(zcookie_new), Z_STRLEN_P(zcookie_new), 0, NULL TSRMLS_CC);
1398 2 : zval_ptr_dtor(&zcookie_new);
1399 2 : MAKE_STD_ZVAL(zcookie_new);
1400 2 : ZVAL_OBJVAL(zcookie_new, php_http_cookie_object_new_ex(php_http_cookie_class_entry, list, NULL TSRMLS_CC), 0);
1401 : }
1402 3 : zend_restore_error_handling(&zeh TSRMLS_CC);
1403 :
1404 3 : set_cookie(getThis(), zcookie_new TSRMLS_CC);
1405 3 : zval_ptr_dtor(&zcookie_new);
1406 :
1407 3 : RETVAL_ZVAL(getThis(), 1, 0);
1408 : }
1409 :
1410 : ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_send, 0, 0, 0)
1411 : ZEND_ARG_INFO(0, stream)
1412 : ZEND_END_ARG_INFO();
1413 21 : static PHP_METHOD(HttpEnvResponse, send)
1414 : {
1415 21 : zval *zstream = NULL;
1416 21 : php_stream *s = NULL;
1417 :
1418 21 : if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|r", &zstream)) {
1419 : /* first flush the output layer to avoid conflicting headers and output;
1420 : * also, ob_start($thisEnvResponse) might have been called */
1421 : #if PHP_VERSION_ID >= 50400
1422 21 : php_output_end_all(TSRMLS_C);
1423 : #else
1424 : php_end_ob_buffers(1 TSRMLS_CC);
1425 : #endif
1426 :
1427 21 : if (zstream) {
1428 : php_http_env_response_t *r;
1429 :
1430 11 : php_stream_from_zval(s, &zstream);
1431 11 : r = php_http_env_response_init(NULL, getThis(), php_http_env_response_get_stream_ops(), s TSRMLS_CC);
1432 11 : if (!r) {
1433 0 : RETURN_FALSE;
1434 : }
1435 :
1436 11 : RETVAL_BOOL(SUCCESS == php_http_env_response_send(r));
1437 11 : php_http_env_response_free(&r);
1438 : } else {
1439 : php_http_env_response_t r;
1440 :
1441 10 : if (!php_http_env_response_init(&r, getThis(), NULL, NULL TSRMLS_CC)) {
1442 0 : RETURN_FALSE;
1443 : }
1444 :
1445 10 : RETVAL_BOOL(SUCCESS == php_http_env_response_send(&r));
1446 10 : php_http_env_response_dtor(&r);
1447 : }
1448 : }
1449 : }
1450 :
1451 : static zend_function_entry php_http_env_response_methods[] = {
1452 : PHP_ME(HttpEnvResponse, __construct, ai_HttpEnvResponse___construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
1453 : PHP_ME(HttpEnvResponse, __invoke, ai_HttpEnvResponse___invoke, ZEND_ACC_PUBLIC)
1454 : PHP_ME(HttpEnvResponse, setEnvRequest, ai_HttpEnvResponse_setEnvRequest, ZEND_ACC_PUBLIC)
1455 : PHP_ME(HttpEnvResponse, setCookie, ai_HttpEnvResponse_setCookie, ZEND_ACC_PUBLIC)
1456 : PHP_ME(HttpEnvResponse, setContentType, ai_HttpEnvResponse_setContentType, ZEND_ACC_PUBLIC)
1457 : PHP_ME(HttpEnvResponse, setContentDisposition, ai_HttpEnvResponse_setContentDisposition, ZEND_ACC_PUBLIC)
1458 : PHP_ME(HttpEnvResponse, setContentEncoding, ai_HttpEnvResponse_setContentEncoding, ZEND_ACC_PUBLIC)
1459 : PHP_ME(HttpEnvResponse, setCacheControl, ai_HttpEnvResponse_setCacheControl, ZEND_ACC_PUBLIC)
1460 : PHP_ME(HttpEnvResponse, setLastModified, ai_HttpEnvResponse_setLastModified, ZEND_ACC_PUBLIC)
1461 : PHP_ME(HttpEnvResponse, isCachedByLastModified, ai_HttpEnvResponse_isCachedByLastModified, ZEND_ACC_PUBLIC)
1462 : PHP_ME(HttpEnvResponse, setEtag, ai_HttpEnvResponse_setEtag, ZEND_ACC_PUBLIC)
1463 : PHP_ME(HttpEnvResponse, isCachedByEtag, ai_HttpEnvResponse_isCachedByEtag, ZEND_ACC_PUBLIC)
1464 : PHP_ME(HttpEnvResponse, setThrottleRate, ai_HttpEnvResponse_setThrottleRate, ZEND_ACC_PUBLIC)
1465 : PHP_ME(HttpEnvResponse, send, ai_HttpEnvResponse_send, ZEND_ACC_PUBLIC)
1466 : EMPTY_FUNCTION_ENTRY
1467 : };
1468 :
1469 : zend_class_entry *php_http_env_response_class_entry;
1470 :
1471 374 : PHP_MINIT_FUNCTION(http_env_response)
1472 : {
1473 374 : zend_class_entry ce = {0};
1474 :
1475 374 : INIT_NS_CLASS_ENTRY(ce, "http\\Env", "Response", php_http_env_response_methods);
1476 374 : php_http_env_response_class_entry = zend_register_internal_class_ex(&ce, php_http_message_class_entry, NULL TSRMLS_CC);
1477 :
1478 374 : zend_declare_class_constant_long(php_http_env_response_class_entry, ZEND_STRL("CONTENT_ENCODING_NONE"), PHP_HTTP_CONTENT_ENCODING_NONE TSRMLS_CC);
1479 374 : zend_declare_class_constant_long(php_http_env_response_class_entry, ZEND_STRL("CONTENT_ENCODING_GZIP"), PHP_HTTP_CONTENT_ENCODING_GZIP TSRMLS_CC);
1480 :
1481 374 : zend_declare_class_constant_long(php_http_env_response_class_entry, ZEND_STRL("CACHE_NO"), PHP_HTTP_CACHE_NO TSRMLS_CC);
1482 374 : zend_declare_class_constant_long(php_http_env_response_class_entry, ZEND_STRL("CACHE_HIT"), PHP_HTTP_CACHE_HIT TSRMLS_CC);
1483 374 : zend_declare_class_constant_long(php_http_env_response_class_entry, ZEND_STRL("CACHE_MISS"), PHP_HTTP_CACHE_MISS TSRMLS_CC);
1484 :
1485 374 : zend_declare_property_null(php_http_env_response_class_entry, ZEND_STRL("request"), ZEND_ACC_PROTECTED TSRMLS_CC);
1486 374 : zend_declare_property_null(php_http_env_response_class_entry, ZEND_STRL("cookies"), ZEND_ACC_PROTECTED TSRMLS_CC);
1487 374 : zend_declare_property_null(php_http_env_response_class_entry, ZEND_STRL("contentType"), ZEND_ACC_PROTECTED TSRMLS_CC);
1488 374 : zend_declare_property_null(php_http_env_response_class_entry, ZEND_STRL("contentDisposition"), ZEND_ACC_PROTECTED TSRMLS_CC);
1489 374 : zend_declare_property_null(php_http_env_response_class_entry, ZEND_STRL("contentEncoding"), ZEND_ACC_PROTECTED TSRMLS_CC);
1490 374 : zend_declare_property_null(php_http_env_response_class_entry, ZEND_STRL("cacheControl"), ZEND_ACC_PROTECTED TSRMLS_CC);
1491 374 : zend_declare_property_null(php_http_env_response_class_entry, ZEND_STRL("etag"), ZEND_ACC_PROTECTED TSRMLS_CC);
1492 374 : zend_declare_property_null(php_http_env_response_class_entry, ZEND_STRL("lastModified"), ZEND_ACC_PROTECTED TSRMLS_CC);
1493 374 : zend_declare_property_null(php_http_env_response_class_entry, ZEND_STRL("throttleDelay"), ZEND_ACC_PROTECTED TSRMLS_CC);
1494 374 : zend_declare_property_null(php_http_env_response_class_entry, ZEND_STRL("throttleChunk"), ZEND_ACC_PROTECTED TSRMLS_CC);
1495 :
1496 374 : return SUCCESS;
1497 : }
1498 :
1499 :
1500 : /*
1501 : * Local variables:
1502 : * tab-width: 4
1503 : * c-basic-offset: 4
1504 : * End:
1505 : * vim600: noet sw=4 ts=4 fdm=marker
1506 : * vim<600: noet sw=4 ts=4
1507 : */
|