reset response headers, write_queue for error docs
[lighttpd.git] / src / plugin.c
blob7802aa568f2435c31ea49f6fa6fc11dade5c2509
1 #include "first.h"
3 #include "plugin.h"
4 #include "log.h"
6 #include <string.h>
7 #include <stdlib.h>
9 #include <stdio.h>
11 #ifdef HAVE_VALGRIND_VALGRIND_H
12 # include <valgrind/valgrind.h>
13 #endif
15 #if !defined(__WIN32) && !defined(LIGHTTPD_STATIC)
16 # include <dlfcn.h>
17 #endif
20 * if you change this enum to add a new callback, be sure
21 * - that PLUGIN_FUNC_SIZEOF is the last entry
22 * - that you add PLUGIN_TO_SLOT twice:
23 * 1. as callback-dispatcher
24 * 2. in plugins_call_init()
28 typedef struct {
29 PLUGIN_DATA;
30 } plugin_data;
32 typedef enum {
33 PLUGIN_FUNC_UNSET,
35 PLUGIN_FUNC_HANDLE_URI_CLEAN,
36 PLUGIN_FUNC_HANDLE_URI_RAW,
37 PLUGIN_FUNC_HANDLE_REQUEST_DONE,
38 PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE,
39 PLUGIN_FUNC_HANDLE_TRIGGER,
40 PLUGIN_FUNC_HANDLE_SIGHUP,
41 PLUGIN_FUNC_HANDLE_SUBREQUEST,
42 PLUGIN_FUNC_HANDLE_SUBREQUEST_START,
43 PLUGIN_FUNC_HANDLE_DOCROOT,
44 PLUGIN_FUNC_HANDLE_PHYSICAL,
45 PLUGIN_FUNC_CONNECTION_RESET,
46 PLUGIN_FUNC_INIT,
47 PLUGIN_FUNC_CLEANUP,
48 PLUGIN_FUNC_SET_DEFAULTS,
50 PLUGIN_FUNC_SIZEOF
51 } plugin_t;
53 static plugin *plugin_init(void) {
54 plugin *p;
56 p = calloc(1, sizeof(*p));
57 force_assert(NULL != p);
59 return p;
62 static void plugin_free(plugin *p) {
63 #if !defined(LIGHTTPD_STATIC)
64 int use_dlclose = 1;
65 #endif
67 if (p->name) buffer_free(p->name);
68 #if defined(HAVE_VALGRIND_VALGRIND_H) && !defined(LIGHTTPD_STATIC)
69 /*if (RUNNING_ON_VALGRIND) use_dlclose = 0;*/
70 #endif
72 #if !defined(LIGHTTPD_STATIC)
73 if (use_dlclose && p->lib) {
74 #if defined(__WIN32)
75 ) FreeLibrary(p->lib);
76 #else
77 dlclose(p->lib);
78 #endif
80 #endif
82 free(p);
85 static int plugins_register(server *srv, plugin *p) {
86 plugin **ps;
87 if (0 == srv->plugins.size) {
88 srv->plugins.size = 4;
89 srv->plugins.ptr = malloc(srv->plugins.size * sizeof(*ps));
90 force_assert(NULL != srv->plugins.ptr);
91 srv->plugins.used = 0;
92 } else if (srv->plugins.used == srv->plugins.size) {
93 srv->plugins.size += 4;
94 srv->plugins.ptr = realloc(srv->plugins.ptr, srv->plugins.size * sizeof(*ps));
95 force_assert(NULL != srv->plugins.ptr);
98 ps = srv->plugins.ptr;
99 ps[srv->plugins.used++] = p;
101 return 0;
110 #if defined(LIGHTTPD_STATIC)
112 /* pre-declare functions, as there is no header for them */
113 #define PLUGIN_INIT(x)\
114 int x ## _plugin_init(plugin *p);
116 #include "plugin-static.h"
118 #undef PLUGIN_INIT
120 /* build NULL-terminated table of name + init-function */
122 typedef struct {
123 const char* name;
124 int (*plugin_init)(plugin *p);
125 } plugin_load_functions;
127 static const plugin_load_functions load_functions[] = {
128 #define PLUGIN_INIT(x) \
129 { #x, &x ## _plugin_init },
131 #include "plugin-static.h"
133 { NULL, NULL }
134 #undef PLUGIN_INIT
137 int plugins_load(server *srv) {
138 plugin *p;
139 size_t i, j;
141 for (i = 0; i < srv->srvconf.modules->used; i++) {
142 data_string *d = (data_string *)srv->srvconf.modules->data[i];
143 char *module = d->value->ptr;
145 for (j = 0; j < i; j++) {
146 if (buffer_is_equal(d->value, ((data_string *) srv->srvconf.modules->data[j])->value)) {
147 log_error_write(srv, __FILE__, __LINE__, "sbs",
148 "Cannot load plugin", d->value,
149 "more than once, please fix your config (lighttpd may not accept such configs in future releases)");
150 continue;
154 for (j = 0; load_functions[j].name; ++j) {
155 if (0 == strcmp(load_functions[j].name, module)) {
156 p = plugin_init();
157 if ((*load_functions[j].plugin_init)(p)) {
158 log_error_write(srv, __FILE__, __LINE__, "ss", module, "plugin init failed" );
159 plugin_free(p);
160 return -1;
162 plugins_register(srv, p);
163 break;
166 if (!load_functions[j].name) {
167 log_error_write(srv, __FILE__, __LINE__, "ss", module, " plugin not found" );
168 return -1;
172 return 0;
174 #else /* defined(LIGHTTPD_STATIC) */
175 int plugins_load(server *srv) {
176 plugin *p;
177 int (*init)(plugin *pl);
178 const char *error;
179 size_t i, j;
181 for (i = 0; i < srv->srvconf.modules->used; i++) {
182 data_string *d = (data_string *)srv->srvconf.modules->data[i];
183 char *module = d->value->ptr;
185 for (j = 0; j < i; j++) {
186 if (buffer_is_equal(d->value, ((data_string *) srv->srvconf.modules->data[j])->value)) {
187 log_error_write(srv, __FILE__, __LINE__, "sbs",
188 "Cannot load plugin", d->value,
189 "more than once, please fix your config (lighttpd may not accept such configs in future releases)");
190 continue;
194 buffer_copy_buffer(srv->tmp_buf, srv->srvconf.modules_dir);
196 buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("/"));
197 buffer_append_string(srv->tmp_buf, module);
198 #if defined(__WIN32) || defined(__CYGWIN__)
199 buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN(".dll"));
200 #else
201 buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN(".so"));
202 #endif
204 p = plugin_init();
205 #ifdef __WIN32
206 if (NULL == (p->lib = LoadLibrary(srv->tmp_buf->ptr))) {
207 LPVOID lpMsgBuf;
208 FormatMessage(
209 FORMAT_MESSAGE_ALLOCATE_BUFFER |
210 FORMAT_MESSAGE_FROM_SYSTEM,
211 NULL,
212 GetLastError(),
213 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
214 (LPTSTR) &lpMsgBuf,
215 0, NULL);
217 log_error_write(srv, __FILE__, __LINE__, "ssb", "LoadLibrary() failed",
218 lpMsgBuf, srv->tmp_buf);
220 plugin_free(p);
222 return -1;
225 #else
226 if (NULL == (p->lib = dlopen(srv->tmp_buf->ptr, RTLD_NOW|RTLD_GLOBAL))) {
227 log_error_write(srv, __FILE__, __LINE__, "sbs", "dlopen() failed for:",
228 srv->tmp_buf, dlerror());
230 plugin_free(p);
232 return -1;
235 #endif
236 buffer_reset(srv->tmp_buf);
237 buffer_copy_string(srv->tmp_buf, module);
238 buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("_plugin_init"));
240 #ifdef __WIN32
241 init = GetProcAddress(p->lib, srv->tmp_buf->ptr);
243 if (init == NULL) {
244 LPVOID lpMsgBuf;
245 FormatMessage(
246 FORMAT_MESSAGE_ALLOCATE_BUFFER |
247 FORMAT_MESSAGE_FROM_SYSTEM,
248 NULL,
249 GetLastError(),
250 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
251 (LPTSTR) &lpMsgBuf,
252 0, NULL);
254 log_error_write(srv, __FILE__, __LINE__, "sbs", "getprocaddress failed:", srv->tmp_buf, lpMsgBuf);
256 plugin_free(p);
257 return -1;
260 #else
261 #if 1
262 init = (int (*)(plugin *))(intptr_t)dlsym(p->lib, srv->tmp_buf->ptr);
263 #else
264 *(void **)(&init) = dlsym(p->lib, srv->tmp_buf->ptr);
265 #endif
266 if ((error = dlerror()) != NULL) {
267 log_error_write(srv, __FILE__, __LINE__, "s", error);
269 plugin_free(p);
270 return -1;
273 #endif
274 if ((*init)(p)) {
275 log_error_write(srv, __FILE__, __LINE__, "ss", module, "plugin init failed" );
277 plugin_free(p);
278 return -1;
280 #if 0
281 log_error_write(srv, __FILE__, __LINE__, "ss", module, "plugin loaded" );
282 #endif
283 plugins_register(srv, p);
286 return 0;
288 #endif /* defined(LIGHTTPD_STATIC) */
290 #define PLUGIN_TO_SLOT(x, y) \
291 handler_t plugins_call_##y(server *srv, connection *con) {\
292 plugin **slot;\
293 size_t j;\
294 if (!srv->plugin_slots) return HANDLER_GO_ON;\
295 slot = ((plugin ***)(srv->plugin_slots))[x];\
296 if (!slot) return HANDLER_GO_ON;\
297 for (j = 0; j < srv->plugins.used && slot[j]; j++) { \
298 plugin *p = slot[j];\
299 handler_t r;\
300 switch(r = p->y(srv, con, p->data)) {\
301 case HANDLER_GO_ON:\
302 break;\
303 case HANDLER_FINISHED:\
304 case HANDLER_COMEBACK:\
305 case HANDLER_WAIT_FOR_EVENT:\
306 case HANDLER_WAIT_FOR_FD:\
307 case HANDLER_ERROR:\
308 return r;\
309 default:\
310 log_error_write(srv, __FILE__, __LINE__, "sbs", #x, p->name, "unknown state");\
311 return HANDLER_ERROR;\
314 return HANDLER_GO_ON;\
318 * plugins that use
320 * - server *srv
321 * - connection *con
322 * - void *p_d (plugin_data *)
325 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean)
326 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw)
327 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_DONE, handle_request_done)
328 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close)
329 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST, handle_subrequest)
330 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST_START, handle_subrequest_start)
331 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_DOCROOT, handle_docroot)
332 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_PHYSICAL, handle_physical)
333 PLUGIN_TO_SLOT(PLUGIN_FUNC_CONNECTION_RESET, connection_reset)
335 #undef PLUGIN_TO_SLOT
337 #define PLUGIN_TO_SLOT(x, y) \
338 handler_t plugins_call_##y(server *srv) {\
339 plugin **slot;\
340 size_t j;\
341 if (!srv->plugin_slots) return HANDLER_GO_ON;\
342 slot = ((plugin ***)(srv->plugin_slots))[x];\
343 if (!slot) return HANDLER_GO_ON;\
344 for (j = 0; j < srv->plugins.used && slot[j]; j++) { \
345 plugin *p = slot[j];\
346 handler_t r;\
347 switch(r = p->y(srv, p->data)) {\
348 case HANDLER_GO_ON:\
349 break;\
350 case HANDLER_FINISHED:\
351 case HANDLER_COMEBACK:\
352 case HANDLER_WAIT_FOR_EVENT:\
353 case HANDLER_WAIT_FOR_FD:\
354 case HANDLER_ERROR:\
355 return r;\
356 default:\
357 log_error_write(srv, __FILE__, __LINE__, "sbsd", #x, p->name, "unknown state:", r);\
358 return HANDLER_ERROR;\
361 return HANDLER_GO_ON;\
365 * plugins that use
367 * - server *srv
368 * - void *p_d (plugin_data *)
371 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger)
372 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SIGHUP, handle_sighup)
373 PLUGIN_TO_SLOT(PLUGIN_FUNC_CLEANUP, cleanup)
374 PLUGIN_TO_SLOT(PLUGIN_FUNC_SET_DEFAULTS, set_defaults)
376 #undef PLUGIN_TO_SLOT
378 #if 0
381 * special handler
384 handler_t plugins_call_handle_fdevent(server *srv, const fd_conn *fdc) {
385 size_t i;
386 plugin **ps;
388 ps = srv->plugins.ptr;
390 for (i = 0; i < srv->plugins.used; i++) {
391 plugin *p = ps[i];
392 if (p->handle_fdevent) {
393 handler_t r;
394 switch(r = p->handle_fdevent(srv, fdc, p->data)) {
395 case HANDLER_GO_ON:
396 break;
397 case HANDLER_FINISHED:
398 case HANDLER_COMEBACK:
399 case HANDLER_WAIT_FOR_EVENT:
400 case HANDLER_ERROR:
401 return r;
402 default:
403 log_error_write(srv, __FILE__, __LINE__, "d", r);
404 break;
409 return HANDLER_GO_ON;
411 #endif
414 * - call init function of all plugins to init the plugin-internals
415 * - added each plugin that supports has callback to the corresponding slot
417 * - is only called once.
420 handler_t plugins_call_init(server *srv) {
421 size_t i;
422 plugin **ps;
424 ps = srv->plugins.ptr;
426 /* fill slots */
428 srv->plugin_slots = calloc(PLUGIN_FUNC_SIZEOF, sizeof(ps));
429 force_assert(NULL != srv->plugin_slots);
431 for (i = 0; i < srv->plugins.used; i++) {
432 size_t j;
433 /* check which calls are supported */
435 plugin *p = ps[i];
437 #define PLUGIN_TO_SLOT(x, y) \
438 if (p->y) { \
439 plugin **slot = ((plugin ***)(srv->plugin_slots))[x]; \
440 if (!slot) { \
441 slot = calloc(srv->plugins.used, sizeof(*slot));\
442 force_assert(NULL != slot); \
443 ((plugin ***)(srv->plugin_slots))[x] = slot; \
445 for (j = 0; j < srv->plugins.used; j++) { \
446 if (slot[j]) continue;\
447 slot[j] = p;\
448 break;\
453 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean);
454 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw);
455 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_DONE, handle_request_done);
456 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close);
457 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger);
458 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SIGHUP, handle_sighup);
459 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST, handle_subrequest);
460 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST_START, handle_subrequest_start);
461 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_DOCROOT, handle_docroot);
462 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_PHYSICAL, handle_physical);
463 PLUGIN_TO_SLOT(PLUGIN_FUNC_CONNECTION_RESET, connection_reset);
464 PLUGIN_TO_SLOT(PLUGIN_FUNC_CLEANUP, cleanup);
465 PLUGIN_TO_SLOT(PLUGIN_FUNC_SET_DEFAULTS, set_defaults);
466 #undef PLUGIN_TO_SLOT
468 if (p->init) {
469 if (NULL == (p->data = p->init())) {
470 log_error_write(srv, __FILE__, __LINE__, "sb",
471 "plugin-init failed for module", p->name);
472 return HANDLER_ERROR;
475 /* used for con->mode, DIRECT == 0, plugins above that */
476 ((plugin_data *)(p->data))->id = i + 1;
478 if (p->version != LIGHTTPD_VERSION_ID) {
479 log_error_write(srv, __FILE__, __LINE__, "sb",
480 "plugin-version doesn't match lighttpd-version for", p->name);
481 return HANDLER_ERROR;
483 } else {
484 p->data = NULL;
488 return HANDLER_GO_ON;
491 void plugins_free(server *srv) {
492 size_t i;
493 plugins_call_cleanup(srv);
495 for (i = 0; i < srv->plugins.used; i++) {
496 plugin *p = ((plugin **)srv->plugins.ptr)[i];
498 plugin_free(p);
501 for (i = 0; srv->plugin_slots && i < PLUGIN_FUNC_SIZEOF; i++) {
502 plugin **slot = ((plugin ***)(srv->plugin_slots))[i];
504 if (slot) free(slot);
507 free(srv->plugin_slots);
508 srv->plugin_slots = NULL;
510 free(srv->plugins.ptr);
511 srv->plugins.ptr = NULL;
512 srv->plugins.used = 0;