mirror of
https://github.com/clearlinux/uwsgi.git
synced 2026-10-04 16:08:31 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a42aa1a273 | ||
|
|
4b2b7ccf82 | ||
|
|
e0fa180a23 | ||
|
|
06ea1fcd1b | ||
|
|
567bcc582d | ||
|
|
844f8c71fa | ||
|
|
bddbbb93cd | ||
|
|
310cc83d36 | ||
|
|
23dcdc5863 | ||
|
|
1286e1835c | ||
|
|
613f2ed939 | ||
|
|
46108f8d0c | ||
|
|
28dcfa4131 | ||
|
|
b48597d3c3 | ||
|
|
fe4c6ba13e | ||
|
|
4049493ffd |
@@ -39,3 +39,4 @@ fb168b0b86169219aa9b8e40f0caa6297cf34dbc 0.9.9-rc1
|
||||
043ba93dd69cf6924e98db3cb9a8759cce997367 1.0-rc5
|
||||
a2b8f25fd17ed7424d1470a287d0b3144d2a12c8 1.0-rc6
|
||||
a3ca2e8e27c5c12c44ba0cacb4de4cb51377f184 1.0-rc7
|
||||
365e2514cc19f0366365318f12a1d63113b02924 1.0-rc8
|
||||
|
||||
@@ -6,12 +6,7 @@ void uwsgi_init_cache() {
|
||||
int i;
|
||||
|
||||
if (!uwsgi.cache_blocksize)
|
||||
uwsgi.cache_blocksize = UMAX16;
|
||||
|
||||
if ((uwsgi.cache_blocksize * uwsgi.cache_max_items) % uwsgi.page_size != 0) {
|
||||
uwsgi_log("invalid cache blocksize %llu: must be a multiple of memory page size (%d bytes)\n", (unsigned long long) uwsgi.cache_blocksize, uwsgi.page_size);
|
||||
exit(1);
|
||||
}
|
||||
uwsgi.cache_blocksize = UMAX16;
|
||||
|
||||
uwsgi.cache_hashtable = (uint64_t *) mmap(NULL, sizeof(uint64_t) * UMAX16, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
|
||||
if (!uwsgi.cache_hashtable) {
|
||||
@@ -91,7 +86,8 @@ void uwsgi_init_cache() {
|
||||
uwsgi.cache_lock = uwsgi_mmap_shared_rwlock();
|
||||
uwsgi_rwlock_init(uwsgi.cache_lock);
|
||||
|
||||
uwsgi_log("*** Cache subsystem initialized: %dMB preallocated ***\n", ((sizeof(uint64_t) * UMAX16) + (sizeof(uint64_t) * uwsgi.cache_max_items) + (uwsgi.cache_blocksize * uwsgi.cache_max_items) + (sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items)) / (1024 * 1024));
|
||||
uwsgi_log("*** Cache subsystem initialized: %dMB (key: %llu bytes, keys: %llu bytes, data: %llu bytes) preallocated ***\n", ((uwsgi.cache_blocksize * uwsgi.cache_max_items) + (sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items)) / (1024 * 1024),
|
||||
(unsigned long long) sizeof(struct uwsgi_cache_item), (unsigned long long) sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items, (unsigned long long) uwsgi.cache_blocksize * uwsgi.cache_max_items);
|
||||
}
|
||||
|
||||
uint32_t djb33x_hash(char *key, int keylen) {
|
||||
|
||||
+710
-43
@@ -1,27 +1,414 @@
|
||||
#include "../../uwsgi.h"
|
||||
|
||||
#include <wordexp.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
char *cgi_docroot;
|
||||
struct uwsgi_cgi {
|
||||
struct uwsgi_dyn_dict *mountpoint;
|
||||
struct uwsgi_dyn_dict *helpers;
|
||||
int buffer_size;
|
||||
int timeout;
|
||||
struct uwsgi_string_list *index;
|
||||
struct uwsgi_string_list *allowed_ext;
|
||||
struct uwsgi_string_list *unset;
|
||||
int optimize;
|
||||
int has_mountpoints;
|
||||
struct uwsgi_dyn_dict *default_cgi;
|
||||
int path_info;
|
||||
} uc ;
|
||||
|
||||
#define LONG_ARGS_CGI_BASE 17000 + ((9 + 1) * 1000)
|
||||
#define LONG_ARGS_CGI LONG_ARGS_CGI_BASE + 1
|
||||
#define LONG_ARGS_CGI_BASE 17000 + ((9 + 1) * 1000)
|
||||
#define LONG_ARGS_CGI LONG_ARGS_CGI_BASE + 1
|
||||
#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
|
||||
#define LONG_ARGS_CGI_ALLOWED_EXT LONG_ARGS_CGI_BASE + 6
|
||||
#define LONG_ARGS_CGI_UNSET LONG_ARGS_CGI_BASE + 7
|
||||
|
||||
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-allowed-ext", required_argument, 0, LONG_ARGS_CGI_ALLOWED_EXT},
|
||||
{"cgi-unset", required_argument, 0, LONG_ARGS_CGI_UNSET},
|
||||
{"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.0 404 Not Found\r\n\r\nNot Found", 35);
|
||||
}
|
||||
|
||||
void uwsgi_cgi_403(struct wsgi_request *wsgi_req) {
|
||||
|
||||
wsgi_req->status = 403;
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_write(wsgi_req, "HTTP/1.0 403 Forbidden\r\n\r\nForbidden", 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\n");
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
char *uwsgi_cgi_get_helper(char *filename) {
|
||||
|
||||
struct uwsgi_dyn_dict *helpers = uc.helpers;
|
||||
size_t len = strlen(filename);
|
||||
|
||||
while(helpers) {
|
||||
if (len >= (size_t) helpers->keylen) {
|
||||
if (!uwsgi_strncmp((filename+len)-helpers->keylen, helpers->keylen, helpers->key, helpers->keylen)) {
|
||||
return helpers->value;
|
||||
}
|
||||
}
|
||||
helpers = helpers->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
int uwsgi_cgi_parse(struct wsgi_request *wsgi_req, char *buf, size_t len) {
|
||||
|
||||
size_t i;
|
||||
char *key = buf, *value = NULL;
|
||||
size_t header_size = 0;
|
||||
int status_sent = 0;
|
||||
|
||||
struct uwsgi_string_list *ah = uwsgi.additional_headers;
|
||||
|
||||
struct iovec iov[4];
|
||||
|
||||
for(i=0;i<len;i++) {
|
||||
// end of a line
|
||||
if (buf[i] == '\n') {
|
||||
// end of headers
|
||||
if (key == NULL) {
|
||||
goto send_body;
|
||||
}
|
||||
// invalid header
|
||||
else if (value == NULL) {
|
||||
return -1;
|
||||
}
|
||||
header_size = (buf+i) - key;
|
||||
// security check
|
||||
if (buf+i > buf) {
|
||||
if ((buf[i-1]) == '\r') {
|
||||
header_size--;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("found CGI header: %.*s\n", header_size, key);
|
||||
#endif
|
||||
|
||||
if (status_sent == 0) {
|
||||
// "Status: NNN"
|
||||
if (header_size >= 11) {
|
||||
if (!strncasecmp("Status: ", key, 8)) {
|
||||
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 = " ";
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// default status
|
||||
if (status_sent == 0) {
|
||||
|
||||
// Location: X
|
||||
if (header_size >= 11) {
|
||||
if (!strncasecmp("Location: ", key, 10)) {
|
||||
|
||||
wsgi_req->status = 302;
|
||||
iov[0].iov_base = wsgi_req->protocol;
|
||||
iov[0].iov_len = wsgi_req->protocol_len;
|
||||
iov[1].iov_base = " 302 Found\r\n";
|
||||
iov[1].iov_len = 12;
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_writev_header(wsgi_req, iov, 2);
|
||||
status_sent = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (status_sent == 0) {
|
||||
wsgi_req->status = 200;
|
||||
iov[0].iov_base = wsgi_req->protocol;
|
||||
iov[0].iov_len = wsgi_req->protocol_len;
|
||||
iov[1].iov_base = " 200 OK\r\n";
|
||||
iov[1].iov_len = 9;
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_writev_header(wsgi_req, iov, 2);
|
||||
status_sent = 1;
|
||||
}
|
||||
}
|
||||
|
||||
iov[0].iov_base = key;
|
||||
iov[0].iov_len = header_size;
|
||||
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;
|
||||
}
|
||||
else if (buf[i] == ':') {
|
||||
value = buf+i;
|
||||
}
|
||||
else if (buf[i] != '\r') {
|
||||
if (key == NULL) {
|
||||
key = buf + i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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, char **script_name) {
|
||||
|
||||
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;
|
||||
*script_name = udd->key;
|
||||
*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;
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
@@ -30,10 +417,21 @@ int uwsgi_cgi_request(struct wsgi_request *wsgi_req) {
|
||||
int i;
|
||||
pid_t cgi_pid;
|
||||
int waitpid_status;
|
||||
char *argv[2];
|
||||
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;
|
||||
char *script_name = NULL;
|
||||
|
||||
/* Standard CGI request */
|
||||
if (!wsgi_req->uh.pktsize) {
|
||||
@@ -43,28 +441,141 @@ 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(cgi_docroot, strlen(cgi_docroot), "/", 1,wsgi_req->path_info, wsgi_req->path_info_len, "", 0);
|
||||
uwsgi_log("requested %s %s\n", path_info, realpath(path_info, full_path));
|
||||
char *docroot = uwsgi_cgi_get_docroot(wsgi_req->path_info, wsgi_req->path_info_len, &need_free, &is_a_file, &discard_base, &script_name);
|
||||
|
||||
if (access(full_path, R_OK)) {
|
||||
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;
|
||||
}
|
||||
|
||||
if (access(full_path, X_OK)) {
|
||||
wsgi_req->status = 500;
|
||||
wsgi_req->socket->proto_write(wsgi_req, "HTTP/1.1 500 Internal Server Error\r\n\r\n", 26);
|
||||
docroot_len = strlen(docroot);
|
||||
memcpy(full_path, docroot, docroot_len);
|
||||
|
||||
if (!is_a_file) {
|
||||
|
||||
*(full_path+docroot_len) = '/';
|
||||
*(full_path+docroot_len+1) = 0;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
*(full_path+docroot_len) = 0;
|
||||
path_info = wsgi_req->path_info+discard_base;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
full_path_len = strlen(full_path);
|
||||
}
|
||||
|
||||
int cgi_allowed = 1;
|
||||
struct uwsgi_string_list *allowed = uc.allowed_ext;
|
||||
while(allowed) {
|
||||
cgi_allowed = 0;
|
||||
if (full_path_len >= allowed->len) {
|
||||
if (!uwsgi_strncmp(full_path+(full_path_len-allowed->len), allowed->len, allowed->value, allowed->len)) {
|
||||
cgi_allowed = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
allowed = allowed->next;
|
||||
}
|
||||
|
||||
if (!cgi_allowed) {
|
||||
uwsgi_cgi_403(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()");
|
||||
uwsgi_cgi_403(wsgi_req);
|
||||
if (need_free)
|
||||
free(docroot);
|
||||
return UWSGI_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pipe(cgi_pipe)) {
|
||||
if (need_free)
|
||||
free(docroot);
|
||||
uwsgi_error("pipe()");
|
||||
return UWSGI_OK;
|
||||
}
|
||||
@@ -73,48 +584,92 @@ 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) {
|
||||
// close input
|
||||
close(wsgi_req->poll.fd);
|
||||
wsgi_req->fd_closed = 1;
|
||||
|
||||
if (need_free)
|
||||
free(docroot);
|
||||
|
||||
close(cgi_pipe[1]);
|
||||
// wait for data
|
||||
char startbuf[8];
|
||||
char *ptr = startbuf;
|
||||
int remains = 8;
|
||||
char *headers_buf = uwsgi_malloc(uc.buffer_size);
|
||||
char *ptr = headers_buf;
|
||||
size_t remains = uc.buffer_size;
|
||||
int completed = 0;
|
||||
while(remains > 0) {
|
||||
uwsgi_log("waiting for fd\n");
|
||||
int ret = uwsgi_waitfd(cgi_pipe[0], 10);
|
||||
uwsgi_log("data available\n");
|
||||
int ret = uwsgi_waitfd(cgi_pipe[0], uc.timeout);
|
||||
if (ret > 0) {
|
||||
len = read(cgi_pipe[0], ptr, remains);
|
||||
if (len > 0) {
|
||||
ptr+=len;
|
||||
remains -= len;
|
||||
}
|
||||
else if (len == 0) {
|
||||
completed = 1;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
uwsgi_error("read()");
|
||||
goto clear;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if (ret == 0) {
|
||||
uwsgi_log("CGI timeout !!!\n");
|
||||
goto clear;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
uwsgi_log("STARTBUF %.*s\n", 8, startbuf);
|
||||
|
||||
if (!memcmp(startbuf, "Status: ", 8)) {
|
||||
// wsgi_req->socket->proto_write(wsgi_req, "HTTP/1.1 "
|
||||
if (uwsgi_cgi_parse(wsgi_req, headers_buf, uc.buffer_size-remains)) {
|
||||
uwsgi_log("invalid CGI output !!!\n");
|
||||
goto clear;
|
||||
}
|
||||
|
||||
// now wait for fd
|
||||
if (waitpid(cgi_pid, &waitpid_status ,0) > 0) {
|
||||
uwsgi_log("CGI FINISHED\n");
|
||||
while (!completed) {
|
||||
int ret = uwsgi_waitfd(cgi_pipe[0], uc.timeout);
|
||||
if (ret > 0) {
|
||||
len = read(cgi_pipe[0], headers_buf, uc.buffer_size);
|
||||
if (len > 0) {
|
||||
wsgi_req->response_size += wsgi_req->socket->proto_write(wsgi_req, headers_buf, len);
|
||||
}
|
||||
// end of output
|
||||
else if (len == 0) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
uwsgi_error("read()");
|
||||
goto clear;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if (ret == 0) {
|
||||
uwsgi_log("CGI timeout !!!\n");
|
||||
goto clear;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
|
||||
clear:
|
||||
free(headers_buf);
|
||||
close(cgi_pipe[0]);
|
||||
|
||||
// now wait for process exit/death
|
||||
if (waitpid(cgi_pid, &waitpid_status, 0) < 0) {
|
||||
uwsgi_error("waitpid()");
|
||||
}
|
||||
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
// close all the fd except wsgi_req->poll.fd and 2;
|
||||
|
||||
for(i=0;i< (int)uwsgi.max_fd;i++) {
|
||||
if (i != wsgi_req->poll.fd && i != 2 && i != cgi_pipe[0] && i != cgi_pipe[1]) {
|
||||
if (i != wsgi_req->poll.fd && i != 2 && i != cgi_pipe[1]) {
|
||||
close(i);
|
||||
}
|
||||
}
|
||||
@@ -125,10 +680,12 @@ int uwsgi_cgi_request(struct wsgi_request *wsgi_req) {
|
||||
close(wsgi_req->poll.fd);
|
||||
}
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("mapping cgi_pipe %d to 1\n", cgi_pipe[1]);
|
||||
#endif
|
||||
|
||||
dup2(cgi_pipe[1],1);
|
||||
|
||||
|
||||
// fill cgi env
|
||||
for(i=0;i<wsgi_req->var_cnt;i++) {
|
||||
// no need to free the putenv() memory
|
||||
@@ -139,16 +696,94 @@ int uwsgi_cgi_request(struct wsgi_request *wsgi_req) {
|
||||
}
|
||||
|
||||
|
||||
argv[0] = full_path;
|
||||
argv[1] = NULL;
|
||||
if (execv(argv[0], argv)) {
|
||||
uwsgi_error("execv()");
|
||||
if (setenv("GATEWAY_INTERFACE", "CGI/1.1", 0)) {
|
||||
uwsgi_error("setenv()");
|
||||
}
|
||||
|
||||
if (setenv("SERVER_SOFTWARE", uwsgi_concat2("uWSGI/", UWSGI_VERSION), 0)) {
|
||||
uwsgi_error("setenv()");
|
||||
}
|
||||
|
||||
if (path_info && wsgi_req->path_info_len-discard_base > 0) {
|
||||
if (setenv("PATH_INFO", uwsgi_concat2n(path_info, wsgi_req->path_info_len-discard_base, "", 0), 1)) {
|
||||
uwsgi_error("setenv()");
|
||||
}
|
||||
|
||||
if (setenv("PATH_TRANSLATED", uwsgi_concat4n(docroot, docroot_len, "/", 1, path_info, wsgi_req->path_info_len-discard_base, "", 0) , 1)) {
|
||||
uwsgi_error("setenv()");
|
||||
}
|
||||
}
|
||||
else {
|
||||
unsetenv("PATH_INFO");
|
||||
unsetenv("PATH_TRANSLATED");
|
||||
}
|
||||
|
||||
if (is_a_file) {
|
||||
if (setenv("DOCUMENT_ROOT", uwsgi.cwd, 0)) {
|
||||
uwsgi_error("setenv()");
|
||||
}
|
||||
|
||||
if (setenv("SCRIPT_FILENAME", docroot, 0)) {
|
||||
uwsgi_error("setenv()");
|
||||
}
|
||||
|
||||
if (script_name && discard_base > 1) {
|
||||
if (setenv("SCRIPT_NAME", uwsgi_concat2n(script_name, discard_base, "", 0), 1)) {
|
||||
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()");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct uwsgi_string_list *drop_env = uc.unset;
|
||||
while(drop_env) {
|
||||
unsetenv(drop_env->value);
|
||||
drop_env = drop_env->next;
|
||||
}
|
||||
|
||||
if (helper) {
|
||||
argv[0] = helper;
|
||||
argv[1] = command;
|
||||
argv[2] = NULL;
|
||||
}
|
||||
else {
|
||||
argv[0] = command;
|
||||
argv[1] = NULL;
|
||||
}
|
||||
|
||||
if (execvp(argv[0], argv)) {
|
||||
uwsgi_error("execvp()");
|
||||
}
|
||||
|
||||
// never here
|
||||
exit(1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -160,10 +795,41 @@ void uwsgi_cgi_after_request(struct wsgi_request *wsgi_req) {
|
||||
|
||||
int uwsgi_cgi_manage_options(int i, char *optarg) {
|
||||
|
||||
char *value;
|
||||
|
||||
switch(i) {
|
||||
case LONG_ARGS_CGI:
|
||||
cgi_docroot = optarg;
|
||||
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);
|
||||
return 1;
|
||||
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_ALLOWED_EXT:
|
||||
uwsgi_string_new_list(&uc.allowed_ext, optarg);
|
||||
return 1;
|
||||
case LONG_ARGS_CGI_UNSET:
|
||||
uwsgi_string_new_list(&uc.unset, optarg);
|
||||
return 1;
|
||||
case LONG_ARGS_CGI_MAP_HELPER:
|
||||
value = strchr(optarg, '=');
|
||||
if (!value) {
|
||||
uwsgi_log("invalid CGI helper syntax, must be ext=command\n");
|
||||
exit(1);
|
||||
}
|
||||
uwsgi_dyn_dict_new(&uc.helpers, optarg, value-optarg, value+1, strlen(value+1));
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -175,6 +841,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;
|
||||
}
|
||||
|
||||
@@ -148,24 +148,14 @@ char *uwsgi_encode_pydict(PyObject * pydict, uint16_t * size) {
|
||||
keysize = PyString_Size(key);
|
||||
valsize = PyString_Size(val);
|
||||
if (bufptr + keysize + 2 + valsize + 2 <= buf + *size) {
|
||||
#ifdef __BIG_ENDIAN__
|
||||
keysize = uwsgi_swap16(keysize);
|
||||
#endif
|
||||
memcpy(bufptr, &keysize, 2);
|
||||
bufptr += 2;
|
||||
#ifdef __BIG_ENDIAN__
|
||||
keysize = uwsgi_swap16(keysize);
|
||||
#endif
|
||||
|
||||
*bufptr++ = (uint8_t) (keysize & 0xff);
|
||||
*bufptr++ = (uint8_t) ((keysize >> 8) & 0xff);
|
||||
memcpy(bufptr, PyString_AsString(key), keysize);
|
||||
bufptr += keysize;
|
||||
#ifdef __BIG_ENDIAN__
|
||||
valsize = uwsgi_swap16(valsize);
|
||||
#endif
|
||||
memcpy(bufptr, &valsize, 2);
|
||||
bufptr += 2;
|
||||
#ifdef __BIG_ENDIAN__
|
||||
valsize = uwsgi_swap16(valsize);
|
||||
#endif
|
||||
|
||||
*bufptr++ = (uint8_t) (valsize & 0xff);
|
||||
*bufptr++ = (uint8_t) ((valsize >> 8) & 0xff);
|
||||
memcpy(bufptr, PyString_AsString(val), valsize);
|
||||
bufptr += valsize;
|
||||
}
|
||||
@@ -1600,24 +1590,15 @@ PyObject *py_uwsgi_send_spool(PyObject * self, PyObject * args, PyObject *kw) {
|
||||
valsize = PyString_Size(val);
|
||||
if (cur_buf + keysize + 2 + valsize + 2 <= spool_buffer + UMAX16) {
|
||||
|
||||
#ifdef __BIG_ENDIAN__
|
||||
keysize = uwsgi_swap16(keysize);
|
||||
#endif
|
||||
memcpy(cur_buf, &keysize, 2);
|
||||
cur_buf += 2;
|
||||
#ifdef __BIG_ENDIAN__
|
||||
keysize = uwsgi_swap16(keysize);
|
||||
#endif
|
||||
*cur_buf++ = (uint8_t) (keysize & 0xff);
|
||||
*cur_buf++ = (uint8_t) ((keysize >> 8) & 0xff);
|
||||
|
||||
memcpy(cur_buf, PyString_AsString(key), keysize);
|
||||
cur_buf += keysize;
|
||||
#ifdef __BIG_ENDIAN__
|
||||
valsize = uwsgi_swap16(valsize);
|
||||
#endif
|
||||
memcpy(cur_buf, &valsize, 2);
|
||||
cur_buf += 2;
|
||||
#ifdef __BIG_ENDIAN__
|
||||
valsize = uwsgi_swap16(valsize);
|
||||
#endif
|
||||
|
||||
*cur_buf++ = (uint8_t) (valsize & 0xff);
|
||||
*cur_buf++ = (uint8_t) ((valsize >> 8) & 0xff);
|
||||
|
||||
memcpy(cur_buf, PyString_AsString(val), valsize);
|
||||
cur_buf += valsize;
|
||||
}
|
||||
|
||||
@@ -25,6 +25,26 @@ VALUE rack_uwsgi_warning(VALUE *class, VALUE rbmessage) {
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
VALUE rack_uwsgi_log(VALUE *class, VALUE msg) {
|
||||
|
||||
Check_Type(msg, T_STRING);
|
||||
|
||||
uwsgi_log("%s\n", RSTRING_PTR(msg));
|
||||
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
VALUE rack_uwsgi_i_am_the_spooler(VALUE *class) {
|
||||
#ifdef UWSGI_SPOOLER
|
||||
if (uwsgi.mypid == uwsgi.shared->spooler_pid) {
|
||||
return Qtrue;
|
||||
}
|
||||
#endif
|
||||
|
||||
return Qfalse;
|
||||
}
|
||||
|
||||
|
||||
|
||||
VALUE rack_uwsgi_setprocname(VALUE *class, VALUE rbname) {
|
||||
|
||||
@@ -727,6 +747,118 @@ VALUE uwsgi_ruby_signal(int argc, VALUE *argv, VALUE *class) {
|
||||
return Qtrue;
|
||||
}
|
||||
|
||||
int rack_uwsgi_build_spool(VALUE rbkey, VALUE rbval, VALUE argv) {
|
||||
char **sa = (char **) argv;
|
||||
|
||||
char *cur_buf = sa[0];
|
||||
char *watermark = sa[1];
|
||||
|
||||
if (TYPE(rbkey) != T_STRING || TYPE(rbval) != T_STRING) {
|
||||
rb_raise(rb_eRuntimeError, "spool hash must contains only strings");
|
||||
return ST_STOP;
|
||||
}
|
||||
|
||||
char *key = RSTRING_PTR(rbkey); uint16_t keylen = RSTRING_LEN(rbkey);
|
||||
char *val = RSTRING_PTR(rbval); uint16_t vallen = RSTRING_LEN(rbval);
|
||||
|
||||
if (cur_buf + (2+keylen+2+vallen) > watermark) {
|
||||
rb_raise(rb_eRuntimeError, "spool hash size can be no more than 64K");
|
||||
return ST_STOP;
|
||||
}
|
||||
|
||||
*cur_buf++ = (uint8_t) (keylen & 0xff);
|
||||
*cur_buf++ = (uint8_t) ((keylen >> 8) & 0xff);
|
||||
memcpy(cur_buf, key, keylen); cur_buf += keylen;
|
||||
|
||||
*cur_buf++ = (uint8_t) (vallen & 0xff);
|
||||
*cur_buf++ = (uint8_t) ((vallen >> 8) & 0xff);
|
||||
memcpy(cur_buf, val, vallen); cur_buf += vallen;
|
||||
|
||||
// fix the ptr
|
||||
sa[0] = cur_buf;
|
||||
|
||||
return ST_CONTINUE;
|
||||
}
|
||||
|
||||
|
||||
VALUE rack_uwsgi_send_spool(VALUE *class, VALUE args) {
|
||||
|
||||
char spool_filename[1024];
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
char *priority = NULL;
|
||||
long numprio = 0;
|
||||
time_t at = 0;
|
||||
char *body = NULL;
|
||||
size_t body_len= 0;
|
||||
|
||||
Check_Type(args, T_HASH);
|
||||
|
||||
// priority
|
||||
#ifdef RUBY19
|
||||
VALUE rbprio = rb_hash_lookup(args, rb_str_new2("priority"));
|
||||
#else
|
||||
VALUE rbprio = rb_hash_aref(args, rb_str_new2("priority"));
|
||||
#endif
|
||||
if (TYPE(rbprio) == T_FIXNUM) {
|
||||
numprio = NUM2INT(rbprio);
|
||||
rb_hash_delete(args, rb_str_new2("priority"));
|
||||
}
|
||||
|
||||
// at
|
||||
#ifdef RUBY19
|
||||
VALUE rbat = rb_hash_lookup(args, rb_str_new2("at"));
|
||||
#else
|
||||
VALUE rbat = rb_hash_aref(args, rb_str_new2("at"));
|
||||
#endif
|
||||
if (TYPE(rbat) == T_FIXNUM) {
|
||||
at = NUM2INT(rbat);
|
||||
rb_hash_delete(args, rb_str_new2("at"));
|
||||
}
|
||||
|
||||
// body
|
||||
#ifdef RUBY19
|
||||
VALUE rbbody = rb_hash_lookup(args, rb_str_new2("body"));
|
||||
#else
|
||||
VALUE rbbody = rb_hash_aref(args, rb_str_new2("body"));
|
||||
#endif
|
||||
if (TYPE(rbbody) == T_STRING) {
|
||||
body = RSTRING_PTR(rbbody);
|
||||
body_len = RSTRING_LEN(rbbody);
|
||||
rb_hash_delete(args, rb_str_new2("body"));
|
||||
}
|
||||
|
||||
char *spool_buffer = uwsgi_malloc(UMAX16);
|
||||
char *argv[2];
|
||||
argv[0] = spool_buffer;
|
||||
argv[1] = spool_buffer + UMAX16 ;
|
||||
|
||||
rb_hash_foreach(args, rack_uwsgi_build_spool, (VALUE) argv);
|
||||
|
||||
if (numprio) {
|
||||
priority = uwsgi_num2str(numprio);
|
||||
}
|
||||
|
||||
int ret = spool_request(spool_filename, uwsgi.workers[0].requests + 1, wsgi_req->async_id, spool_buffer, argv[0] - spool_buffer, priority, at, body, body_len);
|
||||
|
||||
if (priority) {
|
||||
free(priority);
|
||||
}
|
||||
|
||||
free(spool_buffer);
|
||||
|
||||
if (ret > 0) {
|
||||
char *slash = uwsgi_get_last_char(spool_filename, '/');
|
||||
if (slash) {
|
||||
return rb_str_new2(slash+1);
|
||||
}
|
||||
return rb_str_new2(spool_filename);
|
||||
}
|
||||
|
||||
rb_raise(rb_eRuntimeError, "unable to spool job");
|
||||
return Qnil;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void uwsgi_rack_init_api() {
|
||||
@@ -761,6 +893,12 @@ void uwsgi_rack_init_api() {
|
||||
uwsgi_rack_api("request_id", rack_uwsgi_request_id, 0);
|
||||
uwsgi_rack_api("worker_id", rack_uwsgi_worker_id, 0);
|
||||
uwsgi_rack_api("mule_id", rack_uwsgi_mule_id, 0);
|
||||
|
||||
uwsgi_rack_api("i_am_the_spooler", rack_uwsgi_i_am_the_spooler, 0);
|
||||
uwsgi_rack_api("send_to_spooler", rack_uwsgi_send_spool, 1);
|
||||
uwsgi_rack_api("spool", rack_uwsgi_send_spool, 1);
|
||||
|
||||
uwsgi_rack_api("log", rack_uwsgi_log, 1);
|
||||
uwsgi_rack_api("logsize", rack_uwsgi_logsize, 0);
|
||||
|
||||
uwsgi_rack_api("set_warning_message", rack_uwsgi_warning, 1);
|
||||
@@ -820,6 +958,10 @@ void uwsgi_rack_init_api() {
|
||||
|
||||
rb_const_set(rb_uwsgi_embedded, rb_intern("OPT"), uwsgi_rb_opt_hash);
|
||||
|
||||
rb_const_set(rb_uwsgi_embedded, rb_intern("SPOOL_OK"), INT2NUM(-2));
|
||||
rb_const_set(rb_uwsgi_embedded, rb_intern("SPOOL_IGNORE"), INT2NUM(0));
|
||||
rb_const_set(rb_uwsgi_embedded, rb_intern("SPOOL_RETRY"), INT2NUM(-1));
|
||||
|
||||
rb_const_set(rb_uwsgi_embedded, rb_intern("VERSION"), rb_str_new2(UWSGI_VERSION));
|
||||
rb_const_set(rb_uwsgi_embedded, rb_intern("HOSTNAME"), rb_str_new(uwsgi.hostname, uwsgi.hostname_len));
|
||||
if (uwsgi.pidfile) {
|
||||
|
||||
@@ -66,7 +66,7 @@ VALUE rb_uwsgi_io_gets(VALUE obj, VALUE args) {
|
||||
|
||||
// return the whole body as string
|
||||
|
||||
uwsgi_log("rack.input gets is not implemented (req %p)\n", wsgi_req);
|
||||
rb_raise(rb_eRuntimeError, "rack.input::gets is not implemented (req %p)\n", wsgi_req);
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ VALUE rb_uwsgi_io_each(VALUE obj, VALUE args) {
|
||||
Data_Get_Struct(obj, struct wsgi_request, wsgi_req);
|
||||
|
||||
// yield strings chunks
|
||||
uwsgi_log("rack.input each is not implemented (req %p)\n", wsgi_req);
|
||||
rb_raise(rb_eRuntimeError, "rack.input::each is not implemented (req %p)\n", wsgi_req);
|
||||
|
||||
return Qnil;
|
||||
}
|
||||
@@ -88,7 +88,6 @@ VALUE rb_uwsgi_io_read(VALUE obj, VALUE args) {
|
||||
VALUE chunk;
|
||||
int chunk_size;
|
||||
|
||||
|
||||
if (!wsgi_req->post_cl || wsgi_req->buf_pos >= wsgi_req->post_cl) {
|
||||
return Qnil;
|
||||
}
|
||||
@@ -108,8 +107,9 @@ VALUE rb_uwsgi_io_read(VALUE obj, VALUE args) {
|
||||
wsgi_req->buf_pos+=chunk_size;
|
||||
return RARRAY_PTR(args)[1];
|
||||
}
|
||||
chunk = rb_str_new(wsgi_req->post_buffering_buf+wsgi_req->buf_pos, chunk_size);
|
||||
wsgi_req->buf_pos+=chunk_size;
|
||||
return rb_str_new(wsgi_req->post_buffering_buf+wsgi_req->buf_pos, chunk_size);
|
||||
return chunk;
|
||||
}
|
||||
|
||||
return Qnil;
|
||||
@@ -286,9 +286,19 @@ void uwsgi_rack_init_apps(void) {
|
||||
|
||||
ur.dispatcher = Qnil;
|
||||
if (rb_funcall(ac, rb_intern("const_defined?"), 1, ID2SYM(rb_intern("Dispatcher"))) == Qtrue) {
|
||||
|
||||
VALUE ac_dispatcher = rb_const_get(ac, rb_intern("Dispatcher"));
|
||||
if (rb_respond_to(ac_dispatcher, rb_intern("call")) || rb_respond_to(ac_dispatcher, ID2SYM(rb_intern("call")))) {
|
||||
ur.dispatcher = rb_funcall( rb_const_get(ac, rb_intern("Dispatcher")), rb_intern("new"), 0);
|
||||
|
||||
VALUE acd_instance_methods = rb_funcall( ac_dispatcher, rb_intern("instance_methods"), 0);
|
||||
|
||||
VALUE acim_call = rb_funcall( acd_instance_methods, rb_intern("include?"), 1, ID2SYM(rb_intern("call")));
|
||||
|
||||
if (acim_call == Qfalse) {
|
||||
acim_call = rb_funcall( acd_instance_methods, rb_intern("include?"), 1, rb_str_new2("call"));
|
||||
}
|
||||
|
||||
if (acim_call == Qtrue) {
|
||||
ur.dispatcher = rb_funcall( ac_dispatcher, rb_intern("new"), 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -311,6 +321,8 @@ void uwsgi_rack_init_apps(void) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
rb_gc_register_address(&ur.dispatcher);
|
||||
|
||||
goto ready;
|
||||
}
|
||||
|
||||
@@ -569,6 +581,7 @@ int uwsgi_rack_request(struct wsgi_request *wsgi_req) {
|
||||
goto clear;
|
||||
}
|
||||
|
||||
|
||||
if (TYPE(ret) == T_ARRAY) {
|
||||
if (RARRAY_LEN(ret) != 3) {
|
||||
uwsgi_log("Invalid RACK response size: %d\n", RARRAY_LEN(ret));
|
||||
@@ -925,6 +938,61 @@ int uwsgi_rack_signal_handler(uint8_t sig, void *handler) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
VALUE uwsgi_rb_do_spooler(VALUE args) {
|
||||
VALUE uwsgi_rb_embedded = rb_const_get(rb_cObject, rb_intern("UWSGI"));
|
||||
return rb_funcall(uwsgi_rb_embedded, rb_intern("spooler"), 1, args);
|
||||
}
|
||||
|
||||
void uwsgi_ruby_add_item(char *key, uint16_t keylen, char *val, uint16_t vallen, void *data) {
|
||||
|
||||
VALUE *spool_dict = (VALUE*) data;
|
||||
|
||||
rb_hash_aset(*spool_dict, rb_str_new(key, keylen), rb_str_new(val, vallen));
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_rack_spooler(char *filename, char *buf, uint16_t len, char *body, size_t body_len) {
|
||||
|
||||
int error = 0;
|
||||
|
||||
VALUE uwsgi_rb_embedded = rb_const_get(rb_cObject, rb_intern("UWSGI"));
|
||||
if (!rb_respond_to(uwsgi_rb_embedded, rb_intern("spooler"))) {
|
||||
rb_gc();
|
||||
return 0;
|
||||
}
|
||||
|
||||
VALUE spool_dict = rb_hash_new();
|
||||
|
||||
if (uwsgi_hooked_parse(buf, len, uwsgi_ruby_add_item, (void *) &spool_dict)) {
|
||||
rb_gc();
|
||||
// malformed packet, destroy it
|
||||
return 0;
|
||||
}
|
||||
|
||||
rb_hash_aset(spool_dict, rb_str_new2("spooler_task_name"), rb_str_new2(filename));
|
||||
|
||||
if (body && body_len > 0) {
|
||||
rb_hash_aset(spool_dict, rb_str_new2("body"), rb_str_new(body, body_len));
|
||||
}
|
||||
|
||||
VALUE ret = rb_protect(uwsgi_rb_do_spooler, spool_dict, &error);
|
||||
if (error) {
|
||||
uwsgi_ruby_exception();
|
||||
rb_gc();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (TYPE(ret) == T_FIXNUM) {
|
||||
rb_gc();
|
||||
return NUM2INT(ret);
|
||||
}
|
||||
|
||||
// error, retry
|
||||
rb_gc();
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -943,6 +1011,8 @@ struct uwsgi_plugin rack_plugin = {
|
||||
.hijack_worker = uwsgi_rack_hijack,
|
||||
.post_fork = uwsgi_rb_post_fork,
|
||||
|
||||
.spooler = uwsgi_rack_spooler,
|
||||
|
||||
.init_apps = uwsgi_rack_init_apps,
|
||||
//.mount_app = uwsgi_rack_mount_app,
|
||||
.manage_xml = uwsgi_rack_xml,
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#define LONG_ARGS_RUBY_REQUIRE LONG_ARGS_RACK_BASE + 5
|
||||
|
||||
#ifndef RUBY19
|
||||
#include <st.h>
|
||||
#define rb_errinfo() ruby_errinfo
|
||||
#define RUBY_GVL_LOCK
|
||||
#define RUBY_GVL_UNLOCK
|
||||
|
||||
+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;
|
||||
|
||||
@@ -65,13 +65,13 @@ void destroy_spool(char *dir, char *file) {
|
||||
|
||||
if (chdir(dir)) {
|
||||
uwsgi_error("chdir()");
|
||||
uwsgi_log("something horrible happened to the spooler. Better to kill it.\n");
|
||||
uwsgi_log("[spooler] something horrible happened to the spooler. Better to kill it.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (unlink(file)) {
|
||||
uwsgi_error("unlink()");
|
||||
uwsgi_log("something horrible happened to the spooler. Better to kill it.\n");
|
||||
uwsgi_log("[spooler] something horrible happened to the spooler. Better to kill it.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -165,7 +165,7 @@ int spool_request(char *filename, int rn, int core_id, char *buffer, int size, c
|
||||
|
||||
close(fd);
|
||||
|
||||
uwsgi_log("written %d bytes to spool file %s\n", size + body_len + 4, filename);
|
||||
uwsgi_log("[spooler] written %d bytes to file %s\n", size + body_len + 4, filename);
|
||||
|
||||
uwsgi_unlock(uwsgi.spooler_lock);
|
||||
|
||||
@@ -347,7 +347,7 @@ void spooler_manage_task(char *dir, char *task) {
|
||||
return;
|
||||
}
|
||||
if (!access(task, R_OK | W_OK)) {
|
||||
uwsgi_log("managing spool request %s ...\n", task);
|
||||
uwsgi_log("[spooler] managing request %s ...\n", task);
|
||||
|
||||
#ifdef __sun__
|
||||
// lockf needs write permission
|
||||
@@ -426,7 +426,7 @@ void spooler_manage_task(char *dir, char *task) {
|
||||
if (ret == 0) continue;
|
||||
callable_found = 1;
|
||||
if (ret == -2) {
|
||||
uwsgi_log("done with task/spool %s after %d seconds\n", task, time(NULL)-now);
|
||||
uwsgi_log("[spooler] done with task %s after %d seconds\n", task, time(NULL)-now);
|
||||
destroy_spool(dir, task);
|
||||
}
|
||||
// re-spool it
|
||||
|
||||
@@ -518,6 +518,20 @@ void uwsgi_as_root() {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
if (uwsgi.unshare && !uwsgi.reloads) {
|
||||
|
||||
if (unshare(uwsgi.unshare)) {
|
||||
uwsgi_error("unshare()");
|
||||
exit(1);
|
||||
}
|
||||
else {
|
||||
uwsgi_log("[linux-namespace] applied unshare() mask: %d\n", uwsgi.unshare);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
if (uwsgi.chroot && !uwsgi.reloads) {
|
||||
if (!uwsgi.master_as_root)
|
||||
uwsgi_log("chroot() to %s\n", uwsgi.chroot);
|
||||
@@ -532,6 +546,18 @@ void uwsgi_as_root() {
|
||||
#endif
|
||||
}
|
||||
|
||||
// now run the scripts needed by root
|
||||
struct uwsgi_string_list *usl = uwsgi.exec_as_root;
|
||||
while(usl) {
|
||||
uwsgi_log("running \"%s\" (as root)...\n", usl->value);
|
||||
int ret = uwsgi_run_command_and_wait(NULL, usl->value);
|
||||
if (ret != 0) {
|
||||
uwsgi_log("command \"%s\" exited with non-zero code: %d\n", usl->value, ret);
|
||||
exit(1);
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
|
||||
if (uwsgi.gidname) {
|
||||
struct group *ugroup = getgrnam(uwsgi.gidname);
|
||||
if (ugroup) {
|
||||
@@ -607,6 +633,18 @@ void uwsgi_as_root() {
|
||||
cap_free(caps);
|
||||
}
|
||||
#endif
|
||||
|
||||
// now run the scripts needed by the user
|
||||
usl = uwsgi.exec_as_user;
|
||||
while(usl) {
|
||||
uwsgi_log("running \"%s\" (as uid: %d gid: %d) ...\n", usl->value, (int) getuid(), (int) getgid());
|
||||
int ret = uwsgi_run_command_and_wait(NULL, usl->value);
|
||||
if (ret != 0) {
|
||||
uwsgi_log("command \"%s\" exited with non-zero code: %d\n", usl->value, ret);
|
||||
exit(1);
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (uwsgi.chroot && !uwsgi.is_a_reload) {
|
||||
@@ -2817,7 +2855,7 @@ void uwsgi_sig_pause() {
|
||||
|
||||
int uwsgi_run_command_and_wait(char *command, char *arg) {
|
||||
|
||||
char *argv[3];
|
||||
char *argv[4];
|
||||
int waitpid_status = 0;
|
||||
pid_t pid = fork();
|
||||
if (pid < 0) {
|
||||
@@ -2833,11 +2871,26 @@ int uwsgi_run_command_and_wait(char *command, char *arg) {
|
||||
return WEXITSTATUS(waitpid_status);
|
||||
}
|
||||
|
||||
argv[0] = command;
|
||||
argv[1] = arg;
|
||||
argv[2] = NULL;
|
||||
#ifdef __linux__
|
||||
if (prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0)) {
|
||||
uwsgi_error("prctl()");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (command == NULL) {
|
||||
argv[0] = "/bin/sh";
|
||||
argv[1] = "-c";
|
||||
argv[2] = arg;
|
||||
argv[3] = NULL;
|
||||
execvp(argv[0], argv);
|
||||
}
|
||||
else {
|
||||
argv[0] = command;
|
||||
argv[1] = arg;
|
||||
argv[2] = NULL;
|
||||
execvp(command, argv);
|
||||
}
|
||||
|
||||
execvp(command, argv);
|
||||
|
||||
uwsgi_error("execvp()");
|
||||
//never here
|
||||
@@ -3161,6 +3214,67 @@ void uwsgi_build_mime_dict(char *filename) {
|
||||
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
struct uwsgi_unshare_id {
|
||||
char *name;
|
||||
int value;
|
||||
};
|
||||
|
||||
static struct uwsgi_unshare_id uwsgi_unshare_list[] = {
|
||||
#ifdef CLONE_FILES
|
||||
{"files", CLONE_FILES},
|
||||
#endif
|
||||
#ifdef CLONE_FS
|
||||
{"fs", CLONE_FS},
|
||||
#endif
|
||||
#ifdef CLONE_NEWIPC
|
||||
{"ipc", CLONE_NEWIPC},
|
||||
#endif
|
||||
#ifdef CLONE_NEWNET
|
||||
{"net", CLONE_NEWNET},
|
||||
#endif
|
||||
#ifdef CLONE_NEWNS
|
||||
{"ns", CLONE_NEWNS},
|
||||
{"mount", CLONE_NEWNS},
|
||||
#endif
|
||||
#ifdef CLONE_SYSVSEM
|
||||
{"sysvsem", CLONE_SYSVSEM},
|
||||
#endif
|
||||
#ifdef CLONE_NEWUTS
|
||||
{"uts", CLONE_NEWUTS},
|
||||
#endif
|
||||
{ NULL, -1}
|
||||
};
|
||||
|
||||
static int uwsgi_get_unshare_id(char *name) {
|
||||
|
||||
struct uwsgi_unshare_id *uui = uwsgi_unshare_list;
|
||||
while(uui->name) {
|
||||
if (!strcmp(uui->name, name)) return uui->value;
|
||||
uui++;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void uwsgi_build_unshare(char *what) {
|
||||
|
||||
char *list = uwsgi_str(what);
|
||||
|
||||
char *p = strtok(list, ",");
|
||||
while (p != NULL) {
|
||||
int u_id = uwsgi_get_unshare_id(p);
|
||||
if (u_id != -1) {
|
||||
uwsgi.unshare |= u_id;
|
||||
}
|
||||
p = strtok(NULL, ",");
|
||||
}
|
||||
free(list);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef UWSGI_CAP
|
||||
struct uwsgi_cap {
|
||||
char *name;
|
||||
|
||||
@@ -147,6 +147,11 @@ static struct option long_base_options[] = {
|
||||
#ifdef UWSGI_CAP
|
||||
{"cap", required_argument,0, LONG_ARGS_CAP},
|
||||
#endif
|
||||
#ifdef __linux__
|
||||
{"unshare", required_argument,0, LONG_ARGS_UNSHARE},
|
||||
#endif
|
||||
{"exec-as-root", required_argument,0, LONG_ARGS_EXEC_AS_ROOT},
|
||||
{"exec-as-user", required_argument,0, LONG_ARGS_EXEC_AS_USER},
|
||||
#ifdef UWSGI_INI
|
||||
{"ini", required_argument, 0, LONG_ARGS_INI},
|
||||
#endif
|
||||
@@ -261,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
|
||||
@@ -268,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},
|
||||
@@ -2233,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();
|
||||
@@ -3247,6 +3258,11 @@ static int manage_base_opt(int i, char *optarg) {
|
||||
case LONG_ARGS_CAP:
|
||||
uwsgi_build_cap(optarg);
|
||||
return 1;
|
||||
#endif
|
||||
#ifdef __linux__
|
||||
case LONG_ARGS_UNSHARE:
|
||||
uwsgi_build_unshare(optarg);
|
||||
return 1;
|
||||
#endif
|
||||
case LONG_ARGS_BINARY_PATH:
|
||||
uwsgi.binary_path = optarg;
|
||||
@@ -3367,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, '=');
|
||||
@@ -3456,6 +3475,12 @@ static int manage_base_opt(int i, char *optarg) {
|
||||
uwsgi_string_new_list(&uwsgi.touch_reload, optarg);
|
||||
uwsgi.master_process = 1;
|
||||
return 1;
|
||||
case LONG_ARGS_EXEC_AS_ROOT:
|
||||
uwsgi_string_new_list(&uwsgi.exec_as_root, optarg);
|
||||
return 1;
|
||||
case LONG_ARGS_EXEC_AS_USER:
|
||||
uwsgi_string_new_list(&uwsgi.exec_as_user, optarg);
|
||||
return 1;
|
||||
case LONG_ARGS_PRIO:
|
||||
uwsgi.prio = (int) strtol(optarg, NULL, 10);
|
||||
return 1;
|
||||
|
||||
@@ -535,6 +535,10 @@ struct uwsgi_opt {
|
||||
#define LONG_ARGS_LOGFILE_CHMOD 17165
|
||||
#define LONG_ARGS_SUBSCRIBE_FREQ 17166
|
||||
#define LONG_ARGS_SUBSCR_TOLERANCE 17167
|
||||
#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
|
||||
@@ -1143,6 +1147,10 @@ struct uwsgi_server {
|
||||
int cap_count;
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
int unshare;
|
||||
#endif
|
||||
|
||||
// still working on it
|
||||
char *profiler;
|
||||
|
||||
@@ -1192,12 +1200,16 @@ struct uwsgi_server {
|
||||
|
||||
struct uwsgi_probe *probes;
|
||||
|
||||
struct uwsgi_string_list *exec_as_root;
|
||||
struct uwsgi_string_list *exec_as_user;
|
||||
|
||||
struct uwsgi_daemon *daemons;
|
||||
int daemons_cnt;
|
||||
|
||||
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;
|
||||
@@ -1324,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
|
||||
|
||||
|
||||
@@ -2530,6 +2543,7 @@ int uwsgi_is_bad_connection(int);
|
||||
int uwsgi_long2str2n(unsigned long long, char *, int);
|
||||
|
||||
#ifdef __linux__
|
||||
void uwsgi_build_unshare(char *);
|
||||
#ifdef MADV_MERGEABLE
|
||||
void uwsgi_linux_ksm_map(void);
|
||||
#endif
|
||||
|
||||
+18
@@ -14,6 +14,7 @@ end
|
||||
|
||||
$postfork_chain = []
|
||||
$mulefunc_list = []
|
||||
$spoolfunc_list = []
|
||||
|
||||
module UWSGI
|
||||
module_function
|
||||
@@ -21,6 +22,11 @@ module UWSGI
|
||||
$postfork_chain.each {|func| func.call }
|
||||
end
|
||||
|
||||
module_function
|
||||
def spooler(args)
|
||||
$spoolfunc_list[args['ud_spool_func'].to_i].call(args)
|
||||
end
|
||||
|
||||
module_function
|
||||
def mule_msg_hook(message)
|
||||
service = Marshal.load(message)
|
||||
@@ -62,6 +68,18 @@ def postfork(&block)
|
||||
$postfork_chain << block
|
||||
end
|
||||
|
||||
class SpoolProc < Proc
|
||||
def initialize(&block)
|
||||
@block = block
|
||||
@id = (($spoolfunc_list << block).length-1).to_s
|
||||
end
|
||||
|
||||
def call(args)
|
||||
args['ud_spool_func'] = @id
|
||||
UWSGI::send_to_spooler(args)
|
||||
end
|
||||
end
|
||||
|
||||
def rpc(name, &block)
|
||||
if block.arity <= 0
|
||||
UWSGI.register_rpc(name, block, 0)
|
||||
|
||||
Reference in New Issue
Block a user