diff options
Diffstat (limited to 'fluent-bit/lib/monkey/plugins/cgi')
-rw-r--r-- | fluent-bit/lib/monkey/plugins/cgi/CMakeLists.txt | 7 | ||||
-rw-r--r-- | fluent-bit/lib/monkey/plugins/cgi/cgi.c | 501 | ||||
-rw-r--r-- | fluent-bit/lib/monkey/plugins/cgi/cgi.h | 133 | ||||
-rw-r--r-- | fluent-bit/lib/monkey/plugins/cgi/event.c | 170 | ||||
-rw-r--r-- | fluent-bit/lib/monkey/plugins/cgi/request.c | 72 |
5 files changed, 883 insertions, 0 deletions
diff --git a/fluent-bit/lib/monkey/plugins/cgi/CMakeLists.txt b/fluent-bit/lib/monkey/plugins/cgi/CMakeLists.txt new file mode 100644 index 00000000..121144aa --- /dev/null +++ b/fluent-bit/lib/monkey/plugins/cgi/CMakeLists.txt @@ -0,0 +1,7 @@ +set(src + cgi.c + event.c + request.c + ) + +MONKEY_PLUGIN(cgi "${src}") diff --git a/fluent-bit/lib/monkey/plugins/cgi/cgi.c b/fluent-bit/lib/monkey/plugins/cgi/cgi.c new file mode 100644 index 00000000..58c7a647 --- /dev/null +++ b/fluent-bit/lib/monkey/plugins/cgi/cgi.c @@ -0,0 +1,501 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Monkey HTTP Server + * ================== + * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io> + * Copyright (C) 2012-2013, Lauri Kasanen + * + * 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. + */ + +#include <monkey/mk_stream.h> +#include "cgi.h" + +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <sys/stat.h> + +void cgi_finish(struct cgi_request *r) +{ + /* + * Unregister & close the CGI child process pipe reader fd from the + * thread event loop, otherwise we may get unexpected notifications. + */ + mk_api->ev_del(mk_api->sched_loop(), (struct mk_event *) r); + close(r->fd); + if (r->chunked && r->active == MK_TRUE) { + PLUGIN_TRACE("CGI sending Chunked EOF"); + channel_write(r, "0\r\n\r\n", 5); + } + + /* Try to kill any child process */ + if (r->child > 0) { + kill(r->child, SIGKILL); + r->child = 0; + } + + /* Invalidte our socket handler */ + requests_by_socket[r->socket] = NULL; + if (r->active == MK_TRUE) { + mk_api->http_request_end(r->plugin, r->cs, r->hangup); + } + cgi_req_del(r); +} + +int swrite(const int fd, const void *buf, const size_t count) +{ + ssize_t pos = count, ret = 0; + + while (pos > 0 && ret >= 0) { + ret = write(fd, buf, pos); + if (ret < 0) { + return ret; + } + + pos -= ret; + buf += ret; + } + return count; +} + +int channel_write(struct cgi_request *r, void *buf, size_t count) +{ + int ret; + + if (r->active == MK_FALSE) { + return -1; + } + + MK_TRACE("channel write: %d bytes", count); + mk_stream_in_raw(&r->sr->stream, + NULL, + buf, count, + NULL, NULL); + + ret = mk_api->channel_flush(r->sr->session->channel); + if (ret & MK_CHANNEL_ERROR) { + r->active = MK_FALSE; + cgi_finish(r); + } + return 0; +} + +static void cgi_write_post(void *p) +{ + const struct post_t * const in = p; + + swrite(in->fd, in->buf, in->len); + close(in->fd); +} + +static int do_cgi(const char *const __restrict__ file, + const char *const __restrict__ url, + struct mk_http_request *sr, + struct mk_http_session *cs, + struct mk_plugin *plugin, + char *interpreter, + char *mimetype) +{ + int ret; + int devnull; + const int socket = cs->socket; + struct file_info finfo; + struct cgi_request *r = NULL; + struct mk_event *event; + char *env[30]; + int writepipe[2], readpipe[2]; + (void) plugin; + + /* Unchanging env vars */ + env[0] = "PATH_INFO="; + env[1] = "GATEWAY_INTERFACE=CGI/1.1"; + env[2] = "REDIRECT_STATUS=200"; + const int env_start = 3; + char *protocol; + unsigned long len; + + /* Dynamic env vars */ + unsigned short envpos = env_start; + + char method[SHORTLEN]; + char *query = NULL; + char request_uri[PATHLEN]; + char script_filename[PATHLEN]; + char script_name[PATHLEN]; + char query_string[PATHLEN]; + char remote_addr[INET6_ADDRSTRLEN+SHORTLEN]; + char tmpaddr[INET6_ADDRSTRLEN], *ptr = tmpaddr; + char remote_port[SHORTLEN]; + char content_length[SHORTLEN]; + char content_type[SHORTLEN]; + char server_software[SHORTLEN]; + char server_protocol[SHORTLEN]; + char http_host[SHORTLEN]; + + /* Check the interpreter exists */ + if (interpreter) { + ret = mk_api->file_get_info(interpreter, &finfo, MK_FILE_EXEC); + if (ret == -1 || + (finfo.is_file == MK_FALSE && finfo.is_link == MK_FALSE) || + finfo.exec_access == MK_FALSE) { + return 500; + } + } + + if (mimetype) { + sr->content_type.data = mimetype; + sr->content_type.len = strlen(mimetype); + } + + snprintf(method, SHORTLEN, "REQUEST_METHOD=%.*s", (int) sr->method_p.len, sr->method_p.data); + env[envpos++] = method; + + snprintf(server_software, SHORTLEN, "SERVER_SOFTWARE=%s", + mk_api->config->server_signature); + env[envpos++] = server_software; + + snprintf(http_host, SHORTLEN, "HTTP_HOST=%.*s", (int) sr->host.len, sr->host.data); + env[envpos++] = http_host; + + if (sr->protocol == MK_HTTP_PROTOCOL_11) + protocol = MK_HTTP_PROTOCOL_11_STR; + else + protocol = MK_HTTP_PROTOCOL_10_STR; + + snprintf(server_protocol, SHORTLEN, "SERVER_PROTOCOL=%s", protocol); + env[envpos++] = server_protocol; + + if (sr->query_string.len) { + query = mk_api->mem_alloc_z(sr->query_string.len + 1); + memcpy(query, sr->query_string.data, sr->query_string.len); + snprintf(request_uri, PATHLEN, "REQUEST_URI=%s?%s", url, query); + } + else { + snprintf(request_uri, PATHLEN, "REQUEST_URI=%s", url); + } + env[envpos++] = request_uri; + + snprintf(script_filename, PATHLEN, "SCRIPT_FILENAME=%s", file); + env[envpos++] = script_filename; + + snprintf(script_name, PATHLEN, "SCRIPT_NAME=%s", url); + env[envpos++] = script_name; + + if (query) { + snprintf(query_string, PATHLEN, "QUERY_STRING=%s", query); + env[envpos++] = query_string; + mk_api->mem_free(query); + } + + if (mk_api->socket_ip_str(socket, &ptr, INET6_ADDRSTRLEN, &len) < 0) + tmpaddr[0] = '\0'; + snprintf(remote_addr, INET6_ADDRSTRLEN+SHORTLEN, "REMOTE_ADDR=%s", tmpaddr); + env[envpos++] = remote_addr; + + snprintf(remote_port, SHORTLEN, "REMOTE_PORT=%ld", sr->port); + env[envpos++] = remote_port; + + if (sr->data.len) { + snprintf(content_length, SHORTLEN, "CONTENT_LENGTH=%lu", sr->data.len); + env[envpos++] = content_length; + } + + if (sr->content_type.len) { + snprintf(content_type, SHORTLEN, "CONTENT_TYPE=%.*s", (int)sr->content_type.len, sr->content_type.data); + env[envpos++] = content_type; + } + + + /* Must be NULL-terminated */ + env[envpos] = NULL; + + /* pipes, from monkey's POV */ + if (pipe(writepipe) || pipe(readpipe)) { + mk_err("Failed to create pipe"); + return 403; + } + + pid_t pid = vfork(); + if (pid < 0) { + mk_err("Failed to fork"); + return 403; + } + + /* Child */ + if (pid == 0) { + close(writepipe[1]); + close(readpipe[0]); + + /* Our stdin is the read end of monkey's writing */ + if (dup2(writepipe[0], 0) < 0) { + mk_err("dup2 failed"); + _exit(1); + } + close(writepipe[0]); + + /* Our stdout is the write end of monkey's reading */ + if (dup2(readpipe[1], 1) < 0) { + mk_err("dup2 failed"); + _exit(1); + } + close(readpipe[1]); + + /* Our stderr goes to /dev/null */ + devnull = open("/dev/null", O_WRONLY); + if (devnull == -1) { + perror("open"); + _exit(1); + } + + if (dup2(devnull, 2) < 0) { + mk_err("dup2 failed"); + _exit(1); + } + close(devnull); + + char *argv[3] = { NULL }; + + char *tmp = mk_api->str_dup(file); + if (chdir(dirname(tmp))) + _exit(1); + + char *tmp2 = mk_api->str_dup(file); + argv[0] = basename(tmp2); + + /* Restore signals for the child */ + signal(SIGPIPE, SIG_DFL); + signal(SIGCHLD, SIG_DFL); + + if (!interpreter) { + execve(file, argv, env); + } + else { + argv[0] = basename(interpreter); + argv[1] = (char *) file; + execve(interpreter, argv, env); + } + /* Exec failed, return */ + _exit(1); + } + + /* Yay me */ + close(writepipe[0]); + close(readpipe[1]); + + /* If we have POST data to write, spawn a thread to do that */ + if (sr->data.len) { + struct post_t p; + pthread_t tid; + + p.fd = writepipe[1]; + p.buf = sr->data.data; + p.len = sr->data.len; + + ret = mk_api->worker_spawn(cgi_write_post, &p, &tid); + if (ret != 0) { + return 403; + } + } + else { + close(writepipe[1]); + } + + r = cgi_req_create(readpipe[0], socket, plugin, sr, cs); + if (!r) { + return 403; + } + r->child = pid; + + /* + * Hang up?: by default Monkey assumes the CGI scripts generate + * content dynamically (no Content-Length header), so for such HTTP/1.0 + * clients we should close the connection as KeepAlive is not supported + * by specification, only on HTTP/1.1 where the Chunked Transfer encoding + * exists. + */ + if (r->sr->protocol >= MK_HTTP_PROTOCOL_11) { + r->hangup = MK_FALSE; + } + + /* Set transfer encoding */ + if (r->sr->protocol >= MK_HTTP_PROTOCOL_11 && + (r->sr->headers.status < MK_REDIR_MULTIPLE || + r->sr->headers.status > MK_REDIR_USE_PROXY)) { + r->sr->headers.transfer_encoding = MK_HEADER_TE_TYPE_CHUNKED; + r->chunked = 1; + } + + /* Register the 'request' context */ + cgi_req_add(r); + + /* Prepare the built-in event structure */ + event = &r->event; + event->fd = readpipe[0]; + event->type = MK_EVENT_CUSTOM; + event->mask = MK_EVENT_EMPTY; + event->data = r; + event->handler = cb_cgi_read; + + /* Register the event into the worker event-loop */ + ret = mk_api->ev_add(mk_api->sched_loop(), + readpipe[0], + MK_EVENT_CUSTOM, MK_EVENT_READ, r); + if (ret != 0) { + return 403; + } + + + /* XXX Fixme: this needs to be atomic */ + requests_by_socket[socket] = r; + return 200; +} + +int mk_cgi_plugin_init(struct plugin_api **api, char *confdir) +{ + struct rlimit lim; + (void) confdir; + + mk_api = *api; + mk_list_init(&cgi_global_matches); + pthread_key_create(&cgi_request_list, NULL); + + /* + * We try to perform some quick lookup over the list of CGI + * instances. We do this with a fixed length array, if you use CGI + * you don't care too much about performance anyways. + */ + getrlimit(RLIMIT_NOFILE, &lim); + requests_by_socket = mk_api->mem_alloc_z(sizeof(struct cgi_request *) * lim.rlim_cur); + + /* Make sure we act good if the child dies */ + signal(SIGPIPE, SIG_IGN); + signal(SIGCHLD, SIG_IGN); + + return 0; +} + +int mk_cgi_plugin_exit() +{ + regfree(&match_regex); + mk_api->mem_free(requests_by_socket); + + return 0; +} + +int mk_cgi_stage30(struct mk_plugin *plugin, + struct mk_http_session *cs, + struct mk_http_request *sr, + int n_params, + struct mk_list *params) +{ + char *interpreter = NULL; + char *mimetype = NULL; + struct mk_vhost_handler_param *param; + (void) plugin; + + const char *const file = sr->real_path.data; + + if (!sr->file_info.is_file) { + return MK_PLUGIN_RET_NOT_ME; + } + + /* start running the CGI */ + if (cgi_req_get(cs->socket)) { + PLUGIN_TRACE("Error, someone tried to retry\n"); + return MK_PLUGIN_RET_CONTINUE; + } + + if (n_params > 0) { + /* Interpreter */ + param = mk_api->handler_param_get(0, params); + if (param) { + interpreter = param->p.data; + } + + /* Mimetype */ + param = mk_api->handler_param_get(0, params); + if (param) { + mimetype = param->p.data; + } + } + + int status = do_cgi(file, sr->uri_processed.data, + sr, cs, plugin, interpreter, mimetype); + + /* These are just for the other plugins, such as logger; bogus data */ + mk_api->header_set_http_status(sr, status); + if (status != 200) { + return MK_PLUGIN_RET_CLOSE_CONX; + } + + sr->headers.cgi = SH_CGI; + return MK_PLUGIN_RET_CONTINUE; +} + +/* + * Invoked everytime a remote client drop the active connection, this + * callback is triggered by the Monkey Scheduler + */ +int mk_cgi_stage30_hangup(struct mk_plugin *plugin, + struct mk_http_session *cs, + struct mk_http_request *sr) +{ + struct cgi_request *r; + (void) sr; + (void) plugin; + + PLUGIN_TRACE("CGI / Parent connection closed (hangup)"); + r = requests_by_socket[cs->socket]; + if (!r) { + return -1; + } + + r->active = MK_FALSE; + cgi_finish(r); + return 0; +} + +void mk_cgi_worker_init() +{ + struct mk_list *list = mk_api->mem_alloc_z(sizeof(struct mk_list)); + + mk_list_init(list); + pthread_setspecific(cgi_request_list, (void *) list); +} + + +struct mk_plugin_stage mk_plugin_stage_cgi = { + .stage30 = &mk_cgi_stage30, + .stage30_hangup = &mk_cgi_stage30_hangup +}; + +struct mk_plugin mk_plugin_cgi = { + /* Identification */ + .shortname = "cgi", + .name = "Common Gateway Interface", + .version = MK_VERSION_STR, + .hooks = MK_PLUGIN_STAGE, + + /* Init / Exit */ + .init_plugin = mk_cgi_plugin_init, + .exit_plugin = mk_cgi_plugin_exit, + + /* Init Levels */ + .master_init = NULL, + .worker_init = mk_cgi_worker_init, + + /* Type */ + .stage = &mk_plugin_stage_cgi +}; diff --git a/fluent-bit/lib/monkey/plugins/cgi/cgi.h b/fluent-bit/lib/monkey/plugins/cgi/cgi.h new file mode 100644 index 00000000..27123b7a --- /dev/null +++ b/fluent-bit/lib/monkey/plugins/cgi/cgi.h @@ -0,0 +1,133 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Monkey HTTP Server + * ================== + * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io> + * Copyright (C) 2012-2013, Lauri Kasanen + * + * 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. + */ + +#ifndef MK_CGI_H +#define MK_CGI_H + +#include <monkey/mk_api.h> + +#include <sys/types.h> +#include <regex.h> +#include <signal.h> +#include <libgen.h> + +enum { + BUFLEN = 4096, + PATHLEN = 1024, + SHORTLEN = 64 +}; + +regex_t match_regex; + +struct cgi_request **requests_by_socket; + +struct post_t { + int fd; + void *buf; + unsigned long len; +}; + +struct cgi_match_t { + regex_t match; + char *bin; + mk_ptr_t content_type; + + struct mk_list _head; +}; + +struct cgi_vhost_t { + struct mk_vhost *host; + struct mk_list matches; +}; + +struct cgi_vhost_t *cgi_vhosts; +struct mk_list cgi_global_matches; + + +struct cgi_request { + /* Built-in reference for the event loop */ + struct mk_event event; + + char in_buf[BUFLEN]; + + struct mk_list _head; + + struct mk_plugin *plugin; + struct mk_http_request *sr; + struct mk_http_session *cs; + + unsigned int in_len; + + int fd; /* Pipe the CGI proc */ + int socket; /* Client connection */ + int hangup; /* Should close connection when done ? */ + int active; /* Active session ? */ + pid_t child; /* child process ID */ + unsigned char status_done; + unsigned char all_headers_done; + unsigned char chunked; +}; + +/* Global list per worker */ +pthread_key_t cgi_request_list; + +extern struct cgi_request **requests_by_socket; + +void cgi_finish(struct cgi_request *r); + +int swrite(const int fd, const void *buf, const size_t count); +int channel_write(struct cgi_request *r, void *buf, size_t count); + +struct cgi_request *cgi_req_create(int fd, int socket, + struct mk_plugin *plugin, + struct mk_http_request *sr, + struct mk_http_session *cs); +void cgi_req_add(struct cgi_request *r); +int cgi_req_del(struct cgi_request *r); + +// Get the CGI request by the client socket +static inline struct cgi_request *cgi_req_get(int socket) +{ + struct cgi_request *r = requests_by_socket[socket]; + return r; +} + +// Get the CGI request by the CGI app's fd +static inline struct cgi_request *cgi_req_get_by_fd(int fd) +{ + struct mk_list *list, *node; + struct cgi_request *r; + + list = pthread_getspecific(cgi_request_list); + if (mk_list_is_empty(list) == 0) + return NULL; + + mk_list_foreach(node, list) { + r = mk_list_entry(node, struct cgi_request, _head); + if (r->fd == fd) + return r; + } + + return NULL; +} + +int cb_cgi_read(void *data); + +#endif diff --git a/fluent-bit/lib/monkey/plugins/cgi/event.c b/fluent-bit/lib/monkey/plugins/cgi/event.c new file mode 100644 index 00000000..b8d39526 --- /dev/null +++ b/fluent-bit/lib/monkey/plugins/cgi/event.c @@ -0,0 +1,170 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Monkey HTTP Server + * ================== + * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io> + * Copyright (C) 2012-2013, Lauri Kasanen + * + * 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. + */ + +#include "cgi.h" + +/* + * The reason for this function is that some CGI apps + * + * use LFLF and some use CRLFCRLF. + * + * If that app then sends content that has the other break + * in the beginning, monkey can accidentally send part of the + * content as headers. + */ + +static char *getearliestbreak(const char buf[], const unsigned bufsize, + unsigned char * const advance) + { + char * const crend = memmem(buf, bufsize, MK_IOV_CRLFCRLF, + sizeof(MK_IOV_CRLFCRLF) - 1); + char * const lfend = memmem(buf, bufsize, MK_IOV_LFLF, + sizeof(MK_IOV_LFLF) - 1); + + if (!crend && !lfend) + return NULL; + + /* If only one found, return that one */ + if (!crend) { + *advance = 2; + return lfend; + } + if (!lfend) + return crend; + + /* Both found, return the earlier one - the latter one is part of content */ + if (lfend < crend) { + *advance = 2; + return lfend; + } + return crend; +} + +int process_cgi_data(struct cgi_request *r) +{ + int ret; + int len; + int status; + char *buf = r->in_buf; + char *outptr = r->in_buf; + char *end; + char *endl; + unsigned char advance; + + mk_api->socket_cork_flag(r->cs->socket, TCP_CORK_OFF); + if (!r->status_done && r->in_len >= 8) { + if (memcmp(buf, "Status: ", 8) == 0) { + status = atoi(buf + 8); + mk_api->header_set_http_status(r->sr, status); + endl = memchr(buf + 8, '\n', r->in_len - 8); + if (!endl) { + return MK_PLUGIN_RET_EVENT_OWNED; + } + else { + endl++; + outptr = endl; + r->in_len -= endl - buf; + } + } + else if (memcmp(buf, "HTTP", 4) == 0) { + status = atoi(buf + 9); + mk_api->header_set_http_status(r->sr, status); + + endl = memchr(buf + 8, '\n', r->in_len - 8); + if (!endl) { + return MK_PLUGIN_RET_EVENT_OWNED; + } + else { + endl++; + outptr = endl; + r->in_len -= endl - buf; + } + } + mk_api->header_prepare(r->plugin, r->cs, r->sr); + r->status_done = 1; + } + + if (!r->all_headers_done) { + advance = 4; + + /* Write the rest of the headers without chunking */ + end = getearliestbreak(outptr, r->in_len, &advance); + if (!end) { + /* Let's return until we have the headers break */ + return MK_PLUGIN_RET_EVENT_OWNED; + } + end += advance; + len = end - outptr; + channel_write(r, outptr, len); + outptr += len; + r->in_len -= len; + + r->all_headers_done = 1; + if (r->in_len == 0) { + return MK_PLUGIN_RET_EVENT_OWNED; + } + } + + if (r->chunked) { + char tmp[16]; + len = snprintf(tmp, 16, "%x\r\n", r->in_len); + ret = channel_write(r, tmp, len); + if (ret < 0) + return MK_PLUGIN_RET_EVENT_CLOSE; + } + + ret = channel_write(r, outptr, r->in_len); + if (ret < 0) { + return MK_PLUGIN_RET_EVENT_CLOSE; + } + + r->in_len = 0; + if (r->chunked) { + channel_write(r, MK_CRLF, 2); + } + return MK_PLUGIN_RET_EVENT_OWNED; +} + +int cb_cgi_read(void *data) +{ + int n; + struct cgi_request *r = data; + + if (r->active == MK_FALSE) { + return -1; + } + + if ((BUFLEN - r->in_len) < 1) { + PLUGIN_TRACE("CLOSE BY SIZE"); + cgi_finish(r); + return -1; + } + + n = read(r->fd, r->in_buf + r->in_len, BUFLEN - r->in_len); + PLUGIN_TRACE("FD=%i CGI READ=%d", r->fd, n); + if (n <= 0) { + /* It most of cases this means the child process finished */ + cgi_finish(r); + return MK_PLUGIN_RET_EVENT_CLOSE; + } + r->in_len += n; + process_cgi_data(r); + return 0; +} diff --git a/fluent-bit/lib/monkey/plugins/cgi/request.c b/fluent-bit/lib/monkey/plugins/cgi/request.c new file mode 100644 index 00000000..c51a1383 --- /dev/null +++ b/fluent-bit/lib/monkey/plugins/cgi/request.c @@ -0,0 +1,72 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Monkey HTTP Server + * ================== + * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io> + * Copyright (C) 2012-2013, Lauri Kasanen + * + * 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. + */ + +#include "cgi.h" + +struct cgi_request *cgi_req_create(int fd, int socket, + struct mk_plugin *plugin, + struct mk_http_request *sr, + struct mk_http_session *cs) +{ + struct cgi_request *cgi; + + cgi = mk_api->mem_alloc_z(sizeof(struct cgi_request)); + if (!cgi) { + return NULL; + } + + cgi->fd = fd; + cgi->socket = socket; + cgi->plugin = plugin; + cgi->sr = sr; + cgi->cs = cs; + cgi->hangup = MK_TRUE; + cgi->active = MK_TRUE; + cgi->in_len = 0; + + cgi->event.mask = MK_EVENT_EMPTY; + cgi->event.status = MK_EVENT_NONE; + + return cgi; +} + +void cgi_req_add(struct cgi_request *r) +{ + struct mk_list *list; + + list = pthread_getspecific(cgi_request_list); + mk_list_add(&r->_head, list); +} + +int cgi_req_del(struct cgi_request *r) +{ + PLUGIN_TRACE("Delete request child_fd=%i child_pid=%lu", + r->fd, r->child); + + mk_list_del(&r->_head); + if (r->active == MK_FALSE) { + mk_api->sched_event_free(&r->event); + } + else { + mk_mem_free(r); + } + + return 0; +} |