- add http_match_request_header()
[m6w6/ext-http] / http.c
1 /*
2 +----------------------------------------------------------------------+
3 | PECL :: http |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.0 of the PHP license, that |
6 | is bundled with this package in the file LICENSE, and is available |
7 | through the world-wide-web at http://www.php.net/license/3_0.txt. |
8 | If you did not receive a copy of the PHP license and are unable to |
9 | obtain it through the world-wide-web, please send a note to |
10 | license@php.net so we can mail you a copy immediately. |
11 +----------------------------------------------------------------------+
12 | Copyright (c) 2004-2005 Michael Wallner <mike@php.net> |
13 +----------------------------------------------------------------------+
14 */
15
16 /* $Id$ */
17
18
19 #ifdef HAVE_CONFIG_H
20 # include "config.h"
21 #endif
22
23 #ifdef HTTP_HAVE_CURL
24 # ifdef PHP_WIN32
25 # include <winsock2.h>
26 # endif
27 # include <curl/curl.h>
28 #endif
29
30 #include <ctype.h>
31
32 #include "php.h"
33 #include "php_ini.h"
34 #include "ext/standard/info.h"
35
36 #include "SAPI.h"
37
38 #include "php_http.h"
39 #include "php_http_std_defs.h"
40 #include "php_http_api.h"
41 #include "php_http_send_api.h"
42
43 #ifdef ZEND_ENGINE_2
44 # include "php_http_util_object.h"
45 # include "php_http_message_object.h"
46 # include "php_http_response_object.h"
47 # ifdef HTTP_HAVE_CURL
48 # include "php_http_request_object.h"
49 # endif
50 # include "php_http_exception_object.h"
51 #endif
52
53 #include "phpstr/phpstr.h"
54
55 #ifdef HTTP_HAVE_CURL
56 #ifdef ZEND_ENGINE_2
57 static
58 ZEND_BEGIN_ARG_INFO(http_request_info_ref_3, 0)
59 ZEND_ARG_PASS_INFO(0)
60 ZEND_ARG_PASS_INFO(0)
61 ZEND_ARG_PASS_INFO(1)
62 ZEND_END_ARG_INFO();
63
64 static
65 ZEND_BEGIN_ARG_INFO(http_request_info_ref_4, 0)
66 ZEND_ARG_PASS_INFO(0)
67 ZEND_ARG_PASS_INFO(0)
68 ZEND_ARG_PASS_INFO(0)
69 ZEND_ARG_PASS_INFO(1)
70 ZEND_END_ARG_INFO();
71
72 static
73 ZEND_BEGIN_ARG_INFO(http_request_info_ref_5, 0)
74 ZEND_ARG_PASS_INFO(0)
75 ZEND_ARG_PASS_INFO(0)
76 ZEND_ARG_PASS_INFO(0)
77 ZEND_ARG_PASS_INFO(0)
78 ZEND_ARG_PASS_INFO(1)
79 ZEND_END_ARG_INFO();
80 #else
81 static unsigned char http_request_info_ref_3[] = {3, BYREF_NONE, BYREF_NONE, BYREF_FORCE};
82 static unsigned char http_request_info_ref_4[] = {4, BYREF_NONE, BYREF_NONE, BYREF_NONE, BYREF_FORCE};
83 static unsigned char http_request_info_ref_5[] = {5, BYREF_NONE, BYREF_NONE, BYREF_NONE, BYREF_NONE, BYREF_FORCE};
84 #endif /* ZEND_ENGINE_2 */
85 #endif /* HTTP_HAVE_CURL */
86
87 ZEND_DECLARE_MODULE_GLOBALS(http)
88
89 #ifdef COMPILE_DL_HTTP
90 ZEND_GET_MODULE(http)
91 #endif
92
93 /* {{{ http_functions[] */
94 function_entry http_functions[] = {
95 PHP_FE(http_test, NULL)
96 PHP_FE(http_date, NULL)
97 PHP_FE(http_absolute_uri, NULL)
98 PHP_FE(http_negotiate_language, NULL)
99 PHP_FE(http_negotiate_charset, NULL)
100 PHP_FE(http_redirect, NULL)
101 PHP_FE(http_throttle, NULL)
102 PHP_FE(http_send_status, NULL)
103 PHP_FE(http_send_last_modified, NULL)
104 PHP_FE(http_send_content_type, NULL)
105 PHP_FE(http_send_content_disposition, NULL)
106 PHP_FE(http_match_modified, NULL)
107 PHP_FE(http_match_etag, NULL)
108 PHP_FE(http_cache_last_modified, NULL)
109 PHP_FE(http_cache_etag, NULL)
110 PHP_FE(http_send_data, NULL)
111 PHP_FE(http_send_file, NULL)
112 PHP_FE(http_send_stream, NULL)
113 PHP_FE(http_chunked_decode, NULL)
114 PHP_FE(http_split_response, NULL)
115 PHP_FE(http_parse_headers, NULL)
116 PHP_FE(http_get_request_headers, NULL)
117 PHP_FE(http_match_request_header, NULL)
118 #ifdef HTTP_HAVE_CURL
119 PHP_FE(http_get, http_request_info_ref_3)
120 PHP_FE(http_head, http_request_info_ref_3)
121 PHP_FE(http_post_data, http_request_info_ref_4)
122 PHP_FE(http_post_fields, http_request_info_ref_5)
123 PHP_FE(http_put_file, http_request_info_ref_4)
124 PHP_FE(http_put_stream, http_request_info_ref_4)
125 PHP_FE(http_request_method_register, NULL)
126 PHP_FE(http_request_method_unregister, NULL)
127 PHP_FE(http_request_method_exists, NULL)
128 PHP_FE(http_request_method_name, NULL)
129 #endif
130 PHP_FE(http_auth_basic, NULL)
131 PHP_FE(http_auth_basic_cb, NULL)
132 #ifndef ZEND_ENGINE_2
133 PHP_FE(http_build_query, NULL)
134 #endif
135 PHP_FE(ob_etaghandler, NULL)
136 {NULL, NULL, NULL}
137 };
138 /* }}} */
139
140 /* {{{ http_module_entry */
141 zend_module_entry http_module_entry = {
142 #if ZEND_MODULE_API_NO >= 20010901
143 STANDARD_MODULE_HEADER,
144 #endif
145 "http",
146 http_functions,
147 PHP_MINIT(http),
148 PHP_MSHUTDOWN(http),
149 PHP_RINIT(http),
150 PHP_RSHUTDOWN(http),
151 PHP_MINFO(http),
152 #if ZEND_MODULE_API_NO >= 20010901
153 HTTP_PEXT_VERSION,
154 #endif
155 STANDARD_MODULE_PROPERTIES
156 };
157 /* }}} */
158
159 int http_module_number;
160
161 #ifdef HTTP_HAVE_CURL
162 # ifdef HTTP_CURL_USE_ZEND_MM
163 static void http_curl_free(void *p) { efree(p); }
164 static char *http_curl_strdup(const char *p) { return estrdup(p); }
165 static void *http_curl_malloc(size_t s) { return emalloc(s); }
166 static void *http_curl_realloc(void *p, size_t s) { return erealloc(p, s); }
167 static void *http_curl_calloc(size_t n, size_t s) { return ecalloc(n, s); }
168 # endif /* HTTP_CURL_USE_ZEND_MM */
169 static void http_curl_freestr(void *s) { efree(*(char **)s); }
170 #endif /* HTTP_HAVE_CURL */
171
172 /* {{{ http_globals */
173 static inline void http_globals_init(zend_http_globals *G)
174 {
175 memset(G, 0, sizeof(zend_http_globals));
176 G->send.buffer_size = HTTP_SENDBUF_SIZE;
177 zend_hash_init(&G->request.methods.custom, 0, NULL, ZVAL_PTR_DTOR, 0);
178 #ifdef HTTP_HAVE_CURL
179 zend_llist_init(&G->request.curl.copies, sizeof(char *), http_curl_freestr, 0);
180 #endif
181 }
182 static inline void http_globals_free(zend_http_globals *G)
183 {
184 STR_FREE(G->send.content_type);
185 STR_FREE(G->send.unquoted_etag);
186 zend_hash_destroy(&G->request.methods.custom);
187 }
188 /* }}} */
189
190 /* {{{ static inline void http_check_allowed_methods(char *, int) */
191 #define http_check_allowed_methods(m, l) _http_check_allowed_methods((m), (l) TSRMLS_CC)
192 static inline void _http_check_allowed_methods(char *methods, int length TSRMLS_DC)
193 {
194 if (length && SG(request_info).request_method) {
195 if (SUCCESS != http_check_method_ex(SG(request_info).request_method, methods)) {
196 char *header = emalloc(length + sizeof("Allow: "));
197 sprintf(header, "Allow: %s", methods);
198 http_exit(405, header);
199 }
200 }
201 }
202 /* }}} */
203
204 /* {{{ PHP_INI */
205 PHP_INI_MH(http_update_allowed_methods)
206 {
207 http_check_allowed_methods(new_value, new_value_length);
208 return OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
209 }
210
211 PHP_INI_BEGIN()
212 HTTP_PHP_INI_ENTRY("http.allowed_methods", NULL, PHP_INI_ALL, http_update_allowed_methods, request.methods.allowed)
213 HTTP_PHP_INI_ENTRY("http.cache_log", NULL, PHP_INI_ALL, OnUpdateString, log.cache)
214 PHP_INI_END()
215 /* }}} */
216
217
218 /* {{{ PHP_MINIT_FUNCTION */
219 PHP_MINIT_FUNCTION(http)
220 {
221 http_module_number = module_number;
222
223 ZEND_INIT_MODULE_GLOBALS(http, NULL, NULL);
224 REGISTER_INI_ENTRIES();
225
226 #ifdef HTTP_HAVE_CURL
227 # ifdef HTTP_CURL_USE_ZEND_MM
228 if (CURLE_OK != curl_global_init_mem(CURL_GLOBAL_ALL,
229 http_curl_malloc,
230 http_curl_free,
231 http_curl_realloc,
232 http_curl_strdup,
233 http_curl_calloc)) {
234 return FAILURE;
235 }
236 # endif /* HTTP_CURL_USE_ZEND_MM */
237 #endif /* HTTP_HAVE_CURL */
238
239 #ifdef ZEND_ENGINE_2
240 http_util_object_init();
241 http_message_object_init();
242 http_response_object_init();
243 # ifdef HTTP_HAVE_CURL
244 http_request_object_init();
245 # endif /* HTTP_HAVE_CURL */
246 http_exception_object_init();
247 #endif /* ZEND_ENGINE_2 */
248
249 return SUCCESS;
250 }
251 /* }}} */
252
253 /* {{{ PHP_MSHUTDOWN_FUNCTION */
254 PHP_MSHUTDOWN_FUNCTION(http)
255 {
256 UNREGISTER_INI_ENTRIES();
257 #ifdef HTTP_HAVE_CURL
258 curl_global_cleanup();
259 #endif
260 return SUCCESS;
261 }
262 /* }}} */
263
264 /* {{{ PHP_RINIT_FUNCTION */
265 PHP_RINIT_FUNCTION(http)
266 {
267 char *m;
268
269 if (m = INI_STR("http.allowed_methods")) {
270 http_check_allowed_methods(m, strlen(m));
271 }
272
273 http_globals_init(HTTP_GLOBALS);
274 return SUCCESS;
275 }
276 /* }}} */
277
278 /* {{{ PHP_RSHUTDOWN_FUNCTION */
279 PHP_RSHUTDOWN_FUNCTION(http)
280 {
281 http_globals_free(HTTP_GLOBALS);
282 return SUCCESS;
283 }
284 /* }}} */
285
286 /* {{{ PHP_MINFO_FUNCTION */
287 PHP_MINFO_FUNCTION(http)
288 {
289 #ifdef ZEND_ENGINE_2
290 # define HTTP_FUNC_AVAIL(CLASS) "procedural, object oriented (" CLASS ")"
291 #else
292 # define HTTP_FUNC_AVAIL(CLASS) "procedural"
293 #endif
294
295 #ifdef HTTP_HAVE_CURL
296 # define HTTP_CURL_VERSION curl_version()
297 # ifdef ZEND_ENGINE_2
298 # define HTTP_CURL_AVAIL(CLASS) "procedural, object oriented (" CLASS ")"
299 # else
300 # define HTTP_CURL_AVAIL(CLASS) "procedural"
301 # endif
302 #else
303 # define HTTP_CURL_VERSION "libcurl not available"
304 # define HTTP_CURL_AVAIL(CLASS) "libcurl not available"
305 #endif
306
307 #include "php_http_request_api.h"
308
309 php_info_print_table_start();
310 {
311 char full_version_string[1024] = {0};
312 snprintf(full_version_string, 1023, "%s (%s)", HTTP_PEXT_VERSION, HTTP_CURL_VERSION);
313
314 php_info_print_table_row(2, "Extended HTTP support:", "enabled");
315 php_info_print_table_row(2, "Extension Version:", full_version_string);
316 }
317 php_info_print_table_end();
318
319 php_info_print_table_start();
320 {
321 unsigned i;
322 zval **custom_method;
323 phpstr *known_request_methods = phpstr_new();
324 phpstr *custom_request_methods = phpstr_new();
325
326 for (i = HTTP_NO_REQUEST_METHOD+1; i < HTTP_MAX_REQUEST_METHOD; ++i) {
327 phpstr_appendl(known_request_methods, http_request_method_name(i));
328 phpstr_appends(known_request_methods, ", ");
329 }
330 FOREACH_HASH_VAL(&HTTP_G(request).methods.custom, custom_method) {
331 phpstr_append(custom_request_methods, Z_STRVAL_PP(custom_method), Z_STRLEN_PP(custom_method));
332 phpstr_appends(custom_request_methods, ", ");
333 }
334
335 phpstr_append(known_request_methods, PHPSTR_VAL(custom_request_methods), PHPSTR_LEN(custom_request_methods));
336 phpstr_fix(known_request_methods);
337 phpstr_fix(custom_request_methods);
338
339 php_info_print_table_row(2, "Known Request Methods:", PHPSTR_VAL(known_request_methods));
340 php_info_print_table_row(2, "Custom Request Methods:",
341 PHPSTR_LEN(custom_request_methods) ? PHPSTR_VAL(custom_request_methods) : "none registered");
342
343 phpstr_free(known_request_methods);
344 phpstr_free(custom_request_methods);
345 }
346 php_info_print_table_end();
347
348 php_info_print_table_start();
349 {
350 php_info_print_table_header(2, "Functionality", "Availability");
351 php_info_print_table_row(2, "Miscellaneous Utilities:", HTTP_FUNC_AVAIL("HttpUtil, HttpMessage"));
352 php_info_print_table_row(2, "Extended HTTP Responses:", HTTP_FUNC_AVAIL("HttpResponse"));
353 php_info_print_table_row(2, "Extended HTTP Requests:", HTTP_CURL_AVAIL("HttpRequest"));
354 }
355 php_info_print_table_end();
356
357 DISPLAY_INI_ENTRIES();
358 }
359 /* }}} */
360
361 /*
362 * Local variables:
363 * tab-width: 4
364 * c-basic-offset: 4
365 * End:
366 * vim600: noet sw=4 ts=4 fdm=marker
367 * vim<600: noet sw=4 ts=4
368 */
369