mirror of
https://github.com/clearlinux/uwsgi.git
synced 2026-10-04 16:08:31 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b0159ea23b | ||
|
|
d3493df032 | ||
|
|
757c76b569 | ||
|
|
30eebfd335 | ||
|
|
c5d7d30439 | ||
|
|
04bc3e117d | ||
|
|
3480c30674 | ||
|
|
a7e6dfc469 | ||
|
|
5e276b43ad | ||
|
|
9e6a21602a | ||
|
|
952c4ce854 | ||
|
|
951f24e711 | ||
|
|
7bda4c9b63 | ||
|
|
1b25516ced | ||
|
|
b3020e60f9 | ||
|
|
808d37f33a | ||
|
|
8c8a7f77d1 | ||
|
|
3f601af740 | ||
|
|
7b901ab81e | ||
|
|
930eb1e6aa | ||
|
|
77e5931da7 | ||
|
|
3e6ddbb3d5 | ||
|
|
623bce274a | ||
|
|
6c986f8082 | ||
|
|
10a02064ba | ||
|
|
774f5a81a5 | ||
|
|
e270593cc0 | ||
|
|
b559354845 | ||
|
|
46a2fefb04 | ||
|
|
c6c9baa7b5 | ||
|
|
c37710f4c2 | ||
|
|
943c20b88c | ||
|
|
a442614db0 | ||
|
|
5830af37ba | ||
|
|
de4c563169 | ||
|
|
77f008e24c | ||
|
|
df0bd832b4 | ||
|
|
07c42c262f | ||
|
|
cb131836ae | ||
|
|
2c6855a969 | ||
|
|
79ca1940de | ||
|
|
d46879dca9 | ||
|
|
9b889f7b77 | ||
|
|
1128d09187 | ||
|
|
d3d4d04fac | ||
|
|
4a554db63b | ||
|
|
8b799b4f9f |
@@ -25,3 +25,4 @@ Mingli Yuan
|
||||
Natanael Copa
|
||||
Roberto Leandrini
|
||||
Ryan Petrello
|
||||
Danila Shtan <danila@shtan.ru>
|
||||
|
||||
@@ -387,6 +387,23 @@ end:
|
||||
|
||||
}
|
||||
|
||||
static int uwsgi_async_wait_milliseconds_hook(int timeout) {
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
timeout = timeout / 1000;
|
||||
if (!timeout) timeout = 1;
|
||||
async_add_timeout(wsgi_req, timeout);
|
||||
wsgi_req->async_force_again = 1;
|
||||
if (uwsgi.schedule_to_main) {
|
||||
uwsgi.schedule_to_main(wsgi_req);
|
||||
}
|
||||
if (wsgi_req->async_timed_out) {
|
||||
wsgi_req->async_timed_out = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void async_loop() {
|
||||
|
||||
if (uwsgi.async < 2) {
|
||||
@@ -414,6 +431,7 @@ void async_loop() {
|
||||
uwsgi.wait_write_hook = async_wait_fd_write;
|
||||
uwsgi.wait_read_hook = async_wait_fd_read;
|
||||
uwsgi.wait_read2_hook = async_wait_fd_read2;
|
||||
uwsgi.wait_milliseconds_hook = uwsgi_async_wait_milliseconds_hook;
|
||||
|
||||
if (uwsgi.signal_socket > -1) {
|
||||
event_queue_add_fd_read(uwsgi.async_queue, uwsgi.signal_socket);
|
||||
|
||||
+102
-84
@@ -32,7 +32,7 @@ static uint64_t uwsgi_cache_find_free_blocks(struct uwsgi_cache *uc, uint64_t ne
|
||||
// which is the first free bit?
|
||||
uint64_t bitmap_byte = 0;
|
||||
uint8_t bitmap_bit = 0;
|
||||
|
||||
|
||||
if (uc->blocks_bitmap_pos > 0) {
|
||||
bitmap_byte = uc->blocks_bitmap_pos/8;
|
||||
bitmap_bit = uc->blocks_bitmap_pos % 8;
|
||||
@@ -45,6 +45,8 @@ static uint64_t uwsgi_cache_find_free_blocks(struct uwsgi_cache *uc, uint64_t ne
|
||||
uint64_t j;
|
||||
uint64_t found = 0;
|
||||
uint64_t need_to_scan = uc->blocks_bitmap_size;
|
||||
// we make an addition round for the corner case of a single byte map not starting from 0
|
||||
if (bitmap_bit > 0) need_to_scan++;
|
||||
j = bitmap_byte;
|
||||
//uwsgi_log("start scanning %llu bytes starting from %llu need: %llu\n", (unsigned long long) need_to_scan, (unsigned long long) bitmap_byte, (unsigned long long) needed_blocks);
|
||||
while(need_to_scan) {
|
||||
@@ -73,7 +75,9 @@ static uint64_t uwsgi_cache_find_free_blocks(struct uwsgi_cache *uc, uint64_t ne
|
||||
}
|
||||
found++;
|
||||
if (found == needed_blocks) {
|
||||
//printf("found %llu consecutive bit starting from byte %llu\n", found, base);
|
||||
#ifdef UWSGI_DEBUG
|
||||
printf("found %llu consecutive bit starting from byte %llu\n", (unsigned long long) found, (unsigned long long) base);
|
||||
#endif
|
||||
return ((base*8) + base_bit);
|
||||
}
|
||||
}
|
||||
@@ -82,12 +86,14 @@ static uint64_t uwsgi_cache_find_free_blocks(struct uwsgi_cache *uc, uint64_t ne
|
||||
}
|
||||
j++;
|
||||
need_to_scan--;
|
||||
// check for overlap
|
||||
if (j >= need_to_scan) {
|
||||
// check for overlap (that is not supported)
|
||||
if (j >= uc->blocks_bitmap_size) {
|
||||
j = 0;
|
||||
found = 0;
|
||||
base = 0xffffffffffffffffLLU;
|
||||
base_bit = 0;
|
||||
// we use bitmap_bit only at the first round
|
||||
bitmap_bit = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,19 +108,27 @@ static uint64_t cache_mark_blocks(struct uwsgi_cache *uc, uint64_t index, uint64
|
||||
|
||||
uint64_t first_byte = index/8;
|
||||
uint8_t first_byte_bit = index % 8;
|
||||
uint64_t last_byte = (index+needed_blocks)/8;
|
||||
uint8_t last_byte_bit = (index+needed_blocks) % 8;
|
||||
// offset starts with 0, so actual last bit is index + needed_blocks - 1
|
||||
uint64_t last_byte = (index + needed_blocks - 1) / 8;
|
||||
uint8_t last_byte_bit = (index + needed_blocks - 1) % 8;
|
||||
|
||||
uint64_t needed_bytes = (last_byte - first_byte) + 1;
|
||||
|
||||
//uwsgi_log("%llu %u %llu %u\n", first_byte, first_byte_bit, last_byte, last_byte_bit);
|
||||
|
||||
uint8_t mask = 0xff >> first_byte_bit;
|
||||
|
||||
if (needed_bytes == 1) {
|
||||
// kinda hacky, but it does the job
|
||||
mask >>= (7 - last_byte_bit);
|
||||
mask <<= (7 - last_byte_bit);
|
||||
}
|
||||
|
||||
uc->blocks_bitmap[first_byte] |= mask;
|
||||
|
||||
uint64_t needed_bytes = (last_byte - first_byte)+1;
|
||||
|
||||
if (needed_bytes > 1) {
|
||||
mask = 0xff << (8 - last_byte_bit);
|
||||
uc->blocks_bitmap[last_byte-1] |= mask;
|
||||
mask = 0xff << (7 - last_byte_bit);
|
||||
uc->blocks_bitmap[last_byte] |= mask;
|
||||
}
|
||||
|
||||
if (needed_bytes > 2) {
|
||||
@@ -130,19 +144,28 @@ static void cache_unmark_blocks(struct uwsgi_cache *uc, uint64_t index, uint64_t
|
||||
|
||||
uint64_t first_byte = index/8;
|
||||
uint8_t first_byte_bit = index % 8;
|
||||
uint64_t last_byte = (index+needed_blocks)/8;
|
||||
uint8_t last_byte_bit = (index+needed_blocks) % 8;
|
||||
// offset starts with 0, so actual last bit is index + needed_blocks - 1
|
||||
uint64_t last_byte = (index + needed_blocks - 1)/8;
|
||||
uint8_t last_byte_bit = (index + needed_blocks - 1) % 8;
|
||||
|
||||
// here we use XOR (0+0 = 0 | 1+0 = 1 | 0+1 = 1| 1+1 = 0|
|
||||
uint64_t needed_bytes = (last_byte - first_byte) + 1;
|
||||
|
||||
uint8_t mask = 0xff >> first_byte_bit;
|
||||
uc->blocks_bitmap[first_byte] ^= mask;
|
||||
uint8_t mask = 0xff >> first_byte_bit;
|
||||
|
||||
uint64_t needed_bytes = (last_byte - first_byte)+1;
|
||||
if (needed_bytes == 1) {
|
||||
// kinda hacky, but it does the job
|
||||
mask >>= (7 - last_byte_bit);
|
||||
mask <<= (7 - last_byte_bit);
|
||||
}
|
||||
|
||||
// here we use AND (0+0 = 0 | 1+0 = 0 | 0+1 = 0| 1+1 = 1)
|
||||
// 0 in mask means "unmark", 1 in mask means "do not change"
|
||||
// so we need to invert the mask
|
||||
uc->blocks_bitmap[first_byte] &= ~mask;
|
||||
|
||||
if (needed_bytes > 1) {
|
||||
mask = 0xff << (8 - last_byte_bit);
|
||||
uc->blocks_bitmap[last_byte-1] ^= mask;
|
||||
mask = 0xff << (7 - last_byte_bit);
|
||||
uc->blocks_bitmap[last_byte] &= ~mask;
|
||||
}
|
||||
|
||||
if (needed_bytes > 2) {
|
||||
@@ -283,16 +306,24 @@ next2:
|
||||
void uwsgi_cache_init(struct uwsgi_cache *uc) {
|
||||
|
||||
uc->hashtable = uwsgi_calloc_shared(sizeof(uint64_t) * uc->hashsize);
|
||||
uc->unused_blocks_stack = uwsgi_calloc_shared(sizeof(uint64_t) * uc->blocks);
|
||||
// the first cache item is always zero
|
||||
uc->first_available_block = 1;
|
||||
uc->unused_blocks_stack = uwsgi_calloc_shared(sizeof(uint64_t) * uc->max_items);
|
||||
uc->unused_blocks_stack_ptr = 0;
|
||||
uc->filesize = ( (sizeof(struct uwsgi_cache_item)+uc->keysize) * uc->max_items) + (uc->blocksize * uc->blocks);
|
||||
|
||||
uint64_t i;
|
||||
for (i = 1; i < uc->max_items; i++) {
|
||||
uc->unused_blocks_stack_ptr++;
|
||||
uc->unused_blocks_stack[uc->unused_blocks_stack_ptr] = i;
|
||||
}
|
||||
|
||||
if (uc->use_blocks_bitmap) {
|
||||
uc->blocks_bitmap_size = uc->blocks/8;
|
||||
if (uc->blocks % 8 > 0) uc->blocks_bitmap_size++;
|
||||
uint8_t m = uc->blocks % 8;
|
||||
if (m > 0) uc->blocks_bitmap_size++;
|
||||
uc->blocks_bitmap = uwsgi_calloc_shared(uc->blocks_bitmap_size);
|
||||
if (m > 0) {
|
||||
uc->blocks_bitmap[uc->blocks_bitmap_size-1] = 0xff >> m;
|
||||
}
|
||||
}
|
||||
|
||||
//uwsgi.cache_items = (struct uwsgi_cache_item *) mmap(NULL, sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
|
||||
@@ -361,7 +392,7 @@ void uwsgi_cache_init(struct uwsgi_cache *uc) {
|
||||
uc->name,
|
||||
(unsigned long long) uc->filesize / (1024 * 1024),
|
||||
(unsigned long long) sizeof(struct uwsgi_cache_item)+uc->keysize,
|
||||
(unsigned long long) ((sizeof(struct uwsgi_cache_item)+uc->keysize) * uc->max_items), (unsigned long long) (uc->blocksize * uc->max_items),
|
||||
(unsigned long long) ((sizeof(struct uwsgi_cache_item)+uc->keysize) * uc->max_items), (unsigned long long) (uc->blocksize * uc->blocks),
|
||||
(unsigned long long) uc->blocks_bitmap_size);
|
||||
|
||||
uwsgi_cache_setup_nodes(uc);
|
||||
@@ -523,50 +554,52 @@ char *uwsgi_cache_get4(struct uwsgi_cache *uc, char *key, uint16_t keylen, uint6
|
||||
|
||||
int uwsgi_cache_del2(struct uwsgi_cache *uc, char *key, uint16_t keylen, uint64_t index, uint16_t flags) {
|
||||
|
||||
|
||||
struct uwsgi_cache_item *uci;
|
||||
int ret = -1;
|
||||
|
||||
if (!index)
|
||||
index = uwsgi_cache_get_index(uc, key, keylen);
|
||||
if (!index) index = uwsgi_cache_get_index(uc, key, keylen);
|
||||
|
||||
if (index) {
|
||||
uci = cache_item(index);
|
||||
if (uci->keysize > 0) {
|
||||
// unmark blocks
|
||||
if (uc->blocks_bitmap) cache_unmark_blocks(uc, uci->first_block, uci->valsize);
|
||||
// put back the block in unused stack
|
||||
uc->unused_blocks_stack_ptr++;
|
||||
uc->unused_blocks_stack[uc->unused_blocks_stack_ptr] = index;
|
||||
|
||||
// unlink prev and next (if any)
|
||||
if (uci->prev) {
|
||||
struct uwsgi_cache_item *ucii = cache_item(uci->prev);
|
||||
ucii->next = uci->next;
|
||||
}
|
||||
else {
|
||||
// set next as the new entry point (could be 0)
|
||||
uc->hashtable[uci->hash % uc->hashsize] = uci->next;
|
||||
}
|
||||
|
||||
if (uci->next) {
|
||||
struct uwsgi_cache_item *ucii = cache_item(uci->next);
|
||||
ucii->prev = uci->prev;
|
||||
}
|
||||
|
||||
if (!uci->prev && !uci->next) {
|
||||
// reset hashtable entry
|
||||
uc->hashtable[uci->hash % uc->hashsize] = 0;
|
||||
}
|
||||
uc->n_items--;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
uci->keysize = 0;
|
||||
uci->valsize = 0;
|
||||
uc->unused_blocks_stack_ptr++;
|
||||
uc->unused_blocks_stack[uc->unused_blocks_stack_ptr] = index;
|
||||
// unmark blocks
|
||||
if (uc->blocks_bitmap) {
|
||||
cache_unmark_blocks(uc, uci->first_block, uci->valsize);
|
||||
}
|
||||
ret = 0;
|
||||
// relink collisioned entry
|
||||
if (uci->prev) {
|
||||
struct uwsgi_cache_item *ucii = cache_item(uci->prev);
|
||||
ucii->next = uci->next;
|
||||
}
|
||||
else {
|
||||
// set next as the new entry point (could be 0)
|
||||
uc->hashtable[uci->hash % uc->hashsize] = uci->next;
|
||||
}
|
||||
|
||||
if (uci->next) {
|
||||
struct uwsgi_cache_item *ucii = cache_item(uci->next);
|
||||
ucii->prev = uci->prev;
|
||||
}
|
||||
|
||||
if (!uci->prev && !uci->next) {
|
||||
// reset hashtable entry
|
||||
//uwsgi_log("!!! resetted hashtable entry !!!\n");
|
||||
uc->hashtable[uci->hash % uc->hashsize] = 0;
|
||||
}
|
||||
uci->hash = 0;
|
||||
uci->prev = 0;
|
||||
uci->next = 0;
|
||||
uci->expires = 0;
|
||||
|
||||
uc->n_items--;
|
||||
|
||||
if (uc->use_last_modified) {
|
||||
uc->last_modified_at = uwsgi_now();
|
||||
}
|
||||
@@ -584,7 +617,10 @@ void uwsgi_cache_fix(struct uwsgi_cache *uc) {
|
||||
uint64_t i;
|
||||
unsigned long long restored = 0;
|
||||
|
||||
for (i = 0; i < uc->max_items; i++) {
|
||||
// reset unused blocks
|
||||
uc->unused_blocks_stack_ptr = 0;
|
||||
|
||||
for (i = 1; i < uc->max_items; i++) {
|
||||
// valid record ?
|
||||
struct uwsgi_cache_item *uci = cache_item(i);
|
||||
if (uci->keysize) {
|
||||
@@ -596,7 +632,6 @@ void uwsgi_cache_fix(struct uwsgi_cache *uc) {
|
||||
}
|
||||
else {
|
||||
// put this record in unused stack
|
||||
uc->first_available_block = i;
|
||||
uc->unused_blocks_stack_ptr++;
|
||||
uc->unused_blocks_stack[uc->unused_blocks_stack_ptr] = i;
|
||||
}
|
||||
@@ -613,7 +648,6 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v
|
||||
struct uwsgi_cache_item *uci, *ucii;
|
||||
|
||||
// used to reset key allocation in bitmap mode
|
||||
uint8_t rollback_mode = 0;
|
||||
|
||||
int ret = -1;
|
||||
time_t now = 0;
|
||||
@@ -631,24 +665,14 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v
|
||||
//uwsgi_log("putting cache data in key %.*s %d\n", keylen, key, vallen);
|
||||
index = uwsgi_cache_get_index(uc, key, keylen);
|
||||
if (!index) {
|
||||
if (uc->first_available_block >= uc->max_items && !uc->unused_blocks_stack_ptr) {
|
||||
if (!uc->unused_blocks_stack_ptr) {
|
||||
uwsgi_log("*** DANGER cache \"%s\" is FULL !!! ***\n", uc->name);
|
||||
uc->full++;
|
||||
goto end;
|
||||
}
|
||||
if (uc->unused_blocks_stack_ptr) {
|
||||
//uwsgi_log("!!! REUSING CACHE SLOT !!! (faci: %llu)\n", (unsigned long long) uwsgi.shared->cache_first_available_block);
|
||||
index = uc->unused_blocks_stack[uc->unused_blocks_stack_ptr];
|
||||
uc->unused_blocks_stack_ptr--;
|
||||
}
|
||||
else {
|
||||
rollback_mode = 1;
|
||||
index = uc->first_available_block;
|
||||
if (uc->first_available_block < uc->max_items) {
|
||||
rollback_mode = 2;
|
||||
uc->first_available_block++;
|
||||
}
|
||||
}
|
||||
|
||||
index = uc->unused_blocks_stack[uc->unused_blocks_stack_ptr];
|
||||
uc->unused_blocks_stack_ptr--;
|
||||
|
||||
uci = cache_item(index);
|
||||
if (!uc->blocks_bitmap) {
|
||||
@@ -656,26 +680,20 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v
|
||||
}
|
||||
else {
|
||||
uci->first_block = uwsgi_cache_find_free_blocks(uc, vallen);
|
||||
//uwsgi_log("first block = %llu\n", uci->first_block);
|
||||
if (uci->first_block == 0xffffffffffffffffLLU) {
|
||||
uwsgi_log("*** DANGER cache \"%s\" is FULL !!! ***\n", uc->name);
|
||||
uc->full++;
|
||||
if (rollback_mode == 0) {
|
||||
uc->unused_blocks_stack_ptr++;
|
||||
}
|
||||
else if (rollback_mode == 2) {
|
||||
uc->first_available_block--;
|
||||
}
|
||||
uc->unused_blocks_stack_ptr++;
|
||||
goto end;
|
||||
}
|
||||
// mark used blocks;
|
||||
uint64_t needed_blocks = cache_mark_blocks(uc, uci->first_block, vallen);
|
||||
// optimize the scan
|
||||
if (uc->blocks_bitmap_pos + (needed_blocks+1) > uc->blocks) {
|
||||
if (uc->blocks_bitmap_pos + needed_blocks > uc->blocks) {
|
||||
uc->blocks_bitmap_pos = 0;
|
||||
}
|
||||
else {
|
||||
uc->blocks_bitmap_pos = uci->first_block + needed_blocks + 1;
|
||||
uc->blocks_bitmap_pos = uci->first_block + needed_blocks;
|
||||
}
|
||||
}
|
||||
if (expires && !(flags & UWSGI_CACHE_FLAG_ABSEXPIRE)) {
|
||||
@@ -763,14 +781,14 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v
|
||||
// mark used blocks;
|
||||
uint64_t needed_blocks = cache_mark_blocks(uc, uci->first_block, vallen);
|
||||
// optimize the scan
|
||||
if (uc->blocks_bitmap_pos + (needed_blocks+1) > uc->blocks) {
|
||||
if (uc->blocks_bitmap_pos + needed_blocks > uc->blocks) {
|
||||
uc->blocks_bitmap_pos = 0;
|
||||
}
|
||||
else {
|
||||
uc->blocks_bitmap_pos = uci->first_block + needed_blocks + 1;
|
||||
uc->blocks_bitmap_pos = uci->first_block + needed_blocks;
|
||||
}
|
||||
// unmark the old blocks
|
||||
cache_unmark_blocks(uc, uci->first_block, uci->valsize);
|
||||
cache_unmark_blocks(uc, old_first_block, uci->valsize);
|
||||
}
|
||||
if ( !(flags & UWSGI_CACHE_FLAG_MATH)) {
|
||||
memcpy(((char *) uc->data) + (uci->first_block * uc->blocksize), val, vallen);
|
||||
@@ -1788,7 +1806,7 @@ int uwsgi_cache_magic_clear(char *cache) {
|
||||
if (uc) {
|
||||
uint64_t i;
|
||||
uwsgi_wlock(uc->lock);
|
||||
for (i = 1; i < uwsgi.caches->max_items; i++) {
|
||||
for (i = 1; i < uc->max_items; i++) {
|
||||
if (uwsgi_cache_del2(uc, NULL, 0, i, 0)) {
|
||||
uwsgi_rwunlock(uc->lock);
|
||||
return -1;
|
||||
|
||||
+2
-1
@@ -400,7 +400,8 @@ void add_exported_option_do(char *key, char *value, int configured, int placehol
|
||||
if (uwsgi.logic_opt_running)
|
||||
goto add;
|
||||
|
||||
if (!strcmp(key, "end") || !strcmp(key, "endfor") || !strcmp(key, "endif")) {
|
||||
if (!strcmp(key, "end") || !strcmp(key, "endfor") || !strcmp(key, "endif")
|
||||
|| !strcmp(key, "end-if") || !strcmp(key, "end-for")) {
|
||||
if (uwsgi.logic_opt_data) {
|
||||
free(uwsgi.logic_opt_data);
|
||||
}
|
||||
|
||||
@@ -517,12 +517,28 @@ fallback:
|
||||
goto end;
|
||||
}
|
||||
|
||||
// is it a potential virtual file (/proc, /sys...) ?
|
||||
int is_virtual = 0;
|
||||
if (sb.st_size == 0) {
|
||||
is_virtual = 1;
|
||||
sb.st_size = 4096;
|
||||
}
|
||||
|
||||
buffer = uwsgi_malloc(sb.st_size + add_zero);
|
||||
|
||||
len = read(fd, buffer, sb.st_size);
|
||||
if (len != sb.st_size) {
|
||||
uwsgi_error("read()");
|
||||
exit(1);
|
||||
if (!is_virtual) {
|
||||
if (len != sb.st_size) {
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (len >= 0) {
|
||||
sb.st_size = len;
|
||||
}
|
||||
else {
|
||||
uwsgi_error("read()");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
close(fd);
|
||||
@@ -951,6 +967,7 @@ int uwsgi_read_nb(int fd, char *buf, size_t remains, int timeout) {
|
||||
ssize_t uwsgi_read_true_nb(int fd, char *buf, size_t len, int timeout) {
|
||||
int ret;
|
||||
|
||||
errno = 0;
|
||||
ssize_t rlen = read(fd, buf, len);
|
||||
if (rlen > 0) {
|
||||
return rlen;
|
||||
@@ -961,8 +978,10 @@ ssize_t uwsgi_read_true_nb(int fd, char *buf, size_t len, int timeout) {
|
||||
}
|
||||
return -1;
|
||||
wait:
|
||||
errno = 0;
|
||||
ret = uwsgi.wait_read_hook(fd, timeout);
|
||||
if (ret > 0) {
|
||||
errno = 0;
|
||||
rlen = read(fd, buf, len);
|
||||
if (rlen > 0) {
|
||||
return rlen;
|
||||
|
||||
+1
-1
@@ -1116,7 +1116,7 @@ static ssize_t uwsgi_lf_ltime(struct wsgi_request * wsgi_req, char **buf) {
|
||||
}
|
||||
|
||||
static ssize_t uwsgi_lf_ftime(struct wsgi_request * wsgi_req, char **buf) {
|
||||
if (!uwsgi.log_strftime) {
|
||||
if (!uwsgi.logformat_strftime || !uwsgi.log_strftime) {
|
||||
return uwsgi_lf_ltime(wsgi_req, buf);
|
||||
}
|
||||
*buf = uwsgi_malloc(64);
|
||||
|
||||
+23
-9
@@ -43,13 +43,6 @@ void uwsgi_destroy_processes() {
|
||||
|
||||
uwsgi_signal_spoolers(SIGKILL);
|
||||
|
||||
if (uwsgi.emperor_pid >= 0) {
|
||||
kill(uwsgi.emperor_pid, SIGKILL);
|
||||
waitpid(uwsgi.emperor_pid, &waitpid_status, 0);
|
||||
uwsgi_log("The Emperor has been buried (pid: %d)\n", (int) uwsgi.emperor_pid);
|
||||
}
|
||||
|
||||
|
||||
uwsgi_detach_daemons();
|
||||
|
||||
for (i = 0; i < ushared->gateways_cnt; i++) {
|
||||
@@ -68,6 +61,26 @@ void uwsgi_destroy_processes() {
|
||||
uwsgi_log("mule %d has been buried (pid: %d)\n", i, (int) uwsgi.mules[i].pid);
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.emperor_pid > 0) {
|
||||
kill(uwsgi.emperor_pid, SIGINT);
|
||||
time_t timeout = uwsgi_now() + (uwsgi.reload_mercy ? uwsgi.reload_mercy : 3);
|
||||
// increase timeout for being more tolerant
|
||||
timeout+=2;
|
||||
int waitpid_status;
|
||||
while (uwsgi_now() < timeout) {
|
||||
pid_t diedpid = waitpid(uwsgi.emperor_pid, &waitpid_status, WNOHANG);
|
||||
if (diedpid == uwsgi.emperor_pid) {
|
||||
goto nomoremperor;
|
||||
}
|
||||
uwsgi_log("waiting for Emperor death...\n");
|
||||
sleep(1);
|
||||
}
|
||||
kill(uwsgi.emperor_pid, SIGKILL);
|
||||
waitpid(uwsgi.emperor_pid, &waitpid_status, 0);
|
||||
nomoremperor:
|
||||
uwsgi_log("The Emperor has been buried (pid: %d)\n", (int) uwsgi.emperor_pid);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -546,9 +559,10 @@ void uwsgi_fixup_fds(int wid, int muleid, struct uwsgi_gateway *ug) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (uwsgi.shared->spooler_signal_pipe[0] != -1)
|
||||
close(uwsgi.shared->spooler_signal_pipe[0]);
|
||||
if (uwsgi.i_am_a_spooler && uwsgi.i_am_a_spooler->pid != getpid()) {
|
||||
if (uwsgi.shared->spooler_signal_pipe[0] != -1)
|
||||
close(uwsgi.shared->spooler_signal_pipe[0]);
|
||||
if (uwsgi.shared->spooler_signal_pipe[1] != -1)
|
||||
close(uwsgi.shared->spooler_signal_pipe[1]);
|
||||
}
|
||||
|
||||
@@ -312,6 +312,7 @@ int uwsgi_apply_error_routes(struct wsgi_request *wsgi_req) {
|
||||
|
||||
int uwsgi_apply_response_routes(struct wsgi_request *wsgi_req) {
|
||||
|
||||
|
||||
if (!uwsgi.response_routes) return 0;
|
||||
if (wsgi_req->response_routes_applied) return 0;
|
||||
|
||||
|
||||
+12
-10
@@ -269,20 +269,22 @@ int uwsgi_remote_signal_send(char *addr, uint8_t sig) {
|
||||
uh.pktsize = 0;
|
||||
uh.modifier2 = sig;
|
||||
|
||||
int fd = uwsgi_connect(addr, uwsgi.socket_timeout, 0);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
int fd = uwsgi_connect(addr, 0, 1);
|
||||
if (fd < 0) return -1;
|
||||
|
||||
if (write(fd, (char *) &uh, 4) != 4) {
|
||||
uwsgi_error("uwsgi_remote_signal_send()");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
// wait for connection
|
||||
if (uwsgi.wait_write_hook(fd, uwsgi.socket_timeout) <= 0) goto end;
|
||||
|
||||
int ret = uwsgi_read_response(fd, &uh, uwsgi.socket_timeout, NULL);
|
||||
if (uwsgi_write_true_nb(fd, (char *) &uh, 4, uwsgi.socket_timeout)) goto end;
|
||||
|
||||
if (uwsgi_read_whole_true_nb(fd, (char *) &uh, 4, uwsgi.socket_timeout)) goto end;
|
||||
close(fd);
|
||||
return ret;
|
||||
|
||||
return uh.modifier2;
|
||||
|
||||
end:
|
||||
close(fd);
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
+34
-28
@@ -982,19 +982,44 @@ nonroot:
|
||||
}
|
||||
}
|
||||
|
||||
static void close_and_free_request(struct wsgi_request *wsgi_req) {
|
||||
|
||||
// close the connection with the client
|
||||
if (!wsgi_req->fd_closed) {
|
||||
// NOTE, if we close the socket before receiving eventually sent data, socket layer will send a RST
|
||||
wsgi_req->socket->proto_close(wsgi_req);
|
||||
}
|
||||
|
||||
if (wsgi_req->post_file) {
|
||||
fclose(wsgi_req->post_file);
|
||||
}
|
||||
|
||||
if (wsgi_req->post_read_buf) {
|
||||
free(wsgi_req->post_read_buf);
|
||||
}
|
||||
|
||||
if (wsgi_req->post_readline_buf) {
|
||||
free(wsgi_req->post_readline_buf);
|
||||
}
|
||||
|
||||
if (wsgi_req->proto_parser_buf) {
|
||||
free(wsgi_req->proto_parser_buf);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// destroy a request
|
||||
void uwsgi_destroy_request(struct wsgi_request *wsgi_req) {
|
||||
|
||||
wsgi_req->socket->proto_close(wsgi_req);
|
||||
close_and_free_request(wsgi_req);
|
||||
|
||||
int foo;
|
||||
if (uwsgi.threads > 1) {
|
||||
// now the thread can die...
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &foo);
|
||||
}
|
||||
|
||||
memset(wsgi_req, 0, sizeof(struct wsgi_request));
|
||||
if (uwsgi.threads > 1) {
|
||||
// now the thread can die...
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &foo);
|
||||
}
|
||||
|
||||
memset(wsgi_req, 0, sizeof(struct wsgi_request));
|
||||
|
||||
}
|
||||
|
||||
@@ -1053,27 +1078,8 @@ void uwsgi_close_request(struct wsgi_request *wsgi_req) {
|
||||
uwsgi_apply_final_routes(wsgi_req);
|
||||
#endif
|
||||
|
||||
// close the connection with the client
|
||||
if (!wsgi_req->fd_closed) {
|
||||
// NOTE, if we close the socket before receiving eventually sent data, socket layer will send a RST
|
||||
wsgi_req->socket->proto_close(wsgi_req);
|
||||
}
|
||||
|
||||
if (wsgi_req->post_file) {
|
||||
fclose(wsgi_req->post_file);
|
||||
}
|
||||
|
||||
if (wsgi_req->post_read_buf) {
|
||||
free(wsgi_req->post_read_buf);
|
||||
}
|
||||
|
||||
if (wsgi_req->post_readline_buf) {
|
||||
free(wsgi_req->post_readline_buf);
|
||||
}
|
||||
|
||||
if (wsgi_req->proto_parser_buf) {
|
||||
free(wsgi_req->proto_parser_buf);
|
||||
}
|
||||
// close socket and free parsers-allocated memory
|
||||
close_and_free_request(wsgi_req);
|
||||
|
||||
// after_request hook
|
||||
if (!wsgi_req->is_raw && uwsgi.p[wsgi_req->uh->modifier1]->after_request)
|
||||
|
||||
+20
-10
@@ -1916,6 +1916,17 @@ int main(int argc, char *argv[], char *envp[]) {
|
||||
return uwsgi_run();
|
||||
}
|
||||
|
||||
static char *uwsgi_at_file_read(char *filename) {
|
||||
size_t size = 0;
|
||||
char *buffer = uwsgi_open_and_read(filename, &size, 1, NULL);
|
||||
if (size > 1) {
|
||||
if (buffer[size-2] == '\n' || buffer[size-2] == '\r') {
|
||||
buffer[size-2] = 0;
|
||||
}
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void uwsgi_setup(int argc, char *argv[], char *envp[]) {
|
||||
#ifdef UWSGI_AS_SHARED_LIBRARY
|
||||
#ifdef __APPLE__
|
||||
@@ -2113,7 +2124,7 @@ void uwsgi_setup(int argc, char *argv[], char *envp[]) {
|
||||
uwsgi_apply_config_pass('$', (char *(*)(char *)) getenv);
|
||||
|
||||
// third pass: FILEs
|
||||
uwsgi_apply_config_pass('@', uwsgi_simple_file_read);
|
||||
uwsgi_apply_config_pass('@', uwsgi_at_file_read);
|
||||
|
||||
// last pass: REFERENCEs
|
||||
uwsgi_apply_config_pass('%', uwsgi_manage_placeholder);
|
||||
@@ -2772,6 +2783,7 @@ int uwsgi_start(void *v_argv) {
|
||||
!uwsgi.command_mode &&
|
||||
!uwsgi.daemons_cnt &&
|
||||
!uwsgi.crons &&
|
||||
!uwsgi.spoolers &&
|
||||
!uwsgi.emperor_proxy
|
||||
#ifdef __linux__
|
||||
&& !uwsgi.setns_socket
|
||||
@@ -2930,7 +2942,7 @@ unsafe:
|
||||
}
|
||||
|
||||
// initialize locks and socket as soon as possible, as the master could enqueue tasks
|
||||
if (uwsgi.spoolers != NULL && (uwsgi.sockets || uwsgi.loop)) {
|
||||
if (uwsgi.spoolers != NULL) {
|
||||
create_signal_pipe(uwsgi.shared->spooler_signal_pipe);
|
||||
struct uwsgi_spooler *uspool = uwsgi.spoolers;
|
||||
while (uspool) {
|
||||
@@ -3068,15 +3080,13 @@ next:
|
||||
|
||||
|
||||
|
||||
if (uwsgi.spoolers != NULL && (uwsgi.sockets || uwsgi.loop)) {
|
||||
struct uwsgi_spooler *uspool = uwsgi.spoolers;
|
||||
while (uspool) {
|
||||
if (uspool->mode == UWSGI_SPOOLER_EXTERNAL)
|
||||
goto next2;
|
||||
uspool->pid = spooler_start(uspool);
|
||||
struct uwsgi_spooler *uspool = uwsgi.spoolers;
|
||||
while (uspool) {
|
||||
if (uspool->mode == UWSGI_SPOOLER_EXTERNAL)
|
||||
goto next2;
|
||||
uspool->pid = spooler_start(uspool);
|
||||
next2:
|
||||
uspool = uspool->next;
|
||||
}
|
||||
uspool = uspool->next;
|
||||
}
|
||||
|
||||
if (!uwsgi.master_process) {
|
||||
|
||||
+31
-23
@@ -82,12 +82,14 @@ int uwsgi_response_prepare_headers(struct wsgi_request *wsgi_req, char *status,
|
||||
wsgi_req->status = uwsgi_str3_num(status);
|
||||
#ifdef UWSGI_ROUTING
|
||||
// apply error routes
|
||||
if (uwsgi_apply_error_routes(wsgi_req) == UWSGI_ROUTE_BREAK) {
|
||||
// from now on ignore write body requests...
|
||||
wsgi_req->ignore_body = 1;
|
||||
return -1;
|
||||
if (wsgi_req->is_error_routing == 0) {
|
||||
if (uwsgi_apply_error_routes(wsgi_req) == UWSGI_ROUTE_BREAK) {
|
||||
// from now on ignore write body requests...
|
||||
wsgi_req->ignore_body = 1;
|
||||
return -1;
|
||||
}
|
||||
wsgi_req->is_error_routing = 0;
|
||||
}
|
||||
wsgi_req->is_error_routing = 0;
|
||||
#endif
|
||||
if (status_len <= 4) {
|
||||
char *new_sc = NULL;
|
||||
@@ -186,12 +188,14 @@ static int uwsgi_response_write_headers_do0(struct wsgi_request *wsgi_req) {
|
||||
|
||||
#ifdef UWSGI_ROUTING
|
||||
// apply response routes
|
||||
if (uwsgi_apply_response_routes(wsgi_req) == UWSGI_ROUTE_BREAK) {
|
||||
// from now on ignore write body requests...
|
||||
wsgi_req->ignore_body = 1;
|
||||
return -1;
|
||||
}
|
||||
wsgi_req->is_response_routing = 0;
|
||||
if (wsgi_req->is_response_routing == 0) {
|
||||
if (uwsgi_apply_response_routes(wsgi_req) == UWSGI_ROUTE_BREAK) {
|
||||
// from now on ignore write body requests...
|
||||
wsgi_req->ignore_body = 1;
|
||||
return -1;
|
||||
}
|
||||
wsgi_req->is_response_routing = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct uwsgi_string_list *ah = uwsgi.additional_headers;
|
||||
@@ -352,12 +356,14 @@ int uwsgi_response_write_body_do(struct wsgi_request *wsgi_req, char *buf, size_
|
||||
// special case here, we could need to set transformations before
|
||||
if (!wsgi_req->headers_sent) {
|
||||
// apply response routes
|
||||
if (uwsgi_apply_response_routes(wsgi_req) == UWSGI_ROUTE_BREAK) {
|
||||
// from now on ignore write body requests...
|
||||
wsgi_req->ignore_body = 1;
|
||||
return -1;
|
||||
}
|
||||
wsgi_req->is_response_routing = 0;
|
||||
if (wsgi_req->is_response_routing == 0) {
|
||||
if (uwsgi_apply_response_routes(wsgi_req) == UWSGI_ROUTE_BREAK) {
|
||||
// from now on ignore write body requests...
|
||||
wsgi_req->ignore_body = 1;
|
||||
return -1;
|
||||
}
|
||||
wsgi_req->is_response_routing = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -435,12 +441,14 @@ int uwsgi_response_writev_body_do(struct wsgi_request *wsgi_req, struct iovec *i
|
||||
// special case here, we could need to set transformations before
|
||||
if (!wsgi_req->headers_sent) {
|
||||
// apply response routes
|
||||
if (uwsgi_apply_response_routes(wsgi_req) == UWSGI_ROUTE_BREAK) {
|
||||
// from now on ignore write body requests...
|
||||
wsgi_req->ignore_body = 1;
|
||||
return -1;
|
||||
}
|
||||
wsgi_req->is_response_routing = 0;
|
||||
if (wsgi_req->is_response_routing == 0) {
|
||||
if (uwsgi_apply_response_routes(wsgi_req) == UWSGI_ROUTE_BREAK) {
|
||||
// from now on ignore write body requests...
|
||||
wsgi_req->ignore_body = 1;
|
||||
return -1;
|
||||
}
|
||||
wsgi_req->is_response_routing = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
+214
-169
@@ -2,6 +2,8 @@
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
#define kill_on_error if (!uc.do_not_kill_on_error) { if (kill(cgi_pid, SIGKILL)) uwsgi_error("kill()");}
|
||||
|
||||
struct uwsgi_cgi {
|
||||
struct uwsgi_dyn_dict *mountpoint;
|
||||
struct uwsgi_dyn_dict *helpers;
|
||||
@@ -16,6 +18,8 @@ struct uwsgi_cgi {
|
||||
int has_mountpoints;
|
||||
struct uwsgi_dyn_dict *default_cgi;
|
||||
int path_info;
|
||||
int do_not_kill_on_error;
|
||||
int async_max_attempts;
|
||||
} uc ;
|
||||
|
||||
static void uwsgi_opt_add_cgi(char *opt, char *value, void *foobar) {
|
||||
@@ -62,6 +66,9 @@ struct uwsgi_option uwsgi_cgi_options[] = {
|
||||
|
||||
{"cgi-path-info", no_argument, 0, "disable PATH_INFO management in cgi scripts", uwsgi_opt_true, &uc.path_info, 0},
|
||||
|
||||
{"cgi-do-not-kill-on-error", no_argument, 0, "do not send SIGKILL to cgi script on errors", uwsgi_opt_true, &uc.do_not_kill_on_error, 0},
|
||||
{"cgi-async-max-attempts", no_argument, 0, "max waitpid() attempts in cgi async mode (default 10)", uwsgi_opt_set_int, &uc.async_max_attempts, 0},
|
||||
|
||||
{0, 0, 0, 0, 0, 0, 0},
|
||||
|
||||
};
|
||||
@@ -179,118 +186,154 @@ static char *uwsgi_cgi_get_helper(char *filename) {
|
||||
|
||||
}
|
||||
|
||||
static int uwsgi_cgi_parse(struct wsgi_request *wsgi_req, char *buf, size_t len) {
|
||||
|
||||
size_t i;
|
||||
/*
|
||||
start reading each line until Status or Location are found
|
||||
-1 error
|
||||
0 not found
|
||||
1 found
|
||||
*/
|
||||
static int uwsgi_cgi_check_status(struct wsgi_request *wsgi_req, char *buf, size_t len) {
|
||||
char *key = buf, *value = NULL;
|
||||
size_t header_size = 0;
|
||||
int status_sent = 0;
|
||||
size_t i;
|
||||
|
||||
// Search for Status/Location headers
|
||||
for(i=0;i<len;i++) {
|
||||
// end of a line
|
||||
if (buf[i] == '\n') {
|
||||
// end of headers
|
||||
if (key == NULL) {
|
||||
// Default status
|
||||
// end of a line
|
||||
if (buf[i] == '\n') {
|
||||
// end of headers
|
||||
if (key == NULL) {
|
||||
// Default status
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("setting default Status header\n");
|
||||
#endif
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) return -1;
|
||||
break;
|
||||
return 1;
|
||||
}
|
||||
// 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--;
|
||||
}
|
||||
// invalid header
|
||||
else if (value == NULL) return -1;
|
||||
header_size = (buf+i) - key;
|
||||
// security check
|
||||
if (buf+i > buf) {
|
||||
// remove \r
|
||||
if ((buf[i-1]) == '\r') {
|
||||
header_size--;
|
||||
}
|
||||
}
|
||||
|
||||
// enough space for Status ?
|
||||
if (header_size >= 11) {
|
||||
// "Status: NNN"
|
||||
if (!strncasecmp("Status: ", key, 8)) {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("found Status header: %.*s\n", header_size, key);
|
||||
#endif
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, key+8, header_size - 8)) return -1;
|
||||
return 1;
|
||||
}
|
||||
// Location: X
|
||||
if (!strncasecmp("Location: ", key, 10)) {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("found Location header: %.*s\n", header_size, key);
|
||||
#endif
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, "302 Found", 9)) return -1;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (header_size >= 11) {
|
||||
// "Status: NNN"
|
||||
if (!strncasecmp("Status: ", key, 8)) {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("found Status header: %.*s\n", header_size, key);
|
||||
#endif
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, key+8, header_size - 8)) return -1;
|
||||
break;
|
||||
}
|
||||
// Location: X
|
||||
if (!strncasecmp("Location: ", key, 10)) {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("found Location header: %.*s\n", header_size, key);
|
||||
#endif
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, "302 Found", 9)) return -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
key = NULL;
|
||||
value = NULL;
|
||||
key = NULL;
|
||||
value = NULL;
|
||||
}
|
||||
else if (buf[i] == ':') {
|
||||
else if (buf[i] == ':') {
|
||||
value = buf+i;
|
||||
}
|
||||
else if (buf[i] != '\r') {
|
||||
if (key == NULL) {
|
||||
key = buf + i;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (buf[i] != '\r') {
|
||||
if (key == NULL) key = buf + i;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
key = buf;
|
||||
value = NULL;
|
||||
// no Status/Location found
|
||||
return 0;
|
||||
|
||||
for(i=0;i<len;i++) {
|
||||
// end of a line
|
||||
if (buf[i] == '\n') {
|
||||
// end of headers
|
||||
if (key == NULL) {
|
||||
i++;
|
||||
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--;
|
||||
}
|
||||
|
||||
static int uwsgi_cgi_parse(struct wsgi_request *wsgi_req, int fd, char *buf, size_t blen) {
|
||||
|
||||
size_t i;
|
||||
size_t header_size = 0;
|
||||
int status_sent = 0;
|
||||
size_t remains = blen;
|
||||
char *ptr = buf;
|
||||
size_t len = 0;
|
||||
|
||||
while(remains > 0) {
|
||||
ssize_t rlen = uwsgi_read_true_nb(fd, ptr, remains, uc.timeout);
|
||||
if (rlen < 0) {
|
||||
if (!errno) return 1;
|
||||
return -1;
|
||||
}
|
||||
// timed out
|
||||
if (rlen == 0) return -1;
|
||||
remains -= rlen;
|
||||
len += rlen;
|
||||
ptr += rlen;
|
||||
|
||||
// Search for Status/Location headers
|
||||
if (!status_sent) {
|
||||
status_sent = uwsgi_cgi_check_status(wsgi_req, buf, len);
|
||||
if (status_sent < 0) return -1;
|
||||
// need more data ?
|
||||
if (status_sent == 0) continue;
|
||||
}
|
||||
|
||||
// send headers
|
||||
char *key = buf;
|
||||
char *value = NULL;
|
||||
|
||||
for(i=0;i<len;i++) {
|
||||
// end of a line
|
||||
if (buf[i] == '\n') {
|
||||
// end of headers
|
||||
if (key == NULL) {
|
||||
i++;
|
||||
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);
|
||||
uwsgi_log("found CGI header: %.*s\n", header_size, key);
|
||||
#endif
|
||||
|
||||
// Ignore "Status: NNN" header
|
||||
if (status_sent == 0 && header_size >= 11) {
|
||||
if (!strncasecmp("Status: ", key, 8)) {
|
||||
status_sent = 1;
|
||||
key = NULL;
|
||||
value = NULL;
|
||||
continue;
|
||||
// Ignore "Status: NNN" header
|
||||
if (header_size >= 11) {
|
||||
if (!strncasecmp("Status: ", key, 8)) {
|
||||
key = NULL;
|
||||
value = NULL;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_response_add_header(wsgi_req, NULL, 0, key, header_size);
|
||||
key = NULL;
|
||||
value = NULL;
|
||||
}
|
||||
|
||||
uwsgi_response_add_header(wsgi_req, NULL, 0, key, header_size);
|
||||
|
||||
key = NULL;
|
||||
value = NULL;
|
||||
}
|
||||
else if (buf[i] == ':') {
|
||||
value = buf+i;
|
||||
}
|
||||
else if (buf[i] != '\r') {
|
||||
if (key == NULL) {
|
||||
key = buf + i;
|
||||
else if (buf[i] == ':') {
|
||||
value = buf+i;
|
||||
}
|
||||
else if (buf[i] != '\r') {
|
||||
if (key == NULL) {
|
||||
key = buf + i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -592,7 +635,6 @@ static int uwsgi_cgi_run(struct wsgi_request *wsgi_req, char *docroot, size_t do
|
||||
int post_pipe[2];
|
||||
int nargs = 0;
|
||||
int waitpid_status;
|
||||
ssize_t len;
|
||||
int i;
|
||||
char **argv;
|
||||
|
||||
@@ -630,126 +672,96 @@ static int uwsgi_cgi_run(struct wsgi_request *wsgi_req, char *docroot, size_t do
|
||||
close(cgi_pipe[1]);
|
||||
close(post_pipe[0]);
|
||||
|
||||
uwsgi_socket_nb(cgi_pipe[0]);
|
||||
uwsgi_socket_nb(post_pipe[1]);
|
||||
|
||||
// ok start sending post data...
|
||||
size_t remains = wsgi_req->post_cl;
|
||||
while(remains > 0) {
|
||||
ssize_t rlen = 0;
|
||||
char *buf = uwsgi_request_body_read(wsgi_req, 8192, &rlen);
|
||||
if (!buf) {
|
||||
close(post_pipe[1]);
|
||||
goto clear2;
|
||||
}
|
||||
if (buf == uwsgi.empty) break;
|
||||
// write data to the node
|
||||
if (uwsgi_write_true_nb(post_pipe[1], buf, rlen, uc.timeout)) {
|
||||
close(post_pipe[1]);
|
||||
goto clear2;
|
||||
}
|
||||
remains -= rlen;
|
||||
}
|
||||
|
||||
close(post_pipe[1]);
|
||||
// wait for data
|
||||
char *headers_buf = uwsgi_malloc(uc.buffer_size);
|
||||
char *ptr = headers_buf;
|
||||
remains = uc.buffer_size;
|
||||
int completed = 0;
|
||||
while(remains > 0) {
|
||||
int ret = uwsgi.wait_read_hook(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;
|
||||
}
|
||||
char *buf = uwsgi_malloc(uc.buffer_size);
|
||||
|
||||
if (uwsgi_cgi_parse(wsgi_req, headers_buf, uc.buffer_size-remains)) {
|
||||
uwsgi_log("invalid CGI output !!!\n");
|
||||
int completed = uwsgi_cgi_parse(wsgi_req, cgi_pipe[0], buf, uc.buffer_size);
|
||||
if (completed < 0) {
|
||||
uwsgi_log("invalid CGI response !!!\n");
|
||||
kill_on_error
|
||||
goto clear;
|
||||
}
|
||||
|
||||
while (!completed) {
|
||||
int ret = uwsgi.wait_read_hook(cgi_pipe[0], uc.timeout);
|
||||
if (ret > 0) {
|
||||
len = read(cgi_pipe[0], headers_buf, uc.buffer_size);
|
||||
if (len > 0) {
|
||||
uwsgi_response_write_body_do(wsgi_req, headers_buf, len);
|
||||
}
|
||||
// end of output
|
||||
else if (len == 0) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
uwsgi_error("read()");
|
||||
ssize_t rlen = uwsgi_read_true_nb(cgi_pipe[0], buf, uc.buffer_size, uc.timeout);
|
||||
if (rlen > 0) {
|
||||
if (uwsgi_response_write_body_do(wsgi_req, buf, rlen)) {
|
||||
kill_on_error
|
||||
goto clear;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if (ret == 0) {
|
||||
uwsgi_log("CGI timeout !!!\n");
|
||||
goto clear;
|
||||
}
|
||||
break;
|
||||
else if (rlen == 0) {
|
||||
uwsgi_log("CGI timeout !!!\n");
|
||||
kill_on_error
|
||||
goto clear;
|
||||
}
|
||||
else {
|
||||
if (errno) {
|
||||
uwsgi_req_error("error reading CGI response\n");
|
||||
kill_on_error
|
||||
}
|
||||
goto clear;
|
||||
}
|
||||
}
|
||||
|
||||
clear:
|
||||
free(headers_buf);
|
||||
free(buf);
|
||||
clear2:
|
||||
close(cgi_pipe[0]);
|
||||
close(post_pipe[1]);
|
||||
|
||||
// now wait for process exit/death
|
||||
if (waitpid(cgi_pid, &waitpid_status, 0) < 0) {
|
||||
uwsgi_error("waitpid()");
|
||||
// in async mode we need a trick...
|
||||
if (uwsgi.async > 1) {
|
||||
pid_t diedpid = waitpid(cgi_pid, &waitpid_status, WNOHANG);
|
||||
if (diedpid < 0) {
|
||||
uwsgi_error("waitpid()");
|
||||
}
|
||||
else if (diedpid == 0) {
|
||||
// pass the pid of the cgi to async_plagued (the after request hook will clear the process)
|
||||
wsgi_req->async_plagued = (int) cgi_pid;
|
||||
}
|
||||
}
|
||||
else {
|
||||
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 (post_pipe[0] == i) {
|
||||
continue;
|
||||
}
|
||||
if (wsgi_req->post_file) {
|
||||
if (fileno(wsgi_req->post_file) == i) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (i != wsgi_req->fd && i != 2 && i != cgi_pipe[1]) {
|
||||
close(i);
|
||||
}
|
||||
}
|
||||
|
||||
// now map wsgi_req->poll.fd (or async_post) to 0 & cgi_pipe[1] to 1
|
||||
if (post_pipe[0] != 0) {
|
||||
dup2(post_pipe[0], 0);
|
||||
close(post_pipe[0]);
|
||||
}
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("mapping cgi_pipe %d to 1\n", cgi_pipe[1]);
|
||||
#endif
|
||||
dup2(post_pipe[0], 0);
|
||||
close(post_pipe[0]);
|
||||
|
||||
dup2(cgi_pipe[1],1);
|
||||
|
||||
close(cgi_pipe[1]);
|
||||
|
||||
// close all the fd > 2
|
||||
for(i=3;i<(int)uwsgi.max_fd;i++) {
|
||||
close(i);
|
||||
}
|
||||
|
||||
// fill cgi env
|
||||
for(i=0;i<wsgi_req->var_cnt;i++) {
|
||||
// no need to free the putenv() memory
|
||||
@@ -913,6 +925,39 @@ clear2:
|
||||
|
||||
|
||||
static void uwsgi_cgi_after_request(struct wsgi_request *wsgi_req) {
|
||||
if (wsgi_req->async_plagued > 0) {
|
||||
int waitpid_status;
|
||||
pid_t cgi_pid = (pid_t) wsgi_req->async_plagued;
|
||||
int max_attempts = uc.async_max_attempts;
|
||||
if (!max_attempts) max_attempts = 10;
|
||||
while(max_attempts) {
|
||||
pid_t diedpid = waitpid(cgi_pid, &waitpid_status, WNOHANG);
|
||||
if (diedpid < 0) {
|
||||
uwsgi_error("waitpid()");
|
||||
break;
|
||||
}
|
||||
else if (diedpid == 0) {
|
||||
int ret = uwsgi.wait_milliseconds_hook(1000);
|
||||
if (ret < 0) {
|
||||
kill_on_error
|
||||
if (waitpid(cgi_pid, &waitpid_status, 0) < 0) {
|
||||
uwsgi_error("waitpid()");
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
max_attempts--;
|
||||
}
|
||||
if (max_attempts == 0) {
|
||||
kill_on_error
|
||||
if (waitpid(cgi_pid, &waitpid_status, 0) < 0) {
|
||||
uwsgi_error("waitpid()");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log_request(wsgi_req);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,18 +8,20 @@ struct uwsgi_geoip {
|
||||
char *city_db;
|
||||
GeoIP *country;
|
||||
GeoIP *city;
|
||||
int use_disk;
|
||||
|
||||
} ugeoip;
|
||||
|
||||
struct uwsgi_option uwsgi_geoip_options[] = {
|
||||
{"geoip-country", required_argument, 0, "load the specified geoip country database", uwsgi_opt_set_str, &ugeoip.country_db, 0},
|
||||
{"geoip-city", required_argument, 0, "load the specified geoip city database", uwsgi_opt_set_str, &ugeoip.city_db, 0},
|
||||
{ 0, 0, 0, 0, 0, 0, 0 }
|
||||
{"geoip-use-disk", no_argument, 0, "do not cache geoip databases in memory", uwsgi_opt_true, &ugeoip.use_disk, 0},
|
||||
UWSGI_END_OF_OPTIONS
|
||||
};
|
||||
|
||||
static int uwsgi_geoip_init() {
|
||||
if (ugeoip.country_db) {
|
||||
ugeoip.country = GeoIP_open(ugeoip.country_db, GEOIP_MEMORY_CACHE);
|
||||
ugeoip.country = GeoIP_open(ugeoip.country_db, ugeoip.use_disk ? GEOIP_STANDARD : GEOIP_MEMORY_CACHE);
|
||||
if (!ugeoip.country) {
|
||||
uwsgi_log("unable to open GeoIP country database: %s\n", ugeoip.country_db);
|
||||
exit(1);
|
||||
@@ -27,7 +29,7 @@ static int uwsgi_geoip_init() {
|
||||
}
|
||||
|
||||
if (ugeoip.city_db) {
|
||||
ugeoip.city = GeoIP_open(ugeoip.city_db, GEOIP_MEMORY_CACHE);
|
||||
ugeoip.city = GeoIP_open(ugeoip.city_db, ugeoip.use_disk ? GEOIP_STANDARD : GEOIP_MEMORY_CACHE);
|
||||
if (!ugeoip.city) {
|
||||
uwsgi_log("unable to open GeoIP city database: %s\n", ugeoip.city_db);
|
||||
exit(1);
|
||||
|
||||
@@ -28,7 +28,6 @@ static ssize_t uwsgi_pipe_logger(struct uwsgi_logger *ul, char *message, size_t
|
||||
}
|
||||
else {
|
||||
// child
|
||||
setsid();
|
||||
if (setsid() < 0) {
|
||||
uwsgi_error("setsid()");
|
||||
exit(1);
|
||||
|
||||
@@ -31,6 +31,9 @@ struct uwsgi_php {
|
||||
int dump_config;
|
||||
char *server_software;
|
||||
size_t server_software_len;
|
||||
|
||||
struct uwsgi_string_list *exec_before;
|
||||
struct uwsgi_string_list *exec_after;
|
||||
} uphp;
|
||||
|
||||
void uwsgi_opt_php_ini(char *opt, char *value, void *foobar) {
|
||||
@@ -59,8 +62,11 @@ struct uwsgi_option uwsgi_php_options[] = {
|
||||
#endif
|
||||
{"php-var", required_argument, 0, "add/overwrite a CGI variable at each request", uwsgi_opt_add_string_list, &uphp.vars, 0},
|
||||
{"php-dump-config", no_argument, 0, "dump php config (if modified via --php-set or append options)", uwsgi_opt_true, &uphp.dump_config, 0},
|
||||
{0, 0, 0, 0, 0, 0, 0},
|
||||
|
||||
{"php-exec-before", required_argument, 0, "run specified php code before the requested script", uwsgi_opt_add_string_list, &uphp.exec_before, 0},
|
||||
{"php-exec-begin", required_argument, 0, "run specified php code before the requested script", uwsgi_opt_add_string_list, &uphp.exec_before, 0},
|
||||
{"php-exec-after", required_argument, 0, "run specified php code after the requested script", uwsgi_opt_add_string_list, &uphp.exec_after, 0},
|
||||
{"php-exec-end", required_argument, 0, "run specified php code after the requested script", uwsgi_opt_add_string_list, &uphp.exec_after, 0},
|
||||
UWSGI_END_OF_OPTIONS
|
||||
};
|
||||
|
||||
|
||||
@@ -890,8 +896,19 @@ secure3:
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct uwsgi_string_list *usl=NULL;
|
||||
|
||||
uwsgi_foreach(usl, uphp.exec_before) {
|
||||
if (zend_eval_string_ex(usl->value, NULL, "uWSGI php exec before", 1 TSRMLS_CC) == FAILURE) goto end;
|
||||
}
|
||||
|
||||
php_execute_script(&file_handle TSRMLS_CC);
|
||||
|
||||
uwsgi_foreach(usl, uphp.exec_after) {
|
||||
if (zend_eval_string_ex(usl->value, NULL, "uWSGI php exec after", 1 TSRMLS_CC) == FAILURE) goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
php_request_shutdown(NULL);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -65,6 +65,8 @@ struct uwsgi_perl {
|
||||
int shell_oneshot;
|
||||
|
||||
CV *spooler;
|
||||
|
||||
int no_plack;
|
||||
};
|
||||
|
||||
void init_perl_embedded_module(void);
|
||||
|
||||
+46
-37
@@ -313,9 +313,6 @@ int init_psgi_app(struct wsgi_request *wsgi_req, char *app, uint16_t app_len, Pe
|
||||
|
||||
char *app_name = uwsgi_concat2n(app, app_len, "", 0);
|
||||
|
||||
size_t size;
|
||||
char *buf = uwsgi_open_and_read(app_name, &size, 1, NULL);
|
||||
|
||||
if (uwsgi_file_exists(app_name)) {
|
||||
// prepare for $0 (if the file is local)
|
||||
uperl.embedding[1] = app_name;
|
||||
@@ -368,38 +365,30 @@ int init_psgi_app(struct wsgi_request *wsgi_req, char *app, uint16_t app_len, Pe
|
||||
|
||||
uperl.tmp_current_i = i;
|
||||
|
||||
|
||||
if (uperl.locallib) {
|
||||
uwsgi_log("using %s as local::lib directory\n", uperl.locallib);
|
||||
uperl.embedding[1] = uwsgi_concat2("-Mlocal::lib=", uperl.locallib);
|
||||
uperl.embedding[2] = app_name;
|
||||
if (perl_parse(interpreters[i], xs_init, 3, uperl.embedding, NULL)) {
|
||||
// what to do here ? i hope no-one will use threads with dynamic apps... but clear the whole stuff...
|
||||
free(uperl.embedding[1]);
|
||||
uperl.embedding[1] = app_name;
|
||||
free(callables);
|
||||
uwsgi_perl_free_stashes();
|
||||
goto clear;
|
||||
}
|
||||
free(uperl.embedding[1]);
|
||||
uperl.embedding[1] = app_name;
|
||||
}
|
||||
else {
|
||||
if (perl_parse(interpreters[i], xs_init, 2, uperl.embedding, NULL)) {
|
||||
// We need to initialize the interpreter to execute
|
||||
// our xs_init hook, but we're *not* calling it with
|
||||
// uperl.embedding as an argument so we won't execute
|
||||
// BEGIN blocks in app_name twice.
|
||||
{
|
||||
char *perl_init_arg[] = { "", "-e", "0" };
|
||||
if (perl_parse(interpreters[i], xs_init, 3, perl_init_arg, NULL)) {
|
||||
// what to do here ? i hope no-one will use threads with dynamic apps... but clear the whole stuff...
|
||||
free(callables);
|
||||
uwsgi_perl_free_stashes();
|
||||
goto clear;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (uperl.locallib) {
|
||||
uwsgi_log("using %s as local::lib directory\n", uperl.locallib);
|
||||
char *local_lib_use = uwsgi_concat3("use local::lib qw(", uperl.locallib, ");");
|
||||
perl_eval_pv(local_lib_use, 1);
|
||||
free(local_lib_use);
|
||||
}
|
||||
perl_eval_pv("use IO::Handle;", 1);
|
||||
perl_eval_pv("use IO::File;", 1);
|
||||
perl_eval_pv("use IO::Socket;", 1);
|
||||
perl_eval_pv("use Scalar::Util;", 1);
|
||||
if (!uperl.no_die_catch) {
|
||||
perl_eval_pv("use Devel::StackTrace; $SIG{__DIE__} = sub { print Devel::StackTrace->new()->as_string() };", 0);
|
||||
}
|
||||
|
||||
if (uperl.argv_items || uperl.argv_item) {
|
||||
AV *uperl_argv = GvAV(PL_argvgv);
|
||||
@@ -417,12 +406,32 @@ int init_psgi_app(struct wsgi_request *wsgi_req, char *app, uint16_t app_len, Pe
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SV *dollar_zero = get_sv("0", GV_ADD);
|
||||
sv_setsv(dollar_zero, newSVpv(app, app_len));
|
||||
|
||||
callables[i] = perl_eval_pv(uwsgi_concat4("#line 1 ", app_name, "\n", buf), 0);
|
||||
if (!callables[i]) {
|
||||
SV *has_plack = NULL;
|
||||
if (!uperl.no_plack) {
|
||||
has_plack = perl_eval_pv("use Plack::Util;", 0);
|
||||
}
|
||||
|
||||
if (!has_plack || SvTRUE(ERRSV)) {
|
||||
if (!uperl.no_plack) {
|
||||
uwsgi_log("Plack::Util is not installed, using \"do\" instead of \"load_psgi\"\n");
|
||||
}
|
||||
char *code = uwsgi_concat3("my $app = do '", app_name, "'; if ( !$app && ( my $error = $@ || $! )) { die $error; }; $app");
|
||||
callables[i] = perl_eval_pv(code, 0);
|
||||
free(code);
|
||||
}
|
||||
else {
|
||||
char *code = uwsgi_concat3("Plack::Util::load_psgi '", app_name , "';");
|
||||
callables[i] = perl_eval_pv(code, 0);
|
||||
free(code);
|
||||
}
|
||||
|
||||
if (!callables[i] || SvTYPE(callables[i]) == SVt_NULL || SvTRUE(ERRSV)) {
|
||||
if (SvTRUE(ERRSV)) {
|
||||
uwsgi_log("%s", SvPV_nolen(ERRSV));
|
||||
}
|
||||
uwsgi_log("unable to find PSGI function entry point.\n");
|
||||
// what to do here ? i hope no-one will use threads with dynamic apps...
|
||||
free(callables);
|
||||
@@ -430,18 +439,16 @@ int init_psgi_app(struct wsgi_request *wsgi_req, char *app, uint16_t app_len, Pe
|
||||
goto clear;
|
||||
}
|
||||
|
||||
if (!uperl.no_die_catch) {
|
||||
perl_eval_pv("use Devel::StackTrace; $SIG{__DIE__} = sub { print Devel::StackTrace->new()->as_string() };", 0);
|
||||
if(SvTRUE(ERRSV)) {
|
||||
uwsgi_log("%s", SvPV_nolen(ERRSV));
|
||||
}
|
||||
}
|
||||
|
||||
PERL_SET_CONTEXT(interpreters[0]);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
|
||||
if(SvTRUE(ERRSV)) {
|
||||
uwsgi_log("%s", SvPV_nolen(ERRSV));
|
||||
free(callables);
|
||||
uwsgi_perl_free_stashes();
|
||||
goto clear;
|
||||
}
|
||||
|
||||
if (uwsgi_apps_cnt >= uwsgi.max_apps) {
|
||||
uwsgi_log("ERROR: you cannot load more than %d apps in a worker\n", uwsgi.max_apps);
|
||||
goto clear;
|
||||
@@ -504,6 +511,8 @@ void uwsgi_psgi_preinit_apps() {
|
||||
perl_parse(uperl.main[0], xs_init, 3, uperl.embedding, NULL);
|
||||
struct uwsgi_string_list *usl;
|
||||
uwsgi_foreach(usl, uperl.exec) {
|
||||
SV *dollar_zero = get_sv("0", GV_ADD);
|
||||
sv_setsv(dollar_zero, newSVpv(usl->value, usl->len));
|
||||
uwsgi_perl_exec(usl->value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,8 @@ struct uwsgi_option uwsgi_perl_options[] = {
|
||||
|
||||
{"plshell", optional_argument, 0, "run a perl interactive shell", uwsgi_opt_plshell, NULL, 0},
|
||||
{"plshell-oneshot", no_argument, 0, "run a perl interactive shell (one shot)", uwsgi_opt_plshell, NULL, 0},
|
||||
|
||||
{"perl-no-plack", no_argument, 0, "force the use of do instead of Plack::Util::load_psgi", uwsgi_opt_true, &uperl.no_plack, 0},
|
||||
{0, 0, 0, 0, 0, 0, 0},
|
||||
|
||||
};
|
||||
@@ -705,6 +707,8 @@ void uwsgi_perl_post_fork() {
|
||||
|
||||
struct uwsgi_string_list *usl;
|
||||
uwsgi_foreach(usl, uperl.exec_post_fork) {
|
||||
SV *dollar_zero = get_sv("0", GV_ADD);
|
||||
sv_setsv(dollar_zero, newSVpv(usl->value, usl->len));
|
||||
uwsgi_perl_exec(usl->value);
|
||||
}
|
||||
|
||||
|
||||
+22
-25
@@ -35,6 +35,7 @@ void (*u_pypy_thread_attach)(void);
|
||||
void (*u_pypy_init_threads)(void);
|
||||
|
||||
// the hooks you can override with pypy
|
||||
void (*uwsgi_pypy_hook_execute_source)(char *);
|
||||
void (*uwsgi_pypy_hook_loader)(char *);
|
||||
void (*uwsgi_pypy_hook_file_loader)(char *);
|
||||
void (*uwsgi_pypy_hook_paste_loader)(char *);
|
||||
@@ -186,23 +187,21 @@ ready:
|
||||
|
||||
static void uwsgi_pypy_preinit_apps() {
|
||||
|
||||
struct uwsgi_string_list *usl = upypy.eval;
|
||||
while(usl) {
|
||||
if (u_pypy_execute_source(usl->value)) {
|
||||
exit(1);
|
||||
}
|
||||
usl = usl->next;
|
||||
if (!uwsgi_pypy_hook_execute_source) {
|
||||
uwsgi_log("*** WARNING your pypy setup code does not expose a callback for \"execute_source\" ***\n");
|
||||
return;
|
||||
}
|
||||
|
||||
usl = upypy.exec;
|
||||
while(usl) {
|
||||
struct uwsgi_string_list *usl = NULL;
|
||||
uwsgi_foreach(usl, upypy.eval) {
|
||||
uwsgi_pypy_hook_execute_source(usl->value);
|
||||
}
|
||||
|
||||
uwsgi_foreach(usl, upypy.exec) {
|
||||
size_t rlen = 0;
|
||||
char *buffer = uwsgi_open_and_read(usl->value, &rlen, 1, NULL);
|
||||
if (u_pypy_execute_source(buffer)) {
|
||||
exit(1);
|
||||
}
|
||||
uwsgi_pypy_hook_execute_source(buffer);
|
||||
free(buffer);
|
||||
usl = usl->next;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -305,22 +304,15 @@ static uint64_t uwsgi_pypy_rpc(void *func, uint8_t argc, char **argv, uint16_t a
|
||||
|
||||
static void uwsgi_pypy_post_fork() {
|
||||
pthread_mutex_init(&upypy.attach_thread_lock, NULL);
|
||||
struct uwsgi_string_list *usl = upypy.eval_post_fork;
|
||||
while(usl) {
|
||||
if (u_pypy_execute_source(usl->value)) {
|
||||
exit(1);
|
||||
}
|
||||
usl = usl->next;
|
||||
struct uwsgi_string_list *usl = NULL;
|
||||
uwsgi_foreach(usl, upypy.eval_post_fork) {
|
||||
uwsgi_pypy_hook_execute_source(usl->value);
|
||||
}
|
||||
usl = upypy.exec_post_fork;
|
||||
while(usl) {
|
||||
uwsgi_foreach(usl, upypy.exec_post_fork) {
|
||||
size_t rlen = 0;
|
||||
char *buffer = uwsgi_open_and_read(usl->value, &rlen, 1, NULL);
|
||||
if (u_pypy_execute_source(buffer)) {
|
||||
exit(1);
|
||||
}
|
||||
uwsgi_pypy_hook_execute_source(buffer);
|
||||
free(buffer);
|
||||
usl = usl->next;
|
||||
}
|
||||
|
||||
if (uwsgi_pypy_post_fork_hook) {
|
||||
@@ -337,10 +329,15 @@ static void uwsgi_pypy_onload() {
|
||||
|
||||
static int uwsgi_pypy_mule(char *opt) {
|
||||
|
||||
if (!uwsgi_pypy_hook_execute_source) {
|
||||
uwsgi_log("!!! no \"execute_source\" callback in your pypy setup code !!!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (uwsgi_endswith(opt, ".py")) {
|
||||
size_t rlen = 0;
|
||||
char *buffer = uwsgi_open_and_read(opt, &rlen, 1, NULL);
|
||||
u_pypy_execute_source(buffer);
|
||||
uwsgi_pypy_hook_execute_source(buffer);
|
||||
free(buffer);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ ssize_t read(int, void *, size_t);
|
||||
ssize_t write(int, const void *, size_t);
|
||||
int close(int);
|
||||
|
||||
void (*uwsgi_pypy_hook_execute_source)(char *);
|
||||
void (*uwsgi_pypy_hook_loader)(char *);
|
||||
void (*uwsgi_pypy_hook_file_loader)(char *);
|
||||
void (*uwsgi_pypy_hook_paste_loader)(char *);
|
||||
@@ -277,6 +278,14 @@ wsgi_application = None
|
||||
if len(sys.argv) == 0:
|
||||
sys.argv.insert(0, ffi.string(lib.uwsgi_binary_path()))
|
||||
|
||||
"""
|
||||
execute source, we expose it as cffi callback to avoid deadlocks
|
||||
after GIL initialization
|
||||
"""
|
||||
@ffi.callback("void(char *)")
|
||||
def uwsgi_pypy_execute_source(s):
|
||||
source = ffi.string(s)
|
||||
exec(source)
|
||||
|
||||
"""
|
||||
load a wsgi module
|
||||
@@ -480,6 +489,7 @@ def uwsgi_pypy_wsgi_handler(wsgi_req):
|
||||
if hasattr(response, 'close'):
|
||||
response.close()
|
||||
|
||||
lib.uwsgi_pypy_hook_execute_source = uwsgi_pypy_execute_source
|
||||
lib.uwsgi_pypy_hook_loader = uwsgi_pypy_loader
|
||||
lib.uwsgi_pypy_hook_file_loader = uwsgi_pypy_file_loader
|
||||
lib.uwsgi_pypy_hook_paste_loader = uwsgi_pypy_paste_loader
|
||||
|
||||
@@ -21,12 +21,13 @@ int uwsgi_python_send_body(struct wsgi_request *wsgi_req, PyObject *chunk) {
|
||||
char *content = NULL;
|
||||
size_t content_len = 0;
|
||||
|
||||
if (!up.wsgi_accept_buffer && !wsgi_req->is_raw) goto strict;
|
||||
#if defined(PYTHREE) || defined(Py_TPFLAGS_HAVE_NEWBUFFER)
|
||||
Py_buffer pbuf;
|
||||
int has_buffer = 0;
|
||||
#endif
|
||||
|
||||
if (!up.wsgi_accept_buffer && !wsgi_req->is_raw) goto strict;
|
||||
|
||||
#if defined(PYTHREE) || defined(Py_TPFLAGS_HAVE_NEWBUFFER)
|
||||
if (PyObject_CheckBuffer(chunk)) {
|
||||
if (!PyObject_GetBuffer(chunk, &pbuf, PyBUF_SIMPLE)) {
|
||||
|
||||
@@ -13,6 +13,26 @@ pthread_mutex_t ur_basicauth_crypt_mutex;
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
static char *htpasswd_check_sha1(char *pwd) {
|
||||
#ifdef UWSGI_SSL
|
||||
char sha1[20];
|
||||
uwsgi_sha1(pwd, strlen(pwd), sha1);
|
||||
|
||||
size_t len = 0;
|
||||
char *b64 = uwsgi_base64_encode(sha1, 20, &len);
|
||||
if (!b64) return NULL;
|
||||
|
||||
// we add a new line for being fgets-friendly
|
||||
char *crypted = uwsgi_concat3n("{SHA}", 5, b64, len, "\n", 1);
|
||||
free(b64);
|
||||
return crypted;
|
||||
|
||||
#else
|
||||
uwsgi_log("*** WARNING, rebuild uWSGI with SSL support for htpasswd sha1 feature ***\n");
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
static uint16_t htpasswd_check(char *filename, char *auth) {
|
||||
|
||||
char line[1024];
|
||||
@@ -25,11 +45,23 @@ static uint16_t htpasswd_check(char *filename, char *auth) {
|
||||
return 0;
|
||||
}
|
||||
while(fgets(line, 1024, htpasswd)) {
|
||||
char *crypted = NULL;
|
||||
int need_free = 0;
|
||||
char *colon2 = strchr(line, ':');
|
||||
if (!colon2) break;
|
||||
|
||||
char *cpwd = colon2+1;
|
||||
size_t clen = strlen(cpwd);
|
||||
|
||||
// now we check which algo to use
|
||||
// {SHA} ?
|
||||
if (!uwsgi_starts_with(cpwd, clen, "{SHA}", 5)) {
|
||||
crypted = htpasswd_check_sha1(colon+1);
|
||||
if (crypted) need_free = 1;
|
||||
goto check;
|
||||
}
|
||||
|
||||
|
||||
if (clen < 13) break;
|
||||
|
||||
if (clen > 13) cpwd[13] = 0;
|
||||
@@ -39,20 +71,24 @@ static uint16_t htpasswd_check(char *filename, char *auth) {
|
||||
cd.initialized = 0;
|
||||
// we do as nginx here
|
||||
cd.current_salt[0] = ~cpwd[0];
|
||||
char *crypted = crypt_r( colon+1, cpwd, &cd);
|
||||
crypted = crypt_r( colon+1, cpwd, &cd);
|
||||
#else
|
||||
if (uwsgi.threads > 1) pthread_mutex_lock(&ur_basicauth_crypt_mutex);
|
||||
char *crypted = crypt( colon+1, cpwd);
|
||||
crypted = crypt( colon+1, cpwd);
|
||||
if (uwsgi.threads > 1) pthread_mutex_unlock(&ur_basicauth_crypt_mutex);
|
||||
#endif
|
||||
check:
|
||||
if (!crypted) continue;
|
||||
|
||||
if (!strcmp( crypted, cpwd )) {
|
||||
if (!uwsgi_strncmp(auth, colon-auth, line, colon2-line)) {
|
||||
fclose(htpasswd);
|
||||
if (need_free) free(crypted);
|
||||
return colon-auth;
|
||||
}
|
||||
}
|
||||
|
||||
if (need_free) free(crypted);
|
||||
}
|
||||
|
||||
fclose(htpasswd);
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
#include "../../uwsgi.h"
|
||||
#include <uwsgi.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
/* request 110 */
|
||||
int uwsgi_request_signal(struct wsgi_request *wsgi_req) {
|
||||
|
||||
ssize_t len;
|
||||
uint8_t ret_status = 1;
|
||||
|
||||
struct uwsgi_header uh;
|
||||
if (uwsgi_signal_send(uwsgi.signal_socket, wsgi_req->uh->modifier2) < 0) {
|
||||
ret_status = 0;
|
||||
@@ -15,10 +15,11 @@ int uwsgi_request_signal(struct wsgi_request *wsgi_req) {
|
||||
uh.modifier1 = 255;
|
||||
uh.pktsize = 0;
|
||||
uh.modifier2 = ret_status;
|
||||
len = write(wsgi_req->fd, &uh, 4);
|
||||
if (len != 4) {
|
||||
uwsgi_error("write()");
|
||||
|
||||
if (uwsgi_response_write_body_do(wsgi_req, (char *) &uh, 4)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
[uwsgi]
|
||||
socket = /tmp/foo
|
||||
|
||||
cache2 = name=items_1,blocks=4,items=2,bitmap=1,blocksize=1
|
||||
cache2 = name=items_2,blocks=4,items=3,bitmap=1,blocksize=1
|
||||
cache2 = name=items_3,blocks=4,items=4,bitmap=1,blocksize=1
|
||||
cache2 = name=items_4,blocks=5,items=5,bitmap=1,blocksize=1
|
||||
cache2 = name=items_17,blocks=17,items=17,bitmap=1,blocksize=1
|
||||
cache2 = name=items_4_10,blocks=5,items=5,bitmap=1,blocksize=10
|
||||
cache2 = name=items_1_100000,blocks=1000,items=2,bitmap=1,blocksize=100
|
||||
cache2 = name=items_non_bitmap,items=2,blocksize=20
|
||||
pyrun = t/cachebitmap.py
|
||||
@@ -0,0 +1,106 @@
|
||||
import uwsgi
|
||||
import unittest
|
||||
import random
|
||||
import string
|
||||
|
||||
class BitmapTest(unittest.TestCase):
|
||||
|
||||
__caches__ = ['items_1', 'items_2', 'items_3', 'items_4', 'items_17', 'items_4_10', 'items_1_100000', 'items_non_bitmap']
|
||||
|
||||
def setUp(self):
|
||||
for cache in self.__caches__:
|
||||
uwsgi.cache_clear(cache)
|
||||
|
||||
def test_failed_by_one(self):
|
||||
self.assertIsNone(uwsgi.cache_update('key1', 'HELLO', 0, 'items_1'))
|
||||
|
||||
def test_ok_four_bytes(self):
|
||||
self.assertTrue(uwsgi.cache_update('key1', 'HELL', 0, 'items_1'))
|
||||
|
||||
def test_two_items_using_four_blocks(self):
|
||||
self.assertTrue(uwsgi.cache_update('key1', 'HE', 0, 'items_2'))
|
||||
self.assertTrue(uwsgi.cache_update('key2', 'LL', 0, 'items_2'))
|
||||
self.assertTrue(uwsgi.cache_del('key1', 'items_2'))
|
||||
self.assertIsNone(uwsgi.cache_update('key1', 'HEL', 0, 'items_2'))
|
||||
self.assertTrue(uwsgi.cache_update('key1', 'HE', 0, 'items_2'))
|
||||
|
||||
def test_overlapping(self):
|
||||
self.assertTrue(uwsgi.cache_update('key1', 'HE', 0, 'items_2'))
|
||||
self.assertIsNone(uwsgi.cache_update('key1', 'HELL', 0, 'items_2'))
|
||||
self.assertTrue(uwsgi.cache_del('key1', 'items_2'))
|
||||
self.assertTrue(uwsgi.cache_update('key1', 'HELL', 0, 'items_2'))
|
||||
|
||||
def test_big_item(self):
|
||||
self.assertIsNone(uwsgi.cache_update('key1', 'HELLOHELLOHELLOHEL', 0, 'items_17'))
|
||||
self.assertTrue(uwsgi.cache_update('key1', 'HELLOHELLOHELLOHE', 0, 'items_17'))
|
||||
|
||||
def test_set(self):
|
||||
self.assertTrue(uwsgi.cache_set('key1', 'HELLO', 0, 'items_17'))
|
||||
self.assertIsNone(uwsgi.cache_set('key1', 'HELLO', 0, 'items_17'))
|
||||
self.assertTrue(uwsgi.cache_del('key1', 'items_17'))
|
||||
self.assertTrue(uwsgi.cache_set('key1', 'HELLO', 0, 'items_17'))
|
||||
self.assertIsNone(uwsgi.cache_set('key1', 'HELLO', 0, 'items_17'))
|
||||
|
||||
def test_too_much_items(self):
|
||||
self.assertTrue(uwsgi.cache_set('key1', 'HELLO', 0, 'items_4_10'))
|
||||
self.assertTrue(uwsgi.cache_set('key2', 'HELLO', 0, 'items_4_10'))
|
||||
self.assertTrue(uwsgi.cache_set('key3', 'HELLO', 0, 'items_4_10'))
|
||||
self.assertTrue(uwsgi.cache_set('key4', 'HELLO', 0, 'items_4_10'))
|
||||
self.assertIsNone(uwsgi.cache_set('key5', 'HELLO', 0, 'items_4_10'))
|
||||
|
||||
def test_big_delete(self):
|
||||
self.assertTrue(uwsgi.cache_set('key1', 'X' * 50 , 0, 'items_4_10'))
|
||||
self.assertTrue(uwsgi.cache_del('key1', 'items_4_10'))
|
||||
self.assertTrue(uwsgi.cache_set('key1', 'HELLOHELLO', 0, 'items_4_10'))
|
||||
self.assertTrue(uwsgi.cache_set('key2', 'HELLOHELLO', 0, 'items_4_10'))
|
||||
self.assertTrue(uwsgi.cache_set('key3', 'HELLOHELLO', 0, 'items_4_10'))
|
||||
self.assertTrue(uwsgi.cache_set('key4', 'HELLOHELLO', 0, 'items_4_10'))
|
||||
self.assertIsNone(uwsgi.cache_set('key5', 'HELLOHELLO', 0, 'items_4_10'))
|
||||
|
||||
def test_big_update(self):
|
||||
self.assertTrue(uwsgi.cache_set('key1', 'X' * 40 , 0, 'items_4_10'))
|
||||
self.assertTrue(uwsgi.cache_update('key1', 'X' * 10 , 0, 'items_4_10'))
|
||||
self.assertTrue(uwsgi.cache_del('key1', 'items_4_10'))
|
||||
self.assertIsNone(uwsgi.cache_update('key1', 'X' * 51 , 0, 'items_4_10'))
|
||||
self.assertTrue(uwsgi.cache_update('key1', 'X' * 50 , 0, 'items_4_10'))
|
||||
|
||||
def test_multi_clear(self):
|
||||
for i in range(0, 100):
|
||||
self.assertTrue(uwsgi.cache_clear('items_4_10'))
|
||||
|
||||
def test_multi_delete(self):
|
||||
for i in range(0, 100):
|
||||
self.assertTrue(uwsgi.cache_set('key1', 'X' * 50 , 0, 'items_4_10'))
|
||||
self.assertTrue(uwsgi.cache_del('key1', 'items_4_10'))
|
||||
|
||||
for i in range(0, 100):
|
||||
self.assertIsNone(uwsgi.cache_set('key1', 'X' * 51 , 0, 'items_4_10'))
|
||||
self.assertIsNone(uwsgi.cache_del('key1', 'items_4_10'))
|
||||
|
||||
for i in range(0, 100):
|
||||
self.assertTrue(uwsgi.cache_set('key1', 'X' * 50 , 0, 'items_4_10'))
|
||||
self.assertTrue(uwsgi.cache_del('key1', 'items_4_10'))
|
||||
|
||||
def test_big_key(self):
|
||||
self.assertTrue(uwsgi.cache_set('K' * 2048, 'X' * 50 , 0, 'items_4_10'))
|
||||
self.assertIsNone(uwsgi.cache_set('K' * 2049, 'X' * 50 , 0, 'items_4_10'))
|
||||
|
||||
def rand_blob(self, n=32):
|
||||
return ''.join([random.choice(string.ascii_letters + string.digits) for n in range(n)])
|
||||
|
||||
def test_big_random(self):
|
||||
blob = self.rand_blob(100000)
|
||||
self.assertTrue(uwsgi.cache_set('KEY', blob, 0, 'items_1_100000'))
|
||||
get_blob = uwsgi.cache_get('KEY', 'items_1_100000')
|
||||
self.assertEqual(blob, get_blob)
|
||||
self.assertTrue(uwsgi.cache_del('KEY', 'items_1_100000'))
|
||||
self.assertIsNone(uwsgi.cache_set('KEY', 'X' * 100001, 0, 'items_1_100000'))
|
||||
self.assertTrue(uwsgi.cache_set('KEY', 'X' * 10000, 0, 'items_1_100000'))
|
||||
|
||||
def test_non_bitmap(self):
|
||||
self.assertTrue(uwsgi.cache_set('KEY', 'X' * 20, 0, 'items_non_bitmap'))
|
||||
self.assertTrue(uwsgi.cache_del('KEY', 'items_non_bitmap'))
|
||||
self.assertIsNone(uwsgi.cache_set('KEY', 'X' * 21, 0, 'items_non_bitmap'))
|
||||
self.assertTrue(uwsgi.cache_set('KEY', 'X' * 20, 0, 'items_non_bitmap'))
|
||||
|
||||
unittest.main()
|
||||
@@ -1,5 +1,9 @@
|
||||
use strict;
|
||||
use warnings;
|
||||
BEGIN {
|
||||
die "PANIC: We should only load this once" if ++$main::count_BEGIN > 1;
|
||||
}
|
||||
die "PANIC: We should only run this once" if ++$main::count_runs > 1;
|
||||
|
||||
uwsgi::register_rpc('hello', sub {
|
||||
my ($one, $two, $three) = @_;
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ Gem::Specification.new do |s|
|
||||
s.name = 'uwsgi'
|
||||
s.license = 'GPL-2'
|
||||
s.version = `python -c "import uwsgiconfig as uc; print uc.uwsgi_version"`.sub(/-dev-.*/,'')
|
||||
s.date = '2014-02-09'
|
||||
s.date = '2014-02-26'
|
||||
s.summary = "uWSGI"
|
||||
s.description = "The uWSGI server for Ruby/Rack"
|
||||
s.authors = ["Unbit"]
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
# uWSGI build system
|
||||
|
||||
uwsgi_version = '2.0.1'
|
||||
uwsgi_version = '2.0.2'
|
||||
|
||||
import os
|
||||
import re
|
||||
|
||||
Reference in New Issue
Block a user