1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 
3 /*  Monkey HTTP Server
4  *  ==================
5  *  Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
6  *
7  *  Licensed under the Apache License, Version 2.0 (the "License");
8  *  you may not use this file except in compliance with the License.
9  *  You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  *  Unless required by applicable law or agreed to in writing, software
14  *  distributed under the License is distributed on an "AS IS" BASIS,
15  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  *  See the License for the specific language governing permissions and
17  *  limitations under the License.
18  */
19 
20 #include <monkey/monkey.h>
21 #include <monkey/mk_utils.h>
22 #include <monkey/mk_http.h>
23 #include <monkey/mk_clock.h>
24 #include <monkey/mk_plugin.h>
25 #include <monkey/mk_mimetype.h>
26 #include <monkey/mk_vhost.h>
27 #include <monkey/mk_static_plugins.h>
28 #include <monkey/mk_plugin_stage.h>
29 #include <monkey/mk_core.h>
30 #include <monkey/mk_net.h>
31 
32 #ifndef _WIN32
33 #include <dlfcn.h>
34 #include <err.h>
35 #endif
36 
37 enum {
38     bufsize = 256
39 };
40 
41 static struct plugin_stagemap *plg_stagemap;
42 struct plugin_network_io *plg_netiomap;
43 struct plugin_api *api;
44 
mk_plugin_lookup(char * shortname,struct mk_server * server)45 struct mk_plugin *mk_plugin_lookup(char *shortname, struct mk_server *server)
46 {
47     struct mk_list *head;
48     struct mk_plugin *p = NULL;
49 
50     mk_list_foreach(head, &server->plugins) {
51         p = mk_list_entry(head, struct mk_plugin, _head);
52         if (strcmp(p->shortname, shortname) == 0){
53             return p;
54         }
55     }
56 
57     return NULL;
58 }
59 
mk_plugin_load_dynamic(const char * path)60 void *mk_plugin_load_dynamic(const char *path)
61 {
62     void *handle;
63 
64 #ifdef _WIN32
65     handle = (void *) LoadLibraryA(path);
66 #else
67     handle = dlopen(path, RTLD_LAZY);
68 
69     if (!handle) {
70         mk_warn("dlopen() %s", dlerror());
71     }
72 #endif
73 
74     return handle;
75 }
76 
mk_plugin_load_symbol(void * handler,const char * symbol)77 void *mk_plugin_load_symbol(void *handler, const char *symbol)
78 {
79     void *s;
80 
81 #ifdef _WIN32
82     s = GetProcAddress((HMODULE)handler, symbol);
83 #else
84     dlerror();
85     s = dlsym(handler, symbol);
86     if (dlerror() != NULL) {
87         return NULL;
88     }
89 #endif
90 
91     return s;
92 }
93 
94 /* Initialize a plugin, trigger the init_plugin callback */
mk_plugin_init(struct plugin_api * api,struct mk_plugin * plugin,struct mk_server * server)95 static int mk_plugin_init(struct plugin_api *api, struct mk_plugin *plugin,
96                           struct mk_server *server)
97 {
98     int ret;
99     unsigned long len;
100     char path[1024];
101     char *conf_dir = NULL;
102     struct file_info f_info;
103 
104     MK_TRACE("Load Plugin: '%s'", plugin->shortname);
105 
106     snprintf(path, 1024, "%s/%s",
107              server->path_conf_root, server->conf_plugins);
108     ret = mk_file_get_info(path, &f_info, MK_FILE_READ);
109     if (ret == -1 || f_info.is_directory == MK_FALSE) {
110         snprintf(path, 1024, "%s", server->conf_plugins);
111     }
112 
113     /* Build plugin configuration path */
114     mk_string_build(&conf_dir,
115                     &len,
116                     "%s/%s/",
117                     path, plugin->shortname);
118 
119     /* Init plugin */
120     plugin->server_ctx = server;
121     ret = plugin->init_plugin(&api, conf_dir);
122     mk_mem_free(conf_dir);
123 
124     return ret;
125 }
126 
127 
128 /*
129  * Load a plugin into Monkey core, 'type' defines if it's a MK_PLUGIN_STATIC or
130  * a MK_PLUGIN_DYNAMIC. 'shortname' is mandatory and 'path' is only used when
131  * MK_PLUGIN_DYNAMIC is set and represents the absolute path of the shared
132  * library.
133  */
mk_plugin_load(int type,const char * shortname,void * data,struct mk_server * server)134 struct mk_plugin *mk_plugin_load(int type, const char *shortname,
135                                  void *data, struct mk_server *server)
136 {
137     char *path;
138     char symbol[64];
139     void *handler;
140     struct mk_list *head;
141     struct mk_plugin *tmp;
142     struct mk_plugin *plugin = NULL;
143     struct mk_plugin_stage *stage;
144 
145     /* Set main struct name to reference */
146     if (type == MK_PLUGIN_DYNAMIC) {
147         path = (char *) data;
148         handler = mk_plugin_load_dynamic(path);
149         if (!handler) {
150             return NULL;
151         }
152 
153         snprintf(symbol, sizeof(symbol) - 1, "mk_plugin_%s", shortname);
154         plugin  = mk_plugin_load_symbol(handler, symbol);
155         if (!plugin) {
156             mk_warn("Plugin '%s' is not registering properly", path);
157 #ifdef _WIN32
158             FreeLibrary((HMODULE)handler);
159 #else
160             dlclose(handler);
161 #endif
162             return NULL;
163         }
164 
165         /* Make sure this is not loaded twice (ref #218) */
166         mk_list_foreach(head, &server->plugins) {
167             tmp = mk_list_entry(head, struct mk_plugin, _head);
168             if (tmp->load_type == MK_PLUGIN_STATIC &&
169                 strcmp(tmp->name, plugin->name) == 0){
170                 mk_warn("Plugin '%s' have been built-in.",
171                         tmp->shortname);
172 #ifdef _WIN32
173                 FreeLibrary((HMODULE)handler);
174 #else
175                 dlclose(handler);
176 #endif
177                 return NULL;
178             }
179         }
180 
181         plugin->load_type = MK_PLUGIN_DYNAMIC;
182         plugin->handler   = handler;
183         plugin->path      = mk_string_dup(path);
184     }
185     else if (type == MK_PLUGIN_STATIC) {
186         plugin = (struct mk_plugin *) data;
187         plugin->load_type = MK_PLUGIN_STATIC;
188     }
189 
190     if (!plugin) {
191         return NULL;
192     }
193 
194     /* Validate all callbacks are set */
195     if (!plugin->shortname || !plugin->name || !plugin->version ||
196         !plugin->init_plugin || !plugin->exit_plugin) {
197         mk_warn("Plugin '%s' is not registering all fields properly",
198                 shortname);
199         return NULL;
200     }
201 
202     if (plugin->hooks & MK_PLUGIN_NETWORK_LAYER) {
203         mk_bug(!plugin->network);
204     }
205 
206     mk_list_init(&plugin->stage_list);
207     if (plugin->hooks & MK_PLUGIN_STAGE) {
208         struct mk_plugin_stage *st;
209 
210         stage = plugin->stage;
211         if (stage->stage10) {
212             st = mk_mem_alloc(sizeof(struct mk_plugin_stage));
213             st->stage10 = stage->stage10;
214             st->plugin  = plugin;
215             mk_list_add(&st->_head, &server->stage10_handler);
216             mk_list_add(&st->_parent_head, &plugin->stage_list);
217         }
218         if (stage->stage20) {
219             st = mk_mem_alloc(sizeof(struct mk_plugin_stage));
220             st->stage20 = stage->stage20;
221             st->plugin  = plugin;
222             mk_list_add(&st->_head, &server->stage20_handler);
223             mk_list_add(&st->_parent_head, &plugin->stage_list);
224         }
225         if (stage->stage30) {
226             st = mk_mem_alloc(sizeof(struct mk_plugin_stage));
227             st->stage30 = stage->stage30;
228             st->plugin  = plugin;
229             mk_list_add(&st->_head, &server->stage30_handler);
230             mk_list_add(&st->_parent_head, &plugin->stage_list);
231         }
232         if (stage->stage40) {
233             st = mk_mem_alloc(sizeof(struct mk_plugin_stage));
234             st->stage40 = stage->stage40;
235             st->plugin  = plugin;
236             mk_list_add(&st->_head, &server->stage40_handler);
237             mk_list_add(&st->_parent_head, &plugin->stage_list);
238         }
239         if (stage->stage50) {
240             st = mk_mem_alloc(sizeof(struct mk_plugin_stage));
241             st->stage50 = stage->stage50;
242             st->plugin  = plugin;
243             mk_list_add(&st->_head, &server->stage50_handler);
244             mk_list_add(&st->_parent_head, &plugin->stage_list);
245         }
246     }
247 
248     if (type == MK_PLUGIN_DYNAMIC) {
249         /* Add Plugin to the end of the list */
250         mk_list_add(&plugin->_head, &server->plugins);
251     }
252 
253     return plugin;
254 }
255 
mk_plugin_unregister(struct mk_plugin * p)256 void mk_plugin_unregister(struct mk_plugin *p)
257 {
258     mk_mem_free(p->path);
259     mk_list_del(&p->_head);
260     if (p->load_type == MK_PLUGIN_DYNAMIC) {
261 #ifdef _WIN32
262         FreeLibrary((HMODULE)p->handler);
263 #else
264         dlclose(p->handler);
265 #endif
266     }
267 
268 }
269 
mk_plugin_api_init(struct mk_server * server)270 void mk_plugin_api_init(struct mk_server *server)
271 {
272     /* Create an instance of the API */
273     api = mk_mem_alloc_z(sizeof(struct plugin_api));
274 
275 #ifndef _WIN32
276     __builtin_prefetch(api);
277 #endif
278 
279     /* Setup and connections list */
280     /* FIXME: api->config = server; */
281 
282     /* API plugins funcions */
283 
284     /* Error helper */
285     api->_error = mk_print;
286 
287     /* HTTP callbacks */
288     api->http_request_end = mk_plugin_http_request_end;
289     api->http_request_error = mk_plugin_http_error;
290 
291     /* Memory callbacks */
292     api->pointer_set = mk_ptr_set;
293     api->pointer_print = mk_ptr_print;
294     api->pointer_to_buf = mk_ptr_to_buf;
295     api->plugin_load_symbol = mk_plugin_load_symbol;
296     api->mem_alloc = mk_mem_alloc;
297     api->mem_alloc_z = mk_mem_alloc_z;
298     api->mem_realloc = mk_mem_realloc;
299     api->mem_free = mk_mem_free;
300 
301     /* String Callbacks */
302     api->str_build = mk_string_build;
303     api->str_dup = mk_string_dup;
304     api->str_search = mk_string_search;
305     api->str_search_n = mk_string_search_n;
306     api->str_char_search = mk_string_char_search;
307     api->str_copy_substr = mk_string_copy_substr;
308     api->str_itop = mk_string_itop;
309     api->str_split_line = mk_string_split_line;
310     api->str_split_free = mk_string_split_free;
311 
312     /* File Callbacks */
313     api->file_to_buffer = mk_file_to_buffer;
314     api->file_get_info = mk_file_get_info;
315 
316     /* HTTP Callbacks */
317     api->header_prepare = mk_plugin_header_prepare;
318     api->header_add = mk_plugin_header_add;
319     api->header_get = mk_http_header_get;
320     api->header_set_http_status = mk_header_set_http_status;
321 
322     /* Channels / Streams */
323     api->channel_new   = mk_channel_new;
324     api->channel_flush = mk_channel_flush;
325     api->channel_write = mk_channel_write;
326     api->channel_append_stream = mk_channel_append_stream;
327 
328     /* IOV callbacks */
329     api->iov_create  = mk_iov_create;
330     api->iov_realloc = mk_iov_realloc;
331     api->iov_free = mk_iov_free;
332     api->iov_free_marked = mk_iov_free_marked;
333     api->iov_add =  mk_iov_add;
334     api->iov_set_entry =  mk_iov_set_entry;
335     api->iov_send =  mk_iov_send;
336     api->iov_print =  mk_iov_print;
337 
338     /* events mechanism */
339     api->ev_loop_create = mk_event_loop_create;
340     api->ev_add = mk_event_add;
341     api->ev_del = mk_event_del;
342     api->ev_timeout_create = mk_event_timeout_create;
343     api->ev_channel_create = mk_event_channel_create;
344     api->ev_wait = mk_event_wait;
345     api->ev_backend = mk_event_backend;
346 
347     /* Mimetype */
348     api->mimetype_lookup = mk_mimetype_lookup;
349 
350     /* Socket callbacks */
351     api->socket_cork_flag = mk_socket_set_cork_flag;
352     api->socket_connect = mk_socket_connect;
353     api->socket_open = mk_socket_open;
354     api->socket_reset = mk_socket_reset;
355     api->socket_set_tcp_fastopen = mk_socket_set_tcp_fastopen;
356     api->socket_set_tcp_reuseport = mk_socket_set_tcp_reuseport;
357     api->socket_set_tcp_nodelay = mk_socket_set_tcp_nodelay;
358     api->socket_set_nonblocking = mk_socket_set_nonblocking;
359     api->socket_create = mk_socket_create;
360     api->socket_ip_str = mk_socket_ip_str;
361 
362     /* Async network */
363     api->net_conn_create = mk_net_conn_create;
364 
365     /* Config Callbacks */
366     api->config_create = mk_rconf_create;
367     api->config_open = mk_rconf_open;
368     api->config_free = mk_rconf_free;
369     api->config_section_get = mk_rconf_section_get;
370     api->config_section_get_key = mk_rconf_section_get_key;
371 
372     /* Scheduler and Event callbacks */
373     api->sched_loop           = mk_sched_loop;
374     api->sched_get_connection = mk_sched_get_connection;
375     api->sched_event_free     = mk_sched_event_free;
376     api->sched_remove_client  = mk_plugin_sched_remove_client;
377     api->sched_worker_info    = mk_plugin_sched_get_thread_conf;
378 
379     /* Worker functions */
380     api->worker_spawn = mk_utils_worker_spawn;
381     api->worker_rename = mk_utils_worker_rename;
382 
383     /* Time functions */
384     api->time_unix   = mk_plugin_time_now_unix;
385     api->time_to_gmt = mk_utils_utime2gmt;
386     api->time_human  = mk_plugin_time_now_human;
387 
388     api->stacktrace = (void *) mk_utils_stacktrace;
389     api->kernel_version = mk_kernel_version;
390     api->kernel_features_print = mk_kernel_features_print;
391     api->plugins = &server->plugins;
392 
393     /* handler */
394     api->handler_param_get = mk_handler_param_get;
395 }
396 
mk_plugin_load_static(struct mk_server * server)397 void mk_plugin_load_static(struct mk_server *server)
398 {
399     /* Load static plugins */
400     mk_list_init(&server->plugins);
401     mk_static_plugins(&server->plugins);
402 }
403 
mk_plugin_load_all(struct mk_server * server)404 void mk_plugin_load_all(struct mk_server *server)
405 {
406     int ret;
407     char *tmp;
408     char *path;
409     char shortname[64];
410     struct mk_plugin *p;
411     struct mk_rconf *cnf;
412     struct mk_rconf_section *section;
413     struct mk_rconf_entry *entry;
414     struct mk_list *head;
415     struct mk_list *htmp;
416     struct file_info f_info;
417 
418     mk_plugin_load_static(server);
419     mk_list_foreach_safe(head, htmp, &server->plugins) {
420         p = mk_list_entry(head, struct mk_plugin, _head);
421 
422         /* Load the static plugin */
423         p = mk_plugin_load(MK_PLUGIN_STATIC,
424                            p->shortname,
425                            (void *) p,
426                            server);
427         if (!p) {
428             continue;
429         }
430         ret = mk_plugin_init(api, p, server);
431         if (ret == -1) {
432             /* Free plugin, do not register, error initializing */
433             mk_warn("Plugin initialization failed: %s", p->shortname);
434             mk_plugin_unregister(p);
435             continue;
436         }
437         else if (ret == -2) {
438             /* Do not register, just skip it */
439             mk_plugin_unregister(p);
440             continue;
441         }
442     }
443 
444     /* In case there are not dynamic plugins */
445     if (!server->conf_plugin_load) {
446         return;
447     }
448 
449     /* Read configuration file */
450     path = mk_mem_alloc_z(1024);
451     snprintf(path, 1024, "%s/%s", server->path_conf_root,
452              server->conf_plugin_load);
453     ret = mk_file_get_info(path, &f_info, MK_FILE_READ);
454     if (ret == -1 || f_info.is_file == MK_FALSE) {
455         snprintf(path, 1024, "%s", server->conf_plugin_load);
456     }
457 
458     cnf = mk_rconf_open(path);
459     if (!cnf) {
460         mk_warn("No dynamic plugins loaded.");
461         mk_mem_free(path);
462         return;
463     }
464 
465     /* Read section 'PLUGINS' */
466     section = mk_rconf_section_get(cnf, "PLUGINS");
467     if (!section) {
468         exit(EXIT_FAILURE);
469     }
470 
471     /* Read key entries */
472     mk_list_foreach_safe(head, htmp, &section->entries) {
473         entry = mk_list_entry(head, struct mk_rconf_entry, _head);
474         if (strcasecmp(entry->key, "Load") == 0) {
475 
476             /* Get plugin 'shortname' */
477             tmp = memrchr(entry->val, '-', strlen(entry->val));
478             ++tmp;
479             memset(shortname, '\0', sizeof(shortname) - 1);
480             strncpy(shortname, tmp, strlen(tmp) - 3);
481 
482             /* Load the dynamic plugin */
483             p = mk_plugin_load(MK_PLUGIN_DYNAMIC,
484                                shortname,
485                                entry->val,
486                                server);
487             if (!p) {
488                 mk_warn("Invalid plugin '%s'", entry->val);
489                 continue;
490             }
491 
492             ret = mk_plugin_init(api, p, server);
493             if (ret < 0) {
494                 /* Free plugin, do not register */
495                 MK_TRACE("Unregister plugin '%s'", p->shortname);
496                 mk_plugin_unregister(p);
497                 continue;
498             }
499         }
500     }
501 
502     /* Look for plugins thread key data */
503     mk_plugin_preworker_calls(server);
504     mk_vhost_map_handlers(server);
505     mk_mem_free(path);
506     mk_rconf_free(cnf);
507 }
508 
mk_plugin_exit_stages(struct mk_plugin * p)509 static void mk_plugin_exit_stages(struct mk_plugin *p)
510 {
511     struct mk_list *tmp;
512     struct mk_list *head;
513     struct mk_plugin_stage *st;
514 
515     mk_list_foreach_safe(head, tmp, &p->stage_list) {
516         st = mk_list_entry(head, struct mk_plugin_stage, _parent_head);
517 
518         /* remove from direct config->stageN head list */
519         mk_list_del(&st->_head);
520 
521         /* remove from plugin->stage_lists */
522         mk_list_del(&st->_parent_head);
523         mk_mem_free(st);
524     }
525 }
526 
527 /* Invoke all plugins 'exit' hook and free resources by the plugin interface */
mk_plugin_exit_all(struct mk_server * server)528 void mk_plugin_exit_all(struct mk_server *server)
529 {
530     struct mk_plugin *plugin;
531     struct mk_list *head, *tmp;
532 
533     /* Plugins */
534     mk_list_foreach(head, &server->plugins) {
535         plugin = mk_list_entry(head, struct mk_plugin, _head);
536         plugin->exit_plugin();
537     }
538 
539     /* Plugin interface it self */
540     mk_list_foreach_safe(head, tmp, &server->plugins) {
541         plugin = mk_list_entry(head, struct mk_plugin, _head);
542         mk_list_del(&plugin->_head);
543         mk_plugin_exit_stages(plugin);
544 
545         if (plugin->load_type == MK_PLUGIN_DYNAMIC) {
546             mk_mem_free(plugin->path);
547 #ifdef _WIN32
548             FreeLibrary((HMODULE)plugin->handler);
549 #else
550             dlclose(plugin ->handler);
551 #endif
552         }
553     }
554     mk_mem_free(api);
555     mk_mem_free(plg_stagemap);
556 }
557 
558 /*
559  * When a worker is exiting, it invokes this function to release any plugin
560  * associated data.
561  */
mk_plugin_exit_worker()562 void mk_plugin_exit_worker()
563 {
564 }
565 
566 /* This function is called by every created worker
567  * for plugins which need to set some data under a thread
568  * context
569  */
mk_plugin_core_process(struct mk_server * server)570 void mk_plugin_core_process(struct mk_server *server)
571 {
572     struct mk_plugin *node;
573     struct mk_list *head;
574 
575     mk_list_foreach(head, &server->plugins) {
576         node = mk_list_entry(head, struct mk_plugin, _head);
577 
578         /* Init plugin */
579         if (node->master_init) {
580             node->master_init(server);
581         }
582     }
583 }
584 
585 /* This function is called by every created worker
586  * for plugins which need to set some data under a thread
587  * context
588  */
mk_plugin_core_thread(struct mk_server * server)589 void mk_plugin_core_thread(struct mk_server *server)
590 {
591 
592     struct mk_plugin *node;
593     struct mk_list *head;
594 
595     mk_list_foreach(head, &server->plugins) {
596         node = mk_list_entry(head, struct mk_plugin, _head);
597 
598         /* Init plugin thread context */
599         if (node->worker_init) {
600             node->worker_init(server);
601         }
602     }
603 }
604 
605 /* This function is called by Monkey *outside* of the
606  * thread context for plugins, so here's the right
607  * place to set pthread keys or similar
608  */
mk_plugin_preworker_calls(struct mk_server * server)609 void mk_plugin_preworker_calls(struct mk_server *server)
610 {
611     int ret;
612     struct mk_plugin *node;
613     struct mk_list *head;
614 
615     mk_list_foreach(head, &server->plugins) {
616         node = mk_list_entry(head, struct mk_plugin, _head);
617 
618         /* Init pthread keys */
619         if (node->thread_key) {
620             MK_TRACE("[%s] Set thread key", node->shortname);
621 
622             ret = pthread_key_create(node->thread_key, NULL);
623             if (ret != 0) {
624                 mk_err("Plugin Error: could not create key for %s",
625                        node->shortname);
626             }
627         }
628     }
629 }
630 
mk_plugin_http_error(int http_status,struct mk_http_session * cs,struct mk_http_request * sr,struct mk_plugin * plugin)631 int mk_plugin_http_error(int http_status, struct mk_http_session *cs,
632                          struct mk_http_request *sr,
633                          struct mk_plugin *plugin)
634 {
635     return mk_http_error(http_status, cs, sr, plugin->server_ctx);
636 }
637 
638 
mk_plugin_http_request_end(struct mk_plugin * plugin,struct mk_http_session * cs,int close)639 int mk_plugin_http_request_end(struct mk_plugin *plugin,
640                                struct mk_http_session *cs, int close)
641 {
642     int ret;
643     int con;
644     struct mk_http_request *sr;
645     struct mk_server *server = plugin->server_ctx;
646 
647     MK_TRACE("[FD %i] PLUGIN HTTP REQUEST END", cs->socket);
648 
649     cs->status = MK_REQUEST_STATUS_INCOMPLETE;
650     if (mk_list_is_empty(&cs->request_list) == 0) {
651         MK_TRACE("[FD %i] Tried to end non-existing request.", cs->socket);
652         return -1;
653     }
654 
655     sr = mk_list_entry_last(&cs->request_list, struct mk_http_request, _head);
656     mk_plugin_stage_run_40(cs, sr, server);
657 
658     if (close == MK_TRUE) {
659         cs->close_now = MK_TRUE;
660     }
661 
662     /* Let's check if we should ask to finalize the connection or not */
663     ret = mk_http_request_end(cs, server);
664     MK_TRACE("[FD %i] HTTP session end = %i", cs->socket, ret);
665     if (ret < 0) {
666         con = mk_sched_event_close(cs->conn, mk_sched_get_thread_conf(),
667                                    MK_EP_SOCKET_DONE, server);
668         if (con != 0) {
669             return con;
670         }
671         else {
672             return -1;
673         }
674     }
675 
676     return ret;
677 }
678 
679 /* Plugin epoll event handlers
680  * ---------------------------
681  * this functions are called by connection.c functions as mk_conn_read(),
682  * mk_conn_write(),mk_conn_error(), mk_conn_close() and mk_conn_timeout().
683  *
684  * Return Values:
685  * -------------
686  *    MK_PLUGIN_RET_EVENT_NOT_ME: There's no plugin hook associated
687  */
688 
mk_plugin_event_bad_return(const char * hook,int ret)689 void mk_plugin_event_bad_return(const char *hook, int ret)
690 {
691     mk_err("[%s] Not allowed return value %i", hook, ret);
692 }
693 
mk_plugin_time_now_unix()694 int mk_plugin_time_now_unix()
695 {
696     return log_current_utime;
697 }
698 
mk_plugin_time_now_human()699 mk_ptr_t *mk_plugin_time_now_human()
700 {
701     return &log_current_time;
702 }
703 
mk_plugin_sched_remove_client(int socket,struct mk_server * server)704 int mk_plugin_sched_remove_client(int socket, struct mk_server *server)
705 {
706     struct mk_sched_conn *conn;
707     struct mk_sched_worker *sched;
708 
709     MK_TRACE("[FD %i] remove client", socket);
710 
711     sched = mk_sched_get_thread_conf();
712     conn  = mk_sched_get_connection(sched, socket);
713     if (!conn) {
714         return -1;
715     }
716 
717     return mk_sched_remove_client(conn, sched, server);
718 }
719 
mk_plugin_header_prepare(struct mk_plugin * plugin,struct mk_http_session * cs,struct mk_http_request * sr)720 int mk_plugin_header_prepare(struct mk_plugin *plugin,
721                              struct mk_http_session *cs,
722                              struct mk_http_request *sr)
723 {
724     return mk_header_prepare(cs, sr, plugin->server_ctx);
725 }
726 
727 
mk_plugin_header_add(struct mk_http_request * sr,char * row,int len)728 int mk_plugin_header_add(struct mk_http_request *sr, char *row, int len)
729 {
730     mk_bug(!sr);
731 
732     if (!sr->headers._extra_rows) {
733         /*
734          * We allocate space for a fixed number of IOV entries:
735          *
736          *   MK_PLUGIN_HEADER_EXTRA_ROWS = X
737          *
738          *  we use (MK_PLUGIN_HEADER_EXTRA_ROWS * 2) thinking in an ending CRLF
739          */
740         sr->headers._extra_rows = mk_iov_create(MK_PLUGIN_HEADER_EXTRA_ROWS * 2, 0);
741         mk_bug(!sr->headers._extra_rows);
742     }
743 
744     mk_iov_add(sr->headers._extra_rows, row, len,
745                MK_FALSE);
746     mk_iov_add(sr->headers._extra_rows,
747                mk_iov_crlf.data, mk_iov_crlf.len,
748                MK_FALSE);
749     return 0;
750 }
751 
mk_plugin_sched_get_thread_conf()752 struct mk_sched_worker *mk_plugin_sched_get_thread_conf()
753 {
754     return MK_TLS_GET(mk_tls_sched_worker_node);
755 }
756 
mk_plugin_cap(char cap,struct mk_server * server)757 struct mk_plugin *mk_plugin_cap(char cap, struct mk_server *server)
758 {
759     struct mk_list *head;
760     struct mk_plugin *plugin;
761 
762     mk_list_foreach(head, &server->plugins) {
763         plugin = mk_list_entry(head, struct mk_plugin, _head);
764         if (plugin->capabilities & cap) {
765             return plugin;
766         }
767     }
768 
769     return NULL;
770 }
771 
mk_handler_param_get(int id,struct mk_list * params)772 struct mk_vhost_handler_param *mk_handler_param_get(int id,
773                                                     struct mk_list *params)
774 {
775     int i = 0;
776     struct mk_list *head;
777 
778     mk_list_foreach(head, params) {
779         if (i == id) {
780             return mk_list_entry(head, struct mk_vhost_handler_param, _head);
781         }
782         i++;
783     }
784 
785     return NULL;
786 }
787