- fix inclusion of zlib.h
[m6w6/ext-http] / http_api.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-2005, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
11 */
12
13 /* $Id$ */
14
15 #ifdef HAVE_CONFIG_H
16 # include "config.h"
17 #endif
18
19 #include "php_http.h"
20
21 #include "SAPI.h"
22 #include "php_output.h"
23 #include "ext/standard/url.h"
24
25 #include "php_http_api.h"
26 #include "php_http_send_api.h"
27
28 #ifdef ZEND_ENGINE_2
29 # include "php_http_exception_object.h"
30 #endif
31
32 ZEND_EXTERN_MODULE_GLOBALS(http);
33
34 PHP_MINIT_FUNCTION(http_support)
35 {
36 HTTP_LONG_CONSTANT("HTTP_SUPPORT", HTTP_SUPPORT);
37 HTTP_LONG_CONSTANT("HTTP_SUPPORT_REQUESTS", HTTP_SUPPORT_REQUESTS);
38 HTTP_LONG_CONSTANT("HTTP_SUPPORT_MAGICMIME", HTTP_SUPPORT_MAGICMIME);
39 HTTP_LONG_CONSTANT("HTTP_SUPPORT_ENCODINGS", HTTP_SUPPORT_ENCODINGS);
40 HTTP_LONG_CONSTANT("HTTP_SUPPORT_SSLREQUESTS", HTTP_SUPPORT_SSLREQUESTS);
41
42 return SUCCESS;
43 }
44
45 PHP_HTTP_API long _http_support(long feature)
46 {
47 long support = HTTP_SUPPORT;
48
49 #ifdef HTTP_HAVE_CURL
50 support |= HTTP_SUPPORT_REQUESTS;
51 # ifdef HTTP_HAVE_SSL
52 support |= HTTP_SUPPORT_SSLREQUESTS;
53 # endif
54 #endif
55 #ifdef HTTP_HAVE_MAGIC
56 support |= HTTP_SUPPORT_MAGICMIME;
57 #endif
58 #if defined(HTTP_HAVE_ZLIB) || defined(HAVE_ZLIB)
59 support |= HTTP_SUPPORT_ENCODINGS;
60 #endif
61
62 if (feature) {
63 return (feature == (support & feature));
64 }
65 return support;
66 }
67
68 /* char *pretty_key(char *, size_t, zend_bool, zend_bool) */
69 char *_http_pretty_key(char *key, size_t key_len, zend_bool uctitle, zend_bool xhyphen)
70 {
71 if (key && key_len) {
72 size_t i;
73 int wasalpha;
74 if ((wasalpha = isalpha((int) key[0]))) {
75 key[0] = (char) (uctitle ? toupper((int) key[0]) : tolower((int) key[0]));
76 }
77 for (i = 1; i < key_len; i++) {
78 if (isalpha((int) key[i])) {
79 key[i] = (char) (((!wasalpha) && uctitle) ? toupper((int) key[i]) : tolower((int) key[i]));
80 wasalpha = 1;
81 } else {
82 if (xhyphen && (key[i] == '_')) {
83 key[i] = '-';
84 }
85 wasalpha = 0;
86 }
87 }
88 }
89 return key;
90 }
91 /* }}} */
92
93 /* {{{ */
94 void _http_key_list_default_decoder(const char *encoded, size_t encoded_len, char **decoded, size_t *decoded_len TSRMLS_DC)
95 {
96 *decoded = estrndup(encoded, encoded_len);
97 *decoded_len = (size_t) php_url_decode(*decoded, encoded_len);
98 }
99 /* }}} */
100
101 /* {{{ */
102 STATUS _http_parse_key_list(const char *list, HashTable *items, char separator, http_key_list_decode_t decode, zend_bool first_entry_is_name_value_pair TSRMLS_DC)
103 {
104 const char *key = list, *val = NULL;
105 int vallen = 0, keylen = 0, done = 0;
106 zval array;
107
108 INIT_ZARR(array, items);
109
110 if (!(val = strchr(list, '='))) {
111 return FAILURE;
112 }
113
114 #define HTTP_KEYLIST_VAL(array, k, str, len) \
115 { \
116 char *decoded; \
117 size_t decoded_len; \
118 if (decode) { \
119 decode(str, len, &decoded, &decoded_len TSRMLS_CC); \
120 } else { \
121 decoded_len = len; \
122 decoded = estrndup(str, decoded_len); \
123 } \
124 add_assoc_stringl(array, k, decoded, decoded_len, 0); \
125 }
126 #define HTTP_KEYLIST_FIXKEY() \
127 { \
128 while (isspace(*key)) ++key; \
129 keylen = val - key; \
130 while (isspace(key[keylen - 1])) --keylen; \
131 }
132 #define HTTP_KEYLIST_FIXVAL() \
133 { \
134 ++val; \
135 while (isspace(*val)) ++val; \
136 vallen = key - val; \
137 while (isspace(val[vallen - 1])) --vallen; \
138 }
139
140 HTTP_KEYLIST_FIXKEY();
141
142 if (first_entry_is_name_value_pair) {
143 HTTP_KEYLIST_VAL(&array, "name", key, keylen);
144
145 /* just one name=value */
146 if (!(key = strchr(val, separator))) {
147 key = val + strlen(val);
148 HTTP_KEYLIST_FIXVAL();
149 HTTP_KEYLIST_VAL(&array, "value", val, vallen);
150 return SUCCESS;
151 }
152 /* additional info appended */
153 else {
154 HTTP_KEYLIST_FIXVAL();
155 HTTP_KEYLIST_VAL(&array, "value", val, vallen);
156 }
157 }
158
159 do {
160 char *keydup = NULL;
161
162 if (!(val = strchr(key, '='))) {
163 break;
164 }
165
166 /* start at 0 if first_entry_is_name_value_pair==0 */
167 if (zend_hash_num_elements(items)) {
168 ++key;
169 }
170
171 HTTP_KEYLIST_FIXKEY();
172 keydup = estrndup(key, keylen);
173 if (!(key = strchr(val, separator))) {
174 done = 1;
175 key = val + strlen(val);
176 }
177 HTTP_KEYLIST_FIXVAL();
178 HTTP_KEYLIST_VAL(&array, keydup, val, vallen);
179 efree(keydup);
180 } while (!done);
181
182 return SUCCESS;
183 }
184 /* }}} */
185
186 /* {{{ void http_error(long, long, char*) */
187 void _http_error_ex(long type TSRMLS_DC, long code, const char *format, ...)
188 {
189 va_list args;
190
191 va_start(args, format);
192 #ifdef ZEND_ENGINE_2
193 if ((type == E_THROW) || (PG(error_handling) == EH_THROW)) {
194 char *message;
195
196 vspprintf(&message, 0, format, args);
197 zend_throw_exception(http_exception_get_for_code(code), message, code TSRMLS_CC);
198 efree(message);
199 } else
200 #endif
201 php_verror(NULL, "", type, format, args TSRMLS_CC);
202 va_end(args);
203 }
204 /* }}} */
205
206 /* {{{ void http_log(char *, char *, char *) */
207 void _http_log_ex(char *file, const char *ident, const char *message TSRMLS_DC)
208 {
209 time_t now;
210 struct tm nowtm;
211 char datetime[128];
212
213 HTTP_CHECK_OPEN_BASEDIR(file, return);
214
215 time(&now);
216 strftime(datetime, sizeof(datetime), "%Y-%m-%d %H:%M:%S", php_localtime_r(&now, &nowtm));
217
218 #define HTTP_LOG_WRITE(file, type, msg) \
219 if (file && *file) { \
220 php_stream *log = php_stream_open_wrapper(file, "ab", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL); \
221 \
222 if (log) { \
223 php_stream_printf(log TSRMLS_CC, "%s\t[%s]\t%s\t<%s>%s", datetime, type, msg, SG(request_info).request_uri, PHP_EOL); \
224 php_stream_close(log); \
225 } \
226 \
227 }
228
229 HTTP_LOG_WRITE(file, ident, message);
230 HTTP_LOG_WRITE(HTTP_G(log).composite, ident, message);
231 }
232 /* }}} */
233
234 static void http_ob_blackhole(char *output, uint output_len, char **handled_output, uint *handled_output_len, int mode TSRMLS_DC)
235 {
236 *handled_output = ecalloc(1,1);
237 *handled_output_len = 0;
238 }
239
240 /* {{{ STATUS http_exit(int, char*, char*) */
241 STATUS _http_exit_ex(int status, char *header, char *body, zend_bool send_header TSRMLS_DC)
242 {
243 if ( (send_header && (SUCCESS != http_send_status_header(status, header))) ||
244 (!send_header && status && (SUCCESS != http_send_status(status)))) {
245 http_error_ex(HE_WARNING, HTTP_E_HEADER, "Failed to exit with status/header: %d - %s", status, header ? header : "");
246 STR_FREE(header);
247 STR_FREE(body);
248 return FAILURE;
249 }
250
251 php_end_ob_buffers(0 TSRMLS_CC);
252 if ((SUCCESS == sapi_send_headers(TSRMLS_C)) && body) {
253 PHPWRITE(body, strlen(body));
254 }
255
256 switch (status)
257 {
258 case 301: http_log(HTTP_G(log).redirect, "301-REDIRECT", header); break;
259 case 302: http_log(HTTP_G(log).redirect, "302-REDIRECT", header); break;
260 case 303: http_log(HTTP_G(log).redirect, "303-REDIRECT", header); break;
261 case 307: http_log(HTTP_G(log).redirect, "307-REDIRECT", header); break;
262 case 304: http_log(HTTP_G(log).cache, "304-CACHE", header); break;
263 case 405: http_log(HTTP_G(log).allowed_methods, "405-ALLOWED", header); break;
264 default: http_log(NULL, header, body); break;
265 }
266
267 STR_FREE(header);
268 STR_FREE(body);
269
270 if (HTTP_G(force_exit)) {
271 zend_bailout();
272 } else {
273 php_ob_set_internal_handler(http_ob_blackhole, 4096, "blackhole", 0 TSRMLS_CC);
274 }
275
276 return SUCCESS;
277 }
278 /* }}} */
279
280 /* {{{ STATUS http_check_method(char *) */
281 STATUS _http_check_method_ex(const char *method, const char *methods)
282 {
283 const char *found;
284
285 if ( (found = strstr(methods, method)) &&
286 (found == method || !isalpha(found[-1])) &&
287 (strlen(found) >= strlen(method) && !isalpha(found[strlen(method)]))) {
288 return SUCCESS;
289 }
290 return FAILURE;
291 }
292 /* }}} */
293
294 /* {{{ zval *http_get_server_var_ex(char *, size_t) */
295 PHP_HTTP_API zval *_http_get_server_var_ex(const char *key, size_t key_size, zend_bool check TSRMLS_DC)
296 {
297 zval **hsv;
298 zval **var;
299
300 if ((SUCCESS != zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void **) &hsv)) || (Z_TYPE_PP(hsv) != IS_ARRAY)) {
301 return NULL;
302 }
303 if ((SUCCESS != zend_hash_find(Z_ARRVAL_PP(hsv), (char *) key, key_size, (void **) &var)) || (Z_TYPE_PP(var) != IS_STRING)) {
304 return NULL;
305 }
306 if (check && !(Z_STRVAL_PP(var) && Z_STRLEN_PP(var))) {
307 return NULL;
308 }
309 return *var;
310 }
311 /* }}} */
312
313 /* {{{ STATUS http_get_request_body(char **, size_t *) */
314 PHP_HTTP_API STATUS _http_get_request_body_ex(char **body, size_t *length, zend_bool dup TSRMLS_DC)
315 {
316 *length = 0;
317 *body = NULL;
318
319 if (SG(request_info).raw_post_data) {
320 *length = SG(request_info).raw_post_data_length;
321 *body = (char *) (dup ? estrndup(SG(request_info).raw_post_data, *length) : SG(request_info).raw_post_data);
322 return SUCCESS;
323 }
324 return FAILURE;
325 }
326 /* }}} */
327
328
329 /*
330 * Local variables:
331 * tab-width: 4
332 * c-basic-offset: 4
333 * End:
334 * vim600: noet sw=4 ts=4 fdm=marker
335 * vim<600: noet sw=4 ts=4
336 */
337