diff options
Diffstat (limited to 'fluent-bit/lib/monkey/plugins/dirlisting')
13 files changed, 1273 insertions, 0 deletions
diff --git a/fluent-bit/lib/monkey/plugins/dirlisting/ABOUT b/fluent-bit/lib/monkey/plugins/dirlisting/ABOUT new file mode 100644 index 000000000..2d71cb77e --- /dev/null +++ b/fluent-bit/lib/monkey/plugins/dirlisting/ABOUT @@ -0,0 +1,4 @@ +Directory Listing Plugin +======================== +When a directory is requested, this plugin will show +an HTML list of the available content to the client. diff --git a/fluent-bit/lib/monkey/plugins/dirlisting/CMakeLists.txt b/fluent-bit/lib/monkey/plugins/dirlisting/CMakeLists.txt new file mode 100644 index 000000000..7432e1091 --- /dev/null +++ b/fluent-bit/lib/monkey/plugins/dirlisting/CMakeLists.txt @@ -0,0 +1,7 @@ +set(src + dirlisting.c + ) + +MONKEY_PLUGIN(dirlisting "${src}") + +add_subdirectory(conf)
\ No newline at end of file diff --git a/fluent-bit/lib/monkey/plugins/dirlisting/OPTIONAL b/fluent-bit/lib/monkey/plugins/dirlisting/OPTIONAL new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/fluent-bit/lib/monkey/plugins/dirlisting/OPTIONAL diff --git a/fluent-bit/lib/monkey/plugins/dirlisting/conf/CMakeLists.txt b/fluent-bit/lib/monkey/plugins/dirlisting/conf/CMakeLists.txt new file mode 100644 index 000000000..4faf80a4d --- /dev/null +++ b/fluent-bit/lib/monkey/plugins/dirlisting/conf/CMakeLists.txt @@ -0,0 +1,11 @@ +set(conf_dir "${MK_PATH_CONF}/plugins/dirlisting/") + +install(DIRECTORY DESTINATION ${conf_dir}) + +if(BUILD_LOCAL) + file(COPY dirhtml.conf DESTINATION ${conf_dir}) + file(COPY themes DESTINATION ${conf_dir}) +else() + install(FILES dirhtml.conf DESTINATION ${conf_dir}) + install(DIRECTORY themes DESTINATION ${conf_dir}) +endif()
\ No newline at end of file diff --git a/fluent-bit/lib/monkey/plugins/dirlisting/conf/dirhtml.conf b/fluent-bit/lib/monkey/plugins/dirlisting/conf/dirhtml.conf new file mode 100644 index 000000000..c73188df2 --- /dev/null +++ b/fluent-bit/lib/monkey/plugins/dirlisting/conf/dirhtml.conf @@ -0,0 +1,2 @@ +[DIRLISTING] + Theme bootstrap diff --git a/fluent-bit/lib/monkey/plugins/dirlisting/conf/themes/bootstrap/entry.theme b/fluent-bit/lib/monkey/plugins/dirlisting/conf/themes/bootstrap/entry.theme new file mode 100644 index 000000000..8c1ef026d --- /dev/null +++ b/fluent-bit/lib/monkey/plugins/dirlisting/conf/themes/bootstrap/entry.theme @@ -0,0 +1,5 @@ +<tr> + <td><a title='%_target_title_%' href='%_target_url_%'>%_target_name_%</a></td> + <td>%_target_time_%</td> + <td>%_target_size_%</td> +</tr> diff --git a/fluent-bit/lib/monkey/plugins/dirlisting/conf/themes/bootstrap/footer.theme b/fluent-bit/lib/monkey/plugins/dirlisting/conf/themes/bootstrap/footer.theme new file mode 100644 index 000000000..88290ac8b --- /dev/null +++ b/fluent-bit/lib/monkey/plugins/dirlisting/conf/themes/bootstrap/footer.theme @@ -0,0 +1,8 @@ + <tbody> +</table> +</div> +</div> +<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> +<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script> +</body> +</HTML> diff --git a/fluent-bit/lib/monkey/plugins/dirlisting/conf/themes/bootstrap/header.theme b/fluent-bit/lib/monkey/plugins/dirlisting/conf/themes/bootstrap/header.theme new file mode 100644 index 000000000..f7f6cfcfd --- /dev/null +++ b/fluent-bit/lib/monkey/plugins/dirlisting/conf/themes/bootstrap/header.theme @@ -0,0 +1,27 @@ +<html> + <head> + <meta http-equiv="content-type" content="text/html; charset=UTF-8"> + <title>Index of %_html_title_%</title> + <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css"> + <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css"> + <link href="http://maxcdn.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css" rel="stylesheet"> + </head> + <body> + <div class="container"> + <h1>Index of %_html_title_%</h1> + <div class="table-responsive"> + <table class="table table-hover table-bordered"> + <thead> + <tr> + <th> + Name + </th> + <th> + Last time modified + </th> + <th> + Size + </th> + </tr> + </thead> + <tbody> diff --git a/fluent-bit/lib/monkey/plugins/dirlisting/conf/themes/guineo/entry.theme b/fluent-bit/lib/monkey/plugins/dirlisting/conf/themes/guineo/entry.theme new file mode 100644 index 000000000..af00e250c --- /dev/null +++ b/fluent-bit/lib/monkey/plugins/dirlisting/conf/themes/guineo/entry.theme @@ -0,0 +1,14 @@ +<TR> +<TD class="row"> + <A title='%_target_title_%' href='%_target_url_%'> + %_target_name_% + </A> +</TD> +<TD class="row"> + %_target_time_% +</TD> +<TD class="row"> + %_target_size_% + %_theme_path_% +</TD> +</TR> diff --git a/fluent-bit/lib/monkey/plugins/dirlisting/conf/themes/guineo/footer.theme b/fluent-bit/lib/monkey/plugins/dirlisting/conf/themes/guineo/footer.theme new file mode 100644 index 000000000..c785ba97f --- /dev/null +++ b/fluent-bit/lib/monkey/plugins/dirlisting/conf/themes/guineo/footer.theme @@ -0,0 +1,7 @@ +</TABLE> + +</TD> +</TR> +</TABLE> +</BODY></HTML> + diff --git a/fluent-bit/lib/monkey/plugins/dirlisting/conf/themes/guineo/header.theme b/fluent-bit/lib/monkey/plugins/dirlisting/conf/themes/guineo/header.theme new file mode 100644 index 000000000..6a11a458f --- /dev/null +++ b/fluent-bit/lib/monkey/plugins/dirlisting/conf/themes/guineo/header.theme @@ -0,0 +1,58 @@ +<HTML> + <HEAD> + <META http-equiv="content-type" content="text/html; charset=UTF-8"> + <STYLE type="text/css"> + H1.header { + text-align: center; + color: #4a77a0; + font-size: 12pt; + font-weight: bold; + } + .row { + color: #6c95bc; + font-size: 10pt; + background-color: #ffffff; + padding-left: 0.4em; + } + .title {color: #617691; font-size: 10pt; font-weight: bold;} + + a:link { + color: #475f7e; + } + a:visited { + color: #ac7a2a; + } + a:hover { + color: #475f7e; + background-color: #dbdbdb; + text-decoration: none; + } + a:active { + color: #333333; + } + </STYLE> + + <TITLE>Index of %_html_title_%</TITLE> + </HEAD> +<BODY> + +<CENTER> +<IMG src="/imgs/monkey_logo.png"> +<BR> +<h1 class="header">Index of %_html_title_%</h1> +<TABLE cellpadding="0" cellspacing="0" border="0" bgcolor="#000000" width="50%"> +<TR> +<TD> + +<TABLE cellpadding="2" cellspacing="1" border="0" bgcolor="#e7e7e7" width="100%"> +<TR bgcolor="#ececec"> + <TD class="title"> + Name + </TD> + <TD class="title"> + Last time modified + </TD> + <TD class="title"> + Size + </TD> +</TR> diff --git a/fluent-bit/lib/monkey/plugins/dirlisting/dirlisting.c b/fluent-bit/lib/monkey/plugins/dirlisting/dirlisting.c new file mode 100644 index 000000000..1ffd3fac4 --- /dev/null +++ b/fluent-bit/lib/monkey/plugins/dirlisting/dirlisting.c @@ -0,0 +1,949 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Monkey HTTP Server + * ================== + * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Some history about this plugin + * ------------------------------ + * 2008 - Rewrite module, suport dynamic themes by Eduardo Silva + * 2008 - Felipe Astroza (max) provided the mk_dirhtml_human_readable_size_func() + * 2007 - Add struct client_request support by Eduardo + * 2002 - Original version written by Daniel R. Ome + */ + +#include <monkey/mk_api.h> +#include <monkey/mk_stream.h> +#include "dirlisting.h" + +#include <time.h> +#include <dirent.h> +#include <sys/stat.h> + +const mk_ptr_t mk_dirhtml_default_mime = mk_ptr_init(MK_DIRHTML_DEFAULT_MIME); +const mk_ptr_t mk_dir_iov_dash = mk_ptr_init("-"); +const mk_ptr_t mk_dir_iov_none = mk_ptr_init(""); +const mk_ptr_t mk_dir_iov_slash = mk_ptr_init("/"); + +void mk_dirhtml_cb_body_rows(struct mk_stream_input *in); + +/* Function wrote by Max (Felipe Astroza), thanks! */ +static char *mk_dirhtml_human_readable_size(char *buf, size_t size, int len) +{ + unsigned long u = 1024, i; + static const char *__units[] = { + "b", "K", "M", "G", + "T", "P", "E", "Z", "Y", NULL + }; + + for (i = 0; __units[i] != NULL; i++) { + if ((size / u) == 0) { + break; + } + u *= 1024; + } + if (!i) { + snprintf(buf, size, "%lu%s", (long unsigned int) len, __units[0]); + } + else { + float fsize = (float) ((double) len / (u / 1024)); + snprintf(buf, size, "%.1f%s", fsize, __units[i]); + } + + return buf; +} + +static struct mk_f_list *mk_dirhtml_create_element(char *file, + unsigned char type, + char *full_path, + unsigned long *list_len) +{ + int n; + struct tm *st_time; + struct mk_f_list *entry; + + entry = mk_api->mem_alloc_z(sizeof(struct mk_f_list)); + + if (mk_api->file_get_info(full_path, &entry->info, MK_FILE_READ) != 0) { + mk_api->mem_free(entry); + return NULL; + } + + strcpy(entry->name, file); + entry->type = type; + + st_time = localtime((time_t *) & entry->info.last_modification); + n = strftime(entry->ft_modif, MK_DIRHTML_FMOD_LEN, "%d-%b-%G %H:%M", st_time); + if (n == 0) { + mk_mem_free(entry); + return NULL; + } + + if (type != DT_DIR) { + mk_dirhtml_human_readable_size(entry->size, + sizeof(entry->size), + entry->info.size); + } + else { + entry->size[0] = '-'; + entry->size[1] = '\0'; + } + + *list_len = *list_len + 1; + + return entry; +} + +static struct mk_list *mk_dirhtml_create_list(DIR * dir, char *path, + unsigned long *list_len) +{ + char full_path[PATH_MAX]; + struct mk_list *list; + struct dirent *ent; + struct mk_f_list *entry = 0; + + list = mk_api->mem_alloc(sizeof(struct mk_list)); + mk_list_init(list); + + while ((ent = readdir(dir)) != NULL) { + if ((ent->d_name[0] == '.') && (strcmp(ent->d_name, "..") != 0)) + continue; + + /* Look just for files and dirs */ + if (ent->d_type != DT_REG && ent->d_type != DT_DIR + && ent->d_type != DT_LNK && ent->d_type != DT_UNKNOWN) { + continue; + } + + snprintf(full_path, PATH_MAX, "%s%s", path, ent->d_name); + entry = mk_dirhtml_create_element(ent->d_name, + ent->d_type, full_path, list_len); + if (!entry) { + continue; + } + + mk_list_add(&entry->_head, list); + } + + return list; +} + +/* Read dirhtml config and themes */ +int mk_dirhtml_conf(char *confdir) +{ + int ret = 0; + unsigned long len; + char *conf_file = NULL; + + mk_api->str_build(&conf_file, &len, "%s", confdir); + + /* Read configuration */ + ret = mk_dirhtml_read_config(conf_file); + if (ret < 0) { + mk_mem_free(conf_file); + return -1; + } + + /* + * This function will load the default theme setted in dirhtml_conf struct + */ + mk_mem_free(conf_file); + return mk_dirhtml_theme_load(); +} + +/* + * Read the main configuration file for dirhtml: dirhtml.conf, + * it will alloc the dirhtml_conf struct +*/ +int mk_dirhtml_read_config(char *path) +{ + unsigned long len; + char *default_file = NULL; + struct mk_rconf *conf; + struct mk_rconf_section *section; + struct file_info finfo; + + mk_api->str_build(&default_file, &len, "%sdirhtml.conf", path); + conf = mk_api->config_open(default_file); + if (!conf) { + return -1; + } + + section = mk_api->config_section_get(conf, "DIRLISTING"); + if (!section) { + mk_err_ex(mk_api, "Could not find DIRLISTING tag in configuration file"); + exit(EXIT_FAILURE); + } + + /* alloc dirhtml config struct */ + dirhtml_conf = mk_api->mem_alloc(sizeof(struct dirhtml_config)); + dirhtml_conf->theme = mk_api->config_section_get_key(section, "Theme", + MK_RCONF_STR); + dirhtml_conf->theme_path = NULL; + + mk_api->str_build(&dirhtml_conf->theme_path, &len, + "%sthemes/%s/", path, dirhtml_conf->theme); + mk_api->mem_free(default_file); + + if (mk_api->file_get_info(dirhtml_conf->theme_path, + &finfo, MK_FILE_READ) != 0) { + mk_warn_ex(mk_api, "Dirlisting: cannot load theme from '%s'", dirhtml_conf->theme_path); + mk_warn_ex(mk_api, "Dirlisting: unloading plugin"); + return -1; + } + + mk_api->config_free(conf); + return 0; +} + +int mk_dirhtml_theme_load() +{ + /* Data */ + char *header, *entry, *footer; + + /* Load theme files */ + header = mk_dirhtml_load_file(MK_DIRHTML_FILE_HEADER); + entry = mk_dirhtml_load_file(MK_DIRHTML_FILE_ENTRY); + footer = mk_dirhtml_load_file(MK_DIRHTML_FILE_FOOTER); + + if (!header || !entry || !footer) { + mk_api->mem_free(header); + mk_api->mem_free(entry); + mk_api->mem_free(footer); + return -1; + } + + /* Parse themes */ + mk_dirhtml_tpl_header = mk_dirhtml_template_create(header); + mk_dirhtml_tpl_entry = mk_dirhtml_template_create(entry); + mk_dirhtml_tpl_footer = mk_dirhtml_template_create(footer); + +#ifdef DEBUG_THEME + /* Debug data */ + mk_dirhtml_theme_debug(&mk_dirhtml_tpl_header); + mk_dirhtml_theme_debug(&mk_dirhtml_tpl_entry); + mk_dirhtml_theme_debug(&mk_dirhtml_tpl_footer); + +#endif + mk_api->mem_free(header); + mk_api->mem_free(entry); + mk_api->mem_free(footer); + + return 0; +} + +#ifdef DEBUG_THEME +int mk_dirhtml_theme_debug(struct dirhtml_template **st_tpl) +{ + int i = 0; + struct dirhtml_template *aux; + + aux = *st_tpl; + + printf("\n** DEBUG_THEME **"); + fflush(stdout); + + while (aux) { + printf("\n%i) len=%i, tag_id=%i", i, aux->len, aux->tag_id); + if (aux->tag_id >= 0) { + printf(" (%s) ", aux->tags[aux->tag_id]); + } + fflush(stdout); + aux = aux->next; + i++; + } + return 0; +} +#endif + +/* Search which tag exists first in content : + * ex: %_html_title_% + */ +static int mk_dirhtml_theme_match_tag(char *content, char *tpl[]) +{ + int i, len, match; + + for (i = 0; tpl[i]; i++) { + len = strlen(tpl[i]); + match = (int) mk_api->str_search_n(content, tpl[i], MK_STR_INSENSITIVE, len); + if (match >= 0) { + return i; + } + } + + return -1; +} + +struct dirhtml_template *mk_dirhtml_template_create(char *content) +{ + int i = 0, cont_len; + int pos, last = 0; /* 0=search init, 1=search end */ + int n_tags = 0, tpl_idx = 0; + + char *_buf; + int _len; + + /* Global keys */ + char **_tpl = 0; + + /* Template to return */ + struct dirhtml_template *st_tpl = 0; + + cont_len = strlen(content); + if (cont_len <= 0) { + return NULL; + } + + /* Parsing content */ + while (i < cont_len) { + pos = (int) mk_api->str_search(content + i, + MK_DIRHTML_TAG_INIT, MK_STR_INSENSITIVE); + + if (pos < 0) { + break; + } + + /* Checking global tag, if it's not found, proceed with + * 'entry tags' + */ + _tpl = (char **) _tags_global; + tpl_idx = mk_dirhtml_theme_match_tag(content + i + pos, _tpl); + + /* if global template do not match, use the entry tags */ + if (tpl_idx < 0) { + _tpl = (char **) _tags_entry; + tpl_idx = mk_dirhtml_theme_match_tag(content + i + pos, _tpl); + } + + /* if tag found is known, we add them to our list */ + if (tpl_idx >= 0) { + + _buf = mk_api->str_copy_substr(content, i, i + pos); + _len = strlen(_buf); + + /* Dummy if/else to create or pass a created st_tpl */ + if (!st_tpl) { + st_tpl = mk_dirhtml_template_list_add(NULL, + _buf, _len, _tpl, -1); + } + else { + mk_dirhtml_template_list_add(&st_tpl, _buf, _len, _tpl, -1); + } + i += (pos + strlen(_tpl[tpl_idx])); + + /* This means that a value need to be replaced */ + mk_dirhtml_template_list_add(&st_tpl, NULL, -1, _tpl, tpl_idx); + n_tags++; + } + else { + i++; + } + } + + if (last < cont_len) { + _buf = mk_api->str_copy_substr(content, i, cont_len); + _len = strlen(_buf); + + if (n_tags <= 0) { + st_tpl = mk_dirhtml_template_list_add(NULL, _buf, _len, _tpl, -1); + } + else { + mk_dirhtml_template_list_add(&st_tpl, _buf, _len, _tpl, -1); + } + } + + return st_tpl; +} + +struct dirhtml_template *mk_dirhtml_template_list_add(struct dirhtml_template **header, + char *buf, int len, char **tpl, + int tag_id) +{ + struct dirhtml_template *node, *aux; + + node = mk_api->mem_alloc_z(sizeof(struct dirhtml_template)); + if (!node) { + return NULL; + } + + node->buf = buf; + node->len = len; + node->tag_id = tag_id; + node->tags = tpl; + node->next = NULL; + + if (!header || !(*header)) { + return (struct dirhtml_template *) node; + } + + aux = *header; + while ((*aux).next != NULL) { + aux = (*aux).next; + } + + (*aux).next = node; + return (struct dirhtml_template *) node; +} + +static int mk_dirhtml_template_len(struct dirhtml_template *tpl) +{ + int len = 0; + struct dirhtml_template *aux; + + aux = tpl; + while (aux) { + len++; + aux = aux->next; + } + + return len; +} + +static struct mk_iov *mk_dirhtml_theme_compose(struct dirhtml_template *template, + struct mk_list *list) +{ + /* + * template = struct { char buf ; int len, int tag } + * values = struct {int tag, char *value, struct *next} + */ + struct mk_iov *iov; + struct dirhtml_template *tpl = template; + struct dirhtml_value *val; + struct mk_list *head; + + int tpl_len; + + tpl_len = mk_dirhtml_template_len(template); + + /* we duplicate the lenght in case we get separators */ + iov = mk_api->iov_create(1 + tpl_len * 2, 1); + tpl = template; + + while (tpl) { + /* check for dynamic value */ + if (!tpl->buf && tpl->tag_id >= 0) { + mk_list_foreach(head, list) { + val = mk_list_entry(head, struct dirhtml_value, _head); + if (val->tags == tpl->tags && val->tag_id == tpl->tag_id) { + mk_api->iov_add(iov, + val->value, val->len, + MK_FALSE); + mk_api->iov_add(iov, + val->sep.data, val->sep.len, + MK_FALSE); + break; + } + } + } + /* static */ + else { + mk_api->iov_add(iov, + tpl->buf, tpl->len, + MK_FALSE); + } + tpl = tpl->next; + } + + return iov; +} + +struct dirhtml_value *mk_dirhtml_tag_assign(struct mk_list *list, + int tag_id, mk_ptr_t sep, + char *value, char **tags) +{ + struct dirhtml_value *aux = NULL; + + aux = mk_api->mem_alloc(sizeof(struct dirhtml_value)); + if (!aux) { + return NULL; + } + + aux->tag_id = tag_id; + aux->value = value; + aux->sep = sep; + aux->tags = tags; + + if (value) { + aux->len = strlen(value); + } + else { + aux->len = -1; + } + + mk_list_add(&aux->_head, list); + return (struct dirhtml_value *) aux; +} + +static void mk_dirhtml_tag_free_list(struct mk_list *list) +{ + struct mk_list *head; + struct mk_list *tmp; + struct dirhtml_value *target; + + mk_list_foreach_safe(head, tmp, list) { + target = mk_list_entry(head, struct dirhtml_value, _head); + mk_list_del(&target->_head); + mk_api->mem_free(target); + } +} + +char *mk_dirhtml_load_file(char *filename) +{ + char *tmp = 0, *data = 0; + unsigned long len; + + mk_api->str_build(&tmp, &len, "%s%s", dirhtml_conf->theme_path, filename); + + if (!tmp) { + return NULL; + } + + data = mk_api->file_to_buffer(tmp); + mk_api->mem_free(tmp); + + if (!data) { + return NULL; + } + + return (char *) data; +} + +static int mk_dirhtml_entry_cmp(const void *a, const void *b) +{ + struct mk_f_list *const *f_a = a; + struct mk_f_list *const *f_b = b; + + return strcasecmp((*f_a)->name, (*f_b)->name); +} + +static void mk_dirhtml_free_list(struct mk_dirhtml_request *request) +{ + struct mk_list *tmp; + struct mk_list *head; + struct mk_f_list *entry; + + mk_list_foreach_safe(head, tmp, request->file_list) { + entry = mk_list_entry(head, struct mk_f_list, _head); + mk_list_del(&entry->_head); + mk_api->mem_free(entry); + } + + mk_api->mem_free(request->file_list); + mk_api->mem_free(request->toc); +} + +static inline struct mk_iov *enqueue_row(int i, struct mk_dirhtml_request *request) +{ + mk_ptr_t sep; + struct mk_list list; + struct mk_iov *iov_entry; + + /* %_target_title_% */ + if (request->toc[i]->type == DT_DIR) { + sep = mk_dir_iov_slash; + } + else { + sep = mk_dir_iov_none; + } + + mk_list_init(&list); + + /* target title */ + mk_dirhtml_tag_assign(&list, 0, sep, + request->toc[i]->name, + (char **) _tags_entry); + + /* target url */ + mk_dirhtml_tag_assign(&list, 1, sep, + request->toc[i]->name, (char **) _tags_entry); + + /* target name */ + mk_dirhtml_tag_assign(&list, 2, sep, + request->toc[i]->name, (char **) _tags_entry); + + /* target modification time */ + mk_dirhtml_tag_assign(&list, 3, mk_dir_iov_none, + request->toc[i]->ft_modif, (char **) _tags_entry); + + /* target size */ + mk_dirhtml_tag_assign(&list, 4, mk_dir_iov_none, + request->toc[i]->size, (char **) _tags_entry); + + iov_entry = mk_dirhtml_theme_compose(mk_dirhtml_tpl_entry, &list); + + /* free entry list */ + mk_dirhtml_tag_free_list(&list); + return iov_entry; +} + +/* Release all resources for a given Request context */ +void mk_dirhtml_cleanup(struct mk_dirhtml_request *req) +{ + PLUGIN_TRACE("release resources"); + + if (req->iov_header) { + mk_api->iov_free(req->iov_header); + req->iov_header = NULL; + } + if (req->iov_entry) { + mk_api->iov_free(req->iov_entry); + req->iov_entry = NULL; + } + if (req->iov_footer) { + mk_api->iov_free(req->iov_footer); + req->iov_footer = NULL; + } + mk_dirhtml_free_list(req); + closedir(req->dir); + + req->sr->handler_data = NULL; + mk_api->mem_free(req); + req = NULL; +} + +void mk_dirhtml_cb_complete(struct mk_stream_input *in) +{ + struct mk_stream *stream; + struct mk_dirhtml_request *req; + + stream = in->stream; + req = stream->context; + if (req) { + mk_dirhtml_cleanup(req); + } +} + +void mk_dirhtml_cb_error(struct mk_stream *stream, int status) +{ +#ifndef TRACE + (void) status; +#endif + struct mk_dirhtml_request *req = stream->context; + + PLUGIN_TRACE("exception: %i", status); + + if (req) { + mk_dirhtml_cleanup(req); + } +} + +void mk_dirhtml_cb_chunk_body_rows(struct mk_stream_input *in, long bytes) +{ + (void) bytes; + + mk_dirhtml_cb_body_rows(in); +} + +void mk_dirhtml_cb_body_rows(struct mk_stream_input *in) +{ + int len; + char tmp[16]; + struct mk_stream *stream = in->stream; + struct mk_dirhtml_request *req = stream->context; + void (*cb_ok)(struct mk_stream_input *) = NULL; + + if (req->iov_entry) { + mk_api->iov_free(req->iov_entry); + req->iov_entry = NULL; + } + + if (req->toc_idx >= req->toc_len) { + if (req->chunked) { + len = snprintf(tmp, sizeof(tmp), "%x\r\n", + (int) req->iov_footer->total_len); + mk_stream_in_raw(req->stream, + NULL, + tmp, len, + NULL, NULL); + cb_ok = NULL; + } + else { + cb_ok = mk_dirhtml_cb_complete; + } + + mk_stream_in_iov(req->stream, + NULL, + req->iov_footer, + NULL, NULL); + if (req->chunked) { + mk_stream_in_raw(req->stream, + NULL, + "\r\n0\r\n\r\n", 7, + NULL, mk_dirhtml_cb_complete); + } + + return; + } + + req->iov_entry = enqueue_row(req->toc_idx, req); + if (req->chunked) { + len = snprintf(tmp, sizeof(tmp), "%x\r\n", + (int) req->iov_entry->total_len); + mk_stream_in_raw(req->stream, + NULL, + tmp, len, + NULL, NULL); + cb_ok = NULL; + } + else { + cb_ok = mk_dirhtml_cb_body_rows; + } + + mk_stream_in_iov(req->stream, + NULL, + req->iov_entry, + NULL, cb_ok); + + if (req->chunked) { + mk_stream_in_raw(req->stream, + NULL, + "\r\n", 2, + mk_dirhtml_cb_chunk_body_rows, NULL); + } + req->toc_idx++; +} + +/* + * The HTTP Headers were sent, now start registering the + * rows for each directory entry. + */ +void cb_header_finish(struct mk_stream_input *in) +{ + struct mk_stream *stream = in->stream; + struct mk_dirhtml_request *req; + + req = stream->context; + if (req->iov_header) { + mk_api->iov_free(req->iov_header); + req->iov_header = NULL; + } + mk_dirhtml_cb_body_rows(in); +} + +static int mk_dirhtml_init(struct mk_plugin *plugin, + struct mk_http_session *cs, struct mk_http_request *sr) +{ + DIR *dir; + int len; + char tmp[16]; + unsigned int i = 0; + struct mk_list *head; + struct mk_list list; + struct mk_f_list *entry; + struct mk_dirhtml_request *request; + struct mk_stream *stream; + + if (!(dir = opendir(sr->real_path.data))) { + return -1; + } + + /* Create the main context */ + request = mk_api->mem_alloc(sizeof(struct mk_dirhtml_request)); + if (!request) { + closedir(dir); + return -1; + } + + stream = mk_stream_set(NULL, cs->channel, request, + NULL, NULL, mk_dirhtml_cb_error); + if (!stream) { + closedir(dir); + free(request); + return -1; + } + + request->stream = stream; + request->state = MK_DIRHTML_STATE_HTTP_HEADER; + request->dir = dir; + request->toc_idx = 0; + request->cs = cs; + request->sr = sr; + request->toc_len = 0; + request->chunked = MK_FALSE; + request->iov_header = NULL; + request->iov_entry = NULL; + request->iov_footer = NULL; + + sr->handler_data = request; + + request->file_list = mk_dirhtml_create_list(dir, sr->real_path.data, + &request->toc_len); + + /* Building headers */ + mk_api->header_set_http_status(sr, MK_HTTP_OK); + sr->headers.cgi = SH_CGI; + sr->headers.breakline = MK_HEADER_BREAKLINE; + sr->headers.content_type = mk_dirhtml_default_mime; + sr->headers.content_length = -1; + + if (sr->protocol >= MK_HTTP_PROTOCOL_11) { + sr->headers.transfer_encoding = MK_HEADER_TE_TYPE_CHUNKED; + request->chunked = MK_TRUE; + } + + /* + * Creating response template + */ + + mk_list_init(&list); + + /* Set %_html_title_% */ + mk_dirhtml_tag_assign(&list, 0, mk_dir_iov_none, + sr->uri_processed.data, + (char **) _tags_global); + + /* Set %_theme_path_% */ + mk_dirhtml_tag_assign(&list, 1, mk_dir_iov_none, + dirhtml_conf->theme_path, (char **) _tags_global); + + /* HTML Header */ + request->iov_header = mk_dirhtml_theme_compose(mk_dirhtml_tpl_header, + &list); + + /* HTML Footer */ + request->iov_footer = mk_dirhtml_theme_compose(mk_dirhtml_tpl_footer, + &list); + mk_dirhtml_tag_free_list(&list); + + /* Creating table of contents and sorting */ + request->toc = mk_api->mem_alloc(sizeof(struct mk_f_list *) * request->toc_len); + + i = 0; + mk_list_foreach(head, request->file_list) { + entry = mk_list_entry(head, struct mk_f_list, _head); + request->toc[i] = entry; + i++; + } + + qsort(request->toc, + request->toc_len, + sizeof(*request->toc), + mk_dirhtml_entry_cmp); + + /* Prepare HTTP response headers */ + mk_api->header_prepare(plugin, cs, sr); + + if (request->chunked) { + len = snprintf(tmp, sizeof(tmp), "%x\r\n", + (int) request->iov_header->total_len); + mk_stream_in_raw(request->stream, + NULL, + tmp, len, + NULL, mk_dirhtml_cb_complete); + } + + mk_stream_in_iov(request->stream, + NULL, + request->iov_header, + NULL, cb_header_finish); + + if (request->chunked) { + mk_stream_in_raw(request->stream, + NULL, + "\r\n", 2, + NULL, NULL); + } + return 0; +} + +int mk_dirlisting_plugin_init(struct mk_plugin *plugin, char *confdir) +{ + mk_api = plugin->api; + + return mk_dirhtml_conf(confdir); +} + +int mk_dirlisting_plugin_exit(struct mk_plugin *plugin) +{ + (void) plugin; + + mk_api->mem_free(dirhtml_conf->theme); + mk_api->mem_free(dirhtml_conf->theme_path); + mk_api->mem_free(dirhtml_conf); + + return 0; +} + +int mk_dirlisting_stage30(struct mk_plugin *plugin, + struct mk_http_session *cs, + struct mk_http_request *sr, + int n_param, + struct mk_list *params) +{ + (void) plugin; + (void) n_param; + (void) params; + + /* validate file_info */ + if (sr->file_info.size == 0) { + return MK_PLUGIN_RET_NOT_ME; + } + + /* This plugin just handle directories */ + if (sr->file_info.is_directory == MK_FALSE) { + return MK_PLUGIN_RET_NOT_ME; + } + + PLUGIN_TRACE("Dirlisting attending socket %i", cs->socket); + if (mk_dirhtml_init(plugin, cs, sr)) { + /* + * If we failed here, we cannot return RET_END - that causes a mk_bug. + * dirhtml_init only fails if opendir fails. Usually we're at full + * capacity then and can't open new files. + */ + return MK_PLUGIN_RET_CLOSE_CONX; + } + + return MK_PLUGIN_RET_END; +} + +int mk_dirlisting_stage30_hangup(struct mk_plugin *plugin, + struct mk_http_session *cs, + struct mk_http_request *sr) +{ + (void) cs; + (void) plugin; + + if (sr->handler_data) { + mk_dirhtml_cleanup(sr->handler_data); + } + return 0; +} + +struct mk_plugin_stage mk_plugin_stage_dirlisting = { + .stage30 = &mk_dirlisting_stage30, + .stage30_hangup = &mk_dirlisting_stage30_hangup +}; + +struct mk_plugin mk_plugin_dirlisting = { + /* Identification */ + .shortname = "dirlisting", + .name = "Directory Listing", + .version = MK_VERSION_STR, + .hooks = MK_PLUGIN_STAGE, + + /* Init / Exit */ + .init_plugin = mk_dirlisting_plugin_init, + .exit_plugin = mk_dirlisting_plugin_exit, + + /* Init Levels */ + .master_init = NULL, + .worker_init = NULL, + + /* Type */ + .stage = &mk_plugin_stage_dirlisting +}; diff --git a/fluent-bit/lib/monkey/plugins/dirlisting/dirlisting.h b/fluent-bit/lib/monkey/plugins/dirlisting/dirlisting.h new file mode 100644 index 000000000..678a4887b --- /dev/null +++ b/fluent-bit/lib/monkey/plugins/dirlisting/dirlisting.h @@ -0,0 +1,181 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Monkey HTTP Server + * ================== + * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* dir_html.c */ +#ifndef MK_DIRHTML_H +#define MK_DIRHTML_H + +#include <dirent.h> +#include <limits.h> + +#define MK_DIRHTML_URL "/_mktheme" +#define MK_DIRHTML_DEFAULT_MIME "Content-Type: text/html\r\n" + +/* For every directory requested, don't send more than + * this limit of entries. + */ +#define MK_DIRHTML_BUFFER_LIMIT 30 +#define MK_DIRHTML_BUFFER_GROW 5 + +#define MK_HEADER_CHUNKED "Transfer-Encoding: Chunked\r\n\r\n" +#define MK_DIRHTML_FMOD_LEN 24 + +/* Theme files */ +#define MK_DIRHTML_FILE_HEADER "header.theme" +#define MK_DIRHTML_FILE_ENTRY "entry.theme" +#define MK_DIRHTML_FILE_FOOTER "footer.theme" + +#define MK_DIRHTML_TAG_INIT "%_" +#define MK_DIRHTML_TAG_END "_%" +#define MK_DIRHTML_SIZE_DIR "-" + +/* Stream state */ +#define MK_DIRHTML_STATE_HTTP_HEADER 0 +#define MK_DIRHTML_STATE_TPL_HEADER 1 +#define MK_DIRHTML_STATE_BODY 2 +#define MK_DIRHTML_STATE_FOOTER 3 + +char *_tags_global[] = { "%_html_title_%", + "%_theme_path_%", + NULL +}; + +char *_tags_entry[] = { "%_target_title_%", + "%_target_url_%", + "%_target_name_%", + "%_target_time_%", + "%_target_size_%", + NULL +}; + +struct plugin_api *mk_api; + +struct mk_f_list +{ + char ft_modif[MK_DIRHTML_FMOD_LEN]; + struct file_info info; + char name[NAME_MAX + 1]; /* The name can be up to NAME_MAX long; include NULL. */ + char size[16]; + unsigned char type; + + struct mk_list _head; +}; + +/* Main configuration of dirhtml module */ +struct dirhtml_config +{ + char *theme; + char *theme_path; +}; + +/* Represent a request context */ +struct mk_dirhtml_request +{ + /* State */ + int state; + int chunked; + + /* Target directory */ + DIR *dir; + + /* Table of Content */ + unsigned int toc_idx; + unsigned long toc_len; + struct mk_f_list **toc; + struct mk_list *file_list; + + /* Stream handler */ + struct mk_stream *stream; + + /* Reference IOV stuff */ + struct mk_iov *iov_header; + struct mk_iov *iov_entry; + struct mk_iov *iov_footer; + + /* Session data */ + struct mk_http_session *cs; + struct mk_http_request *sr; +}; + + +extern const mk_ptr_t mk_dirhtml_default_mime; +extern const mk_ptr_t mk_iov_dash; + +/* Global config */ +struct dirhtml_config *dirhtml_conf; + +/* Used to keep splitted content of every template */ +struct dirhtml_template +{ + char *buf; + int tag_id; + int len; + struct dirhtml_template *next; + char **tags; /* array of theme tags: [%_xaa__%, %_xyz_%] */ +}; + +/* Templates for header, entries and footer */ +struct dirhtml_template *mk_dirhtml_tpl_header; +struct dirhtml_template *mk_dirhtml_tpl_entry; +struct dirhtml_template *mk_dirhtml_tpl_footer; + +struct dirhtml_value +{ + int tag_id; + mk_ptr_t sep; /* separator code after value */ + + /* string data */ + int len; + char *value; + + /* next node */ + struct mk_list _head; + + char **tags; /* array of tags which values correspond */ +}; + +struct dirhtml_value *mk_dirhtml_value_global; + +/* Configuration struct */ +struct mk_config *conf; + +char *check_string(char *str); +char *read_header_footer_file(char *file_path); + +int mk_dirhtml_conf(); +char *mk_dirhtml_load_file(char *filename); + +struct dirhtml_template *mk_dirhtml_template_create(char *content); + +struct dirhtml_template + *mk_dirhtml_template_list_add(struct dirhtml_template **header, + char *buf, int len, char **tpl, int tag); + +int mk_dirhtml_read_config(char *path); +int mk_dirhtml_theme_load(); +int mk_dirhtml_theme_debug(struct dirhtml_template **st_tpl); + +struct dirhtml_value *mk_dirhtml_tag_assign(struct mk_list *list, + int tag_id, mk_ptr_t sep, + char *value, char **tags); + +struct f_list *get_dir_content(struct mk_http_request *sr, char *path); + + +#endif |