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