2 +--------------------------------------------------------------------+
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-2006, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
15 #define HTTP_WANT_SAPI
18 #include "php_output.h"
19 #include "ext/standard/url.h"
21 #include "php_http_api.h"
22 #include "php_http_send_api.h"
25 # include "php_http_exception_object.h"
28 PHP_MINIT_FUNCTION(http_support
)
30 HTTP_LONG_CONSTANT("HTTP_SUPPORT", HTTP_SUPPORT
);
31 HTTP_LONG_CONSTANT("HTTP_SUPPORT_REQUESTS", HTTP_SUPPORT_REQUESTS
);
32 HTTP_LONG_CONSTANT("HTTP_SUPPORT_MAGICMIME", HTTP_SUPPORT_MAGICMIME
);
33 HTTP_LONG_CONSTANT("HTTP_SUPPORT_ENCODINGS", HTTP_SUPPORT_ENCODINGS
);
34 HTTP_LONG_CONSTANT("HTTP_SUPPORT_SSLREQUESTS", HTTP_SUPPORT_SSLREQUESTS
);
36 HTTP_LONG_CONSTANT("HTTP_PARAMS_ALLOW_COMMA", HTTP_PARAMS_ALLOW_COMMA
);
37 HTTP_LONG_CONSTANT("HTTP_PARAMS_ALLOW_FAILURE", HTTP_PARAMS_ALLOW_FAILURE
);
38 HTTP_LONG_CONSTANT("HTTP_PARAMS_RAISE_ERROR", HTTP_PARAMS_RAISE_ERROR
);
39 HTTP_LONG_CONSTANT("HTTP_PARAMS_DEFAULT", HTTP_PARAMS_DEFAULT
);
44 PHP_HTTP_API
long _http_support(long feature
)
46 long support
= HTTP_SUPPORT
;
49 support
|= HTTP_SUPPORT_REQUESTS
;
51 support
|= HTTP_SUPPORT_SSLREQUESTS
;
54 #ifdef HTTP_HAVE_MAGIC
55 support
|= HTTP_SUPPORT_MAGICMIME
;
58 support
|= HTTP_SUPPORT_ENCODINGS
;
62 return (feature
== (support
& feature
));
67 /* char *pretty_key(char *, size_t, zend_bool, zend_bool) */
68 char *_http_pretty_key(char *key
, size_t key_len
, zend_bool uctitle
, zend_bool xhyphen
)
73 if ((wasalpha
= isalpha((int) key
[0]))) {
74 key
[0] = (char) (uctitle
? toupper((int) key
[0]) : tolower((int) key
[0]));
76 for (i
= 1; i
< key_len
; i
++) {
77 if (isalpha((int) key
[i
])) {
78 key
[i
] = (char) (((!wasalpha
) && uctitle
) ? toupper((int) key
[i
]) : tolower((int) key
[i
]));
81 if (xhyphen
&& (key
[i
] == '_')) {
92 /* {{{ void http_error(long, long, char*) */
93 void _http_error_ex(long type TSRMLS_DC
, long code
, const char *format
, ...)
97 va_start(args
, format
);
99 if ((type
== E_THROW
) || (PG(error_handling
) == EH_THROW
)) {
102 vspprintf(&message
, 0, format
, args
);
103 zend_throw_exception(http_exception_get_for_code(code
), message
, code TSRMLS_CC
);
107 php_verror(NULL
, "", type
, format
, args TSRMLS_CC
);
112 /* {{{ void http_log(char *, char *, char *) */
113 void _http_log_ex(char *file
, const char *ident
, const char *message TSRMLS_DC
)
117 char datetime
[20] = {0};
119 now
= HTTP_G
->request
.time
;
120 strftime(datetime
, sizeof(datetime
), "%Y-%m-%d %H:%M:%S", php_localtime_r(&now
, &nowtm
));
122 #define HTTP_LOG_WRITE(file, type, msg) \
123 if (file && *file) { \
124 php_stream *log = php_stream_open_wrapper_ex(file, "ab", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL, HTTP_DEFAULT_STREAM_CONTEXT); \
127 php_stream_printf(log TSRMLS_CC, "%s\t[%s]\t%s\t<%s>%s", datetime, type, msg, SG(request_info).request_uri, PHP_EOL); \
128 php_stream_close(log); \
133 HTTP_LOG_WRITE(file
, ident
, message
);
134 HTTP_LOG_WRITE(HTTP_G
->log
.composite
, ident
, message
);
138 static void http_ob_blackhole(char *output
, uint output_len
, char **handled_output
, uint
*handled_output_len
, int mode TSRMLS_DC
)
140 *handled_output
= ecalloc(1,1);
141 *handled_output_len
= 0;
144 /* {{{ STATUS http_exit(int, char*, char*) */
145 STATUS
_http_exit_ex(int status
, char *header
, char *body
, zend_bool send_header TSRMLS_DC
)
147 if ( (send_header
&& (SUCCESS
!= http_send_status_header(status
, header
))) ||
148 (!send_header
&& status
&& (SUCCESS
!= http_send_status(status
)))) {
149 http_error_ex(HE_WARNING
, HTTP_E_HEADER
, "Failed to exit with status/header: %d - %s", status
, header
? header
: "");
156 php_end_ob_buffers(0 TSRMLS_CC
);
158 if ((SUCCESS
== sapi_send_headers(TSRMLS_C
)) && body
) {
159 PHPWRITE(body
, strlen(body
));
163 case 301: http_log(HTTP_G
->log
.redirect
, "301-REDIRECT", header
); break;
164 case 302: http_log(HTTP_G
->log
.redirect
, "302-REDIRECT", header
); break;
165 case 303: http_log(HTTP_G
->log
.redirect
, "303-REDIRECT", header
); break;
166 case 305: http_log(HTTP_G
->log
.redirect
, "305-REDIRECT", header
); break;
167 case 307: http_log(HTTP_G
->log
.redirect
, "307-REDIRECT", header
); break;
168 case 304: http_log(HTTP_G
->log
.cache
, "304-CACHE", header
); break;
169 case 405: http_log(HTTP_G
->log
.allowed_methods
, "405-ALLOWED", header
); break;
170 default: http_log(NULL
, header
, body
); break;
176 if (HTTP_G
->force_exit
) {
179 php_ob_set_internal_handler(http_ob_blackhole
, 4096, "blackhole", 0 TSRMLS_CC
);
186 /* {{{ STATUS http_check_method(char *) */
187 STATUS
_http_check_method_ex(const char *method
, const char *methods
)
191 if ( (found
= strstr(methods
, method
)) &&
192 (found
== method
|| !isalpha(found
[-1])) &&
193 (strlen(found
) >= strlen(method
) && !isalpha(found
[strlen(method
)]))) {
200 /* {{{ zval *http_get_server_var_ex(char *, size_t) */
201 PHP_HTTP_API zval
*_http_get_server_var_ex(const char *key
, size_t key_size
, zend_bool check TSRMLS_DC
)
206 zend_is_auto_global("_SERVER", lenof("_SERVER") TSRMLS_CC
);
208 if ((SUCCESS
!= zend_hash_find(&EG(symbol_table
), "_SERVER", sizeof("_SERVER"), (void *) &hsv
)) || (Z_TYPE_PP(hsv
) != IS_ARRAY
)) {
211 if ((SUCCESS
!= zend_hash_find(Z_ARRVAL_PP(hsv
), (char *) key
, key_size
, (void *) &var
))) {
214 if (check
&& !((Z_TYPE_PP(var
) == IS_STRING
) && Z_STRVAL_PP(var
) && Z_STRLEN_PP(var
))) {
221 /* {{{ STATUS http_get_request_body(char **, size_t *) */
222 PHP_HTTP_API STATUS
_http_get_request_body_ex(char **body
, size_t *length
, zend_bool dup TSRMLS_DC
)
227 if (SG(request_info
).raw_post_data
) {
228 *length
= SG(request_info
).raw_post_data_length
;
229 *body
= SG(request_info
).raw_post_data
;
232 *body
= estrndup(*body
, *length
);
235 } else if (sapi_module
.read_post
&& !HTTP_G
->read_post_data
) {
239 HTTP_G
->read_post_data
= 1;
241 while (0 < (len
= sapi_module
.read_post(buf
, sizeof(buf
) TSRMLS_CC
))) {
242 *body
= erealloc(*body
, *length
+ len
+ 1);
243 memcpy(*body
+ *length
, buf
, len
);
245 (*body
)[*length
] = '\0';
248 /* check for error */
255 SG(request_info
).raw_post_data
= *body
;
256 SG(request_info
).raw_post_data_length
= *length
;
259 *body
= estrndup(*body
, *length
);
268 /* {{{ php_stream *http_get_request_body_stream(void) */
269 PHP_HTTP_API php_stream
*_http_get_request_body_stream(TSRMLS_D
)
271 php_stream
*s
= NULL
;
273 if (SG(request_info
).raw_post_data
) {
274 s
= php_stream_open_wrapper("php://input", "rb", 0, NULL
);
275 } else if (sapi_module
.read_post
&& !HTTP_G
->read_post_data
) {
276 HTTP_G
->read_post_data
= 1;
278 if ((s
= php_stream_temp_new())) {
282 while (0 < (len
= sapi_module
.read_post(buf
, sizeof(buf
) TSRMLS_CC
))) {
283 php_stream_write(s
, buf
, len
);
290 php_stream_rewind(s
);
299 /* {{{ void http_parse_params_default_callback(...) */
300 PHP_HTTP_API
void _http_parse_params_default_callback(void *arg
, const char *key
, int keylen
, const char *val
, int vallen TSRMLS_DC
)
304 HashTable
*ht
= (HashTable
*) arg
;
310 MAKE_STD_ZVAL(entry
);
312 kdup
= estrndup(key
, keylen
);
313 add_assoc_stringl_ex(entry
, kdup
, keylen
+ 1, (char *) val
, vallen
, 1);
315 add_next_index_zval(&tmp
, entry
);
317 add_next_index_stringl(&tmp
, (char *) key
, keylen
, 1);
323 /* {{{ STATUS http_parse_params(const char *, HashTable *) */
324 PHP_HTTP_API STATUS
_http_parse_params_ex(const char *param
, int flags
, http_parse_params_callback cb
, void *cb_arg TSRMLS_DC
)
332 int st
= ST_KEY
, keylen
= 0, vallen
= 0;
333 char *s
, *c
, *key
= NULL
, *val
= NULL
;
335 for(c
= s
= estrdup(param
);;) {
337 char *tk
= NULL
, *tv
= NULL
;
341 tk
= estrndup(key
, keylen
);
345 tk
[3]='.'; tk
[4]='.'; tk
[5]='.';
350 tv
= estrndup(val
, vallen
);
354 tv
[3]='.'; tv
[4]='.'; tv
[5]='.';
357 fprintf(stderr
, "[%6s] %c \"%s=%s\"\n",
359 st
== ST_QUOTE
? "QUOTE" :
360 st
== ST_VALUE
? "VALUE" :
361 st
== ST_KEY
? "KEY" :
362 st
== ST_ASSIGN
? "ASSIGN" :
363 st
== ST_ADD
? "ADD":
367 STR_FREE(tk
); STR_FREE(tv
);
374 if (*(c
-1) == '\\') {
375 memmove(c
-1, c
, strlen(c
)+1);
407 if (flags
& HTTP_PARAMS_ALLOW_COMMA
) {
421 if (flags
& HTTP_PARAMS_ALLOW_COMMA
) {
468 } else if (!*c
|| *c
== ';' || ((flags
& HTTP_PARAMS_ALLOW_COMMA
) && *c
== ',')) {
470 } else if (*c
!= ' ') {
479 if (st
!= ST_QUOTE
) {
480 while (val
[vallen
-1] == ' ') --vallen
;
487 cb(cb_arg
, key
, keylen
, val
, vallen TSRMLS_CC
);
496 } else if (st
== ST_ADD
) {
507 if (flags
& HTTP_PARAMS_RAISE_ERROR
) {
508 http_error_ex(HE_WARNING
, HTTP_E_INVALID_PARAM
, "Unexpected character (%c) at pos %tu of %zu", *c
, c
-s
, strlen(s
));
510 if (flags
& HTTP_PARAMS_ALLOW_FAILURE
) {
525 * vim600: noet sw=4 ts=4 fdm=marker
526 * vim<600: noet sw=4 ts=4