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