mirror of
https://github.com/clearlinux/uwsgi.git
synced 2026-09-05 13:11:33 +00:00
more apache-compliant cgi plugin
This commit is contained in:
+415
-48
@@ -1,14 +1,17 @@
|
||||
#include "../../uwsgi.h"
|
||||
|
||||
#include <wordexp.h>
|
||||
|
||||
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<len;i++) {
|
||||
// end of a line
|
||||
@@ -92,15 +200,20 @@ int uwsgi_cgi_parse(struct wsgi_request *wsgi_req, char *buf, size_t len) {
|
||||
// "Status: NNN"
|
||||
if (header_size >= 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;i<wsgi_req->path_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,
|
||||
|
||||
+2
-1
@@ -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;
|
||||
}
|
||||
|
||||
+42
-18
@@ -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;
|
||||
|
||||
@@ -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, '=');
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user