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