diff --git a/plugins/cgi/cgi_plugin.c b/plugins/cgi/cgi_plugin.c index 6688a233..846c0820 100644 --- a/plugins/cgi/cgi_plugin.c +++ b/plugins/cgi/cgi_plugin.c @@ -1,14 +1,17 @@ #include "../../uwsgi.h" -#include - extern struct uwsgi_server uwsgi; struct uwsgi_cgi { - char *docroot; + struct uwsgi_dyn_dict *mountpoint; struct uwsgi_dyn_dict *helpers; int buffer_size; int timeout; + struct uwsgi_string_list *index; + int optimize; + int has_mountpoints; + struct uwsgi_dyn_dict *default_cgi; + int path_info; } uc ; #define LONG_ARGS_CGI_BASE 17000 + ((9 + 1) * 1000) @@ -16,25 +19,128 @@ struct uwsgi_cgi { #define LONG_ARGS_CGI_MAP_HELPER LONG_ARGS_CGI_BASE + 2 #define LONG_ARGS_CGI_BUFFER_SIZE LONG_ARGS_CGI_BASE + 3 #define LONG_ARGS_CGI_TIMEOUT LONG_ARGS_CGI_BASE + 4 +#define LONG_ARGS_CGI_INDEX LONG_ARGS_CGI_BASE + 5 struct option uwsgi_cgi_options[] = { {"cgi", required_argument, 0, LONG_ARGS_CGI}, {"cgi-map-helper", required_argument, 0, LONG_ARGS_CGI_MAP_HELPER}, + {"cgi-helper", required_argument, 0, LONG_ARGS_CGI_MAP_HELPER}, {"cgi-buffer-size", required_argument, 0, LONG_ARGS_CGI_BUFFER_SIZE}, {"cgi-timeout", required_argument, 0, LONG_ARGS_CGI_TIMEOUT}, + {"cgi-index", required_argument, 0, LONG_ARGS_CGI_INDEX}, + {"cgi-optimize", no_argument, &uc.optimize, 1}, + {"cgi-optimized", no_argument, &uc.optimize, 1}, + {"cgi-path-info", no_argument, &uc.path_info, 1}, {0, 0, 0, 0}, }; +void uwsgi_cgi_404(struct wsgi_request *wsgi_req) { + + wsgi_req->status = 404; + wsgi_req->headers_size += wsgi_req->socket->proto_write(wsgi_req, "HTTP/1.1 404 Not Found\r\n\r\nNot Found", 35); +} + +void uwsgi_cgi_redirect_to_slash(struct wsgi_request *wsgi_req) { + + struct iovec iov[6]; + + wsgi_req->status = 301; + iov[0].iov_base = wsgi_req->protocol; + iov[0].iov_len = wsgi_req->protocol_len; + iov[1].iov_base = " 301 Moved Permanently\r\n"; + iov[1].iov_len = 24; + wsgi_req->headers_size += wsgi_req->socket->proto_writev_header(wsgi_req, iov, 2); + + iov[0].iov_base = "Location: "; + iov[0].iov_len = 10; + iov[1].iov_base = wsgi_req->path_info; + iov[1].iov_len = wsgi_req->path_info_len; + iov[2].iov_base = "/"; + iov[2].iov_len = 1; + + if (wsgi_req->query_string_len > 0) { + iov[3].iov_base = "?"; + iov[3].iov_len = 1; + iov[4].iov_base = wsgi_req->query_string; + iov[4].iov_len = wsgi_req->query_string_len; + iov[5].iov_base = "\r\n\r\n"; + iov[5].iov_len = 4; + wsgi_req->headers_size += wsgi_req->socket->proto_writev_header(wsgi_req, iov, 6); + wsgi_req->header_cnt++; + } + else { + iov[3].iov_base = "\r\n\r\n"; + iov[3].iov_len = 4; + wsgi_req->headers_size += wsgi_req->socket->proto_writev_header(wsgi_req, iov, 4); + wsgi_req->header_cnt++; + } +} + +void uwsgi_cgi_apps() { + + struct uwsgi_dyn_dict *udd = uc.mountpoint; + struct stat st; + + while(udd) { + if (udd->vallen) { + if (uc.optimize) { + udd->value = realpath(udd->value, NULL); + if (!udd->value) { + uwsgi_log("unable to find CGI path %.*s\n", udd->vallen, udd->value); + exit(1); + } + udd->vallen = strlen(udd->value); + udd->status = 1; + if (stat(udd->value, &st)) { + uwsgi_error("stat()"); + uwsgi_log("something horrible happened during CGI initialization\n"); + exit(1); + } + + if (!S_ISDIR(st.st_mode)) { + udd->status = 2; + } + } + uc.has_mountpoints = 1; + uwsgi_log("initialized CGI mountpoint: %.*s = %.*s\n", udd->keylen, udd->key, udd->vallen, udd->value); + } + else { + if (uc.optimize) { + udd->key = realpath(udd->key, NULL); + if (!udd->key) { + uwsgi_log("unable to find CGI path %.*s\n", udd->keylen, udd->key); + exit(1); + } + udd->keylen = strlen(udd->key); + udd->status = 1; + + if (stat(udd->key, &st)) { + uwsgi_error("stat()"); + uwsgi_log("something horrible happened during CGI initialization\n"); + exit(1); + } + + if (!S_ISDIR(st.st_mode)) { + udd->status = 2; + } + + } + uwsgi_log("initialized CGI path: %.*s\n", udd->keylen, udd->key); + uc.default_cgi = udd; + } + udd = udd->next; + } + +} + int uwsgi_cgi_init(){ if (!uc.buffer_size) uc.buffer_size = 65536; if (!uc.timeout) uc.timeout = 60; - uwsgi_log("initialized CGI engine on directory %s\n", uc.docroot); - - return 1; + return 0; } @@ -63,7 +169,9 @@ int uwsgi_cgi_parse(struct wsgi_request *wsgi_req, char *buf, size_t len) { size_t header_size = 0; int status_sent = 0; - struct iovec iov[3]; + struct uwsgi_string_list *ah = uwsgi.additional_headers; + + struct iovec iov[4]; for(i=0;i= 11) { if (!strncasecmp("Status: ", key, 8)) { - wsgi_req->status = uwsgi_str3_num(key+9); + wsgi_req->status = uwsgi_str3_num(key+8); iov[0].iov_base = wsgi_req->protocol; iov[0].iov_len = wsgi_req->protocol_len; - iov[1].iov_base = key+9; - iov[1].iov_len = header_size - 9; - iov[2].iov_base = "\r\n"; - iov[2].iov_len = 2; - wsgi_req->headers_size += wsgi_req->socket->proto_writev_header(wsgi_req, iov, 3); + iov[1].iov_base = " "; + iov[1].iov_len = 1; + iov[2].iov_base = key+8; + iov[2].iov_len = header_size - 8; + iov[3].iov_base = "\r\n"; + iov[3].iov_len = 2; + wsgi_req->headers_size += wsgi_req->socket->proto_writev_header(wsgi_req, iov, 4); status_sent = 1; + key = NULL; + value = NULL; + continue; } } } @@ -138,6 +251,7 @@ int uwsgi_cgi_parse(struct wsgi_request *wsgi_req, char *buf, size_t len) { iov[1].iov_base = "\r\n"; iov[1].iov_len = 2; wsgi_req->headers_size += wsgi_req->socket->proto_writev_header(wsgi_req, iov, 2); + wsgi_req->header_cnt++; key = NULL; value = NULL; @@ -155,6 +269,17 @@ int uwsgi_cgi_parse(struct wsgi_request *wsgi_req, char *buf, size_t len) { return -1; send_body: + + while(ah) { + iov[0].iov_base = ah->value; + iov[0].iov_len = ah->len; + iov[1].iov_base = "\r\n"; + iov[1].iov_len = 2; + wsgi_req->headers_size += wsgi_req->socket->proto_writev_header(wsgi_req, iov, 2); + wsgi_req->header_cnt++; + ah = ah->next; + } + wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, "\r\n", 2); if (len-i > 0) { wsgi_req->response_size += wsgi_req->socket->proto_write(wsgi_req, buf+i, len-i); @@ -163,6 +288,116 @@ send_body: return 0; } +char *uwsgi_cgi_get_docroot(char *path_info, uint16_t path_info_len, int *need_free, int *is_a_file, int *discard_base) { + + struct uwsgi_dyn_dict *udd = uc.mountpoint, *choosen_udd = NULL; + int best_found = 0; + struct stat st; + char *path = NULL; + + if (uc.has_mountpoints) { + while(udd) { + if (udd->vallen) { + if (!uwsgi_starts_with(path_info, path_info_len, udd->key, udd->keylen) && udd->keylen > best_found) { + best_found = udd->keylen ; + choosen_udd = udd; + path = udd->value; + *discard_base = udd->keylen; + if (udd->key[udd->keylen-1] == '/') { + *discard_base = *discard_base-1; + } + } + } + udd = udd->next; + } + } + + if (choosen_udd == NULL) { + choosen_udd = uc.default_cgi; + if (!choosen_udd) return NULL; + path = choosen_udd->key; + } + + if (choosen_udd->status == 0) { + char *tmp_udd = realpath(path, NULL); + if (!tmp_udd) { + return NULL; + } + + if (stat(tmp_udd, &st)) { + uwsgi_error("stat()"); + free(tmp_udd); + return NULL; + } + + if (!S_ISDIR(st.st_mode)) { + *is_a_file = 1; + } + + *need_free = 1; + return tmp_udd; + } + + if (choosen_udd->status == 2) + *is_a_file = 1; + return path; +} + +int uwsgi_cgi_walk(struct wsgi_request *wsgi_req, char *full_path, char *docroot, size_t docroot_len, int discard_base, char **path_info) { + + // and now start walking... + uint16_t i; + char *ptr = wsgi_req->path_info+discard_base; + char *dst = full_path+docroot_len; + char *part = ptr; + int part_size = 0; + struct stat st; + + if (ptr[0] == '/') part_size++; + + for(i=0;ipath_info_len-discard_base;i++) { + if (ptr[i] == '/') { + memcpy(dst, part, part_size-1); + *(dst+part_size-1) = 0; + + if (stat(full_path, &st)) { + uwsgi_cgi_404(wsgi_req); + return -1; + } + + + // not a directory, stop walking + if (!S_ISDIR(st.st_mode)) { + if (i < (wsgi_req->path_info_len-discard_base)-1) { + *path_info = ptr + i + 1; + } + + return 0; + } + + + // check for buffer overflow !!! + *(dst+part_size-1) = '/'; + *(dst+part_size) = 0; + + dst += part_size ; + part_size = 0; + part = ptr + i + 1; + } + + part_size++; + } + + if (part < wsgi_req->path_info+wsgi_req->path_info_len) { + memcpy(dst, part, part_size-1); + *(dst+part_size-1) = 0; + } + + return 0; + + +} + int uwsgi_cgi_request(struct wsgi_request *wsgi_req) { int i; @@ -170,8 +405,18 @@ int uwsgi_cgi_request(struct wsgi_request *wsgi_req) { int waitpid_status; char *argv[3]; char full_path[PATH_MAX]; + char tmp_path[PATH_MAX]; int cgi_pipe[2]; ssize_t len; + struct stat cgi_stat; + int need_free = 0; + int is_a_file = 0; + int discard_base = 0; + size_t docroot_len = 0; + size_t full_path_len = 0; + char *helper = NULL; + char *command = NULL; + char *path_info = NULL; /* Standard CGI request */ if (!wsgi_req->uh.pktsize) { @@ -181,47 +426,112 @@ int uwsgi_cgi_request(struct wsgi_request *wsgi_req) { if (uwsgi_parse_vars(wsgi_req)) { - uwsgi_log("Invalid CGI request. skip.\n"); return -1; } // check for file availability (and 'runnability') - char *path_info = uwsgi_concat4n(uc.docroot, strlen(uc.docroot), "/", 1,wsgi_req->path_info, wsgi_req->path_info_len, "", 0); + char *docroot = uwsgi_cgi_get_docroot(wsgi_req->path_info, wsgi_req->path_info_len, &need_free, &is_a_file, &discard_base); - if (realpath(path_info, full_path) == NULL) { - free(path_info); - wsgi_req->status = 404; - wsgi_req->socket->proto_write(wsgi_req, "HTTP/1.1 404 Not Found\r\n\r\n", 26); + if (docroot == NULL) { + uwsgi_cgi_404(wsgi_req); return UWSGI_OK; } - free(path_info); + if (!is_a_file) { + docroot_len = strlen(docroot); - if (uwsgi_starts_with(full_path, strlen(full_path), uc.docroot, strlen(uc.docroot))) { - uwsgi_log("CGI security error: %s is not under %s\n", full_path, uc.docroot); - return -1; - } + memcpy(full_path, docroot, docroot_len); + *(full_path+docroot_len) = '/'; + *(full_path+docroot_len+1) = 0; - if (access(full_path, R_OK)) { - uwsgi_error("access()"); - wsgi_req->status = 404; - wsgi_req->socket->proto_write(wsgi_req, "HTTP/1.1 404 Not Found\r\n\r\n", 26); - return UWSGI_OK; - } - - char *helper = uwsgi_cgi_get_helper(full_path); - - if (helper == NULL) { - if (access(full_path, X_OK)) { - uwsgi_error("access()"); - wsgi_req->status = 500; - wsgi_req->socket->proto_write(wsgi_req, "HTTP/1.1 500 Internal Server Error\r\n\r\n", 38); + if (uwsgi_cgi_walk(wsgi_req, full_path, docroot, docroot_len, discard_base, &path_info)) { + if (need_free) + free(docroot); return UWSGI_OK; } + + if (realpath(full_path, tmp_path) == NULL) { + if (need_free) + free(docroot); + uwsgi_cgi_404(wsgi_req); + return UWSGI_OK; + } + + full_path_len = strlen(tmp_path); + // add +1 to copy the null byte + memcpy(full_path, tmp_path, full_path_len+1); + + if (uwsgi_starts_with(full_path, full_path_len, docroot, docroot_len)) { + if (need_free) + free(docroot); + uwsgi_log("CGI security error: %s is not under %s\n", full_path, docroot); + return -1; + } + + } + + if (stat(full_path, &cgi_stat)) { + uwsgi_cgi_404(wsgi_req); + if (need_free) + free(docroot); + return UWSGI_OK; + } + + if (S_ISDIR(cgi_stat.st_mode)) { + + // add / to directories + if (wsgi_req->path_info_len == 0 || wsgi_req->path_info[wsgi_req->path_info_len-1] != '/') { + uwsgi_cgi_redirect_to_slash(wsgi_req); + if (need_free) + free(docroot); + return UWSGI_OK; + } + struct uwsgi_string_list *ci = uc.index; + full_path[full_path_len] = '/'; + full_path_len++; + int found = 0; + while(ci) { + if (full_path_len + ci->len + 1 < PATH_MAX) { + // add + 1 to ensure null byte + memcpy(full_path+full_path_len, ci->value, ci->len + 1); + if (!access(full_path, R_OK)) { + found = 1; + break; + } + } + ci = ci->next; + } + + if (!found) { + uwsgi_cgi_404(wsgi_req); + if (need_free) + free(docroot); + return UWSGI_OK; + } + + } + + if (is_a_file) { + command = docroot; + } + else { + command = full_path; + helper = uwsgi_cgi_get_helper(full_path); + + if (helper == NULL) { + if (access(full_path, X_OK)) { + uwsgi_error("access()"); + wsgi_req->status = 500; + wsgi_req->socket->proto_write(wsgi_req, "HTTP/1.1 500 Internal Server Error\r\n\r\nInternal Server Error", 59); + return UWSGI_OK; + } + } } if (pipe(cgi_pipe)) { + if (need_free) + free(docroot); uwsgi_error("pipe()"); return UWSGI_OK; } @@ -230,10 +540,16 @@ int uwsgi_cgi_request(struct wsgi_request *wsgi_req) { if (cgi_pid < 0) { uwsgi_error("fork()"); + if (need_free) + free(docroot); return -1; } if (cgi_pid > 0) { + + if (need_free) + free(docroot); + close(cgi_pipe[1]); // wait for data char *headers_buf = uwsgi_malloc(uc.buffer_size); @@ -335,9 +651,6 @@ clear: i++; } - if (setenv("DOCUMENT_ROOT", uc.docroot, 0)) { - uwsgi_error("setenv()"); - } if (setenv("GATEWAY_INTERFACE", "CGI/1.1", 0)) { uwsgi_error("setenv()"); @@ -347,21 +660,65 @@ clear: uwsgi_error("setenv()"); } - if (setenv("SCRIPT_NAME", uwsgi_concat2n(wsgi_req->path_info, wsgi_req->path_info_len, "", 0), 0)) { - uwsgi_error("setenv()"); + if (path_info) { + if (setenv("PATH_INFO", path_info, 1)) { + uwsgi_error("setenv()"); + } + + if (setenv("PATH_TRANSLATED", uwsgi_concat3(docroot, "/", path_info) , 1)) { + uwsgi_error("setenv()"); + } + } + else { + unsetenv("PATH_INFO"); + unsetenv("PATH_TRANSLATED"); } - if (setenv("SCRIPT_FILENAME", uwsgi_concat3n(uc.docroot, strlen(uc.docroot), wsgi_req->path_info, wsgi_req->path_info_len, "", 0), 0)) { - uwsgi_error("setenv()"); + if (is_a_file) { + if (setenv("DOCUMENT_ROOT", uwsgi.cwd, 0)) { + uwsgi_error("setenv()"); + } + + if (setenv("SCRIPT_FILENAME", docroot, 0)) { + uwsgi_error("setenv()"); + } + } + else { + if (setenv("DOCUMENT_ROOT", docroot, 0)) { + uwsgi_error("setenv()"); + } + + if (setenv("SCRIPT_FILENAME", full_path, 0)) { + uwsgi_error("setenv()"); + } + + if (setenv("SCRIPT_NAME", full_path+(docroot_len-discard_base), 1)) { + uwsgi_error("setenv()"); + } + + char *base = uwsgi_get_last_char(full_path, '/'); + if (base) { + // a little trick :P + *base = 0; + if (chdir(full_path)) { + uwsgi_error("chdir()"); + } + *base = '/'; + } + else { + if (chdir(docroot)) { + uwsgi_error("chdir()"); + } + } } if (helper) { argv[0] = helper; - argv[1] = full_path; + argv[1] = command; argv[2] = NULL; } else { - argv[0] = full_path; + argv[0] = command; argv[1] = NULL; } @@ -386,7 +743,13 @@ int uwsgi_cgi_manage_options(int i, char *optarg) { switch(i) { case LONG_ARGS_CGI: - uc.docroot = realpath(optarg, NULL); + value = strchr(optarg, '='); + if (!value) { + uwsgi_dyn_dict_new(&uc.mountpoint, optarg, strlen(optarg), NULL, 0); + } + else { + uwsgi_dyn_dict_new(&uc.mountpoint, optarg, value-optarg, value+1, strlen(value+1)); + } return 1; case LONG_ARGS_CGI_BUFFER_SIZE: uc.buffer_size = atoi(optarg); @@ -394,6 +757,9 @@ int uwsgi_cgi_manage_options(int i, char *optarg) { case LONG_ARGS_CGI_TIMEOUT: uc.timeout = atoi(optarg); return 1; + case LONG_ARGS_CGI_INDEX: + uwsgi_string_new_list(&uc.index, optarg); + return 1; case LONG_ARGS_CGI_MAP_HELPER: value = strchr(optarg, '='); if (!value) { @@ -413,6 +779,7 @@ struct uwsgi_plugin cgi_plugin = { .name = "cgi", .modifier1 = 9, .init = uwsgi_cgi_init, + .init_apps = uwsgi_cgi_apps, .options = uwsgi_cgi_options, .manage_opt = uwsgi_cgi_manage_options, .request = uwsgi_cgi_request, diff --git a/plugins/http/http.c b/plugins/http/http.c index 580b7f43..cc54f92d 100644 --- a/plugins/http/http.c +++ b/plugins/http/http.c @@ -584,7 +584,8 @@ void http_loop() { event_queue_add_fd_read(uhttp_queue, uhttp_session->fd); #endif if (len <= 0) { - uwsgi_error("recv()"); + if (len < 0) + uwsgi_error("recv()"); close_session(uhttp_table, uhttp_session); break; } diff --git a/protocol.c b/protocol.c index 717d10a8..24f81585 100644 --- a/protocol.c +++ b/protocol.c @@ -863,14 +863,32 @@ next: } } - // check if a file named uwsgi.check_static+env['PATH_INFO'] exists + // check for static files if (wsgi_req->path_info_len > 1) { + + // skip extensions + struct uwsgi_string_list *sse = uwsgi.static_skip_ext; + while(sse) { + if (wsgi_req->path_info_len >= sse->len) { + if (!uwsgi_strncmp(wsgi_req->path_info+(wsgi_req->path_info_len - sse->len), sse->len, sse->value, sse->len)) { + return 0; + } + } + sse = sse->next; + } + // check if a file named uwsgi.check_static+env['PATH_INFO'] exists udd = uwsgi.check_static; while(udd) { // need to build the path ? if (udd->value == NULL) { +#ifdef UWSGI_THREADING + if (uwsgi.threads > 1) pthread_mutex_lock(&uwsgi.lock_static); +#endif udd->value = realpath(udd->key, NULL); +#ifdef UWSGI_THREADING + if (uwsgi.threads > 1) pthread_mutex_unlock(&uwsgi.lock_static); +#endif if (!udd->value) goto nextcs; udd->vallen = strlen(udd->value); } @@ -881,29 +899,35 @@ next: nextcs: udd = udd->next; } - } - // check static-map - udd = uwsgi.static_maps; - while(udd) { + // check static-map + udd = uwsgi.static_maps; + while(udd) { #ifdef UWSGI_DEBUG - uwsgi_log("checking for %.*s <-> %.*s\n", wsgi_req->path_info_len, wsgi_req->path_info, udd->keylen, udd->key); + uwsgi_log("checking for %.*s <-> %.*s\n", wsgi_req->path_info_len, wsgi_req->path_info, udd->keylen, udd->key); #endif - if (udd->status == 0) { - char *real_docroot = realpath(udd->value, NULL); - if (!real_docroot) goto nextsm; - udd->value = real_docroot; - udd->vallen = strlen(udd->value); - udd->status = 1; - } + if (udd->status == 0) { +#ifdef UWSGI_THREADING + if (uwsgi.threads > 1) pthread_mutex_lock(&uwsgi.lock_static); +#endif + char *real_docroot = realpath(udd->value, NULL); +#ifdef UWSGI_THREADING + if (uwsgi.threads > 1) pthread_mutex_unlock(&uwsgi.lock_static); +#endif + if (!real_docroot) goto nextsm; + udd->value = real_docroot; + udd->vallen = strlen(udd->value); + udd->status = 1; + } - if (!uwsgi_starts_with(wsgi_req->path_info, wsgi_req->path_info_len, udd->key, udd->keylen)) { - if (!uwsgi_file_serve(wsgi_req, udd->value, udd->vallen, wsgi_req->path_info+udd->keylen, wsgi_req->path_info_len-udd->keylen)) { - return -1; + if (!uwsgi_starts_with(wsgi_req->path_info, wsgi_req->path_info_len, udd->key, udd->keylen)) { + if (!uwsgi_file_serve(wsgi_req, udd->value, udd->vallen, wsgi_req->path_info+udd->keylen, wsgi_req->path_info_len-udd->keylen)) { + return -1; + } } - } nextsm: - udd = udd->next; + udd = udd->next; + } } return 0; diff --git a/uwsgi.c b/uwsgi.c index 13cac3fb..e70f97e0 100644 --- a/uwsgi.c +++ b/uwsgi.c @@ -266,6 +266,8 @@ static struct option long_base_options[] = { {"threads", required_argument, 0, LONG_ARGS_THREADS}, {"threads-stacksize", required_argument, 0, LONG_ARGS_THREADS_STACKSIZE}, {"thread-stacksize", required_argument, 0, LONG_ARGS_THREADS_STACKSIZE}, + {"threads-stack-size", required_argument, 0, LONG_ARGS_THREADS_STACKSIZE}, + {"thread-stack-size", required_argument, 0, LONG_ARGS_THREADS_STACKSIZE}, {"vhost", no_argument, &uwsgi.vhost, 1}, {"vhost-host", no_argument, 0, LONG_ARGS_VHOSTHOST}, #ifdef UWSGI_ROUTING @@ -273,6 +275,7 @@ static struct option long_base_options[] = { #endif {"add-header", required_argument, 0, LONG_ARGS_ADD_HEADER}, {"check-static", required_argument, 0, LONG_ARGS_CHECK_STATIC}, + {"static-skip-ext", required_argument, 0, LONG_ARGS_STATIC_SKIP_EXT}, {"static-map", required_argument, 0, LONG_ARGS_STATIC_MAP}, {"mimefile", required_argument, 0, LONG_ARGS_MIMEFILE}, {"mime-file", required_argument, 0, LONG_ARGS_MIMEFILE}, @@ -2238,6 +2241,9 @@ skipzero: uwsgi_log("!!! unable to set requested threads stacksize !!!\n"); } } + + pthread_mutex_init(&uwsgi.lock_static, NULL); + for (i = 0; i < 0xFF; i++) { if (uwsgi.p[i]->enable_threads) uwsgi.p[i]->enable_threads(); @@ -3377,6 +3383,9 @@ static int manage_base_opt(int i, char *optarg) { } uc->command = optarg+i; return 1; + case LONG_ARGS_STATIC_SKIP_EXT: + uwsgi_string_new_list(&uwsgi.static_skip_ext, optarg); + return 1; case LONG_ARGS_STATIC_MAP: mountpoint = uwsgi_str(optarg); docroot = strchr(mountpoint, '='); diff --git a/uwsgi.h b/uwsgi.h index 77bf1171..3fc2fd8e 100644 --- a/uwsgi.h +++ b/uwsgi.h @@ -538,6 +538,7 @@ struct uwsgi_opt { #define LONG_ARGS_UNSHARE 17168 #define LONG_ARGS_EXEC_AS_ROOT 17169 #define LONG_ARGS_EXEC_AS_USER 17170 +#define LONG_ARGS_STATIC_SKIP_EXT 17171 #define UWSGI_OK 0 @@ -1208,6 +1209,7 @@ struct uwsgi_server { struct uwsgi_dyn_dict *static_maps; struct uwsgi_dyn_dict *check_static; struct uwsgi_dyn_dict *mimetypes; + struct uwsgi_string_list *static_skip_ext; char *logfile; int logfile_chown; @@ -1334,6 +1336,7 @@ struct uwsgi_server { #ifdef UWSGI_THREADING // avoid thundering herd in threaded modes pthread_mutex_t six_feet_under_lock; + pthread_mutex_t lock_static; #endif