mirror of
https://github.com/clearlinux/uwsgi.git
synced 2026-06-16 02:15:48 +00:00
665 lines
18 KiB
C
665 lines
18 KiB
C
#include "uwsgi.h"
|
|
|
|
extern struct uwsgi_server uwsgi;
|
|
|
|
int uwsgi_static_want_gzip(struct wsgi_request *wsgi_req, char *filename, size_t *filename_len, struct stat *st) {
|
|
// check for filename size
|
|
if (*filename_len + 4 > PATH_MAX) return 0;
|
|
// check for supported encodings
|
|
if (!uwsgi_contains_n(wsgi_req->encoding, wsgi_req->encoding_len, "gzip", 4) ) return 0;
|
|
|
|
// check for 'all'
|
|
if (uwsgi.static_gzip_all) goto gzip;
|
|
|
|
// check for dirs/prefix
|
|
struct uwsgi_string_list *usl = uwsgi.static_gzip_dir;
|
|
while(usl) {
|
|
if (!uwsgi_starts_with(filename, *filename_len, usl->value, usl->len)) {
|
|
goto gzip;
|
|
}
|
|
usl = usl->next;
|
|
}
|
|
|
|
// check for ext/suffix
|
|
usl = uwsgi.static_gzip_ext;
|
|
while(usl) {
|
|
if (!uwsgi_strncmp(filename + (*filename_len - usl->len), usl->len, usl->value, usl->len)) {
|
|
goto gzip;
|
|
}
|
|
usl = usl->next;
|
|
}
|
|
|
|
#ifdef UWSGI_PCRE
|
|
// check for regexp
|
|
struct uwsgi_regexp_list *url = uwsgi.static_gzip;
|
|
while(url) {
|
|
if (uwsgi_regexp_match(url->pattern, url->pattern_extra, filename, *filename_len) >= 0) {
|
|
goto gzip;
|
|
}
|
|
url = url->next;
|
|
}
|
|
#endif
|
|
return 0;
|
|
|
|
gzip:
|
|
|
|
memcpy(filename + *filename_len, ".gz\0", 4);
|
|
*filename_len += 3;
|
|
|
|
if (stat(filename, st)) {
|
|
*filename_len -= 3;
|
|
filename[*filename_len] = 0;
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
int uwsgi_http_date(time_t t, char *dst) {
|
|
|
|
static char *week[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
|
|
static char *months[] = {
|
|
"Jan", "Feb", "Mar", "Apr",
|
|
"May", "Jun", "Jul", "Aug",
|
|
"Sep", "Oct", "Nov", "Dec"
|
|
};
|
|
|
|
struct tm *hdtm = gmtime(&t);
|
|
|
|
int ret = snprintf(dst, 31, "%s, %02d %s %4d %02d:%02d:%02d GMT",
|
|
week[hdtm->tm_wday], hdtm->tm_mday, months[hdtm->tm_mon], hdtm->tm_year + 1900, hdtm->tm_hour, hdtm->tm_min, hdtm->tm_sec);
|
|
if (ret <= 0 || ret > 31) {
|
|
return 0;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
// only RFC 1123 is supported
|
|
static time_t parse_http_date(char *date, uint16_t len) {
|
|
|
|
struct tm hdtm;
|
|
|
|
if (len != 29 && date[3] != ',')
|
|
return 0;
|
|
|
|
hdtm.tm_mday = uwsgi_str2_num(date + 5);
|
|
|
|
switch (date[8]) {
|
|
case 'J':
|
|
if (date[9] == 'a') {
|
|
hdtm.tm_mon = 0;
|
|
break;
|
|
}
|
|
|
|
if (date[9] == 'u') {
|
|
if (date[10] == 'n') {
|
|
hdtm.tm_mon = 5;
|
|
break;
|
|
}
|
|
|
|
if (date[10] == 'l') {
|
|
hdtm.tm_mon = 6;
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
return 0;
|
|
|
|
case 'F':
|
|
hdtm.tm_mon = 1;
|
|
break;
|
|
|
|
case 'M':
|
|
if (date[9] != 'a')
|
|
return 0;
|
|
|
|
if (date[10] == 'r') {
|
|
hdtm.tm_mon = 2;
|
|
break;
|
|
}
|
|
|
|
if (date[10] == 'y') {
|
|
hdtm.tm_mon = 4;
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
|
|
case 'A':
|
|
if (date[10] == 'r') {
|
|
hdtm.tm_mon = 3;
|
|
break;
|
|
}
|
|
if (date[10] == 'g') {
|
|
hdtm.tm_mon = 7;
|
|
break;
|
|
}
|
|
return 0;
|
|
|
|
case 'S':
|
|
hdtm.tm_mon = 8;
|
|
break;
|
|
|
|
case 'O':
|
|
hdtm.tm_mon = 9;
|
|
break;
|
|
|
|
case 'N':
|
|
hdtm.tm_mon = 10;
|
|
break;
|
|
|
|
case 'D':
|
|
hdtm.tm_mon = 11;
|
|
break;
|
|
default:
|
|
return 0;
|
|
}
|
|
|
|
hdtm.tm_year = uwsgi_str4_num(date + 12) - 1900;
|
|
|
|
hdtm.tm_hour = uwsgi_str2_num(date + 17);
|
|
hdtm.tm_min = uwsgi_str2_num(date + 20);
|
|
hdtm.tm_sec = uwsgi_str2_num(date + 23);
|
|
|
|
return timegm(&hdtm);
|
|
|
|
}
|
|
|
|
time_t uwsgi_parse_http_date(char *buf, uint16_t len) {
|
|
return parse_http_date(buf, len);
|
|
}
|
|
|
|
|
|
int uwsgi_add_expires_type(struct wsgi_request *wsgi_req, char *mime_type, int mime_type_len, struct stat *st) {
|
|
|
|
struct uwsgi_dyn_dict *udd = uwsgi.static_expires_type;
|
|
time_t now = wsgi_req->start_of_request / 1000000;
|
|
// 30+1
|
|
char expires[31];
|
|
|
|
while (udd) {
|
|
if (!uwsgi_strncmp(udd->key, udd->keylen, mime_type, mime_type_len)) {
|
|
int delta = uwsgi_str_num(udd->value, udd->vallen);
|
|
int size = uwsgi_http_date(now + delta, expires);
|
|
if (size > 0) {
|
|
if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
udd = udd->next;
|
|
}
|
|
|
|
udd = uwsgi.static_expires_type_mtime;
|
|
while (udd) {
|
|
if (!uwsgi_strncmp(udd->key, udd->keylen, mime_type, mime_type_len)) {
|
|
int delta = uwsgi_str_num(udd->value, udd->vallen);
|
|
int size = uwsgi_http_date(st->st_mtime + delta, expires);
|
|
if (size > 0) {
|
|
if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
udd = udd->next;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifdef UWSGI_PCRE
|
|
int uwsgi_add_expires(struct wsgi_request *wsgi_req, char *filename, int filename_len, struct stat *st) {
|
|
|
|
struct uwsgi_dyn_dict *udd = uwsgi.static_expires;
|
|
time_t now = wsgi_req->start_of_request / 1000000;
|
|
// 30+1
|
|
char expires[31];
|
|
|
|
while (udd) {
|
|
if (uwsgi_regexp_match(udd->pattern, udd->pattern_extra, filename, filename_len) >= 0) {
|
|
int delta = uwsgi_str_num(udd->value, udd->vallen);
|
|
int size = uwsgi_http_date(now + delta, expires);
|
|
if (size > 0) {
|
|
if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
udd = udd->next;
|
|
}
|
|
|
|
udd = uwsgi.static_expires_mtime;
|
|
while (udd) {
|
|
if (uwsgi_regexp_match(udd->pattern, udd->pattern_extra, filename, filename_len) >= 0) {
|
|
int delta = uwsgi_str_num(udd->value, udd->vallen);
|
|
int size = uwsgi_http_date(st->st_mtime + delta, expires);
|
|
if (size > 0) {
|
|
if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
udd = udd->next;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int uwsgi_add_expires_path_info(struct wsgi_request *wsgi_req, struct stat *st) {
|
|
|
|
struct uwsgi_dyn_dict *udd = uwsgi.static_expires_path_info;
|
|
time_t now = wsgi_req->start_of_request / 1000000;
|
|
// 30+1
|
|
char expires[31];
|
|
|
|
while (udd) {
|
|
if (uwsgi_regexp_match(udd->pattern, udd->pattern_extra, wsgi_req->path_info, wsgi_req->path_info_len) >= 0) {
|
|
int delta = uwsgi_str_num(udd->value, udd->vallen);
|
|
int size = uwsgi_http_date(now + delta, expires);
|
|
if (size > 0) {
|
|
if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
udd = udd->next;
|
|
}
|
|
|
|
udd = uwsgi.static_expires_path_info_mtime;
|
|
while (udd) {
|
|
if (uwsgi_regexp_match(udd->pattern, udd->pattern_extra, wsgi_req->path_info, wsgi_req->path_info_len) >= 0) {
|
|
int delta = uwsgi_str_num(udd->value, udd->vallen);
|
|
int size = uwsgi_http_date(st->st_mtime + delta, expires);
|
|
if (size > 0) {
|
|
if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
udd = udd->next;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int uwsgi_add_expires_uri(struct wsgi_request *wsgi_req, struct stat *st) {
|
|
|
|
struct uwsgi_dyn_dict *udd = uwsgi.static_expires_uri;
|
|
time_t now = wsgi_req->start_of_request / 1000000;
|
|
// 30+1
|
|
char expires[31];
|
|
|
|
while (udd) {
|
|
if (uwsgi_regexp_match(udd->pattern, udd->pattern_extra, wsgi_req->uri, wsgi_req->uri_len) >= 0) {
|
|
int delta = uwsgi_str_num(udd->value, udd->vallen);
|
|
int size = uwsgi_http_date(now + delta, expires);
|
|
if (size > 0) {
|
|
if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
udd = udd->next;
|
|
}
|
|
|
|
udd = uwsgi.static_expires_uri_mtime;
|
|
while (udd) {
|
|
if (uwsgi_regexp_match(udd->pattern, udd->pattern_extra, wsgi_req->uri, wsgi_req->uri_len) >= 0) {
|
|
int delta = uwsgi_str_num(udd->value, udd->vallen);
|
|
int size = uwsgi_http_date(st->st_mtime + delta, expires);
|
|
if (size > 0) {
|
|
if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
udd = udd->next;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
char *uwsgi_get_mime_type(char *name, int namelen, size_t *size) {
|
|
|
|
int i;
|
|
int count = 0;
|
|
char *ext = NULL;
|
|
for (i = namelen - 1; i >= 0; i--) {
|
|
if (!isalnum((int) name[i])) {
|
|
if (name[i] == '.') {
|
|
ext = name + (namelen - count);
|
|
break;
|
|
}
|
|
}
|
|
count++;
|
|
}
|
|
|
|
if (!ext)
|
|
return NULL;
|
|
|
|
|
|
if (uwsgi.threads > 1)
|
|
pthread_mutex_lock(&uwsgi.lock_static);
|
|
|
|
struct uwsgi_dyn_dict *udd = uwsgi.mimetypes;
|
|
while (udd) {
|
|
if (!uwsgi_strncmp(ext, count, udd->key, udd->keylen)) {
|
|
udd->hits++;
|
|
// auto optimization
|
|
if (udd->prev) {
|
|
if (udd->hits > udd->prev->hits) {
|
|
struct uwsgi_dyn_dict *udd_parent = udd->prev->prev, *udd_prev = udd->prev;
|
|
if (udd_parent) {
|
|
udd_parent->next = udd;
|
|
}
|
|
|
|
if (udd->next) {
|
|
udd->next->prev = udd_prev;
|
|
}
|
|
|
|
udd_prev->prev = udd;
|
|
udd_prev->next = udd->next;
|
|
|
|
udd->prev = udd_parent;
|
|
udd->next = udd_prev;
|
|
|
|
if (udd->prev == NULL) {
|
|
uwsgi.mimetypes = udd;
|
|
}
|
|
}
|
|
}
|
|
*size = udd->vallen;
|
|
if (uwsgi.threads > 1)
|
|
pthread_mutex_unlock(&uwsgi.lock_static);
|
|
return udd->value;
|
|
}
|
|
udd = udd->next;
|
|
}
|
|
|
|
if (uwsgi.threads > 1)
|
|
pthread_mutex_unlock(&uwsgi.lock_static);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
ssize_t uwsgi_append_static_path(char *dir, size_t dir_len, char *file, size_t file_len) {
|
|
|
|
|
|
size_t len = dir_len;
|
|
|
|
if (len + 1 + file_len > PATH_MAX) {
|
|
return -1;
|
|
}
|
|
|
|
if (dir[len - 1] == '/') {
|
|
memcpy(dir + len, file, file_len);
|
|
dir[len + file_len] = 0;
|
|
len += file_len;
|
|
}
|
|
else {
|
|
dir[len] = '/';
|
|
memcpy(dir + len + 1, file, file_len);
|
|
dir[len + 1 + file_len] = 0;
|
|
len += 1 + file_len;
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
static int uwsgi_static_stat(struct wsgi_request *wsgi_req, char *filename, size_t *filename_len, struct stat *st, struct uwsgi_string_list **index) {
|
|
|
|
int ret = stat(filename, st);
|
|
// if non-existant return -1
|
|
if (ret < 0)
|
|
return -1;
|
|
|
|
if (S_ISREG(st->st_mode))
|
|
return 0;
|
|
|
|
// check for index
|
|
if (S_ISDIR(st->st_mode)) {
|
|
struct uwsgi_string_list *usl = uwsgi.static_index;
|
|
while (usl) {
|
|
ssize_t new_len = uwsgi_append_static_path(filename, *filename_len, usl->value, usl->len);
|
|
if (new_len >= 0) {
|
|
#ifdef UWSGI_DEBUG
|
|
uwsgi_log("checking for %s\n", filename);
|
|
#endif
|
|
if (uwsgi_is_file2(filename, st)) {
|
|
*index = usl;
|
|
*filename_len = new_len;
|
|
return 0;
|
|
}
|
|
// reset to original name
|
|
filename[*filename_len] = 0;
|
|
}
|
|
usl = usl->next;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
int uwsgi_real_file_serve(struct wsgi_request *wsgi_req, char *real_filename, size_t real_filename_len, struct stat *st) {
|
|
|
|
size_t mime_type_size = 0;
|
|
char http_last_modified[49];
|
|
int use_gzip = 0;
|
|
|
|
char *mime_type = uwsgi_get_mime_type(real_filename, real_filename_len, &mime_type_size);
|
|
|
|
// here we need to choose if we want the gzip variant;
|
|
if (uwsgi_static_want_gzip(wsgi_req, real_filename, &real_filename_len, st)) use_gzip = 1;
|
|
|
|
if (wsgi_req->if_modified_since_len) {
|
|
time_t ims = parse_http_date(wsgi_req->if_modified_since, wsgi_req->if_modified_since_len);
|
|
if (st->st_mtime <= ims) {
|
|
if (uwsgi_response_prepare_headers(wsgi_req, "304 Not Modified", 16))
|
|
return -1;
|
|
return uwsgi_response_write_headers_do(wsgi_req);
|
|
}
|
|
}
|
|
#ifdef UWSGI_DEBUG
|
|
uwsgi_log("[uwsgi-fileserve] file %s found, mimetype %s\n", real_filename, mime_type);
|
|
#endif
|
|
|
|
// static file - don't update avg_rt after request
|
|
wsgi_req->do_not_account_avg_rt = 1;
|
|
|
|
size_t fsize = st->st_size;
|
|
// security check
|
|
if (wsgi_req->range_from > fsize) {
|
|
wsgi_req->range_from = 0;
|
|
wsgi_req->range_to = 0;
|
|
}
|
|
else {
|
|
fsize -= wsgi_req->range_from;
|
|
}
|
|
|
|
if (wsgi_req->range_to) {
|
|
fsize = (wsgi_req->range_to - wsgi_req->range_from)+1;
|
|
if (fsize + wsgi_req->range_from > (size_t) (st->st_size)) {
|
|
fsize = st->st_size - wsgi_req->range_from;
|
|
}
|
|
}
|
|
|
|
// HTTP status
|
|
if (fsize > 0 && (wsgi_req->range_from || wsgi_req->range_to)) {
|
|
if (uwsgi_response_prepare_headers(wsgi_req, "206 Partial Content", 19)) return -1;
|
|
}
|
|
else {
|
|
if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) return -1;
|
|
}
|
|
|
|
#ifdef UWSGI_PCRE
|
|
uwsgi_add_expires(wsgi_req, real_filename, real_filename_len, st);
|
|
uwsgi_add_expires_path_info(wsgi_req, st);
|
|
uwsgi_add_expires_uri(wsgi_req, st);
|
|
#endif
|
|
|
|
if (use_gzip) {
|
|
if (uwsgi_response_add_header(wsgi_req, "Content-Encoding", 16, "gzip", 4)) return -1;
|
|
}
|
|
|
|
// Content-Type (if available)
|
|
if (mime_type_size > 0 && mime_type) {
|
|
if (uwsgi_response_add_content_type(wsgi_req, mime_type, mime_type_size)) return -1;
|
|
// check for content-type related headers
|
|
uwsgi_add_expires_type(wsgi_req, mime_type, mime_type_size, st);
|
|
}
|
|
|
|
// increase static requests counter
|
|
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].static_requests++;
|
|
|
|
// nginx
|
|
if (uwsgi.file_serve_mode == 1) {
|
|
if (uwsgi_response_add_header(wsgi_req, "X-Accel-Redirect", 16, real_filename, real_filename_len)) return -1;
|
|
// this is the final header (\r\n added)
|
|
int size = uwsgi_http_date(st->st_mtime, http_last_modified);
|
|
if (uwsgi_response_add_header(wsgi_req, "Last-Modified", 13, http_last_modified, size)) return -1;
|
|
}
|
|
// apache
|
|
else if (uwsgi.file_serve_mode == 2) {
|
|
if (uwsgi_response_add_header(wsgi_req, "X-Sendfile", 10, real_filename, real_filename_len)) return -1;
|
|
// this is the final header (\r\n added)
|
|
int size = uwsgi_http_date(st->st_mtime, http_last_modified);
|
|
if (uwsgi_response_add_header(wsgi_req, "Last-Modified", 13, http_last_modified, size)) return -1;
|
|
}
|
|
// raw
|
|
else {
|
|
// set Content-Length (to fsize NOT st->st_size)
|
|
if (uwsgi_response_add_content_length(wsgi_req, fsize)) return -1;
|
|
if (fsize > 0 && (wsgi_req->range_from || wsgi_req->range_to)) {
|
|
// here use the original size !!!
|
|
if (uwsgi_response_add_content_range(wsgi_req, wsgi_req->range_from, wsgi_req->range_to, st->st_size)) return -1;
|
|
}
|
|
int size = uwsgi_http_date(st->st_mtime, http_last_modified);
|
|
if (uwsgi_response_add_header(wsgi_req, "Last-Modified", 13, http_last_modified, size)) return -1;
|
|
|
|
// if it is a HEAD request just skip transfer
|
|
if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "HEAD", 4)) {
|
|
wsgi_req->status = 200;
|
|
return 0;
|
|
}
|
|
|
|
// Ok, the file must be transferred from uWSGI
|
|
// offloading will be automatically managed
|
|
int fd = open(real_filename, O_RDONLY);
|
|
if (fd < 0) return -1;
|
|
// fd will be closed in the following function
|
|
uwsgi_response_sendfile_do(wsgi_req, fd, wsgi_req->range_from, fsize);
|
|
}
|
|
|
|
wsgi_req->status = 200;
|
|
return 0;
|
|
}
|
|
|
|
|
|
int uwsgi_file_serve(struct wsgi_request *wsgi_req, char *document_root, uint16_t document_root_len, char *path_info, uint16_t path_info_len, int is_a_file) {
|
|
|
|
struct stat st;
|
|
char real_filename[PATH_MAX + 1];
|
|
size_t real_filename_len = 0;
|
|
char *filename = NULL;
|
|
size_t filename_len = 0;
|
|
|
|
struct uwsgi_string_list *index = NULL;
|
|
|
|
if (!is_a_file) {
|
|
filename = uwsgi_concat3n(document_root, document_root_len, "/", 1, path_info, path_info_len);
|
|
filename_len = document_root_len + 1 + path_info_len;
|
|
}
|
|
else {
|
|
filename = uwsgi_concat2n(document_root, document_root_len, "", 0);
|
|
filename_len = document_root_len;
|
|
}
|
|
|
|
#ifdef UWSGI_DEBUG
|
|
uwsgi_log("[uwsgi-fileserve] checking for %s\n", filename);
|
|
#endif
|
|
|
|
if (uwsgi.static_cache_paths) {
|
|
uwsgi_rlock(uwsgi.static_cache_paths->lock);
|
|
uint64_t item_len;
|
|
char *item = uwsgi_cache_get2(uwsgi.static_cache_paths, filename, filename_len, &item_len);
|
|
if (item && item_len > 0 && item_len <= PATH_MAX) {
|
|
memcpy(real_filename, item, item_len);
|
|
real_filename_len = item_len;
|
|
real_filename[real_filename_len] = 0;
|
|
uwsgi_rwunlock(uwsgi.static_cache_paths->lock);
|
|
goto found;
|
|
}
|
|
uwsgi_rwunlock(uwsgi.static_cache_paths->lock);
|
|
}
|
|
|
|
if (!realpath(filename, real_filename)) {
|
|
#ifdef UWSGI_DEBUG
|
|
uwsgi_log("[uwsgi-fileserve] unable to get realpath() of the static file\n");
|
|
#endif
|
|
free(filename);
|
|
return -1;
|
|
}
|
|
real_filename_len = strlen(real_filename);
|
|
|
|
if (uwsgi.static_cache_paths) {
|
|
uwsgi_wlock(uwsgi.static_cache_paths->lock);
|
|
uwsgi_cache_set2(uwsgi.static_cache_paths, filename, filename_len, real_filename, real_filename_len, uwsgi.use_static_cache_paths, UWSGI_CACHE_FLAG_UPDATE);
|
|
uwsgi_rwunlock(uwsgi.static_cache_paths->lock);
|
|
}
|
|
|
|
found:
|
|
free(filename);
|
|
|
|
if (uwsgi_starts_with(real_filename, real_filename_len, document_root, document_root_len)) {
|
|
struct uwsgi_string_list *safe = uwsgi.static_safe;
|
|
while(safe) {
|
|
if (!uwsgi_starts_with(real_filename, real_filename_len, safe->value, safe->len)) {
|
|
goto safe;
|
|
}
|
|
safe = safe->next;
|
|
}
|
|
uwsgi_log("[uwsgi-fileserve] security error: %s is not under %.*s or a safe path\n", real_filename, document_root_len, document_root);
|
|
return -1;
|
|
}
|
|
|
|
safe:
|
|
|
|
if (!uwsgi_static_stat(wsgi_req, real_filename, &real_filename_len, &st, &index)) {
|
|
|
|
if (index) {
|
|
// if we are here the PATH_INFO need to be changed
|
|
if (uwsgi_req_append_path_info_with_index(wsgi_req, index->value, index->len)) {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
// skip methods other than GET and HEAD
|
|
if (uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "GET", 3) && uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "HEAD", 4)) {
|
|
return -1;
|
|
}
|
|
|
|
// check for skippable ext
|
|
struct uwsgi_string_list *sse = uwsgi.static_skip_ext;
|
|
while (sse) {
|
|
if (real_filename_len >= sse->len) {
|
|
if (!uwsgi_strncmp(real_filename + (real_filename_len - sse->len), sse->len, sse->value, sse->len)) {
|
|
return -1;
|
|
}
|
|
}
|
|
sse = sse->next;
|
|
}
|
|
|
|
#ifdef UWSGI_ROUTING
|
|
// before sending the file, we need to check if some rule applies
|
|
if (!wsgi_req->is_routing && uwsgi_apply_routes_do(uwsgi.routes, wsgi_req, NULL, 0) == UWSGI_ROUTE_BREAK) {
|
|
return 0;
|
|
}
|
|
wsgi_req->routes_applied = 1;
|
|
#endif
|
|
|
|
return uwsgi_real_file_serve(wsgi_req, real_filename, real_filename_len, &st);
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|