back to dev
[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-2014, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
11 */
12
13 #include "php_http_api.h"
14 #include "php_variables.h"
15
16 PHP_RINIT_FUNCTION(http_env)
17 {
18 PHP_HTTP_G->env.request.time = sapi_get_request_time(TSRMLS_C);
19
20 /* populate form data on non-POST requests */
21 if (SG(request_info).request_method && strcasecmp(SG(request_info).request_method, "POST") && SG(request_info).content_type && *SG(request_info).content_type) {
22 uint ct_len = strlen(SG(request_info).content_type);
23 char *ct_str = estrndup(SG(request_info).content_type, ct_len);
24 php_http_params_opts_t opts;
25 HashTable params;
26
27 php_http_params_opts_default_get(&opts);
28 opts.input.str = ct_str;
29 opts.input.len = ct_len;
30
31 SG(request_info).content_type_dup = ct_str;
32
33 ZEND_INIT_SYMTABLE(&params);
34 if (php_http_params_parse(&params, &opts TSRMLS_CC)) {
35 char *key_str;
36 uint key_len;
37 ulong key_num;
38
39 if (HASH_KEY_IS_STRING == zend_hash_get_current_key_ex(&params, &key_str, &key_len, &key_num, 0, NULL)) {
40 sapi_post_entry *post_entry = NULL;
41
42 if (SUCCESS == zend_hash_find(&SG(known_post_content_types), key_str, key_len, (void *) &post_entry)) {
43 zval *files = PG(http_globals)[TRACK_VARS_FILES];
44
45 if (post_entry) {
46 SG(request_info).post_entry = post_entry;
47
48 if (post_entry->post_reader) {
49 post_entry->post_reader(TSRMLS_C);
50 }
51 }
52
53 if (sapi_module.default_post_reader) {
54 sapi_module.default_post_reader(TSRMLS_C);
55 }
56
57 sapi_handle_post(PG(http_globals)[TRACK_VARS_POST] TSRMLS_CC);
58
59 /*
60 * the rfc1867 handler is an awkward buddy
61 */
62 if (files != PG(http_globals)[TRACK_VARS_FILES] && PG(http_globals)[TRACK_VARS_FILES]) {
63 Z_ADDREF_P(PG(http_globals)[TRACK_VARS_FILES]);
64 zend_hash_update(&EG(symbol_table), "_FILES", sizeof("_FILES"), &PG(http_globals)[TRACK_VARS_FILES], sizeof(zval *), NULL);
65 if (files) {
66 zval_ptr_dtor(&files);
67 }
68 }
69 }
70 }
71 zend_hash_destroy(&params);
72 }
73 }
74
75 STR_SET(SG(request_info).content_type_dup, NULL);
76
77 return SUCCESS;
78 }
79
80 PHP_RSHUTDOWN_FUNCTION(http_env)
81 {
82 if (PHP_HTTP_G->env.request.headers) {
83 zend_hash_destroy(PHP_HTTP_G->env.request.headers);
84 FREE_HASHTABLE(PHP_HTTP_G->env.request.headers);
85 PHP_HTTP_G->env.request.headers = NULL;
86 }
87 if (PHP_HTTP_G->env.request.body) {
88 php_http_message_body_free(&PHP_HTTP_G->env.request.body);
89 }
90
91 if (PHP_HTTP_G->env.server_var) {
92 zval_ptr_dtor(&PHP_HTTP_G->env.server_var);
93 PHP_HTTP_G->env.server_var = NULL;
94 }
95
96 return SUCCESS;
97 }
98
99 void php_http_env_get_request_headers(HashTable *headers TSRMLS_DC)
100 {
101 php_http_array_hashkey_t key = php_http_array_hashkey_init(0);
102 zval **hsv, **header;
103 HashPosition pos;
104
105 if (!PHP_HTTP_G->env.request.headers) {
106 ALLOC_HASHTABLE(PHP_HTTP_G->env.request.headers);
107 zend_hash_init(PHP_HTTP_G->env.request.headers, 0, NULL, ZVAL_PTR_DTOR, 0);
108
109 zend_is_auto_global("_SERVER", lenof("_SERVER") TSRMLS_CC);
110
111 if (SUCCESS == zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void *) &hsv) && Z_TYPE_PP(hsv) == IS_ARRAY) {
112 FOREACH_KEY(pos, *hsv, key) {
113 if (key.type == HASH_KEY_IS_STRING && key.len > 6 && *key.str == 'H' && !strncmp(key.str, "HTTP_", 5)) {
114 key.len -= 5;
115 key.str = php_http_pretty_key(estrndup(key.str + 5, key.len - 1), key.len - 1, 1, 1);
116
117 zend_hash_get_current_data_ex(Z_ARRVAL_PP(hsv), (void *) &header, &pos);
118 Z_ADDREF_P(*header);
119 zend_symtable_update(PHP_HTTP_G->env.request.headers, key.str, key.len, (void *) header, sizeof(zval *), NULL);
120
121 efree(key.str);
122 } else if (key.type == HASH_KEY_IS_STRING && key.len > 9 && *key.str == 'C' && !strncmp(key.str, "CONTENT_", 8)) {
123 key.str = php_http_pretty_key(estrndup(key.str, key.len - 1), key.len - 1, 1, 1);
124
125 zend_hash_get_current_data_ex(Z_ARRVAL_PP(hsv), (void *) &header, &pos);
126 Z_ADDREF_P(*header);
127 zend_symtable_update(PHP_HTTP_G->env.request.headers, key.str, key.len, (void *) header, sizeof(zval *), NULL);
128
129 efree(key.str);
130 }
131 }
132 }
133 }
134
135 if (headers) {
136 zend_hash_copy(headers, PHP_HTTP_G->env.request.headers, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
137 }
138 }
139
140 char *php_http_env_get_request_header(const char *name_str, size_t name_len, size_t *len, php_http_message_t *request TSRMLS_DC)
141 {
142 HashTable *request_headers;
143 zval **zvalue = NULL;
144 char *val = NULL, *key = php_http_pretty_key(estrndup(name_str, name_len), name_len, 1, 1);
145
146 if (request) {
147 request_headers = &request->hdrs;
148 } else {
149 php_http_env_get_request_headers(NULL TSRMLS_CC);
150 request_headers = PHP_HTTP_G->env.request.headers;
151 }
152
153 if (SUCCESS == zend_symtable_find(request_headers, key, name_len + 1, (void *) &zvalue)) {
154 zval *zcopy = php_http_ztyp(IS_STRING, *zvalue);
155
156 val = estrndup(Z_STRVAL_P(zcopy), Z_STRLEN_P(zcopy));
157 if (len) {
158 *len = Z_STRLEN_P(zcopy);
159 }
160 zval_ptr_dtor(&zcopy);
161 }
162
163 efree(key);
164
165 return val;
166 }
167
168 int php_http_env_got_request_header(const char *name_str, size_t name_len, php_http_message_t *request TSRMLS_DC)
169 {
170 HashTable *request_headers;
171 char *key = php_http_pretty_key(estrndup(name_str, name_len), name_len, 1, 1);
172 int got;
173
174 if (request) {
175 request_headers = &request->hdrs;
176 } else {
177 php_http_env_get_request_headers(NULL TSRMLS_CC);
178 request_headers = PHP_HTTP_G->env.request.headers;
179 }
180 got = zend_symtable_exists(request_headers, key, name_len + 1);
181 efree(key);
182
183 return got;
184 }
185
186 zval *php_http_env_get_superglobal(const char *key, size_t key_len TSRMLS_DC)
187 {
188 zval **hsv;
189
190 zend_is_auto_global(key, key_len TSRMLS_CC);
191
192 if ((SUCCESS != zend_hash_find(&EG(symbol_table), key, key_len + 1, (void *) &hsv)) || (Z_TYPE_PP(hsv) != IS_ARRAY)) {
193 return NULL;
194 }
195
196 return *hsv;
197 }
198
199 zval *php_http_env_get_server_var(const char *key, size_t key_len, zend_bool check TSRMLS_DC)
200 {
201 zval *hsv, **var;
202 char *env;
203
204 /* if available, this is a lot faster than accessing $_SERVER */
205 if (sapi_module.getenv) {
206 if ((!(env = sapi_module.getenv((char *) key, key_len TSRMLS_CC))) || (check && !*env)) {
207 return NULL;
208 }
209 if (PHP_HTTP_G->env.server_var) {
210 zval_ptr_dtor(&PHP_HTTP_G->env.server_var);
211 }
212 MAKE_STD_ZVAL(PHP_HTTP_G->env.server_var);
213 ZVAL_STRING(PHP_HTTP_G->env.server_var, env, 1);
214 return PHP_HTTP_G->env.server_var;
215 }
216
217 if (!(hsv = php_http_env_get_superglobal(ZEND_STRL("_SERVER") TSRMLS_CC))) {
218 return NULL;
219 }
220 if ((SUCCESS != zend_symtable_find(Z_ARRVAL_P(hsv), key, key_len + 1, (void *) &var))) {
221 return NULL;
222 }
223 if (check && !((Z_TYPE_PP(var) == IS_STRING) && Z_STRVAL_PP(var) && Z_STRLEN_PP(var))) {
224 return NULL;
225 }
226 return *var;
227 }
228
229 php_http_message_body_t *php_http_env_get_request_body(TSRMLS_D)
230 {
231 if (!PHP_HTTP_G->env.request.body) {
232 php_stream *s = php_stream_temp_new();
233 #if PHP_VERSION_ID >= 50600
234 php_stream *input = php_stream_open_wrapper("php://input", "r", 0, NULL);
235
236 /* php://input does not support stat */
237 php_stream_copy_to_stream_ex(input, s, -1, NULL);
238 php_stream_close(input);
239 #else
240 if (SG(request_info).post_data || SG(request_info).raw_post_data) {
241 /* php://input does not support seek() in PHP <= 5.5 */
242 if (SG(request_info).raw_post_data) {
243 php_stream_write(s, SG(request_info).raw_post_data, SG(request_info).raw_post_data_length);
244 } else {
245 php_stream_write(s, SG(request_info).post_data, SG(request_info).post_data_length);
246 }
247 } else if (sapi_module.read_post && !SG(read_post_bytes)) {
248 char *buf = emalloc(4096);
249 int len;
250
251 while (0 < (len = sapi_module.read_post(buf, 4096 TSRMLS_CC))) {
252 SG(read_post_bytes) += len;
253 php_stream_write(s, buf, len);
254
255 if (len < 4096) {
256 break;
257 }
258 }
259 efree(buf);
260 }
261 #endif
262 php_stream_rewind(s);
263 PHP_HTTP_G->env.request.body = php_http_message_body_init(NULL, s TSRMLS_CC);
264 }
265
266 return PHP_HTTP_G->env.request.body;
267 }
268
269 const char *php_http_env_get_request_method(php_http_message_t *request TSRMLS_DC)
270 {
271 const char *m;
272
273 if (PHP_HTTP_MESSAGE_TYPE(REQUEST, request)) {
274 m = request->http.info.request.method;
275 } else {
276 m = SG(request_info).request_method;
277 }
278
279 return m ? m : "GET";
280 }
281
282 php_http_range_status_t php_http_env_get_request_ranges(HashTable *ranges, size_t length, php_http_message_t *request TSRMLS_DC)
283 {
284 zval *zentry;
285 char *range, *rp, c;
286 long begin = -1, end = -1, *ptr;
287
288 if (!(range = php_http_env_get_request_header(ZEND_STRL("Range"), NULL, request TSRMLS_CC))) {
289 return PHP_HTTP_RANGE_NO;
290 }
291 if (strncmp(range, "bytes=", lenof("bytes="))) {
292 STR_FREE(range);
293 return PHP_HTTP_RANGE_NO;
294 }
295
296 rp = range + lenof("bytes=");
297 ptr = &begin;
298
299 do {
300 switch (c = *(rp++)) {
301 case '0':
302 /* allow 000... - shall we? */
303 if (*ptr != -10) {
304 *ptr *= 10;
305 }
306 break;
307
308 case '1': case '2': case '3':
309 case '4': case '5': case '6':
310 case '7': case '8': case '9':
311 /*
312 * If the value of the pointer is already set (non-negative)
313 * then multiply its value by ten and add the current value,
314 * else initialise the pointers value with the current value
315 * --
316 * This let us recognize empty fields when validating the
317 * ranges, i.e. a "-10" for begin and "12345" for the end
318 * was the following range request: "Range: bytes=0-12345";
319 * While a "-1" for begin and "12345" for the end would
320 * have been: "Range: bytes=-12345".
321 */
322 if (*ptr > 0) {
323 *ptr *= 10;
324 *ptr += c - '0';
325 } else {
326 *ptr = c - '0';
327 }
328 break;
329
330 case '-':
331 ptr = &end;
332 break;
333
334 case ' ':
335 break;
336
337 case 0:
338 case ',':
339
340 if (length) {
341 /* validate ranges */
342 switch (begin) {
343 /* "0-12345" */
344 case -10:
345 switch (end) {
346 /* "0-" */
347 case -1:
348 STR_FREE(range);
349 return PHP_HTTP_RANGE_NO;
350
351 /* "0-0" */
352 case -10:
353 end = 0;
354 break;
355
356 default:
357 if (length <= (size_t) end) {
358 end = length - 1;
359 }
360 break;
361 }
362 begin = 0;
363 break;
364
365 /* "-12345" */
366 case -1:
367 /* "-", "-0" */
368 if (end == -1 || end == -10) {
369 STR_FREE(range);
370 return PHP_HTTP_RANGE_ERR;
371 }
372 begin = length - end;
373 end = length - 1;
374 break;
375
376 /* "12345-(NNN)" */
377 default:
378 if (length <= (size_t) begin) {
379 STR_FREE(range);
380 return PHP_HTTP_RANGE_ERR;
381 }
382 switch (end) {
383 /* "12345-0" */
384 case -10:
385 STR_FREE(range);
386 return PHP_HTTP_RANGE_ERR;
387
388 /* "12345-" */
389 case -1:
390 end = length - 1;
391 break;
392
393 /* "12345-67890" */
394 default:
395 if (length <= (size_t) end) {
396 end = length - 1;
397 } else if (end < begin) {
398 STR_FREE(range);
399 return PHP_HTTP_RANGE_ERR;
400 }
401 break;
402 }
403 break;
404 }
405 }
406
407 MAKE_STD_ZVAL(zentry);
408 array_init(zentry);
409 add_index_long(zentry, 0, begin);
410 add_index_long(zentry, 1, end);
411 zend_hash_next_index_insert(ranges, &zentry, sizeof(zval *), NULL);
412
413 begin = -1;
414 end = -1;
415 ptr = &begin;
416
417 break;
418
419 default:
420 STR_FREE(range);
421 return PHP_HTTP_RANGE_NO;
422 }
423 } while (c != 0);
424
425 STR_FREE(range);
426 return PHP_HTTP_RANGE_OK;
427 }
428
429 static void grab_headers(void *data, void *arg TSRMLS_DC)
430 {
431 php_http_buffer_appendl(PHP_HTTP_BUFFER(arg), ((sapi_header_struct *)data)->header);
432 php_http_buffer_appends(PHP_HTTP_BUFFER(arg), PHP_HTTP_CRLF);
433 }
434
435 STATUS php_http_env_get_response_headers(HashTable *headers_ht TSRMLS_DC)
436 {
437 STATUS status;
438 php_http_buffer_t headers;
439
440 php_http_buffer_init(&headers);
441 zend_llist_apply_with_argument(&SG(sapi_headers).headers, grab_headers, &headers TSRMLS_CC);
442 php_http_buffer_fix(&headers);
443
444 status = php_http_header_parse(headers.data, headers.used, headers_ht, NULL, NULL TSRMLS_CC);
445 php_http_buffer_dtor(&headers);
446
447 return status;
448 }
449
450 char *php_http_env_get_response_header(const char *name_str, size_t name_len TSRMLS_DC)
451 {
452 char *val = NULL;
453 HashTable headers;
454
455 zend_hash_init(&headers, 0, NULL, ZVAL_PTR_DTOR, 0);
456 if (SUCCESS == php_http_env_get_response_headers(&headers TSRMLS_CC)) {
457 zval **zvalue;
458 char *key = php_http_pretty_key(estrndup(name_str, name_len), name_len, 1, 1);
459
460 if (SUCCESS == zend_symtable_find(&headers, key, name_len + 1, (void *) &zvalue)) {
461 zval *zcopy = php_http_ztyp(IS_STRING, *zvalue);
462
463 val = estrndup(Z_STRVAL_P(zcopy), Z_STRLEN_P(zcopy));
464 zval_ptr_dtor(&zcopy);
465 }
466
467 efree(key);
468 }
469 zend_hash_destroy(&headers);
470
471 return val;
472 }
473
474 long php_http_env_get_response_code(TSRMLS_D)
475 {
476 long code = SG(sapi_headers).http_response_code;
477 return code ? code : 200;
478 }
479
480 STATUS php_http_env_set_response_code(long http_code TSRMLS_DC)
481 {
482 return sapi_header_op(SAPI_HEADER_SET_STATUS, (void *) http_code TSRMLS_CC);
483 }
484
485 STATUS php_http_env_set_response_status_line(long code, php_http_version_t *v TSRMLS_DC)
486 {
487 sapi_header_line h = {NULL, 0, 0};
488 STATUS ret;
489
490 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));
491 ret = sapi_header_op(SAPI_HEADER_REPLACE, (void *) &h TSRMLS_CC);
492 efree(h.line);
493
494 return ret;
495 }
496
497 STATUS php_http_env_set_response_protocol_version(php_http_version_t *v TSRMLS_DC)
498 {
499 return php_http_env_set_response_status_line(php_http_env_get_response_code(TSRMLS_C), v TSRMLS_CC);
500 }
501
502 STATUS php_http_env_set_response_header(long http_code, const char *header_str, size_t header_len, zend_bool replace TSRMLS_DC)
503 {
504 sapi_header_line h = {estrndup(header_str, header_len), header_len, http_code};
505 STATUS ret = sapi_header_op(replace ? SAPI_HEADER_REPLACE : SAPI_HEADER_ADD, (void *) &h TSRMLS_CC);
506 efree(h.line);
507 return ret;
508 }
509
510 STATUS php_http_env_set_response_header_va(long http_code, zend_bool replace, const char *fmt, va_list argv TSRMLS_DC)
511 {
512 STATUS ret = FAILURE;
513 sapi_header_line h = {NULL, 0, http_code};
514
515 h.line_len = vspprintf(&h.line, 0, fmt, argv);
516
517 if (h.line) {
518 if (h.line_len) {
519 ret = sapi_header_op(replace ? SAPI_HEADER_REPLACE : SAPI_HEADER_ADD, (void *) &h TSRMLS_CC);
520 }
521 efree(h.line);
522 }
523 return ret;
524 }
525
526 STATUS php_http_env_set_response_header_format(long http_code, zend_bool replace TSRMLS_DC, const char *fmt, ...)
527 {
528 STATUS ret;
529 va_list args;
530
531 va_start(args, fmt);
532 ret = php_http_env_set_response_header_va(http_code, replace, fmt, args TSRMLS_CC);
533 va_end(args);
534
535 return ret;
536 }
537
538 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)
539 {
540 if (!value) {
541 sapi_header_line h = {(char *) name_str, name_len, http_code};
542
543 return sapi_header_op(SAPI_HEADER_DELETE, (void *) &h TSRMLS_CC);
544 }
545
546 if(Z_TYPE_P(value) == IS_ARRAY || Z_TYPE_P(value) == IS_OBJECT) {
547 HashPosition pos;
548 int first = replace;
549 zval **data_ptr;
550
551 FOREACH_HASH_VAL(pos, HASH_OF(value), data_ptr) {
552 if (SUCCESS != php_http_env_set_response_header_value(http_code, name_str, name_len, *data_ptr, first TSRMLS_CC)) {
553 return FAILURE;
554 }
555 first = 0;
556 }
557
558 return SUCCESS;
559 } else {
560 zval *data = php_http_ztyp(IS_STRING, value);
561
562 if (!Z_STRLEN_P(data)) {
563 zval_ptr_dtor(&data);
564 return php_http_env_set_response_header_value(http_code, name_str, name_len, NULL, replace TSRMLS_CC);
565 } else {
566 sapi_header_line h;
567 STATUS ret;
568
569 if (name_len > INT_MAX) {
570 name_len = INT_MAX;
571 }
572 h.response_code = http_code;
573 h.line_len = spprintf(&h.line, 0, "%.*s: %.*s", (int) name_len, name_str, Z_STRLEN_P(data), Z_STRVAL_P(data));
574
575 ret = sapi_header_op(replace ? SAPI_HEADER_REPLACE : SAPI_HEADER_ADD, (void *) &h TSRMLS_CC);
576
577 zval_ptr_dtor(&data);
578 STR_FREE(h.line);
579
580 return ret;
581 }
582 }
583 }
584
585 static PHP_HTTP_STRLIST(php_http_env_response_status) =
586 PHP_HTTP_STRLIST_ITEM("Continue")
587 PHP_HTTP_STRLIST_ITEM("Switching Protocols")
588 PHP_HTTP_STRLIST_ITEM("Processing")
589 PHP_HTTP_STRLIST_NEXT
590 PHP_HTTP_STRLIST_ITEM("OK")
591 PHP_HTTP_STRLIST_ITEM("Created")
592 PHP_HTTP_STRLIST_ITEM("Accepted")
593 PHP_HTTP_STRLIST_ITEM("Non-Authoritative Information")
594 PHP_HTTP_STRLIST_ITEM("No Content")
595 PHP_HTTP_STRLIST_ITEM("Reset Content")
596 PHP_HTTP_STRLIST_ITEM("Partial Content")
597 PHP_HTTP_STRLIST_ITEM("Multi-Status")
598 PHP_HTTP_STRLIST_ITEM("Already Reported")
599 PHP_HTTP_STRLIST_ITEM("(Unused)")
600 PHP_HTTP_STRLIST_ITEM("(Unused)")
601 PHP_HTTP_STRLIST_ITEM("(Unused)")
602 PHP_HTTP_STRLIST_ITEM("(Unused)")
603 PHP_HTTP_STRLIST_ITEM("(Unused)")
604 PHP_HTTP_STRLIST_ITEM("(Unused)")
605 PHP_HTTP_STRLIST_ITEM("(Unused)")
606 PHP_HTTP_STRLIST_ITEM("(Unused)")
607 PHP_HTTP_STRLIST_ITEM("(Unused)")
608 PHP_HTTP_STRLIST_ITEM("(Unused)")
609 PHP_HTTP_STRLIST_ITEM("(Unused)")
610 PHP_HTTP_STRLIST_ITEM("(Unused)")
611 PHP_HTTP_STRLIST_ITEM("(Unused)")
612 PHP_HTTP_STRLIST_ITEM("(Unused)")
613 PHP_HTTP_STRLIST_ITEM("(Unused)")
614 PHP_HTTP_STRLIST_ITEM("(Unused)")
615 PHP_HTTP_STRLIST_ITEM("(Unused)")
616 PHP_HTTP_STRLIST_ITEM("IM Used")
617 PHP_HTTP_STRLIST_NEXT
618 PHP_HTTP_STRLIST_ITEM("Multiple Choices")
619 PHP_HTTP_STRLIST_ITEM("Moved Permanently")
620 PHP_HTTP_STRLIST_ITEM("Found")
621 PHP_HTTP_STRLIST_ITEM("See Other")
622 PHP_HTTP_STRLIST_ITEM("Not Modified")
623 PHP_HTTP_STRLIST_ITEM("Use Proxy")
624 PHP_HTTP_STRLIST_ITEM("(Unused)")
625 PHP_HTTP_STRLIST_ITEM("Temporary Redirect")
626 PHP_HTTP_STRLIST_ITEM("Permanent Redirect")
627 PHP_HTTP_STRLIST_NEXT
628 PHP_HTTP_STRLIST_ITEM("Bad Request")
629 PHP_HTTP_STRLIST_ITEM("Unauthorized")
630 PHP_HTTP_STRLIST_ITEM("Payment Required")
631 PHP_HTTP_STRLIST_ITEM("Forbidden")
632 PHP_HTTP_STRLIST_ITEM("Not Found")
633 PHP_HTTP_STRLIST_ITEM("Method Not Allowed")
634 PHP_HTTP_STRLIST_ITEM("Not Acceptable")
635 PHP_HTTP_STRLIST_ITEM("Proxy Authentication Required")
636 PHP_HTTP_STRLIST_ITEM("Request Timeout")
637 PHP_HTTP_STRLIST_ITEM("Conflict")
638 PHP_HTTP_STRLIST_ITEM("Gone")
639 PHP_HTTP_STRLIST_ITEM("Length Required")
640 PHP_HTTP_STRLIST_ITEM("Precondition Failed")
641 PHP_HTTP_STRLIST_ITEM("Request Entity Too Large")
642 PHP_HTTP_STRLIST_ITEM("Request URI Too Long")
643 PHP_HTTP_STRLIST_ITEM("Unsupported Media Type")
644 PHP_HTTP_STRLIST_ITEM("Requested Range Not Satisfiable")
645 PHP_HTTP_STRLIST_ITEM("Expectation Failed")
646 PHP_HTTP_STRLIST_ITEM("(Unused)")
647 PHP_HTTP_STRLIST_ITEM("(Unused)")
648 PHP_HTTP_STRLIST_ITEM("(Unused)")
649 PHP_HTTP_STRLIST_ITEM("(Unused)")
650 PHP_HTTP_STRLIST_ITEM("Unprocessible Entity")
651 PHP_HTTP_STRLIST_ITEM("Locked")
652 PHP_HTTP_STRLIST_ITEM("Failed Dependency")
653 PHP_HTTP_STRLIST_ITEM("(Reserved)")
654 PHP_HTTP_STRLIST_ITEM("Upgrade Required")
655 PHP_HTTP_STRLIST_ITEM("(Unused)")
656 PHP_HTTP_STRLIST_ITEM("Precondition Required")
657 PHP_HTTP_STRLIST_ITEM("Too Many Requests")
658 PHP_HTTP_STRLIST_ITEM("(Unused)")
659 PHP_HTTP_STRLIST_ITEM("Request Header Fields Too Large")
660 PHP_HTTP_STRLIST_NEXT
661 PHP_HTTP_STRLIST_ITEM("Internal Server Error")
662 PHP_HTTP_STRLIST_ITEM("Not Implemented")
663 PHP_HTTP_STRLIST_ITEM("Bad Gateway")
664 PHP_HTTP_STRLIST_ITEM("Service Unavailable")
665 PHP_HTTP_STRLIST_ITEM("Gateway Timeout")
666 PHP_HTTP_STRLIST_ITEM("HTTP Version Not Supported")
667 PHP_HTTP_STRLIST_ITEM("Variant Also Negotiates")
668 PHP_HTTP_STRLIST_ITEM("Insufficient Storage")
669 PHP_HTTP_STRLIST_ITEM("Loop Detected")
670 PHP_HTTP_STRLIST_ITEM("(Unused)")
671 PHP_HTTP_STRLIST_ITEM("Not Extended")
672 PHP_HTTP_STRLIST_ITEM("Network Authentication Required")
673 PHP_HTTP_STRLIST_STOP
674 ;
675
676 const char *php_http_env_get_response_status_for_code(unsigned code)
677 {
678 return php_http_strlist_find(php_http_env_response_status, 100, code);
679 }
680
681 ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_getRequestHeader, 0, 0, 0)
682 ZEND_ARG_INFO(0, header_name)
683 ZEND_END_ARG_INFO();
684 static PHP_METHOD(HttpEnv, getRequestHeader)
685 {
686 char *header_name_str = NULL;
687 int header_name_len = 0;
688
689 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!", &header_name_str, &header_name_len)) {
690 return;
691 }
692 if (header_name_str && header_name_len) {
693 size_t header_length;
694 char *header_value = php_http_env_get_request_header(header_name_str, header_name_len, &header_length, NULL TSRMLS_CC);
695
696 if (header_value) {
697 RETURN_STRINGL(header_value, header_length, 0);
698 }
699 } else {
700 array_init(return_value);
701 php_http_env_get_request_headers(Z_ARRVAL_P(return_value) TSRMLS_CC);
702 }
703 }
704
705 ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_getRequestBody, 0, 0, 0)
706 ZEND_ARG_INFO(0, body_class_name)
707 ZEND_END_ARG_INFO();
708 static PHP_METHOD(HttpEnv, getRequestBody)
709 {
710 zend_object_value ov;
711 php_http_message_body_t *body;
712 zend_class_entry *class_entry = php_http_message_body_class_entry;
713
714 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|C", &class_entry), invalid_arg, return);
715
716 body = php_http_env_get_request_body(TSRMLS_C);
717 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)) {
718 php_http_message_body_addref(body);
719 RETVAL_OBJVAL(ov, 0);
720 }
721 }
722
723 ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_getResponseStatusForCode, 0, 0, 1)
724 ZEND_ARG_INFO(0, code)
725 ZEND_END_ARG_INFO();
726 static PHP_METHOD(HttpEnv, getResponseStatusForCode)
727 {
728 long code;
729
730 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &code)) {
731 return;
732 }
733 RETURN_STRING(php_http_env_get_response_status_for_code(code), 1);
734 }
735
736 ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_getResponseStatusForAllCodes, 0, 0, 0)
737 ZEND_END_ARG_INFO();
738 static PHP_METHOD(HttpEnv, getResponseStatusForAllCodes)
739 {
740 const char *s;
741 unsigned c;
742 php_http_strlist_iterator_t i;
743
744 if (SUCCESS != zend_parse_parameters_none()) {
745 return;
746 }
747
748 array_init(return_value);
749 for ( php_http_strlist_iterator_init(&i, php_http_env_response_status, 100);
750 *(s = php_http_strlist_iterator_this(&i, &c));
751 php_http_strlist_iterator_next(&i)
752 ) {
753 add_index_string(return_value, c, s, 1);
754 }
755 }
756
757 ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_getResponseHeader, 0, 0, 0)
758 ZEND_ARG_INFO(0, header_name)
759 ZEND_END_ARG_INFO();
760 static PHP_METHOD(HttpEnv, getResponseHeader)
761 {
762 char *header_name_str = NULL;
763 int header_name_len = 0;
764
765 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!", &header_name_str, &header_name_len)) {
766 return;
767 }
768 if (header_name_str && header_name_len) {
769 char *header_value = php_http_env_get_response_header(header_name_str, header_name_len TSRMLS_CC);
770
771 if (header_value) {
772 RETURN_STRING(header_value, 0);
773 }
774 } else {
775 array_init(return_value);
776 php_http_env_get_response_headers(Z_ARRVAL_P(return_value) TSRMLS_CC);
777 }
778 }
779
780 ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_getResponseCode, 0, 0, 0)
781 ZEND_END_ARG_INFO();
782 static PHP_METHOD(HttpEnv, getResponseCode)
783 {
784 if (SUCCESS != zend_parse_parameters_none()) {
785 return;
786 }
787 RETURN_LONG(php_http_env_get_response_code(TSRMLS_C));
788 }
789
790 ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_setResponseHeader, 0, 0, 1)
791 ZEND_ARG_INFO(0, header_name)
792 ZEND_ARG_INFO(0, header_value)
793 ZEND_ARG_INFO(0, response_code)
794 ZEND_ARG_INFO(0, replace_header)
795 ZEND_END_ARG_INFO();
796 static PHP_METHOD(HttpEnv, setResponseHeader)
797 {
798 char *header_name_str;
799 int header_name_len;
800 zval *header_value = NULL;
801 long code = 0;
802 zend_bool replace_header = 1;
803
804 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z!lb", &header_name_str, &header_name_len, &header_value, &code, &replace_header)) {
805 return;
806 }
807 RETURN_BOOL(SUCCESS == php_http_env_set_response_header_value(code, header_name_str, header_name_len, header_value, replace_header TSRMLS_CC));
808 }
809
810 ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_setResponseCode, 0, 0, 1)
811 ZEND_ARG_INFO(0, code)
812 ZEND_END_ARG_INFO();
813 static PHP_METHOD(HttpEnv, setResponseCode)
814 {
815 long code;
816
817 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &code)) {
818 return;
819 }
820 RETURN_BOOL(SUCCESS == php_http_env_set_response_code(code TSRMLS_CC));
821 }
822
823 ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_negotiateLanguage, 0, 0, 1)
824 ZEND_ARG_INFO(0, supported)
825 ZEND_ARG_INFO(1, result_array)
826 ZEND_END_ARG_INFO();
827 static PHP_METHOD(HttpEnv, negotiateLanguage)
828 {
829 HashTable *supported;
830 zval *rs_array = NULL;
831
832 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "H|z", &supported, &rs_array)) {
833 return;
834 }
835 if (rs_array) {
836 zval_dtor(rs_array);
837 array_init(rs_array);
838 }
839
840 PHP_HTTP_DO_NEGOTIATE(language, supported, rs_array);
841 }
842
843 ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_negotiateCharset, 0, 0, 1)
844 ZEND_ARG_INFO(0, supported)
845 ZEND_ARG_INFO(1, result_array)
846 ZEND_END_ARG_INFO();
847 static PHP_METHOD(HttpEnv, negotiateCharset)
848 {
849 HashTable *supported;
850 zval *rs_array = NULL;
851
852 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "H|z", &supported, &rs_array)) {
853 return;
854 }
855 if (rs_array) {
856 zval_dtor(rs_array);
857 array_init(rs_array);
858 }
859 PHP_HTTP_DO_NEGOTIATE(charset, supported, rs_array);
860 }
861
862 ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_negotiateEncoding, 0, 0, 1)
863 ZEND_ARG_INFO(0, supported)
864 ZEND_ARG_INFO(1, result_array)
865 ZEND_END_ARG_INFO();
866 static PHP_METHOD(HttpEnv, negotiateEncoding)
867 {
868 HashTable *supported;
869 zval *rs_array = NULL;
870
871 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "H|z", &supported, &rs_array)) {
872 return;
873 }
874 if (rs_array) {
875 zval_dtor(rs_array);
876 array_init(rs_array);
877 }
878 PHP_HTTP_DO_NEGOTIATE(encoding, supported, rs_array);
879 }
880
881 ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_negotiateContentType, 0, 0, 1)
882 ZEND_ARG_INFO(0, supported)
883 ZEND_ARG_INFO(1, result_array)
884 ZEND_END_ARG_INFO();
885 static PHP_METHOD(HttpEnv, negotiateContentType)
886 {
887 HashTable *supported;
888 zval *rs_array = NULL;
889
890 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "H|z", &supported, &rs_array)) {
891 return;
892 }
893 if (rs_array) {
894 zval_dtor(rs_array);
895 array_init(rs_array);
896 }
897 PHP_HTTP_DO_NEGOTIATE(content_type, supported, rs_array);
898 }
899
900 ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_negotiate, 0, 0, 2)
901 ZEND_ARG_INFO(0, params)
902 ZEND_ARG_INFO(0, supported)
903 ZEND_ARG_INFO(0, primary_type_separator)
904 ZEND_ARG_INFO(1, result_array)
905 ZEND_END_ARG_INFO();
906 static PHP_METHOD(HttpEnv, negotiate)
907 {
908 HashTable *supported, *rs;
909 zval *rs_array = NULL;
910 char *value_str, *sep_str = NULL;
911 int value_len, sep_len = 0;
912
913 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sH|s!z", &value_str, &value_len, &supported, &sep_str, &sep_len, &rs_array)) {
914 return;
915 }
916
917
918 if (rs_array) {
919 zval_dtor(rs_array);
920 array_init(rs_array);
921 }
922
923 if ((rs = php_http_negotiate(value_str, value_len, supported, sep_str, sep_len TSRMLS_CC))) {
924 PHP_HTTP_DO_NEGOTIATE_HANDLE_RESULT(rs, supported, rs_array);
925 } else {
926 PHP_HTTP_DO_NEGOTIATE_HANDLE_DEFAULT(supported, rs_array);
927 }
928 }
929
930 static zend_function_entry php_http_env_methods[] = {
931 PHP_ME(HttpEnv, getRequestHeader, ai_HttpEnv_getRequestHeader, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
932 PHP_ME(HttpEnv, getRequestBody, ai_HttpEnv_getRequestBody, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
933
934 PHP_ME(HttpEnv, getResponseStatusForCode, ai_HttpEnv_getResponseStatusForCode, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
935 PHP_ME(HttpEnv, getResponseStatusForAllCodes, ai_HttpEnv_getResponseStatusForAllCodes, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
936
937 PHP_ME(HttpEnv, getResponseHeader, ai_HttpEnv_getResponseHeader, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
938 PHP_ME(HttpEnv, getResponseCode, ai_HttpEnv_getResponseCode, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
939 PHP_ME(HttpEnv, setResponseHeader, ai_HttpEnv_setResponseHeader, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
940 PHP_ME(HttpEnv, setResponseCode, ai_HttpEnv_setResponseCode, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
941
942 PHP_ME(HttpEnv, negotiateLanguage, ai_HttpEnv_negotiateLanguage, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
943 PHP_ME(HttpEnv, negotiateContentType, ai_HttpEnv_negotiateContentType, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
944 PHP_ME(HttpEnv, negotiateEncoding, ai_HttpEnv_negotiateEncoding, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
945 PHP_ME(HttpEnv, negotiateCharset, ai_HttpEnv_negotiateCharset, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
946 PHP_ME(HttpEnv, negotiate, ai_HttpEnv_negotiate, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
947
948 EMPTY_FUNCTION_ENTRY
949 };
950
951 #ifdef PHP_HTTP_HAVE_JSON
952 #include "ext/json/php_json.h"
953
954 static SAPI_POST_HANDLER_FUNC(php_http_json_post_handler)
955 {
956 zval *zarg = arg;
957 char *json_str = NULL;
958 size_t json_len = 0;
959
960 #if PHP_VERSION_ID >= 50600
961 if (SG(request_info).request_body) {
962 /* FG(stream_wrappers) not initialized yet, so we cannot use php://input */
963 php_stream_rewind(SG(request_info).request_body);
964 json_len = php_stream_copy_to_mem(SG(request_info).request_body, &json_str, PHP_STREAM_COPY_ALL, 0);
965 }
966 #else
967 json_str = SG(request_info).raw_post_data;
968 json_len = SG(request_info).raw_post_data_length;
969 #endif
970
971 if (json_len) {
972 zval zjson;
973
974 INIT_ZVAL(zjson);
975 php_json_decode(&zjson, json_str, json_len, 1, PG(max_input_nesting_level) TSRMLS_CC);
976 if (Z_TYPE(zjson) != IS_NULL) {
977 zval_dtor(zarg);
978 ZVAL_COPY_VALUE(zarg, (&zjson));
979 }
980 }
981 #if PHP_VERSION_ID >= 50600
982 STR_FREE(json_str);
983 #endif
984 }
985
986 static void php_http_env_register_json_handler(TSRMLS_D)
987 {
988 sapi_post_entry entry = {NULL, 0, NULL, NULL};
989
990 entry.post_reader = sapi_read_standard_form_data;
991 entry.post_handler = php_http_json_post_handler;
992
993 entry.content_type = "text/json";
994 entry.content_type_len = lenof("text/json");
995 sapi_register_post_entry(&entry TSRMLS_CC);
996
997 entry.content_type = "application/json";
998 entry.content_type_len = lenof("application/json");
999 sapi_register_post_entry(&entry TSRMLS_CC);
1000 }
1001 #endif
1002
1003 zend_class_entry *php_http_env_class_entry;
1004
1005 PHP_MINIT_FUNCTION(http_env)
1006 {
1007 zend_class_entry ce = {0};
1008
1009 INIT_NS_CLASS_ENTRY(ce, "http", "Env", php_http_env_methods);
1010 php_http_env_class_entry = zend_register_internal_class(&ce TSRMLS_CC);
1011
1012 #ifdef PHP_HTTP_HAVE_JSON
1013 php_http_env_register_json_handler(TSRMLS_C);
1014 #endif
1015
1016 return SUCCESS;
1017 }
1018
1019
1020 /*
1021 * Local variables:
1022 * tab-width: 4
1023 * c-basic-offset: 4
1024 * End:
1025 * vim600: noet sw=4 ts=4 fdm=marker
1026 * vim<600: noet sw=4 ts=4
1027 */