Compare commits

...
20 Commits
Author SHA1 Message Date
roberto@precise64 ab7abc6a48 added upstart socket activation support and applied git001 patch for additional include paths 2012-04-20 09:59:59 +02:00
roberto@mrspurr 4986bdf202 added --static-map2 2012-04-20 07:04:02 +02:00
roberto@precise64 11aaddac98 fixed --static-map to a file 2012-04-19 19:44:35 +02:00
roberto@precise64 da9b2b4378 added static-expires/static-expires-mtime 2012-04-19 19:22:00 +02:00
roberto@freebsd9 9771a98bc6 fixed a typecast in rack plugin 2012-04-18 15:47:55 +02:00
roberto@precise64 033ee5f4e9 fixed a typo 2012-04-18 14:38:30 +02:00
roberto@precise64 1383163627 import dummy_threading whenever threads are in place 2012-04-18 10:14:41 +02:00
roberto@precise64 1d31b35c4f export static_offload_threads in statistics 2012-04-18 08:01:48 +02:00
roberto@precise64 7b2cc757b2 fixed SERVER_PORT in zeromq 2012-04-18 00:54:43 +02:00
roberto@precise64 68cddd1c2e fixed REMOTE_ADDR in mongrel2 when protocol is tnetstring 2012-04-17 23:41:04 +02:00
roberto@goyle b2a9fbbc5c set offload threading stacksize to 512k 2012-04-17 22:26:32 +02:00
roberto@goyle 0fcb13b9f1 implemented offload static file serving 2012-04-17 22:01:54 +02:00
roberto@goyle 938a22ce2e multiple mime file support 2012-04-17 20:04:48 +02:00
roberto@goyle 2df5dbfe52 added support for expires header 2012-04-17 19:24:13 +02:00
roberto@goyle feed0d0faa fixed get_mime_type 2012-04-15 22:33:05 +02:00
roberto@goyle c8373d20a9 added a check for strlen in the cgi plugin 2012-04-15 17:42:28 +02:00
roberto@mrspurr 170267a04a fixed mod_Ruwsgi 2012-04-15 07:11:45 +02:00
roberto@precise64 bd5969db67 fix initial messages 2012-04-15 07:06:33 +02:00
roberto@precise64 02256c013c added --carbon-no-workers 2012-04-14 13:54:41 +02:00
roberto@precise64 89be9a0d4a Added tag 1.2-rc1 for changeset 24c8fe5a26e5 2012-04-14 12:55:03 +02:00
14 changed files with 476 additions and 115 deletions
+1
View File
@@ -49,3 +49,4 @@ af490b8c30f83bc5fb6f3837a760981474647755 1.0-rc10
ede5c664978bb40e476e8d4a5789562928f28507 1.1-rc3
ef99144291f06822d026e981d5d856cbec14d867 1.1-rc4
e1568fd16b7b586cc72deb4dfccbbe64ae0b84df 1.1
24c8fe5a26e557db41cf1cee45b8964d5885e484 1.2-rc1
+1 -1
View File
@@ -186,7 +186,7 @@ static void log_debug(const char *file, int line, int ami, request_rec *r, const
ap_log_rerror(file, line, APLOG_MODULE_INDEX, APLOG_DEBUG, APR_SUCCESS, r, "uwsgi: %s", msg);
#else
static void log_debug(const char *file, int line, request_rec *r, const
char *msg)
char *msg) {
ap_log_rerror(file, line, APLOG_DEBUG, APR_SUCCESS, r, "uwsgi: %s", msg);
#endif
}
+2 -2
View File
@@ -481,7 +481,7 @@ void uwsgi_setup_locking() {
// use the fastest avaikable locking
if (uwsgi.lock_engine) {
if (!strcmp(uwsgi.lock_engine, "ipcsem")) {
uwsgi_log("lock engine: ipcsem\n");
uwsgi_log_initial("lock engine: ipcsem\n");
atexit(uwsgi_ipcsem_clear);
uwsgi.lock_ops.lock_init = uwsgi_lock_ipcsem_init;
uwsgi.lock_ops.lock_check = uwsgi_lock_ipcsem_check;
@@ -498,7 +498,7 @@ void uwsgi_setup_locking() {
}
}
uwsgi_log("lock engine: %s\n", UWSGI_LOCK_ENGINE_NAME);
uwsgi_log_initial("lock engine: %s\n", UWSGI_LOCK_ENGINE_NAME);
#ifdef UWSGI_IPCSEM_ATEXIT
atexit(uwsgi_ipcsem_clear);
#endif
+4
View File
@@ -136,6 +136,7 @@ void log_request(struct wsgi_request *wsgi_req) {
char *msg1 = " via sendfile() ";
#endif
char *msg3 = " via route() ";
char *msg4 = " via offload() ";
struct uwsgi_app *wi;
@@ -159,6 +160,9 @@ void log_request(struct wsgi_request *wsgi_req) {
if (wsgi_req->status == -17) {
via = msg3;
}
else if (wsgi_req->status == -30) {
via = msg4;
}
#ifdef __sun__
ctime_r((const time_t *) &wsgi_req->start_of_request.tv_sec, time_request, 26);
+1
View File
@@ -772,6 +772,7 @@ void uwsgi_send_stats(int fd) {
stats_send_llu("\"delta_requests\": %llu, ", uwsgi.workers[i + 1].delta_requests);
stats_send_llu("\"exceptions\": %llu, ", uwsgi.workers[i + 1].exceptions);
stats_send_llu("\"signals\": %llu, ", uwsgi.workers[i + 1].signals);
stats_send_llu("\"static_offload_threads\": %llu, ", uwsgi.workers[i + 1].static_offload_threads);
if (uwsgi.workers[i + 1].cheaped) {
fprintf(output, "\"status\": \"cheap\", ");
+6
View File
@@ -7,6 +7,7 @@ struct uwsgi_carbon {
int freq;
int timeout;
char *id;
int no_workers;
} u_carbon;
struct uwsgi_option carbon_options[] = {
@@ -14,6 +15,7 @@ struct uwsgi_option carbon_options[] = {
{"carbon-timeout", required_argument, 0, "set carbon connection timeout", uwsgi_opt_set_int, &u_carbon.timeout, 0},
{"carbon-freq", required_argument, 0, "set carbon push frequency", uwsgi_opt_set_int, &u_carbon.freq, 0},
{"carbon-id", required_argument, 0, "set carbon id", uwsgi_opt_set_str, &u_carbon.id, 0},
{"carbon-no-workers", no_argument, 0, "disable generation of single worker metrics", uwsgi_opt_true, &u_carbon.no_workers, 0},
{0, 0, 0, 0, 0, 0, 0},
};
@@ -73,6 +75,8 @@ void carbon_master_cycle() {
rlen = snprintf(ptr, 4096, "uwsgi.%s.%s.requests %llu %llu\n", uwsgi.hostname, u_carbon.id, (unsigned long long ) uwsgi.workers[0].requests, (unsigned long long ) uwsgi.current_time);
if (rlen < 1) goto clear;
if (write(fd, ptr, rlen) <= 0) { uwsgi_error("write()"); goto clear;}
if (u_carbon.no_workers) goto gmetrics;
for(i=1;i<=uwsgi.numproc;i++) {
rlen = snprintf(ptr, 4096, "uwsgi.%s.%s.worker%d.requests %llu %llu\n", uwsgi.hostname, u_carbon.id, i, (unsigned long long ) uwsgi.workers[i].requests, (unsigned long long ) uwsgi.current_time);
@@ -109,6 +113,8 @@ void carbon_master_cycle() {
if (write(fd, ptr, rlen) <= 0) { uwsgi_error("write()"); goto clear;}
}
gmetrics:
rlen = snprintf(ptr, 4096, "uwsgi.%s.%s.rss_size %llu %llu\n", uwsgi.hostname, u_carbon.id, (unsigned long long ) total_rss, (unsigned long long ) uwsgi.current_time);
if (rlen < 1) goto clear;
if (write(fd, ptr, rlen) <= 0) { uwsgi_error("write()"); goto clear;}
+2 -1
View File
@@ -512,7 +512,8 @@ int uwsgi_cgi_request(struct wsgi_request *wsgi_req) {
}
else {
docroot = uwsgi_cgi_get_docroot(wsgi_req->path_info, wsgi_req->path_info_len, &need_free, &is_a_file, &discard_base, &script_name);
docroot_len = strlen(docroot);
if (docroot)
docroot_len = strlen(docroot);
}
if (docroot == NULL || docroot_len == 0) {
+1 -1
View File
@@ -275,7 +275,7 @@ void uwsgi_python_atexit() {
PyObject *module = PyImport_ImportModule("atexit");
Py_XDECREF(module);
if (uwsgi.threads > 1) {
if (uwsgi.has_threads) {
if (!PyImport_AddModule("dummy_threading"))
PyErr_Clear();
}
+1 -1
View File
@@ -709,7 +709,7 @@ int uwsgi_rack_request(struct wsgi_request *wsgi_req) {
VALUE dws_wr = Data_Wrap_Struct(ur.rb_uwsgi_io_class, 0, 0, wsgi_req);
if (wsgi_req->async_post) {
rb_hash_aset(env, rb_str_new2("rack.input"), rb_funcall( rb_const_get(rb_cObject, rb_intern("IO")), rb_intern("new"), 2, INT2NUM(fileno(wsgi_req->async_post)), rb_str_new("r",1) ));
rb_hash_aset(env, rb_str_new2("rack.input"), rb_funcall( rb_const_get(rb_cObject, rb_intern("IO")), rb_intern("new"), 2, INT2NUM(fileno((FILE*)wsgi_req->async_post)), rb_str_new("r",1) ));
}
else {
rb_hash_aset(env, rb_str_new2("rack.input"), rb_funcall(ur.rb_uwsgi_io_class, rb_intern("new"), 1, dws_wr ));
+3 -3
View File
@@ -195,9 +195,9 @@ static int uwsgi_mongrel2_tnetstring_parse(struct wsgi_request *wsgi_req, char *
else {
// add header
if (!uwsgi_strncmp("host", 4, key, keylen)) {
char *colon = strchr(val, ':');
char *colon = memchr(val, ':', vallen);
if (colon) {
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PORT", 11, colon + 1, (colon + 1) - val);
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PORT", 11, colon + 1, vallen - ((colon + 1)-val));
}
else {
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PORT", 11, "80", 2);
@@ -217,7 +217,7 @@ static int uwsgi_mongrel2_tnetstring_parse(struct wsgi_request *wsgi_req, char *
free(post_filename);
}
else if (!uwsgi_strncmp("x-forwarded-for", 15, key, keylen)) {
char *colon = strchr(val, ',');
char *colon = memchr(val, ',', vallen);
if (colon) {
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "REMOTE_ADDR", 11, colon + 1, (colon + 1) - val);
}
+300 -74
View File
@@ -16,7 +16,8 @@ static size_t get_content_length(char *buf, uint16_t size) {
return val;
}
void set_http_date(time_t t, char *dst) {
int set_http_date(time_t t, char *header, int header_len, char *dst, int last) {
static char *week[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
static char *months[] = {
@@ -26,12 +27,96 @@ void set_http_date(time_t t, char *dst) {
};
struct tm *hdtm = gmtime(&t);
snprintf(dst, 49, "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n\r\n",
if (last) {
return snprintf(dst, 36+header_len, "%.*s: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n\r\n",
header_len, header,
week[hdtm->tm_wday], hdtm->tm_mday,
months[hdtm->tm_mon], hdtm->tm_year+1900,
hdtm->tm_hour, hdtm->tm_min, hdtm->tm_sec);
}
return snprintf(dst, 34+header_len, "%.*s: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
header_len, header,
week[hdtm->tm_wday], hdtm->tm_mday,
months[hdtm->tm_mon], hdtm->tm_year+1900,
hdtm->tm_hour, hdtm->tm_min, hdtm->tm_sec);
}
void 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.tv_sec;
// Expires+34+1
char expires[42];
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 = set_http_date(now+delta, "Expires", 7, expires, 0);
if (size > 0) {
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, expires, size);
wsgi_req->header_cnt++;
}
return;
}
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 = set_http_date(st->st_mtime+delta, "Expires", 7, expires, 0);
if (size > 0) {
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, expires, size);
wsgi_req->header_cnt++;
}
return;
}
udd = udd->next;
}
}
#ifdef UWSGI_PCRE
void 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.tv_sec;
// Expires+34+1
char expires[42];
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 = set_http_date(now+delta, "Expires", 7, expires, 0);
if (size > 0) {
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, expires, size);
wsgi_req->header_cnt++;
}
return;
}
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 = set_http_date(st->st_mtime+delta, "Expires", 7, expires, 0);
if (size > 0) {
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, expires, size);
wsgi_req->header_cnt++;
}
return;
}
udd = udd->next;
}
}
#endif
// only RFC 1123 is supported
time_t parse_http_date(char *date, uint16_t len) {
@@ -916,7 +1001,7 @@ next:
udd->vallen = strlen(udd->value);
}
if (!uwsgi_file_serve(wsgi_req, udd->value, udd->vallen, wsgi_req->path_info, wsgi_req->path_info_len)) {
if (!uwsgi_file_serve(wsgi_req, udd->value, udd->vallen, wsgi_req->path_info, wsgi_req->path_info_len, 0)) {
return -1;
}
nextcs:
@@ -944,11 +1029,11 @@ nextcs:
if (!real_docroot) goto nextsm;
udd->value = real_docroot;
udd->vallen = strlen(udd->value);
udd->status = 1;
udd->status = 1 + uwsgi_is_file(real_docroot);
}
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)) {
if (!uwsgi_file_serve(wsgi_req, udd->value, udd->vallen, wsgi_req->path_info+udd->keylen, wsgi_req->path_info_len-udd->keylen, udd->status-1)) {
return -1;
}
}
@@ -956,13 +1041,47 @@ nextsm:
udd = udd->next;
}
// check for static_maps in append mode
udd = uwsgi.static_maps2;
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);
#endif
if (udd->status == 0) {
#ifdef UWSGI_THREADING
if (uwsgi.threads > 1) pthread_mutex_lock(&uwsgi.lock_static);
#endif
char *real_docroot = uwsgi_malloc(PATH_MAX+1);
if (!realpath(udd->value, real_docroot)) {
free(real_docroot);
udd->value = NULL;
}
#ifdef UWSGI_THREADING
if (uwsgi.threads > 1) pthread_mutex_unlock(&uwsgi.lock_static);
#endif
if (!real_docroot) goto nextsm2;
udd->value = real_docroot;
udd->vallen = strlen(udd->value);
udd->status = 1 + uwsgi_is_file(real_docroot);
}
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, wsgi_req->path_info_len, udd->status-1)) {
return -1;
}
}
nextsm2:
udd = udd->next;
}
// finally check for docroot
if (uwsgi.check_static_docroot && wsgi_req->document_root_len > 0) {
char *real_docroot = uwsgi_expand_path(wsgi_req->document_root, wsgi_req->document_root_len, NULL);
if (!real_docroot) {
return -1;
}
if (!uwsgi_file_serve(wsgi_req, real_docroot, strlen(real_docroot), wsgi_req->path_info, wsgi_req->path_info_len)) {
if (!uwsgi_file_serve(wsgi_req, real_docroot, strlen(real_docroot), wsgi_req->path_info, wsgi_req->path_info_len, 0)) {
free(real_docroot);
return -1;
}
@@ -1520,31 +1639,41 @@ char *uwsgi_get_mime_type(char *name, int namelen, int *size) {
count++;
}
if (ext) {
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;
}
udd_prev->prev = udd;
udd_prev->next = udd->next;
if (!ext) return NULL;
udd->prev = udd_parent;
udd->next = udd_prev;
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;
return udd->value;
}
udd = udd->next;
*size = udd->vallen;
return udd->value;
}
udd = udd->next;
}
return NULL;
}
@@ -1599,54 +1728,15 @@ int uwsgi_static_stat(char *filename, struct stat *st) {
return -1;
}
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 uwsgi_real_file_serve(struct wsgi_request *wsgi_req, char *real_filename, size_t real_filename_len, struct stat *st) {
struct stat st;
struct iovec headers_vec[8];
char real_filename[PATH_MAX+1];
int mime_type_size = 0;
char http_last_modified[49];
char content_length[sizeof(UMAX64_STR)+1];
size_t real_filename_len = 0;
char *filename = uwsgi_concat3n(document_root, document_root_len, "/", 1, path_info, path_info_len);
#ifdef UWSGI_DEBUG
uwsgi_log("[uwsgi-fileserve] checking for %s\n", filename);
#endif
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;
}
free(filename);
if (uwsgi_starts_with(real_filename, strlen(real_filename), document_root, document_root_len)) {
uwsgi_log("[uwsgi-fileserve] security error: %s is not under %.*s\n", real_filename, document_root_len, document_root);
return -1;
}
if (!uwsgi_static_stat(real_filename, &st)) {
real_filename_len = strlen(real_filename);
// 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)) {
#ifdef UWSGI_ROUTING
if (uwsgi_apply_routes_fast(wsgi_req, real_filename, real_filename_len) == UWSGI_ROUTE_BREAK) return 0;
#endif
return -1;
}
}
sse = sse->next;
}
int mime_type_size = 0;
char http_last_modified[49];
#ifdef UWSGI_THREADING
if (uwsgi.threads > 1) pthread_mutex_lock(&uwsgi.lock_static);
#endif
@@ -1654,9 +1744,10 @@ int uwsgi_file_serve(struct wsgi_request *wsgi_req, char *document_root, uint16_
#ifdef UWSGI_THREADING
if (uwsgi.threads > 1) pthread_mutex_unlock(&uwsgi.lock_static);
#endif
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 (st->st_mtime <= ims) {
wsgi_req->status = 304;
headers_vec[0].iov_base = wsgi_req->protocol;
headers_vec[0].iov_len = wsgi_req->protocol_len;
@@ -1703,6 +1794,10 @@ int uwsgi_file_serve(struct wsgi_request *wsgi_req, char *document_root, uint16_
ah = ah->next;
}
#ifdef UWSGI_PCRE
uwsgi_add_expires(wsgi_req, real_filename, real_filename_len, st);
#endif
// Content-Type (if available)
if (mime_type_size > 0 && mime_type) {
headers_vec[0].iov_base = "Content-Type: ";
@@ -1713,6 +1808,9 @@ int uwsgi_file_serve(struct wsgi_request *wsgi_req, char *document_root, uint16_
headers_vec[2].iov_len = 2;
wsgi_req->headers_size += wsgi_req->socket->proto_writev_header(wsgi_req, headers_vec, 3);
wsgi_req->header_cnt++;
// check for content-type related headers
uwsgi_add_expires_type(wsgi_req, mime_type, mime_type_size, st);
}
// nginx
@@ -1722,7 +1820,7 @@ int uwsgi_file_serve(struct wsgi_request *wsgi_req, char *document_root, uint16_
headers_vec[2].iov_base = "\r\n"; headers_vec[2].iov_len = 2;
wsgi_req->headers_size += wsgi_req->socket->proto_writev_header(wsgi_req, headers_vec, 3);
// this is the final header (\r\n added)
set_http_date(st.st_mtime, http_last_modified);
set_http_date(st->st_mtime, "Last-Modified", 13, http_last_modified, 1);
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, http_last_modified, 48);
wsgi_req->header_cnt += 2;
}
@@ -1733,7 +1831,7 @@ int uwsgi_file_serve(struct wsgi_request *wsgi_req, char *document_root, uint16_
headers_vec[2].iov_base = "\r\n"; headers_vec[2].iov_len = 2;
wsgi_req->headers_size += wsgi_req->socket->proto_writev_header(wsgi_req, headers_vec, 3);
// this is the final header (\r\n added)
set_http_date(st.st_mtime, http_last_modified);
set_http_date(st->st_mtime, "Last-Modified", 13, http_last_modified, 1);
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, http_last_modified, 48);
wsgi_req->header_cnt += 2;
}
@@ -1742,12 +1840,12 @@ int uwsgi_file_serve(struct wsgi_request *wsgi_req, char *document_root, uint16_
// set Content-Length
headers_vec[0].iov_base = "Content-Length: ";
headers_vec[0].iov_len = 16;
headers_vec[1].iov_len = uwsgi_long2str2n(st.st_size, content_length, sizeof(UMAX64_STR)+1);
headers_vec[1].iov_len = uwsgi_long2str2n(st->st_size, content_length, sizeof(UMAX64_STR)+1);
headers_vec[1].iov_base = content_length;
headers_vec[2].iov_base = "\r\n";
headers_vec[2].iov_len = 2;
// this is the final header (\r\n added)
set_http_date(st.st_mtime, http_last_modified);
set_http_date(st->st_mtime, "Last-Modified", 13, http_last_modified, 1);
headers_vec[3].iov_base = http_last_modified;
headers_vec[3].iov_len = 48;
wsgi_req->headers_size += wsgi_req->socket->proto_writev_header(wsgi_req, headers_vec, 4);
@@ -1761,6 +1859,134 @@ int uwsgi_file_serve(struct wsgi_request *wsgi_req, char *document_root, uint16_
wsgi_req->status = 200;
return 0;
}
void *uwsgi_static_offload_thread(void *req) {
struct uwsgi_offload_request *uof_req = (struct uwsgi_offload_request *) req;
uwsgi_real_file_serve(&uof_req->wsgi_req, uof_req->real_filename, uof_req->real_filename_len, &uof_req->st);
// close the connection with the webserver
if (!uof_req->wsgi_req.fd_closed || !uof_req->wsgi_req.body_as_file) {
// NOTE, if we close the socket before receiving eventually sent data, socket layer will send a RST
uof_req->wsgi_req.socket->proto_close(&uof_req->wsgi_req);
}
// free buffer
free(uof_req->buffer);
// free hvec
free(uof_req->hvec);
free(uof_req);
pthread_mutex_lock(&uwsgi.static_offload_thread_lock);
uwsgi.workers[uwsgi.mywid].static_offload_threads--;
pthread_mutex_unlock(&uwsgi.static_offload_thread_lock);
return NULL;
}
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;
if (!is_a_file) {
filename = uwsgi_concat3n(document_root, document_root_len, "/", 1, path_info, path_info_len);
}
else {
filename = uwsgi_concat2n(document_root, document_root_len, "", 0);
}
#ifdef UWSGI_DEBUG
uwsgi_log("[uwsgi-fileserve] checking for %s\n", filename);
#endif
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;
}
free(filename);
if (uwsgi_starts_with(real_filename, strlen(real_filename), document_root, document_root_len)) {
uwsgi_log("[uwsgi-fileserve] security error: %s is not under %.*s\n", real_filename, document_root_len, document_root);
return -1;
}
if (!uwsgi_static_stat(real_filename, &st)) {
real_filename_len = strlen(real_filename);
// 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)) {
#ifdef UWSGI_ROUTING
if (uwsgi_apply_routes_fast(wsgi_req, real_filename, real_filename_len) == UWSGI_ROUTE_BREAK) return 0;
#endif
return -1;
}
}
sse = sse->next;
}
// Ok, the file must be served as static from uWSGI
if (uwsgi.static_offload_to_thread) {
pthread_mutex_lock(&uwsgi.static_offload_thread_lock);
uint64_t offload_thread_count = uwsgi.workers[uwsgi.mywid].static_offload_threads;
pthread_mutex_unlock(&uwsgi.static_offload_thread_lock);
if (offload_thread_count > (uint64_t) uwsgi.static_offload_to_thread) {
uwsgi_log_verbose("OVERLOAD !!! unable to offload static file serving\n");
return uwsgi_real_file_serve(wsgi_req, real_filename, real_filename_len, &st);
}
struct uwsgi_offload_request *uor = uwsgi_malloc(sizeof(struct uwsgi_offload_request));
// buffer
uor->buffer = uwsgi_malloc(uwsgi.buffer_size); memcpy(uor->buffer, wsgi_req->buffer, uwsgi.buffer_size);
// iovec
uor->hvec = uwsgi_malloc(sizeof(struct iovec) * uwsgi.vec_size); memcpy(uor->hvec, wsgi_req->hvec, sizeof(struct iovec) * uwsgi.vec_size);
// wsgi_req
memcpy(&uor->wsgi_req, wsgi_req, sizeof(struct wsgi_request));
uor->wsgi_req.buffer = uor->buffer;
uor->wsgi_req.hvec = uor->hvec;
// stat
memcpy(&uor->st, &st, sizeof(struct stat));
// filename
memcpy(uor->real_filename, real_filename, real_filename_len);
uor->real_filename_len = real_filename_len;
// avoid closing the connection
wsgi_req->fd_closed = 1;
pthread_mutex_lock(&uwsgi.static_offload_thread_lock);
uwsgi.workers[uwsgi.mywid].static_offload_threads++;
pthread_mutex_unlock(&uwsgi.static_offload_thread_lock);
if (pthread_create(&uor->tid, &uwsgi.static_offload_thread_attr, uwsgi_static_offload_thread, (void *) uor)) {
uwsgi_error("pthread_create()");
// bad condition, better to exit...
exit(1);
}
wsgi_req->status = -30;
return 0;
}
else {
return uwsgi_real_file_serve(wsgi_req, real_filename, real_filename_len, &st);
}
}
return -1;
+107 -28
View File
@@ -59,6 +59,9 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"xmlconfig", required_argument, 'x', "load config from xml file", uwsgi_opt_load_xml, NULL, UWSGI_OPT_IMMEDIATE},
{"xml", required_argument, 'x', "load config from xml file", uwsgi_opt_load_xml, NULL, UWSGI_OPT_IMMEDIATE},
#endif
{"skip-zero", no_argument, 0, "skip check of file descriptor 0", uwsgi_opt_true, &uwsgi.skip_zero,0},
{"set", required_argument, 'S', "set a custom placeholder", uwsgi_opt_set_placeholder, NULL, UWSGI_OPT_IMMEDIATE},
{"for", required_argument, 0, "(opt logic) for cycle", uwsgi_opt_logic, (void *) uwsgi_logic_opt_for, UWSGI_OPT_IMMEDIATE},
@@ -363,17 +366,29 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"route-qs", required_argument, 0, "add a route based on QUERY_STRING", uwsgi_opt_add_route, "query_string", 0},
#endif
{"add-header", required_argument, 0, "automatically add HTTP headers to response", uwsgi_opt_add_string_list, &uwsgi.additional_headers, 0},
{"check-static", required_argument, 0, "check for static files in the specified directory", uwsgi_opt_check_static, NULL, 0},
{"check-static-docroot", no_argument, 0, "check for static files in the requested DOCUMENT_ROOT", uwsgi_opt_true, &uwsgi.check_static_docroot, UWSGI_OPT_MIME},
{"static-check", required_argument, 0, "check for static files in the specified directory", uwsgi_opt_check_static, NULL, 0},
{"static-map", required_argument, 0, "map mountpoint to static directory", uwsgi_opt_static_map, NULL, 0},
{"static-skip-ext", required_argument, 0, "skip specified extension from staticfile checks", uwsgi_opt_add_string_list, &uwsgi.static_skip_ext, 0},
{"static-index", required_argument, 0, "search for specified file if a directory is requested", uwsgi_opt_add_string_list, &uwsgi.static_index, 0},
{"mimefile", required_argument, 0, "set mime types file path (default /etc/mime.types)", uwsgi_opt_set_str, &uwsgi.mime_file, 0},
{"mime-file", required_argument, 0, "set mime types file path (default /etc/mime.types)", uwsgi_opt_set_str, &uwsgi.mime_file, 0},
{"file-serve-mode", required_argument, 0, "set static file serving mode", uwsgi_opt_fileserve_mode, NULL,0},
{"fileserve-mode", required_argument, 0, "set static file serving mode", uwsgi_opt_fileserve_mode, NULL,0},
{"check-static", required_argument, 0, "check for static files in the specified directory", uwsgi_opt_check_static, NULL, UWSGI_OPT_MIME},
{"check-static-docroot", no_argument, 0, "check for static files in the requested DOCUMENT_ROOT", uwsgi_opt_true, &uwsgi.check_static_docroot, UWSGI_OPT_MIME},
{"static-check", required_argument, 0, "check for static files in the specified directory", uwsgi_opt_check_static, NULL, UWSGI_OPT_MIME},
{"static-map", required_argument, 0, "map mountpoint to static directory (or file)", uwsgi_opt_static_map, &uwsgi.static_maps, UWSGI_OPT_MIME},
{"static-map2", required_argument, 0, "like static-map but completely appending the requested resource to the docroot", uwsgi_opt_static_map, &uwsgi.static_maps2, UWSGI_OPT_MIME},
{"static-skip-ext", required_argument, 0, "skip specified extension from staticfile checks", uwsgi_opt_add_string_list, &uwsgi.static_skip_ext, UWSGI_OPT_MIME},
{"static-index", required_argument, 0, "search for specified file if a directory is requested", uwsgi_opt_add_string_list, &uwsgi.static_index, UWSGI_OPT_MIME},
{"mimefile", required_argument, 0, "set mime types file path (default /etc/mime.types)", uwsgi_opt_add_string_list, &uwsgi.mime_file, UWSGI_OPT_MIME},
{"mime-file", required_argument, 0, "set mime types file path (default /etc/mime.types)", uwsgi_opt_add_string_list, &uwsgi.mime_file, UWSGI_OPT_MIME},
{"static-expires-type", required_argument, 0, "set the Expires header based on content type", uwsgi_opt_add_dyn_dict, &uwsgi.static_expires_type, UWSGI_OPT_MIME},
{"static-expires-type-mtime", required_argument, 0, "set the Expires header based on content type and file mtime", uwsgi_opt_add_dyn_dict, &uwsgi.static_expires_type_mtime, UWSGI_OPT_MIME},
#ifdef UWSGI_PCRE
{"static-expires", required_argument, 0, "set the Expires header based on filename regexp", uwsgi_opt_add_regexp_dyn_dict, &uwsgi.static_expires, UWSGI_OPT_MIME},
{"static-expires-mtime", required_argument, 0, "set the Expires header based on filename regexp and file mtime", uwsgi_opt_add_regexp_dyn_dict, &uwsgi.static_expires_mtime, UWSGI_OPT_MIME},
#endif
{"static-offload-to-thread", required_argument, 0, "offload static file serving to a thread (upto the specified number of threads)", uwsgi_opt_set_int, &uwsgi.static_offload_to_thread, UWSGI_OPT_MIME},
{"file-serve-mode", required_argument, 0, "set static file serving mode", uwsgi_opt_fileserve_mode, NULL, UWSGI_OPT_MIME},
{"fileserve-mode", required_argument, 0, "set static file serving mode", uwsgi_opt_fileserve_mode, NULL, UWSGI_OPT_MIME},
{"check-cache", no_argument, 0, "check for response data in the cache", uwsgi_opt_true, &uwsgi.check_cache, 0},
{"close-on-exec", no_argument, 0, "set close-on-exec on sockets (could be required for spawning processes in requests)", uwsgi_opt_true, &uwsgi.close_on_exec, 0},
@@ -1341,7 +1356,6 @@ int main(int argc, char *argv[], char *envp[]) {
uwsgi.shared->worker_log_pipe[0] = -1;
uwsgi.shared->worker_log_pipe[1] = -1;
uwsgi.mime_file = "/etc/mime.types";
#ifdef UWSGI_BLACKLIST
if (!uwsgi_file_to_string_list(UWSGI_BLACKLIST, &uwsgi.blacklist)) {
@@ -1849,14 +1863,24 @@ int uwsgi_start(void *v_argv) {
sanitize_args();
// initialize workers
if (uwsgi.build_mime_dict) {
if (!access(uwsgi.mime_file, R_OK)) {
uwsgi_build_mime_dict(uwsgi.mime_file);
if (!uwsgi.mime_file) uwsgi_string_new_list(&uwsgi.mime_file, "/etc/mime.types");
struct uwsgi_string_list *umd = uwsgi.mime_file;
while(umd) {
if (!access(umd->value, R_OK)) {
uwsgi_build_mime_dict(umd->value);
}
else {
uwsgi_log("!!! no mime.types file found !!!\n");
uwsgi_log("!!! no %s file found !!!\n", umd->value);
}
umd = umd->next;
}
if (uwsgi.static_offload_to_thread) {
pthread_attr_init(&uwsgi.static_offload_thread_attr);
pthread_attr_setdetachstate(&uwsgi.static_offload_thread_attr, PTHREAD_CREATE_DETACHED);
// 512K should be enough...
pthread_attr_setstacksize(&uwsgi.static_offload_thread_attr, 512*1024);
pthread_mutex_init(&uwsgi.static_offload_thread_lock, NULL);
}
// end of generic initialization
@@ -1930,7 +1954,7 @@ int uwsgi_start(void *v_argv) {
if (!getrlimit(RLIMIT_NOFILE, &uwsgi.rl)) {
uwsgi.max_fd = uwsgi.rl.rlim_cur;
uwsgi_log("detected max file descriptor number: %d\n", (int) uwsgi.max_fd);
uwsgi_log_initial("detected max file descriptor number: %d\n", (int) uwsgi.max_fd);
}
uwsgi.wsgi_requests = uwsgi_malloc(sizeof(struct wsgi_request *) * uwsgi.cores);
@@ -2050,10 +2074,9 @@ int uwsgi_start(void *v_argv) {
}
}
if (!uwsgi.no_server) {
// systemd socket activation
// systemd/upstart/zerg socket activation
if (!uwsgi.is_a_reload) {
char *listen_pid = getenv("LISTEN_PID");
if (listen_pid) {
@@ -2062,20 +2085,33 @@ int uwsgi_start(void *v_argv) {
if (listen_fds) {
int systemd_fds = atoi(listen_fds);
if (systemd_fds > 0) {
uwsgi_log("- SystemD socket activation detected -\n");
for(i=3;i<3+systemd_fds;i++) {
uwsgi_sock = uwsgi_new_socket(NULL);
uwsgi_add_socket_from_fd(uwsgi_sock, i);
}
uwsgi.skip_zero = 1;
}
unsetenv("LISTEN_PID");
unsetenv("LISTEN_FDS");
goto skipzero;
}
}
}
}
if (!uwsgi.is_a_reload) {
char *upstart_events = getenv("UPSTART_EVENTS");
if (upstart_events && !strcmp(upstart_events, "socket")) {
char *upstart_fds = getenv("UPSTART_FDS");
if (upstart_fds) {
uwsgi_log("- Upstart socket bridge detected (job: %s) -\n", getenv("UPSTART_JOB"));
uwsgi_sock = uwsgi_new_socket(NULL);
uwsgi_add_socket_from_fd(uwsgi_sock, atoi(upstart_fds));
uwsgi.skip_zero = 1;
}
unsetenv("UPSTART_EVENTS");
unsetenv("UPSTART_FDS");
}
struct uwsgi_string_list *zn = uwsgi.zerg_node;
while (zn) {
if (uwsgi_zerg_attach(zn->value)) {
@@ -2108,6 +2144,7 @@ int uwsgi_start(void *v_argv) {
}
}
//check for inherited sockets
if (uwsgi.is_a_reload) {
@@ -2197,6 +2234,8 @@ int uwsgi_start(void *v_argv) {
}
}
}
//now bind all the unbound sockets
uwsgi_sock = uwsgi.sockets;
while (uwsgi_sock) {
@@ -2256,7 +2295,7 @@ int uwsgi_start(void *v_argv) {
if (!zero_used) {
socket_type_len = sizeof(struct sockaddr_un);
gsa.sa = (struct sockaddr *) &usa;
if (!getsockname(0, gsa.sa, &socket_type_len)) {
if (!uwsgi.skip_zero && !getsockname(0, gsa.sa, &socket_type_len)) {
if (gsa.sa->sa_family == AF_UNIX) {
uwsgi_sock = uwsgi_new_socket(usa.sa_un.sun_path);
uwsgi_sock->family = AF_UNIX;
@@ -2294,8 +2333,6 @@ int uwsgi_start(void *v_argv) {
}
skipzero:
// check for auto_port socket
uwsgi_sock = uwsgi.sockets;
while (uwsgi_sock) {
@@ -3689,6 +3726,44 @@ void uwsgi_opt_check_static(char *opt, char *value, void *foobar) {
}
void uwsgi_opt_add_dyn_dict(char *opt, char *value, void *dict) {
char *equal = strchr(value, '=');
if (!equal) {
uwsgi_log("invalid dictionary syntax for %s\n", opt);
exit(1);
}
struct uwsgi_dyn_dict **udd = (struct uwsgi_dyn_dict **) dict;
uwsgi_dyn_dict_new(udd, value, equal-value, equal+1, strlen(equal+1));
}
#ifdef UWSGI_PCRE
void uwsgi_opt_add_regexp_dyn_dict(char *opt, char *value, void *dict) {
char *space = strchr(value, ' ');
if (!space) {
uwsgi_log("invalid dictionary syntax for %s\n", opt);
exit(1);
}
struct uwsgi_dyn_dict **udd = (struct uwsgi_dyn_dict **) dict;
struct uwsgi_dyn_dict *new_udd = uwsgi_dyn_dict_new(udd, value, space-value, space+1, strlen(space+1));
char *regexp = uwsgi_concat2n(value, space-value, "", 0);
if (uwsgi_regexp_build(regexp, &new_udd->pattern, &new_udd->pattern_extra)) {
exit(1);
}
free(regexp);
}
#endif
void uwsgi_opt_fileserve_mode(char *opt, char *value, void *foobar) {
if (!strcasecmp("x-sendfile", value)) {
@@ -3709,16 +3784,20 @@ void uwsgi_opt_fileserve_mode(char *opt, char *value, void *foobar) {
}
void uwsgi_opt_static_map(char *opt, char *value, void *foobar) {
void uwsgi_opt_static_map(char *opt, char *value, void *static_maps) {
struct uwsgi_dyn_dict **maps = (struct uwsgi_dyn_dict **) static_maps;
char *mountpoint = uwsgi_str(value);
char *docroot = strchr(mountpoint, '=');
char *docroot = strchr(mountpoint, '=');
if (!docroot) {
uwsgi_log("invalid document root in static map, syntax mountpoint=docroot\n");
exit(1);
}
docroot[0] = 0;
docroot++;
uwsgi_dyn_dict_new(&uwsgi.static_maps, mountpoint, strlen(mountpoint), docroot, strlen(docroot));
uwsgi_dyn_dict_new(maps, mountpoint, strlen(mountpoint), docroot, strlen(docroot));
uwsgi_log("[uwsgi-static] added mapping for %s => %s\n", mountpoint, docroot);
uwsgi.build_mime_dict = 1;
}
+41 -3
View File
@@ -334,6 +334,9 @@ struct uwsgi_lock_ops {
#define uwsgi_wlock(x) uwsgi.lock_ops.wlock(x)
#define uwsgi_rwunlock(x) uwsgi.lock_ops.rwunlock(x)
#ifdef UWSGI_PCRE
#include <pcre.h>
#endif
struct uwsgi_dyn_dict {
@@ -345,6 +348,11 @@ struct uwsgi_dyn_dict {
uint64_t hits;
int status;
#ifdef UWSGI_PCRE
pcre *pattern;
pcre_extra *pattern_extra;
#endif
struct uwsgi_dyn_dict *prev;
struct uwsgi_dyn_dict *next;
};
@@ -647,7 +655,6 @@ struct uwsgi_plugin {
};
#ifdef UWSGI_PCRE
#include <pcre.h>
int uwsgi_regexp_build(char *, pcre **, pcre_extra **);
int uwsgi_regexp_match(pcre *, pcre_extra *, char *, int);
int uwsgi_regexp_match_ovec(pcre *, pcre_extra *, char *, int, int *, int);
@@ -1247,7 +1254,8 @@ struct uwsgi_server {
// static file serving
int file_serve_mode;
int build_mime_dict;
char *mime_file;
struct uwsgi_string_list *mime_file;
struct uwsgi_probe *probes;
@@ -1270,11 +1278,22 @@ struct uwsgi_server {
int daemons_cnt;
struct uwsgi_dyn_dict *static_maps;
struct uwsgi_dyn_dict *static_maps2;
struct uwsgi_dyn_dict *check_static;
struct uwsgi_dyn_dict *mimetypes;
struct uwsgi_string_list *static_skip_ext;
struct uwsgi_string_list *static_index;
struct uwsgi_dyn_dict *static_expires_type;
struct uwsgi_dyn_dict *static_expires_type_mtime;
struct uwsgi_dyn_dict *static_expires;
struct uwsgi_dyn_dict *static_expires_mtime;
int check_static_docroot;
int static_offload_to_thread;
pthread_attr_t static_offload_thread_attr;
pthread_mutex_t static_offload_thread_lock;
char *daemonize;
char *daemonize2;
@@ -1461,6 +1480,7 @@ struct uwsgi_server {
int no_orphans;
int skip_zero;
char *chdir;
char *chdir2;
@@ -1634,6 +1654,17 @@ struct uwsgi_server {
};
struct uwsgi_offload_request {
pthread_t tid;
struct wsgi_request wsgi_req;
char *buffer;
struct iovec *hvec;
char real_filename[PATH_MAX+1];
size_t real_filename_len;
struct stat st;
};
struct uwsgi_rpc {
char name[0xff];
void *func;
@@ -1855,6 +1886,8 @@ struct uwsgi_worker {
uint64_t avg_response_time;
uint64_t static_offload_threads;
char name[0xff];
};
@@ -2349,7 +2382,7 @@ int uwsgi_netlink_del(char *);
int uwsgi_amqp_consume_queue(int, char *, char *, char *, char *, char *, char *);
char *uwsgi_amqp_consume(int, uint64_t *, char **);
int uwsgi_file_serve(struct wsgi_request *, char *, uint16_t, char *, uint16_t);
int uwsgi_file_serve(struct wsgi_request *, char *, uint16_t, char *, uint16_t, int);
inline int uwsgi_starts_with(char *, int, char *, int);
#ifdef __sun__
@@ -2637,6 +2670,10 @@ void uwsgi_opt_set_str(char *, char *, void *);
void uwsgi_opt_set_logger(char *, char *, void *);
void uwsgi_opt_set_str_spaced(char *, char *, void *);
void uwsgi_opt_add_string_list(char *, char *, void *);
void uwsgi_opt_add_dyn_dict(char *, char *, void *);
#ifdef UWSGI_PCRE
void uwsgi_opt_add_regexp_dyn_dict(char *, char *, void *);
#endif
void uwsgi_opt_set_int(char *, char *, void *);
void uwsgi_opt_set_64bit(char *, char *, void *);
void uwsgi_opt_set_megabytes(char *, char *, void *);
@@ -2779,6 +2816,7 @@ char *uwsgi_expand_path(char *, int, char *);
int uwsgi_try_autoload(char *);
uint64_t uwsgi_micros(void);
int uwsgi_is_file(char *);
#ifdef UWSGI_AS_SHARED_LIBRARY
int uwsgi_init(int, char **, char **);
+6 -1
View File
@@ -1,6 +1,6 @@
# uWSGI build system
uwsgi_version = '1.2-rc1'
uwsgi_version = '1.2-rc2'
import os
import re
@@ -306,6 +306,11 @@ class uConf(object):
raise
except:
self.include_path = ['/usr/include', '/usr/local/include']
additional_include_paths = self.get('additional_include_paths')
if additional_include_paths:
for ipath in additional_include_paths.split():
self.include_path.append(ipath)
if not mute:
print("detected include path: %s" % self.include_path)