1 #include "first.h" 2 3 #include "plugins.h" 4 #include "plugin.h" 5 #include "base.h" 6 #include "array.h" 7 #include "log.h" 8 9 #include <string.h> 10 #include <stdlib.h> 11 12 #ifdef HAVE_VALGRIND_VALGRIND_H 13 # include <valgrind/valgrind.h> 14 #endif 15 16 #ifndef LIGHTTPD_STATIC 17 #ifdef HAVE_DLFCN_H 18 #include <dlfcn.h> 19 #endif 20 #endif 21 /* 22 * 23 * if you change this enum to add a new callback, be sure 24 * - that PLUGIN_FUNC_SIZEOF is the last entry 25 * - that you add: 26 * 1. PLUGIN_CALL_... as callback-dispatcher 27 * 2. count and assignment in plugins_call_init() 28 * 29 */ 30 31 typedef enum { 32 PLUGIN_FUNC_HANDLE_URI_CLEAN, 33 PLUGIN_FUNC_HANDLE_DOCROOT, 34 PLUGIN_FUNC_HANDLE_PHYSICAL, 35 PLUGIN_FUNC_HANDLE_SUBREQUEST_START, 36 /* PLUGIN_FUNC_HANDLE_SUBREQUEST, *//* max one handler_module per req */ 37 PLUGIN_FUNC_HANDLE_RESPONSE_START, 38 PLUGIN_FUNC_HANDLE_REQUEST_DONE, 39 PLUGIN_FUNC_HANDLE_REQUEST_RESET, 40 PLUGIN_FUNC_HANDLE_REQUEST_ENV, 41 PLUGIN_FUNC_HANDLE_CONNECTION_ACCEPT, 42 PLUGIN_FUNC_HANDLE_CONNECTION_SHUT_WR, 43 PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, 44 PLUGIN_FUNC_HANDLE_TRIGGER, 45 PLUGIN_FUNC_HANDLE_WAITPID, 46 PLUGIN_FUNC_HANDLE_SIGHUP, 47 /* PLUGIN_FUNC_INIT, *//* handled here in plugin.c */ 48 /* PLUGIN_FUNC_CLEANUP, *//* handled here in plugin.c */ 49 PLUGIN_FUNC_SET_DEFAULTS, 50 PLUGIN_FUNC_WORKER_INIT, 51 52 PLUGIN_FUNC_SIZEOF 53 } plugin_t; 54 55 __attribute_malloc__ 56 __attribute_returns_nonnull__ 57 static plugin *plugin_init(void) { 58 return ck_calloc(1, sizeof(plugin)); 59 } 60 61 static void plugin_free(plugin *p) { 62 if (NULL == p) return; /*(should not happen w/ current usage)*/ 63 #if !defined(LIGHTTPD_STATIC) 64 if (p->lib) { 65 #if defined(HAVE_VALGRIND_VALGRIND_H) 66 /*if (!RUNNING_ON_VALGRIND) */ 67 #endif 68 #ifdef _WIN32 69 FreeLibrary(p->lib); 70 #else 71 dlclose(p->lib); 72 #endif 73 } 74 #endif 75 76 free(p); 77 } 78 79 #ifdef _WIN32 80 __attribute_cold__ 81 static void 82 log_w32_syserror_2 (log_error_st *const errh, const char *file, const int line, const char * const str1, const char * const str2) 83 { 84 TCHAR lpMsgBuf[1024]; 85 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 86 0, /* MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT) */ 87 (LPTSTR)lpMsgBuf, sizeof(lpMsgBuf)/sizeof(TCHAR), NULL); 88 log_error(errh, file, line, "%s for %s: %s", str1, str2, (char *)lpMsgBuf); 89 } 90 #endif 91 92 /** 93 * 94 * 95 * 96 */ 97 98 #if defined(LIGHTTPD_STATIC) 99 100 /* pre-declare functions, as there is no header for them */ 101 #define PLUGIN_INIT(x)\ 102 int x ## _plugin_init(plugin *p); 103 104 #include "plugin-static.h" 105 106 #undef PLUGIN_INIT 107 108 /* build NULL-terminated table of name + init-function */ 109 110 typedef struct { 111 const char* name; 112 int (*plugin_init)(plugin *p); 113 } plugin_load_functions; 114 115 static const plugin_load_functions load_functions[] = { 116 #define PLUGIN_INIT(x) \ 117 { #x, &x ## _plugin_init }, 118 119 #include "plugin-static.h" 120 121 { NULL, NULL } 122 #undef PLUGIN_INIT 123 }; 124 125 int plugins_load(server *srv) { 126 ck_realloc_u32(&srv->plugins.ptr, 0, 127 srv->srvconf.modules->used, sizeof(plugin *)); 128 129 for (uint32_t i = 0; i < srv->srvconf.modules->used; ++i) { 130 data_string *ds = (data_string *)srv->srvconf.modules->data[i]; 131 char *module = ds->value.ptr; 132 133 uint32_t j; 134 for (j = 0; load_functions[j].name; ++j) { 135 if (0 == strcmp(load_functions[j].name, module)) { 136 plugin * const p = plugin_init(); 137 if ((*load_functions[j].plugin_init)(p)) { 138 log_error(srv->errh, __FILE__, __LINE__, "%s plugin init failed", module); 139 plugin_free(p); 140 return -1; 141 } 142 ((plugin **)srv->plugins.ptr)[srv->plugins.used++] = p; 143 break; 144 } 145 } 146 if (!load_functions[j].name) { 147 log_error(srv->errh, __FILE__, __LINE__, "%s plugin not found", module); 148 if (srv->srvconf.compat_module_load) { 149 if (buffer_eq_slen(&ds->value, CONST_STR_LEN("mod_deflate"))) 150 continue; 151 } 152 return -1; 153 } 154 } 155 156 return 0; 157 } 158 159 #else /* defined(LIGHTTPD_STATIC) */ 160 161 int plugins_load(server *srv) { 162 ck_realloc_u32(&srv->plugins.ptr, 0, 163 srv->srvconf.modules->used, sizeof(plugin *)); 164 165 buffer * const tb = srv->tmp_buf; 166 int (*init)(plugin *pl); 167 168 for (uint32_t i = 0; i < srv->srvconf.modules->used; ++i) { 169 const buffer * const module = &((data_string *)srv->srvconf.modules->data[i])->value; 170 void *lib = NULL; 171 172 /* check if module is built-in to main executable */ 173 buffer_clear(tb); 174 buffer_append_str2(tb, BUF_PTR_LEN(module), 175 CONST_STR_LEN("_plugin_init")); 176 #ifdef _WIN32 177 init = (int(WINAPI *)(plugin *))(intptr_t) 178 GetProcAddress(GetModuleHandle(NULL), tb->ptr); 179 #else 180 init = (int (*)(plugin *))(intptr_t)dlsym(RTLD_DEFAULT, tb->ptr); 181 #endif 182 183 if (NULL == init) { 184 buffer_copy_string(tb, srv->srvconf.modules_dir); 185 buffer_append_path_len(tb, BUF_PTR_LEN(module)); 186 187 #ifdef _WIN32 188 buffer_append_string_len(tb, CONST_STR_LEN(".dll")); 189 if (NULL == (lib = LoadLibrary(tb->ptr))) { 190 log_w32_syserror_2(srv->errh, __FILE__, __LINE__, 191 "LoadLibrary()", tb->ptr); 192 if (srv->srvconf.compat_module_load) { 193 if (buffer_eq_slen(module, CONST_STR_LEN("mod_deflate"))) 194 continue; 195 } 196 return -1; 197 } 198 buffer_copy_buffer(tb, module); 199 buffer_append_string_len(tb, CONST_STR_LEN("_plugin_init")); 200 init = (int(WINAPI *)(plugin *))(intptr_t)GetProcAddress(lib, tb->ptr); 201 if (init == NULL) { 202 log_w32_syserror_2(srv->errh, __FILE__, __LINE__, 203 "GetProcAddress()", tb->ptr); 204 FreeLibrary(lib); 205 return -1; 206 } 207 #else 208 #if defined(__CYGWIN__) 209 buffer_append_string_len(tb, CONST_STR_LEN(".dll")); 210 #else 211 buffer_append_string_len(tb, CONST_STR_LEN(".so")); 212 #endif 213 if (NULL == (lib = dlopen(tb->ptr, RTLD_NOW|RTLD_GLOBAL))) { 214 log_error(srv->errh, __FILE__, __LINE__, 215 "dlopen() failed for: %s %s", tb->ptr, dlerror()); 216 if (srv->srvconf.compat_module_load) { 217 if (buffer_eq_slen(module, CONST_STR_LEN("mod_deflate"))) 218 continue; 219 } 220 return -1; 221 } 222 buffer_clear(tb); 223 buffer_append_str2(tb, BUF_PTR_LEN(module), 224 CONST_STR_LEN("_plugin_init")); 225 init = (int (*)(plugin *))(intptr_t)dlsym(lib, tb->ptr); 226 if (NULL == init) { 227 const char *error = dlerror(); 228 if (error != NULL) { 229 log_error(srv->errh, __FILE__, __LINE__, "dlsym: %s", error); 230 } else { 231 log_error(srv->errh, __FILE__, __LINE__, "dlsym symbol not found: %s", tb->ptr); 232 } 233 dlclose(lib); 234 return -1; 235 } 236 #endif 237 } 238 239 plugin *p = plugin_init(); 240 p->lib = lib; 241 if ((*init)(p)) { 242 log_error(srv->errh, __FILE__, __LINE__, "%s plugin init failed", module->ptr); 243 plugin_free(p); 244 return -1; 245 } 246 ((plugin **)srv->plugins.ptr)[srv->plugins.used++] = p; 247 } 248 249 return 0; 250 } 251 252 #endif /* defined(LIGHTTPD_STATIC) */ 253 254 typedef handler_t(*pl_cb_t)(void *, void *); 255 256 /*(alternative to multiple structs would be union for fn ptr type)*/ 257 258 typedef struct { 259 pl_cb_t fn; 260 plugin_data_base *data; 261 } plugin_fn_data; 262 263 typedef struct { 264 handler_t(*fn)(request_st *, void *); 265 plugin_data_base *data; 266 } plugin_fn_req_data; 267 268 typedef struct { 269 handler_t(*fn)(connection *, void *); 270 plugin_data_base *data; 271 } plugin_fn_con_data; 272 273 typedef struct { 274 handler_t(*fn)(server *, void *); 275 plugin_data_base *data; 276 } plugin_fn_srv_data; 277 278 typedef struct { 279 handler_t(*fn)(server *, void *, pid_t, int); 280 plugin_data_base *data; 281 } plugin_fn_waitpid_data; 282 283 __attribute_hot__ 284 static handler_t plugins_call_fn_req_data(request_st * const r, const int e) { 285 const void * const plugin_slots = r->con->plugin_slots; 286 const uint32_t offset = ((const uint16_t *)plugin_slots)[e]; 287 if (0 == offset) return HANDLER_GO_ON; 288 const plugin_fn_req_data *plfd = (const plugin_fn_req_data *) 289 (((uintptr_t)plugin_slots) + offset); 290 handler_t rc = HANDLER_GO_ON; 291 while (plfd->fn && (rc = plfd->fn(r, plfd->data)) == HANDLER_GO_ON) 292 ++plfd; 293 return rc; 294 } 295 296 __attribute_hot__ 297 static handler_t plugins_call_fn_con_data(connection * const con, const int e) { 298 const void * const plugin_slots = con->plugin_slots; 299 const uint32_t offset = ((const uint16_t *)plugin_slots)[e]; 300 if (0 == offset) return HANDLER_GO_ON; 301 const plugin_fn_con_data *plfd = (const plugin_fn_con_data *) 302 (((uintptr_t)plugin_slots) + offset); 303 handler_t rc = HANDLER_GO_ON; 304 while (plfd->fn && (rc = plfd->fn(con, plfd->data)) == HANDLER_GO_ON) 305 ++plfd; 306 return rc; 307 } 308 309 static handler_t plugins_call_fn_srv_data(server * const srv, const int e) { 310 const uint32_t offset = ((const uint16_t *)srv->plugin_slots)[e]; 311 if (0 == offset) return HANDLER_GO_ON; 312 const plugin_fn_srv_data *plfd = (const plugin_fn_srv_data *) 313 (((uintptr_t)srv->plugin_slots) + offset); 314 handler_t rc = HANDLER_GO_ON; 315 while (plfd->fn && (rc = plfd->fn(srv,plfd->data)) == HANDLER_GO_ON) 316 ++plfd; 317 return rc; 318 } 319 320 static void plugins_call_fn_srv_data_all(server * const srv, const int e) { 321 const uint32_t offset = ((const uint16_t *)srv->plugin_slots)[e]; 322 if (0 == offset) return; 323 const plugin_fn_srv_data *plfd = (const plugin_fn_srv_data *) 324 (((uintptr_t)srv->plugin_slots) + offset); 325 for (; plfd->fn; ++plfd) 326 plfd->fn(srv, plfd->data); 327 } 328 329 /** 330 * plugins that use 331 * 332 * - request_st *r 333 * - void *p_d (plugin_data *) 334 */ 335 336 #define PLUGIN_CALL_FN_REQ_DATA(x, y) \ 337 handler_t plugins_call_##y(request_st * const r) {\ 338 return plugins_call_fn_req_data(r, x); \ 339 } 340 341 PLUGIN_CALL_FN_REQ_DATA(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean) 342 PLUGIN_CALL_FN_REQ_DATA(PLUGIN_FUNC_HANDLE_DOCROOT, handle_docroot) 343 PLUGIN_CALL_FN_REQ_DATA(PLUGIN_FUNC_HANDLE_PHYSICAL, handle_physical) 344 PLUGIN_CALL_FN_REQ_DATA(PLUGIN_FUNC_HANDLE_SUBREQUEST_START, handle_subrequest_start) 345 PLUGIN_CALL_FN_REQ_DATA(PLUGIN_FUNC_HANDLE_RESPONSE_START, handle_response_start) 346 PLUGIN_CALL_FN_REQ_DATA(PLUGIN_FUNC_HANDLE_REQUEST_DONE, handle_request_done) 347 PLUGIN_CALL_FN_REQ_DATA(PLUGIN_FUNC_HANDLE_REQUEST_RESET, handle_request_reset) 348 PLUGIN_CALL_FN_REQ_DATA(PLUGIN_FUNC_HANDLE_REQUEST_ENV, handle_request_env) 349 350 /** 351 * plugins that use 352 * 353 * - connection *con 354 * - void *p_d (plugin_data *) 355 */ 356 357 #define PLUGIN_CALL_FN_CON_DATA(x, y) \ 358 handler_t plugins_call_##y(connection *con) {\ 359 return plugins_call_fn_con_data(con, x); \ 360 } 361 362 PLUGIN_CALL_FN_CON_DATA(PLUGIN_FUNC_HANDLE_CONNECTION_ACCEPT, handle_connection_accept) 363 PLUGIN_CALL_FN_CON_DATA(PLUGIN_FUNC_HANDLE_CONNECTION_SHUT_WR, handle_connection_shut_wr) 364 PLUGIN_CALL_FN_CON_DATA(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close) 365 366 #undef PLUGIN_CALL_FN_SRV_CON_DATA 367 368 /** 369 * plugins that use 370 * 371 * - server *srv 372 * - void *p_d (plugin_data *) 373 */ 374 375 handler_t plugins_call_set_defaults(server *srv) { 376 return plugins_call_fn_srv_data(srv, PLUGIN_FUNC_SET_DEFAULTS); 377 } 378 379 handler_t plugins_call_worker_init(server *srv) { 380 return plugins_call_fn_srv_data(srv, PLUGIN_FUNC_WORKER_INIT); 381 } 382 383 void plugins_call_handle_trigger(server *srv) { 384 plugins_call_fn_srv_data_all(srv, PLUGIN_FUNC_HANDLE_TRIGGER); 385 } 386 387 void plugins_call_handle_sighup(server *srv) { 388 plugins_call_fn_srv_data_all(srv, PLUGIN_FUNC_HANDLE_SIGHUP); 389 } 390 391 handler_t plugins_call_handle_waitpid(server *srv, pid_t pid, int status) { 392 const uint32_t offset = 393 ((const uint16_t *)srv->plugin_slots)[PLUGIN_FUNC_HANDLE_WAITPID]; 394 if (0 == offset) return HANDLER_GO_ON; 395 const plugin_fn_waitpid_data *plfd = (const plugin_fn_waitpid_data *) 396 (((uintptr_t)srv->plugin_slots) + offset); 397 handler_t rc = HANDLER_GO_ON; 398 while (plfd->fn&&(rc=plfd->fn(srv,plfd->data,pid,status))==HANDLER_GO_ON) 399 ++plfd; 400 return rc; 401 } 402 403 static void plugins_call_cleanup(server * const srv) { 404 plugin ** const ps = srv->plugins.ptr; 405 for (uint32_t i = 0; i < srv->plugins.used; ++i) { 406 plugin *p = ps[i]; 407 if (NULL == p) continue; 408 if (NULL != p->data) { 409 plugin_data_base *pd = p->data; 410 if (p->cleanup) 411 p->cleanup(p->data); 412 free(pd->cvlist); 413 free(pd); 414 p->data = NULL; 415 } 416 } 417 } 418 419 __attribute_cold__ 420 static void plugins_call_init_reverse(server *srv, const uint32_t offset) { 421 if (0 == offset) return; 422 plugin_fn_data *a = (plugin_fn_data *) 423 (((uintptr_t)srv->plugin_slots) + offset); 424 plugin_fn_data *b = a; 425 while (b->fn) ++b; 426 for (; a < --b; ++a) { /* swap to reverse list */ 427 plugin_fn_data tmp = *a; 428 *a = *b; 429 *b = tmp; 430 } 431 } 432 433 __attribute_cold__ 434 static void plugins_call_init_slot(server *srv, pl_cb_t fn, void *data, const uint32_t offset) { 435 if (fn) { 436 plugin_fn_data *plfd = (plugin_fn_data *) 437 (((uintptr_t)srv->plugin_slots) + offset); 438 while (plfd->fn) ++plfd; 439 plfd->fn = fn; 440 plfd->data = data; 441 } 442 } 443 444 handler_t plugins_call_init(server *srv) { 445 plugin ** const ps = srv->plugins.ptr; 446 uint16_t offsets[PLUGIN_FUNC_SIZEOF]; 447 memset(offsets, 0, sizeof(offsets)); 448 449 for (uint32_t i = 0; i < srv->plugins.used; ++i) { 450 /* check which calls are supported */ 451 452 plugin *p = ps[i]; 453 454 if (p->init) { 455 if (NULL == (p->data = p->init())) { 456 log_error(srv->errh, __FILE__, __LINE__, 457 "plugin-init failed for module %s", p->name); 458 return HANDLER_ERROR; 459 } 460 461 ((plugin_data_base *)(p->data))->self = p; 462 ((plugin_data_base *)(p->data))->id = i + 1; 463 464 if (p->version != LIGHTTPD_VERSION_ID) { 465 log_error(srv->errh, __FILE__, __LINE__, 466 "plugin-version doesn't match lighttpd-version for %s", p->name); 467 return HANDLER_ERROR; 468 } 469 } 470 471 if (p->priv_defaults && HANDLER_ERROR==p->priv_defaults(srv, p->data)) { 472 return HANDLER_ERROR; 473 } 474 475 if (p->handle_uri_clean) 476 ++offsets[PLUGIN_FUNC_HANDLE_URI_CLEAN]; 477 if (p->handle_uri_raw && !p->handle_uri_clean) 478 ++offsets[PLUGIN_FUNC_HANDLE_URI_CLEAN]; /*(same as above)*/ 479 if (p->handle_request_env) 480 ++offsets[PLUGIN_FUNC_HANDLE_REQUEST_ENV]; 481 if (p->handle_request_done) 482 ++offsets[PLUGIN_FUNC_HANDLE_REQUEST_DONE]; 483 if (p->handle_connection_accept) 484 ++offsets[PLUGIN_FUNC_HANDLE_CONNECTION_ACCEPT]; 485 if (p->handle_connection_shut_wr) 486 ++offsets[PLUGIN_FUNC_HANDLE_CONNECTION_SHUT_WR]; 487 if (p->handle_connection_close) 488 ++offsets[PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE]; 489 if (p->handle_trigger) 490 ++offsets[PLUGIN_FUNC_HANDLE_TRIGGER]; 491 if (p->handle_sighup) 492 ++offsets[PLUGIN_FUNC_HANDLE_SIGHUP]; 493 if (p->handle_waitpid) 494 ++offsets[PLUGIN_FUNC_HANDLE_WAITPID]; 495 if (p->handle_subrequest_start) 496 ++offsets[PLUGIN_FUNC_HANDLE_SUBREQUEST_START]; 497 if (p->handle_response_start) 498 ++offsets[PLUGIN_FUNC_HANDLE_RESPONSE_START]; 499 if (p->handle_docroot) 500 ++offsets[PLUGIN_FUNC_HANDLE_DOCROOT]; 501 if (p->handle_physical) 502 ++offsets[PLUGIN_FUNC_HANDLE_PHYSICAL]; 503 if (p->handle_request_reset) 504 ++offsets[PLUGIN_FUNC_HANDLE_REQUEST_RESET]; 505 if (p->set_defaults) 506 ++offsets[PLUGIN_FUNC_SET_DEFAULTS]; 507 if (p->worker_init) 508 ++offsets[PLUGIN_FUNC_WORKER_INIT]; 509 } 510 511 uint32_t nslots = 512 (sizeof(offsets)+sizeof(plugin_fn_data)-1) / sizeof(plugin_fn_data); 513 for (uint32_t i = 0; i < PLUGIN_FUNC_SIZEOF; ++i) { 514 if (offsets[i]) { 515 uint32_t offset = nslots; 516 nslots += offsets[i]+1; /* +1 to mark end of each list */ 517 force_assert(offset * sizeof(plugin_fn_data) <= USHRT_MAX); 518 offsets[i] = (uint16_t)(offset * sizeof(plugin_fn_data)); 519 } 520 } 521 522 /* allocate and fill slots of two dimensional array */ 523 srv->plugin_slots = ck_calloc(nslots, sizeof(plugin_fn_data)); 524 memcpy(srv->plugin_slots, offsets, sizeof(offsets)); 525 526 /* add handle_uri_raw before handle_uri_clean, but in same slot */ 527 for (uint32_t i = 0; i < srv->plugins.used; ++i) { 528 plugin * const p = ps[i]; 529 plugins_call_init_slot(srv, (pl_cb_t)p->handle_uri_raw, p->data, 530 offsets[PLUGIN_FUNC_HANDLE_URI_CLEAN]); 531 } 532 533 for (uint32_t i = 0; i < srv->plugins.used; ++i) { 534 plugin * const p = ps[i]; 535 536 if (!p->handle_uri_raw) 537 plugins_call_init_slot(srv, (pl_cb_t)p->handle_uri_clean, p->data, 538 offsets[PLUGIN_FUNC_HANDLE_URI_CLEAN]); 539 plugins_call_init_slot(srv, (pl_cb_t)p->handle_request_env, p->data, 540 offsets[PLUGIN_FUNC_HANDLE_REQUEST_ENV]); 541 plugins_call_init_slot(srv, (pl_cb_t)p->handle_request_done, p->data, 542 offsets[PLUGIN_FUNC_HANDLE_REQUEST_DONE]); 543 plugins_call_init_slot(srv, (pl_cb_t)p->handle_connection_accept, p->data, 544 offsets[PLUGIN_FUNC_HANDLE_CONNECTION_ACCEPT]); 545 plugins_call_init_slot(srv, (pl_cb_t)p->handle_connection_shut_wr, p->data, 546 offsets[PLUGIN_FUNC_HANDLE_CONNECTION_SHUT_WR]); 547 plugins_call_init_slot(srv, (pl_cb_t)p->handle_connection_close, p->data, 548 offsets[PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE]); 549 plugins_call_init_slot(srv, (pl_cb_t)p->handle_trigger, p->data, 550 offsets[PLUGIN_FUNC_HANDLE_TRIGGER]); 551 plugins_call_init_slot(srv, (pl_cb_t)p->handle_sighup, p->data, 552 offsets[PLUGIN_FUNC_HANDLE_SIGHUP]); 553 plugins_call_init_slot(srv, (pl_cb_t)(uintptr_t)p->handle_waitpid, p->data, 554 offsets[PLUGIN_FUNC_HANDLE_WAITPID]); 555 plugins_call_init_slot(srv, (pl_cb_t)p->handle_subrequest_start, p->data, 556 offsets[PLUGIN_FUNC_HANDLE_SUBREQUEST_START]); 557 plugins_call_init_slot(srv, (pl_cb_t)p->handle_response_start, p->data, 558 offsets[PLUGIN_FUNC_HANDLE_RESPONSE_START]); 559 plugins_call_init_slot(srv, (pl_cb_t)p->handle_docroot, p->data, 560 offsets[PLUGIN_FUNC_HANDLE_DOCROOT]); 561 plugins_call_init_slot(srv, (pl_cb_t)p->handle_physical, p->data, 562 offsets[PLUGIN_FUNC_HANDLE_PHYSICAL]); 563 plugins_call_init_slot(srv, (pl_cb_t)p->handle_request_reset, p->data, 564 offsets[PLUGIN_FUNC_HANDLE_REQUEST_RESET]); 565 plugins_call_init_slot(srv, (pl_cb_t)p->set_defaults, p->data, 566 offsets[PLUGIN_FUNC_SET_DEFAULTS]); 567 plugins_call_init_slot(srv, (pl_cb_t)p->worker_init, p->data, 568 offsets[PLUGIN_FUNC_WORKER_INIT]); 569 } 570 571 /* reverse cleanup lists to balance ctor/dtor-like plugin behaviors */ 572 plugins_call_init_reverse(srv,offsets[PLUGIN_FUNC_HANDLE_REQUEST_RESET]); 573 plugins_call_init_reverse(srv,offsets[PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE]); 574 575 return HANDLER_GO_ON; 576 } 577 578 void plugins_free(server *srv) { 579 if (srv->plugin_slots) { 580 plugins_call_cleanup(srv); 581 free(srv->plugin_slots); 582 srv->plugin_slots = NULL; 583 } 584 585 for (uint32_t i = 0; i < srv->plugins.used; ++i) { 586 plugin_free(((plugin **)srv->plugins.ptr)[i]); 587 } 588 free(srv->plugins.ptr); 589 srv->plugins.ptr = NULL; 590 srv->plugins.used = 0; 591 array_free_data(&plugin_stats); 592 } 593