mirror of
https://github.com/clearlinux/uwsgi.git
synced 2026-10-04 16:08:31 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e4a4942980 | ||
|
|
6f671936fc | ||
|
|
7d1d992d58 | ||
|
|
930f71c562 | ||
|
|
959bb11f77 | ||
|
|
13d8505738 | ||
|
|
93fe463ca8 | ||
|
|
5c64c21745 | ||
|
|
f825ab542d | ||
|
|
e744aef144 | ||
|
|
4ded485a8e | ||
|
|
2ce5ec3986 | ||
|
|
af95f90fb0 | ||
|
|
7989dc748b | ||
|
|
f85f3e8178 | ||
|
|
97809192c8 | ||
|
|
5f74e6d964 | ||
|
|
ae87fdd0f7 | ||
|
|
36c44c83af | ||
|
|
48e13bfc65 | ||
|
|
16cd55637d | ||
|
|
39cf2887c4 | ||
|
|
671bf8a258 | ||
|
|
89a8ceea81 | ||
|
|
6699f4046e | ||
|
|
88474b3d96 | ||
|
|
32b6463d06 | ||
|
|
63cc29a61d | ||
|
|
d58f79eeab | ||
|
|
7b24d2f5de | ||
|
|
a93db73d0c | ||
|
|
c118c75bfe | ||
|
|
624631d443 | ||
|
|
b681eab385 | ||
|
|
91dfe779ff | ||
|
|
0ad50711c0 | ||
|
|
df6ed26479 | ||
|
|
d08778b39c | ||
|
|
0c8c2932cf | ||
|
|
131bd7da2f | ||
|
|
d247424442 | ||
|
|
332fab2150 | ||
|
|
62d74951db | ||
|
|
839638a0ad | ||
|
|
536ae8d013 | ||
|
|
367c4b9bab | ||
|
|
3965c01880 | ||
|
|
7e4341a7cd | ||
|
|
8c118c8f62 | ||
|
|
5d76b63fac | ||
|
|
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 |
@@ -7,6 +7,7 @@
|
||||
|
||||
/uwsgi
|
||||
/uwsgibuild.*
|
||||
/core/config_py.c
|
||||
|
||||
/t/ring/target
|
||||
|
||||
|
||||
@@ -25,3 +25,5 @@ Mingli Yuan
|
||||
Natanael Copa
|
||||
Roberto Leandrini
|
||||
Ryan Petrello
|
||||
Danila Shtan <danila@shtan.ru>
|
||||
Ævar Arnfjörð Bjarmason
|
||||
|
||||
+4
-4
@@ -18,18 +18,18 @@ void uwsgi_alarm_init_log(struct uwsgi_alarm_instance *uai) {
|
||||
void uwsgi_alarm_func_log(struct uwsgi_alarm_instance *uai, char *msg, size_t len) {
|
||||
if (msg[len-1] != '\n') {
|
||||
if (uai->arg && strlen(uai->arg) > 0) {
|
||||
uwsgi_log_alarm("] %s %.*s\n", uai->arg, len, msg);
|
||||
uwsgi_log_verbose("ALARM: %s %.*s\n", uai->arg, len, msg);
|
||||
}
|
||||
else {
|
||||
uwsgi_log_alarm("] %.*s\n", len, msg);
|
||||
uwsgi_log_verbose("ALARM: %.*s\n", len, msg);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (uai->arg && strlen(uai->arg) > 0) {
|
||||
uwsgi_log_alarm("] %s %.*s", uai->arg, len, msg);
|
||||
uwsgi_log_verbose("ALARM: %s %.*s", uai->arg, len, msg);
|
||||
}
|
||||
else {
|
||||
uwsgi_log_alarm("] %.*s", len, msg);
|
||||
uwsgi_log_verbose("ALARM: %.*s", len, msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
+140
-38
@@ -39,6 +39,70 @@ struct uwsgi_emperor_blacklist_item {
|
||||
|
||||
struct uwsgi_emperor_blacklist_item *emperor_blacklist;
|
||||
|
||||
/*
|
||||
this should be placed in core/socket.c but we realized it was needed
|
||||
only after 2.0 so we cannot change uwsgi.h
|
||||
|
||||
basically it is a stripped down bind_to_tcp/bind_to_unix with rollback
|
||||
*/
|
||||
static int on_demand_bind(char *socket_name) {
|
||||
union uwsgi_sockaddr us;
|
||||
socklen_t addr_len = sizeof(struct sockaddr_un);
|
||||
char *is_tcp = strchr(socket_name, ':');
|
||||
int af_family = is_tcp ? AF_INET : AF_UNIX;
|
||||
int fd = socket(af_family, SOCK_STREAM, 0);
|
||||
if (fd < 0) return -1;
|
||||
|
||||
memset(&us, 0, sizeof(union uwsgi_sockaddr));
|
||||
|
||||
if (is_tcp) {
|
||||
int reuse = 1;
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void *) &reuse, sizeof(int)) < 0) {
|
||||
goto error;
|
||||
}
|
||||
us.sa_in.sin_family = AF_INET;
|
||||
us.sa_in.sin_port = htons(atoi(is_tcp+1));
|
||||
*is_tcp = 0;
|
||||
if (socket_name[0] != 0) {
|
||||
us.sa_in.sin_addr.s_addr = inet_addr(socket_name);
|
||||
}
|
||||
else {
|
||||
us.sa_in.sin_addr.s_addr = INADDR_ANY;
|
||||
}
|
||||
*is_tcp = ':';
|
||||
addr_len = sizeof(struct sockaddr_in);
|
||||
}
|
||||
else {
|
||||
if (unlink(socket_name) != 0 && errno != ENOENT) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
us.sa_un.sun_family = AF_UNIX;
|
||||
memcpy(us.sa_un.sun_path, socket_name, UMIN(strlen(socket_name), 102));
|
||||
addr_len = strlen(socket_name) + ((void *) us.sa_un.sun_path - (void *) &us.sa_un);
|
||||
}
|
||||
|
||||
if (bind(fd, (struct sockaddr *) &us, addr_len) != 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!is_tcp) {
|
||||
if (chmod(socket_name, 0666)) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (listen(fd, uwsgi.listen_queue) != 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
return fd;
|
||||
|
||||
error:
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct uwsgi_emperor_blacklist_item *uwsgi_emperor_blacklist_check(char *id) {
|
||||
struct uwsgi_emperor_blacklist_item *uebi = emperor_blacklist;
|
||||
while (uebi) {
|
||||
@@ -157,7 +221,7 @@ static char *emperor_check_on_demand_socket(char *filename) {
|
||||
if (fd < 0) return NULL;
|
||||
char *ret = uwsgi_read_fd(fd, &len, 1);
|
||||
close(fd);
|
||||
// change the first non prinabel character to 0
|
||||
// change the first non printable character to 0
|
||||
size_t i;
|
||||
for(i=0;i<len;i++) {
|
||||
if (ret[i] < 32) {
|
||||
@@ -629,6 +693,10 @@ void emperor_del(struct uwsgi_instance *c_ui) {
|
||||
free(c_ui->socket_name);
|
||||
}
|
||||
|
||||
if (c_ui->on_demand_fd != -1) {
|
||||
close(c_ui->on_demand_fd);
|
||||
}
|
||||
|
||||
free(c_ui);
|
||||
|
||||
}
|
||||
@@ -637,8 +705,10 @@ void emperor_stop(struct uwsgi_instance *c_ui) {
|
||||
if (c_ui->status == 1) return;
|
||||
// remove uWSGI instance
|
||||
|
||||
if (write(c_ui->pipe[0], "\0", 1) != 1) {
|
||||
uwsgi_error("emperor_stop()/write()");
|
||||
if (c_ui->pid != -1) {
|
||||
if (write(c_ui->pipe[0], "\0", 1) != 1) {
|
||||
uwsgi_error("emperor_stop()/write()");
|
||||
}
|
||||
}
|
||||
|
||||
c_ui->status = 1;
|
||||
@@ -658,10 +728,27 @@ void emperor_curse(struct uwsgi_instance *c_ui) {
|
||||
|
||||
}
|
||||
|
||||
// send configuration (if required to the vassal)
|
||||
static void emperor_push_config(struct uwsgi_instance *c_ui) {
|
||||
struct uwsgi_header uh;
|
||||
|
||||
if (c_ui->use_config) {
|
||||
uh.modifier1 = 115;
|
||||
uh.pktsize = c_ui->config_len;
|
||||
uh.modifier2 = 0;
|
||||
if (write(c_ui->pipe_config[0], &uh, 4) != 4) {
|
||||
uwsgi_error("[uwsgi-emperor] write() header config");
|
||||
}
|
||||
else {
|
||||
if (write(c_ui->pipe_config[0], c_ui->config, c_ui->config_len) != (long) c_ui->config_len) {
|
||||
uwsgi_error("[uwsgi-emperor] write() config");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void emperor_respawn(struct uwsgi_instance *c_ui, time_t mod) {
|
||||
|
||||
struct uwsgi_header uh;
|
||||
|
||||
// reload the uWSGI instance
|
||||
if (write(c_ui->pipe[0], "\1", 1) != 1) {
|
||||
@@ -669,20 +756,7 @@ void emperor_respawn(struct uwsgi_instance *c_ui, time_t mod) {
|
||||
}
|
||||
|
||||
// push the config to the config pipe (if needed)
|
||||
if (c_ui->use_config) {
|
||||
uh.modifier1 = 115;
|
||||
uh.pktsize = c_ui->config_len;
|
||||
uh.modifier2 = 0;
|
||||
if (write(c_ui->pipe_config[0], &uh, 4) != 4) {
|
||||
uwsgi_error("[uwsgi-emperor] write() header config");
|
||||
}
|
||||
else {
|
||||
if (write(c_ui->pipe_config[0], c_ui->config, c_ui->config_len) != (long) c_ui->config_len) {
|
||||
uwsgi_error("[uwsgi-emperor] write() config");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
emperor_push_config(c_ui);
|
||||
|
||||
c_ui->respawns++;
|
||||
c_ui->last_mod = mod;
|
||||
@@ -794,21 +868,12 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha
|
||||
}
|
||||
|
||||
n_ui->pid = -1;
|
||||
n_ui->pipe[0] = -1;
|
||||
n_ui->pipe[1] = -1;
|
||||
|
||||
// ok here we check if we need to bind to the specified socket or continue with the activation
|
||||
if (socket_name) {
|
||||
char *tcp_port = strchr(socket_name, ':');
|
||||
if (tcp_port) {
|
||||
// disable deferred accept for this socket
|
||||
int current_defer_accept = uwsgi.no_defer_accept;
|
||||
uwsgi.no_defer_accept = 1;
|
||||
n_ui->on_demand_fd = bind_to_tcp(socket_name, uwsgi.listen_queue, tcp_port);
|
||||
uwsgi.no_defer_accept = current_defer_accept;
|
||||
}
|
||||
else {
|
||||
n_ui->on_demand_fd = bind_to_unix(socket_name, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket);
|
||||
}
|
||||
|
||||
n_ui->on_demand_fd = on_demand_bind(socket_name);
|
||||
if (n_ui->on_demand_fd < 0) {
|
||||
uwsgi_error("emperor_add()/bind()");
|
||||
free(n_ui);
|
||||
@@ -838,6 +903,7 @@ int uwsgi_emperor_vassal_start(struct uwsgi_instance *n_ui) {
|
||||
uwsgi_error("socketpair()");
|
||||
return -1;
|
||||
}
|
||||
uwsgi_socket_nb(n_ui->pipe[0]);
|
||||
|
||||
event_queue_add_fd_read(uwsgi.emperor_queue, n_ui->pipe[0]);
|
||||
|
||||
@@ -846,6 +912,7 @@ int uwsgi_emperor_vassal_start(struct uwsgi_instance *n_ui) {
|
||||
uwsgi_error("socketpair()");
|
||||
return -1;
|
||||
}
|
||||
uwsgi_socket_nb(n_ui->pipe_config[0]);
|
||||
}
|
||||
|
||||
if (n_ui->zerg) {
|
||||
@@ -1452,6 +1519,17 @@ int uwsgi_emperor_scanner_event(int fd) {
|
||||
|
||||
}
|
||||
|
||||
static void emperor_wakeup(int sn) {}
|
||||
|
||||
static void emperor_cleanup() {
|
||||
uwsgi_log_verbose("[uwsgi-emperor] cleaning up blacklist ...\n");
|
||||
struct uwsgi_instance *ui_current = ui;
|
||||
while (ui_current->ui_next) {
|
||||
uwsgi_emperor_blacklist_remove(ui_current->name);
|
||||
ui_current = ui_current->ui_next;
|
||||
}
|
||||
}
|
||||
|
||||
void emperor_loop() {
|
||||
|
||||
// monitor a directory
|
||||
@@ -1480,11 +1558,13 @@ void emperor_loop() {
|
||||
}
|
||||
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
signal(SIGWINCH, emperor_wakeup);
|
||||
uwsgi_unix_signal(SIGINT, royal_death);
|
||||
uwsgi_unix_signal(SIGTERM, royal_death);
|
||||
uwsgi_unix_signal(SIGQUIT, royal_death);
|
||||
uwsgi_unix_signal(SIGUSR1, emperor_stats);
|
||||
uwsgi_unix_signal(SIGHUP, emperor_massive_reload);
|
||||
uwsgi_unix_signal(SIGURG, emperor_cleanup);
|
||||
|
||||
memset(&ui_base, 0, sizeof(struct uwsgi_instance));
|
||||
|
||||
@@ -1552,7 +1632,11 @@ void emperor_loop() {
|
||||
ui_current = ui->ui_next;
|
||||
while (ui_current) {
|
||||
uwsgi_log_verbose("[emperor] NO MERCY for vassal %s !!!\n", ui_current->name);
|
||||
kill(ui_current->pid, SIGKILL);
|
||||
if (kill(ui_current->pid, SIGKILL) < 0) {
|
||||
uwsgi_error("[emperor] kill()");
|
||||
emperor_del(ui_current);
|
||||
break;
|
||||
}
|
||||
ui_current = ui_current->ui_next;
|
||||
}
|
||||
break;
|
||||
@@ -1635,6 +1719,9 @@ void emperor_loop() {
|
||||
ui_current->last_ready = uwsgi_now();
|
||||
uwsgi_log_verbose("[emperor] vassal %s has been spawned\n", ui_current->name);
|
||||
}
|
||||
else if (byte == 2) {
|
||||
emperor_push_config(ui_current);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -1667,8 +1754,10 @@ void emperor_loop() {
|
||||
// set last_heartbeat to 0 avoiding races
|
||||
ui_current->last_heartbeat = 0;
|
||||
if (ui_current->pid > 0) {
|
||||
if (kill(ui_current->pid, SIGKILL)) {
|
||||
if (kill(ui_current->pid, SIGKILL) < 0) {
|
||||
uwsgi_error("[emperor] kill()");
|
||||
emperor_del(ui_current);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1676,6 +1765,8 @@ void emperor_loop() {
|
||||
ui_current = ui_current->ui_next;
|
||||
}
|
||||
|
||||
|
||||
recheck:
|
||||
// check for removed instances
|
||||
ui_current = ui;
|
||||
has_children = 0;
|
||||
@@ -1720,7 +1811,7 @@ void emperor_loop() {
|
||||
while (ui_current->ui_next) {
|
||||
ui_current = ui_current->ui_next;
|
||||
time_t now = uwsgi_now();
|
||||
if (ui_current->pid == diedpid) {
|
||||
if (diedpid > 0 && ui_current->pid == diedpid) {
|
||||
if (ui_current->status == 0) {
|
||||
// respawn an accidentally dead instance if its exit code is not UWSGI_EXILE_CODE
|
||||
if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_EXILE_CODE) {
|
||||
@@ -1743,15 +1834,26 @@ void emperor_loop() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (ui_current->cursed_at > 0 && now - ui_current->cursed_at >= uwsgi.emperor_curse_tolerance) {
|
||||
ui_current->cursed_at = now;
|
||||
if (kill(ui_current->pid, SIGKILL)) {
|
||||
uwsgi_error("[emperor] kill");
|
||||
else if (ui_current->cursed_at > 0) {
|
||||
if (ui_current->pid == -1) {
|
||||
emperor_del(ui_current);
|
||||
break;
|
||||
}
|
||||
else if (now - ui_current->cursed_at >= uwsgi.emperor_curse_tolerance) {
|
||||
ui_current->cursed_at = now;
|
||||
if (kill(ui_current->pid, SIGKILL) < 0) {
|
||||
uwsgi_error("[emperor] kill()");
|
||||
// delete the vassal, something is seriously wrong better to not leak memory...
|
||||
emperor_del(ui_current);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if waitpid returned an item, let's check for another (potential) one
|
||||
if (diedpid > 0) goto recheck;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -48,6 +48,14 @@ static void subscriptions_blocker() {
|
||||
}
|
||||
}
|
||||
|
||||
static void emperor_rescan() {
|
||||
if (uwsgi.emperor_pid > 0) {
|
||||
if (kill(uwsgi.emperor_pid, SIGWINCH)) {
|
||||
uwsgi_error("emperor_rescan()/kill()");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
this is called as soon as possibile allowing plugins (or hooks) to override it
|
||||
@@ -74,6 +82,7 @@ void uwsgi_master_fifo_prepare() {
|
||||
uwsgi_fifo_table['+'] = uwsgi_cheaper_increase;
|
||||
uwsgi_fifo_table['c'] = uwsgi_chain_reload;
|
||||
uwsgi_fifo_table['C'] = uwsgi_go_cheap;
|
||||
uwsgi_fifo_table['E'] = emperor_rescan;
|
||||
uwsgi_fifo_table['f'] = uwsgi_refork_master;
|
||||
uwsgi_fifo_table['l'] = uwsgi_log_reopen;
|
||||
uwsgi_fifo_table['L'] = uwsgi_log_rotate;
|
||||
|
||||
@@ -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);
|
||||
|
||||
+32
-10
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -399,9 +412,17 @@ void uwsgi_reload(char **argv) {
|
||||
uwsgi_log("fork()'ing uWSGI...\n");
|
||||
}
|
||||
|
||||
// ask for configuration (if needed)
|
||||
if (uwsgi.has_emperor && uwsgi.emperor_fd_config > -1) {
|
||||
char byte = 2;
|
||||
if (write(uwsgi.emperor_fd, &byte, 1) != 1) {
|
||||
uwsgi_error("uwsgi_reload()/write()");
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_log("chdir() to %s\n", uwsgi.cwd);
|
||||
if (chdir(uwsgi.cwd)) {
|
||||
uwsgi_error("chdir()");
|
||||
uwsgi_error("uwsgi_reload()/chdir()");
|
||||
}
|
||||
|
||||
/* check fd table (a module can obviosly open some fd on initialization...) */
|
||||
@@ -546,9 +567,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;
|
||||
|
||||
@@ -942,6 +943,20 @@ static int uwsgi_router_clearheaders(struct uwsgi_route *ur, char *arg) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// disable headers
|
||||
static int uwsgi_router_disableheaders_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
wsgi_req->headers_sent = 1;
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
|
||||
static int uwsgi_router_disableheaders(struct uwsgi_route *ur, char *arg) {
|
||||
ur->func = uwsgi_router_disableheaders_func;
|
||||
ur->data = arg;
|
||||
ur->data_len = strlen(arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// signal route
|
||||
static int uwsgi_router_signal_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route) {
|
||||
@@ -1736,6 +1751,7 @@ void uwsgi_register_embedded_routers() {
|
||||
uwsgi_register_router("remheader", uwsgi_router_remheader);
|
||||
uwsgi_register_router("clearheaders", uwsgi_router_clearheaders);
|
||||
uwsgi_register_router("resetheaders", uwsgi_router_clearheaders);
|
||||
uwsgi_register_router("disableheaders", uwsgi_router_disableheaders);
|
||||
uwsgi_register_router("signal", uwsgi_router_signal);
|
||||
uwsgi_register_router("send", uwsgi_router_send);
|
||||
uwsgi_register_router("send-crnl", uwsgi_router_send_crnl);
|
||||
|
||||
+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;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -190,6 +190,11 @@ static void spooler_req_parser_hook(char *key, uint16_t key_len, char *value, ui
|
||||
}
|
||||
|
||||
if (!uwsgi_strncmp(key, key_len, "at", 2)) {
|
||||
// at can be a float...
|
||||
char *dot = memchr(value, '.', value_len);
|
||||
if (dot) {
|
||||
value_len = dot - value;
|
||||
}
|
||||
sr->at = uwsgi_str_num(value, value_len);
|
||||
return;
|
||||
}
|
||||
|
||||
+9
-7
@@ -245,17 +245,19 @@ SSL_CTX *uwsgi_ssl_new_server_context(char *name, char *crt, char *key, char *ci
|
||||
if (dh) {
|
||||
SSL_CTX_set_tmp_dh(ctx, dh);
|
||||
DH_free(dh);
|
||||
}
|
||||
}
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
|
||||
#ifndef OPENSSL_NO_ECDH
|
||||
#ifdef NID_X9_62_prime256v1
|
||||
EC_KEY *ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
|
||||
SSL_CTX_set_tmp_ecdh(ctx, ecdh);
|
||||
EC_KEY_free(ecdh);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
EC_KEY *ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
|
||||
if (ecdh) {
|
||||
SSL_CTX_set_tmp_ecdh(ctx, ecdh);
|
||||
EC_KEY_free(ecdh);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (crt_need_free) free(crt);
|
||||
|
||||
|
||||
+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) {
|
||||
|
||||
+9
-7
@@ -1,4 +1,4 @@
|
||||
#include "uwsgi.h"
|
||||
#include <uwsgi.h>
|
||||
|
||||
/*
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
#define REQ_DATA wsgi_req->method_len, wsgi_req->method, wsgi_req->uri_len, wsgi_req->uri, wsgi_req->remote_addr_len, wsgi_req->remote_addr
|
||||
|
||||
static struct uwsgi_buffer *uwsgi_websocket_message(struct wsgi_request *wsgi_req, char *msg, size_t len, uint8_t opcode) {
|
||||
struct uwsgi_buffer *ub = wsgi_req->websocket_send_buf;
|
||||
if (!ub) {
|
||||
@@ -61,7 +63,7 @@ static int uwsgi_websockets_check_pingpong(struct wsgi_request *wsgi_req) {
|
||||
// pong not received ?
|
||||
if (wsgi_req->websocket_last_pong < wsgi_req->websocket_last_ping) {
|
||||
if (wsgi_req->websocket_last_ping - wsgi_req->websocket_last_pong > uwsgi.websockets_pong_tolerance) {
|
||||
uwsgi_log("[uwsgi-websocket] no PONG received in %d seconds !!!\n", uwsgi.websockets_pong_tolerance);
|
||||
uwsgi_log("[uwsgi-websocket] \"%.*s %.*s\" (%.*s) no PONG received in %d seconds !!!\n", REQ_DATA, uwsgi.websockets_pong_tolerance);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
@@ -189,7 +191,7 @@ static ssize_t uwsgi_websockets_recv_pkt(struct wsgi_request *wsgi_req, int nb)
|
||||
}
|
||||
goto wait;
|
||||
}
|
||||
uwsgi_error("uwsgi_websockets_recv_pkt()");
|
||||
uwsgi_req_error("uwsgi_websockets_recv_pkt()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -201,7 +203,7 @@ wait:
|
||||
if (rlen <= 0) return -1;
|
||||
}
|
||||
if (ret < 0) {
|
||||
uwsgi_error("uwsgi_websockets_recv_pkt()");
|
||||
uwsgi_req_error("uwsgi_websockets_recv_pkt()");
|
||||
return -1;
|
||||
}
|
||||
// send unsolicited pong
|
||||
@@ -254,11 +256,11 @@ static struct uwsgi_buffer *uwsgi_websocket_recv_do(struct wsgi_request *wsgi_re
|
||||
wsgi_req->websocket_size = uwsgi_be64(wsgi_req->websocket_buf->buf+2);
|
||||
}
|
||||
else {
|
||||
uwsgi_log("[uwsgi-websocket] BUG error in websocket parser\n");
|
||||
uwsgi_log("[uwsgi-websocket] \"%.*s %.*s\" (%.*s) BUG error in websocket parser\n", REQ_DATA);
|
||||
return NULL;
|
||||
}
|
||||
if (wsgi_req->websocket_size > (uwsgi.websockets_max_size*1024)) {
|
||||
uwsgi_log("[uwsgi-websocket] invalid packet size received: %llu, max allowed: %llu\n", wsgi_req->websocket_size, uwsgi.websockets_max_size * 1024);
|
||||
uwsgi_log("[uwsgi-websocket] \"%.*s %.*s\" (%.*s) invalid packet size received: %llu, max allowed: %llu\n", REQ_DATA, wsgi_req->websocket_size, uwsgi.websockets_max_size * 1024);
|
||||
return NULL;
|
||||
}
|
||||
wsgi_req->websocket_phase = 2;
|
||||
@@ -312,7 +314,7 @@ static struct uwsgi_buffer *uwsgi_websocket_recv_do(struct wsgi_request *wsgi_re
|
||||
break;
|
||||
// oops
|
||||
default:
|
||||
uwsgi_log("[uwsgi-websocket] BUG error in websocket parser\n");
|
||||
uwsgi_log("[uwsgi-websocket] \"%.*s %.*s\" (%.*s) BUG error in websocket parser\n", REQ_DATA);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
+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);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
#define cr_add_timeout_fast(u, x, t) uwsgi_add_rb_timer(u->timeouts, t+u->socket_timeout, x)
|
||||
#define cr_del_timeout(u, x) uwsgi_del_rb_timer(u->timeouts, x->timeout); free(x->timeout);
|
||||
|
||||
#define uwsgi_cr_error(x, y) uwsgi_log("[uwsgi-%s client_addr: %s client_port: %s] %s: %s [%s line %d]\n", x->session->corerouter->short_name, x->session->client_address, x->session->client_port, y, strerror(errno), __FILE__, __LINE__)
|
||||
#define uwsgi_cr_log(x, y, ...) uwsgi_log("[uwsgi-%s client_addr: %s client_port: %s]" y, x->session->corerouter->short_name, x->session->client_address, x->session->client_port, __VA_ARGS__)
|
||||
#define uwsgi_cr_error(x, y) uwsgi_log("[uwsgi-%s key: %.*s client_addr: %s client_port: %s] %s: %s [%s line %d]\n", x->session->corerouter->short_name, x->session->main_peer ? x->session->main_peer->key_len : 0, x->session->main_peer ? x->session->main_peer->key: "", x->session->client_address, x->session->client_port, y, strerror(errno), __FILE__, __LINE__)
|
||||
#define uwsgi_cr_log(x, y, ...) uwsgi_log("[uwsgi-%s key: %.*s client_addr: %s client_port: %s]" y, x->session->corerouter->short_name, x->session->main_peer ? x->session->main_peer->key_len : 0, x->session->main_peer ? x->session->main_peer->key : "", x->session->client_address, x->session->client_port, __VA_ARGS__)
|
||||
|
||||
#define cr_try_again if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {\
|
||||
errno = EINPROGRESS;\
|
||||
|
||||
@@ -20,7 +20,7 @@ extern "C" void uwsgi_imperial_monitor_mongodb(struct uwsgi_emperor_scanner *ues
|
||||
try {
|
||||
|
||||
// requested fields
|
||||
mongo::BSONObj p = BSON( "name" << 1 << "config" << 1 << "ts" << 1 << "uid" << 1 << "gid" << 1 );
|
||||
mongo::BSONObj p = BSON( "name" << 1 << "config" << 1 << "ts" << 1 << "uid" << 1 << "gid" << 1 << "socket" << 1 );
|
||||
mongo::BSONObj q = mongo::fromjson(uems->json);
|
||||
// the connection object (will be automatically destroyed at each cycle)
|
||||
mongo::DBClientConnection c;
|
||||
@@ -31,7 +31,7 @@ extern "C" void uwsgi_imperial_monitor_mongodb(struct uwsgi_emperor_scanner *ues
|
||||
|
||||
// run the query
|
||||
std::auto_ptr<mongo::DBClientCursor> cursor = c.query(uems->collection, q, 0, 0, &p);
|
||||
while( cursor->more() ) {
|
||||
while(cursor.get() && cursor->more() ) {
|
||||
mongo::BSONObj p = cursor->next();
|
||||
|
||||
// checking for an empty string is not required, but we reduce the load
|
||||
@@ -40,6 +40,7 @@ extern "C" void uwsgi_imperial_monitor_mongodb(struct uwsgi_emperor_scanner *ues
|
||||
if (strlen(name) == 0) continue;
|
||||
|
||||
const char *config = p.getStringField("config");
|
||||
if (strlen(config) == 0) config = NULL;
|
||||
|
||||
time_t vassal_ts = 0;
|
||||
// ts must be a Date object !!!
|
||||
@@ -61,6 +62,7 @@ extern "C" void uwsgi_imperial_monitor_mongodb(struct uwsgi_emperor_scanner *ues
|
||||
}
|
||||
|
||||
const char *socket_name = p.getStringField("socket");
|
||||
if (strlen(socket_name) == 0) socket_name = NULL;
|
||||
|
||||
uwsgi_emperor_simple_do(ues, (char *) name, (char *) config, vassal_ts/1000, vassal_uid, vassal_gid, (char *) socket_name);
|
||||
}
|
||||
@@ -76,6 +78,7 @@ extern "C" void uwsgi_imperial_monitor_mongodb(struct uwsgi_emperor_scanner *ues
|
||||
b.append("name", c_ui->name);
|
||||
mongo::BSONObj q2 = b.obj();
|
||||
cursor = c.query(uems->collection, q2, 0, 0, &p);
|
||||
if (!cursor.get()) return;
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("JSON: %s\n", q2.toString().c_str());
|
||||
#endif
|
||||
|
||||
@@ -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);
|
||||
|
||||
+46
-33
@@ -102,6 +102,10 @@ static int uwsgi_mongrel2_json_parse(json_t * root, struct wsgi_request *wsgi_re
|
||||
}
|
||||
}
|
||||
|
||||
if ((json_val = uwsgi_mongrel2_json_get_string(root, "URL_SCHEME"))) {
|
||||
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "UWSGI_SCHEME", 12, json_val, strlen(json_val));
|
||||
}
|
||||
|
||||
if ((json_val = uwsgi_mongrel2_json_get_string(root, "host"))) {
|
||||
char *colon = strchr(json_val, ':');
|
||||
if (colon) {
|
||||
@@ -210,6 +214,9 @@ static int uwsgi_mongrel2_tnetstring_parse(struct wsgi_request *wsgi_req, char *
|
||||
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REQUEST_URI", 11, val, vallen);
|
||||
}
|
||||
}
|
||||
else if (!uwsgi_strncmp("URL_SCHEME", 10, key, keylen)) {
|
||||
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "UWSGI_SCHEME", 12, val, vallen);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// add header
|
||||
@@ -299,6 +306,13 @@ void uwsgi_proto_zeromq_thread_fixup(struct uwsgi_socket *uwsgi_sock, int async_
|
||||
|
||||
// fake function, the body is in a file or completely in memory
|
||||
ssize_t uwsgi_proto_zeromq_read_body(struct wsgi_request *wsgi_req, char *buf, size_t len) {
|
||||
size_t remains = wsgi_req->post_cl - wsgi_req->proto_parser_status;
|
||||
if (remains > 0) {
|
||||
if (len > remains) len = remains;
|
||||
memcpy(buf, wsgi_req->proto_parser_buf + wsgi_req->proto_parser_buf_size + wsgi_req->proto_parser_status, len);
|
||||
wsgi_req->proto_parser_status += len;
|
||||
return len;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -410,7 +424,8 @@ int uwsgi_proto_zeromq_accept(struct wsgi_request *wsgi_req, int fd) {
|
||||
}
|
||||
|
||||
// pre-build the mongrel2 response_header
|
||||
wsgi_req->proto_parser_buf = uwsgi_malloc(req_uuid_len + 1 + 11 + 1 + req_id_len + 1 + 1);
|
||||
wsgi_req->proto_parser_buf_size = req_uuid_len + 1 + 11 + 1 + req_id_len + 1 + 1;
|
||||
wsgi_req->proto_parser_buf = uwsgi_malloc(wsgi_req->proto_parser_buf_size);
|
||||
memcpy(wsgi_req->proto_parser_buf, req_uuid, req_uuid_len);
|
||||
((char *) wsgi_req->proto_parser_buf)[req_uuid_len] = ' ';
|
||||
resp_id_len = uwsgi_num2str2(req_id_len, wsgi_req->proto_parser_buf + req_uuid_len + 1);
|
||||
@@ -422,13 +437,22 @@ int uwsgi_proto_zeromq_accept(struct wsgi_request *wsgi_req, int fd) {
|
||||
wsgi_req->proto_parser_pos = (uint64_t) req_uuid_len + 1 + resp_id_len + 1 + req_id_len + 1 + 1;
|
||||
|
||||
// handle post data (in memory)
|
||||
// reallocate wsgi_req->proto_parser_buf and change its size to be able to store request body
|
||||
// the parser status holds the current position for read_body hook
|
||||
if (wsgi_req->post_cl > 0 && !wsgi_req->post_file) {
|
||||
if (uwsgi_netstring(post_data, message_size - (post_data - message_ptr), &message_ptr, &wsgi_req->post_cl)) {
|
||||
char *tmp = realloc(wsgi_req->proto_parser_buf, wsgi_req->proto_parser_buf_size + wsgi_req->post_cl);
|
||||
if (!tmp) {
|
||||
uwsgi_error("realloc()");
|
||||
exit(1);
|
||||
}
|
||||
wsgi_req->proto_parser_buf = tmp;
|
||||
// status is an offset...
|
||||
wsgi_req->proto_parser_status = 0;
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("post_size: %d\n", wsgi_req->post_cl);
|
||||
#endif
|
||||
wsgi_req->post_read_buf = uwsgi_malloc(wsgi_req->post_cl);
|
||||
memcpy(wsgi_req->post_read_buf, message_ptr, wsgi_req->post_cl);
|
||||
memcpy(wsgi_req->proto_parser_buf + wsgi_req->proto_parser_buf_size, message_ptr, wsgi_req->post_cl);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -452,33 +476,7 @@ retry:
|
||||
return -1;
|
||||
}
|
||||
|
||||
void uwsgi_proto_zeromq_close(struct wsgi_request *wsgi_req) {
|
||||
zmq_msg_t reply;
|
||||
|
||||
// check for already freed wsgi_req->proto_parser_buf/wsgi_req->proto_parser_pos
|
||||
if (!wsgi_req->proto_parser_pos)
|
||||
return;
|
||||
|
||||
// no need to pass a free function (the buffer will be freed during cloe_request)
|
||||
zmq_msg_init_data(&reply, wsgi_req->proto_parser_buf, wsgi_req->proto_parser_pos, NULL, NULL);
|
||||
if (uwsgi.threads > 1)
|
||||
pthread_mutex_lock(&wsgi_req->socket->lock);
|
||||
#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3,0,0)
|
||||
if (zmq_sendmsg(wsgi_req->socket->pub, &reply, 0)) {
|
||||
uwsgi_error("uwsgi_proto_zeromq_close()/zmq_sendmsg()");
|
||||
#else
|
||||
if (zmq_send(wsgi_req->socket->pub, &reply, 0)) {
|
||||
uwsgi_error("uwsgi_proto_zeromq_close()/zmq_send()");
|
||||
#endif
|
||||
}
|
||||
if (uwsgi.threads > 1)
|
||||
pthread_mutex_unlock(&wsgi_req->socket->lock);
|
||||
zmq_msg_close(&reply);
|
||||
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_proto_zeromq_write(struct wsgi_request *wsgi_req, char *buf, size_t len) {
|
||||
static int uwsgi_proto_zeromq_write_do(struct wsgi_request *wsgi_req, char *buf, size_t len) {
|
||||
zmq_msg_t reply;
|
||||
|
||||
if (zmq_msg_init_size(&reply, wsgi_req->proto_parser_pos + len)) {
|
||||
@@ -489,7 +487,8 @@ int uwsgi_proto_zeromq_write(struct wsgi_request *wsgi_req, char *buf, size_t le
|
||||
|
||||
char *zmq_body = zmq_msg_data(&reply);
|
||||
memcpy(zmq_body, wsgi_req->proto_parser_buf, wsgi_req->proto_parser_pos);
|
||||
memcpy(zmq_body + wsgi_req->proto_parser_pos, buf, len);
|
||||
if (len > 0)
|
||||
memcpy(zmq_body + wsgi_req->proto_parser_pos, buf, len);
|
||||
|
||||
if (uwsgi.threads > 1)
|
||||
pthread_mutex_lock(&wsgi_req->socket->lock);
|
||||
@@ -510,6 +509,18 @@ int uwsgi_proto_zeromq_write(struct wsgi_request *wsgi_req, char *buf, size_t le
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
int uwsgi_proto_zeromq_write(struct wsgi_request *wsgi_req, char *buf, size_t len) {
|
||||
int ret = uwsgi_proto_zeromq_write_do(wsgi_req, buf, len);
|
||||
if (ret == UWSGI_OK) {
|
||||
wsgi_req->write_pos += len;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void uwsgi_proto_zeromq_close(struct wsgi_request *wsgi_req) {
|
||||
uwsgi_proto_zeromq_write_do(wsgi_req, "", 0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
we have a problem... recent Mongrel2 releases introduced a ring buffer that limit the amount of messages we can send (or better, the amount of
|
||||
@@ -532,7 +543,7 @@ int uwsgi_proto_zeromq_sendfile(struct wsgi_request *wsgi_req, int fd, size_t po
|
||||
return -1;
|
||||
}
|
||||
wsgi_req->write_pos += rlen;
|
||||
if (uwsgi_proto_zeromq_write(wsgi_req, tmp_buf, rlen) < 0) {
|
||||
if (uwsgi_proto_zeromq_write_do(wsgi_req, tmp_buf, rlen) < 0) {
|
||||
free(tmp_buf);
|
||||
return -1;
|
||||
}
|
||||
@@ -574,6 +585,7 @@ static void mongrel2_register_proto() {
|
||||
static void mongrel2_connect() {
|
||||
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
|
||||
while(uwsgi_sock) {
|
||||
if (uwsgi_sock->proto != uwsgi_proto_zeromq_parser) goto next;
|
||||
uwsgi_sock->ctx = zmq_init(1);
|
||||
if (!uwsgi_sock->ctx) {
|
||||
uwsgi_error("mongrel2_connect()/zmq_init()");
|
||||
@@ -581,7 +593,7 @@ static void mongrel2_connect() {
|
||||
}
|
||||
char *responder = strchr(uwsgi_sock->name, ',');
|
||||
if (!responder) {
|
||||
uwsgi_log("invalid zeromq address\n");
|
||||
uwsgi_log("invalid zeromq address: %s\n", uwsgi_sock->name);
|
||||
exit(1);
|
||||
}
|
||||
uwsgi_sock->receiver = uwsgi_concat2n(uwsgi_sock->name, responder - uwsgi_sock->name, "", 0);
|
||||
@@ -653,6 +665,7 @@ static void mongrel2_connect() {
|
||||
#else
|
||||
uwsgi_sock->recv_flag = ZMQ_NOBLOCK;
|
||||
#endif
|
||||
next:
|
||||
uwsgi_sock = uwsgi_sock->next;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
+52
-39
@@ -54,7 +54,7 @@ XS(XS_psgix_logger) {
|
||||
psgi_check_args(1);
|
||||
HV *hv_args = (HV *) (SvRV(ST(0)));
|
||||
if (!hv_exists(hv_args, "level", 5) || !hv_exists(hv_args, "message", 7)) {
|
||||
Perl_croak(aTHX_ "psgix.logger requires bot level and message items");
|
||||
Perl_croak(aTHX_ "psgix.logger requires both level and message items");
|
||||
}
|
||||
char *level = SvPV_nolen(*(hv_fetch(hv_args, "level", 5, 0)));
|
||||
char *message = SvPV_nolen(*(hv_fetch(hv_args, "message", 7, 0)));
|
||||
@@ -108,7 +108,7 @@ XS(XS_input_read) {
|
||||
unsigned long arg_len = SvIV(ST(2));
|
||||
|
||||
long offset = 0;
|
||||
if (items > 2) {
|
||||
if (items > 3) {
|
||||
offset = (long) SvIV(ST(3));
|
||||
}
|
||||
|
||||
@@ -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,34 @@ 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_e_arg = uwsgi_concat2("#line 0 ", app_name);
|
||||
char *perl_init_arg[] = { "", "-e", perl_e_arg };
|
||||
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);
|
||||
free(perl_e_arg);
|
||||
uwsgi_perl_free_stashes();
|
||||
goto clear;
|
||||
}
|
||||
} else {
|
||||
free(perl_e_arg);
|
||||
}
|
||||
}
|
||||
|
||||
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 +410,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 +443,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 +515,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);
|
||||
}
|
||||
|
||||
|
||||
@@ -955,6 +955,27 @@ XS(XS_spool) {
|
||||
XSRETURN_UNDEF;
|
||||
}
|
||||
|
||||
XS(XS_add_var) {
|
||||
dXSARGS;
|
||||
psgi_check_args(2);
|
||||
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
|
||||
STRLEN keylen;
|
||||
char *key = SvPV(ST(0), keylen);
|
||||
|
||||
STRLEN vallen;
|
||||
char *val = SvPV(ST(1), vallen);
|
||||
|
||||
if (!uwsgi_req_append(wsgi_req, key, keylen, val, vallen)) {
|
||||
croak("unable to add request var, check your buffer size");
|
||||
XSRETURN_UNDEF;
|
||||
}
|
||||
|
||||
XSRETURN_YES;
|
||||
|
||||
}
|
||||
|
||||
void init_perl_embedded_module() {
|
||||
psgi_xs(reload);
|
||||
|
||||
@@ -1016,5 +1037,7 @@ void init_perl_embedded_module() {
|
||||
|
||||
psgi_xs(spooler);
|
||||
psgi_xs(spool);
|
||||
|
||||
psgi_xs(add_var);
|
||||
|
||||
}
|
||||
|
||||
+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
|
||||
|
||||
@@ -197,6 +197,12 @@ int uwsgi_python_init() {
|
||||
uwsgi_log_initial("Python version: %.*s %s\n", pyversion-Py_GetVersion(), Py_GetVersion(), Py_GetCompiler()+1);
|
||||
}
|
||||
|
||||
if (Py_IsInitialized()) {
|
||||
uwsgi_log("--- Python VM already initialized ---\n");
|
||||
PyGILState_Ensure();
|
||||
goto ready;
|
||||
}
|
||||
|
||||
if (up.home != NULL) {
|
||||
#ifdef PYTHREE
|
||||
// check for PEP 405 virtualenv (starting from python 3.3)
|
||||
@@ -251,6 +257,8 @@ pep405:
|
||||
|
||||
Py_Initialize();
|
||||
|
||||
ready:
|
||||
|
||||
if (!uwsgi.has_threads) {
|
||||
uwsgi_log_initial("*** Python threads support is disabled. You can enable it with --enable-threads ***\n");
|
||||
}
|
||||
|
||||
@@ -4,6 +4,26 @@ extern struct uwsgi_server uwsgi;
|
||||
extern struct uwsgi_python up;
|
||||
extern struct uwsgi_plugin python_plugin;
|
||||
|
||||
static PyObject *py_uwsgi_add_var(PyObject * self, PyObject * args) {
|
||||
char *key = NULL;
|
||||
Py_ssize_t keylen = 0;
|
||||
char *val = NULL;
|
||||
Py_ssize_t vallen = 0;
|
||||
struct wsgi_request *wsgi_req = py_current_wsgi_req();
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s#s#", &key, &keylen, &val, &vallen)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!uwsgi_req_append(wsgi_req, key, keylen, val, vallen)) {
|
||||
return PyErr_Format(PyExc_ValueError, "unable to add request var, check your buffer size");
|
||||
}
|
||||
|
||||
Py_INCREF(Py_True);
|
||||
return Py_True;
|
||||
}
|
||||
|
||||
|
||||
static PyObject *py_uwsgi_signal_wait(PyObject * self, PyObject * args) {
|
||||
|
||||
struct wsgi_request *wsgi_req = py_current_wsgi_req();
|
||||
@@ -2417,6 +2437,8 @@ static PyMethodDef uwsgi_advanced_methods[] = {
|
||||
|
||||
{"ready_fd", py_uwsgi_ready_fd, METH_VARARGS, ""},
|
||||
|
||||
{"add_var", py_uwsgi_add_var, METH_VARARGS, ""},
|
||||
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -93,7 +93,11 @@ ssize_t uwsgi_syslog_logger(struct uwsgi_logger *ul, char *message, size_t len)
|
||||
ul->configured = 1;
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
syslog(LOG_NOTICE, "%.*s", (int) len, message);
|
||||
#else
|
||||
syslog(LOG_INFO, "%.*s", (int) len, message);
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
+18
-8
@@ -2,6 +2,16 @@
|
||||
|
||||
extern struct uwsgi_tuntap utt;
|
||||
|
||||
// error reporting
|
||||
void uwsgi_tuntap_error_do(struct uwsgi_tuntap_peer *uttp, char *msg, char *file, int line) {
|
||||
if (uttp) {
|
||||
uwsgi_log_verbose("[tuntap] peer fd: %d ip: %s %s: %s [%s line %d]\n", uttp->fd, uttp->ip, msg, strerror(errno), file, line);
|
||||
}
|
||||
else {
|
||||
uwsgi_log_verbose("[tuntap] %s: %s [%s line %d]\n", msg, strerror(errno), file, line);
|
||||
}
|
||||
}
|
||||
|
||||
// create a new peer
|
||||
struct uwsgi_tuntap_peer *uwsgi_tuntap_peer_create(struct uwsgi_tuntap_router *uttr, int fd, int is_router) {
|
||||
|
||||
@@ -183,7 +193,7 @@ int uwsgi_tuntap_register_addr(struct uwsgi_tuntap_router *uttr, struct uwsgi_tu
|
||||
char ip[INET_ADDRSTRLEN + 1];
|
||||
memset(ip, 0, INET_ADDRSTRLEN + 1);
|
||||
if (!inet_ntop(AF_INET, &uttp->addr, ip, INET_ADDRSTRLEN)) {
|
||||
uwsgi_error("uwsgi_tuntap_register_addr()/inet_ntop()");
|
||||
uwsgi_tuntap_error(uttp, "uwsgi_tuntap_register_addr()/inet_ntop()");
|
||||
return -1;
|
||||
}
|
||||
if (uttp != tmp_uttp) {
|
||||
@@ -205,7 +215,7 @@ int uwsgi_tuntap_peer_dequeue(struct uwsgi_tuntap_router *uttr, struct uwsgi_tun
|
||||
if (rlen < 0) {
|
||||
if (uwsgi_is_again())
|
||||
return 0;
|
||||
uwsgi_error("uwsgi_tuntap_peer_dequeue()/read()");
|
||||
uwsgi_tuntap_error(uttp, "uwsgi_tuntap_peer_dequeue()/read()");
|
||||
return -1;
|
||||
}
|
||||
uttp->buf_pos += rlen;
|
||||
@@ -265,7 +275,7 @@ enqueue:
|
||||
if (rlen < 0) {
|
||||
if (uwsgi_is_again())
|
||||
return 0;
|
||||
uwsgi_error("uwsgi_tuntap_peer_dequeue()/read()");
|
||||
uwsgi_tuntap_error(uttp, "uwsgi_tuntap_peer_dequeue()/read()");
|
||||
return -1;
|
||||
}
|
||||
uttp->header_pos += rlen;
|
||||
@@ -282,14 +292,14 @@ int uwsgi_tuntap_peer_enqueue(struct uwsgi_tuntap_router *uttr, struct uwsgi_tun
|
||||
|
||||
ssize_t rlen = write(uttp->fd, uttp->write_buf + uttp->written, uttp->write_buf_pktsize - uttp->written);
|
||||
if (rlen == 0) {
|
||||
uwsgi_error("uwsgi_tuntap_peer_enqueue()/write()");
|
||||
uwsgi_tuntap_error(uttp, "uwsgi_tuntap_peer_enqueue()/write()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rlen < 0) {
|
||||
if (uwsgi_is_again())
|
||||
goto retry;
|
||||
uwsgi_error("uwsgi_tuntap_peer_enqueue()/write()");
|
||||
uwsgi_tuntap_error(uttp, "uwsgi_tuntap_peer_enqueue()/write()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -303,13 +313,13 @@ int uwsgi_tuntap_peer_enqueue(struct uwsgi_tuntap_router *uttr, struct uwsgi_tun
|
||||
if (uttr->wait_for_write) {
|
||||
uttp->blocked_read = 1;
|
||||
if (event_queue_del_fd(uttr->queue, uttp->fd, event_queue_write())) {
|
||||
uwsgi_error("uwsgi_tuntap_peer_enqueue()/event_queue_del_fd()");
|
||||
uwsgi_tuntap_error(uttp, "uwsgi_tuntap_peer_enqueue()/event_queue_del_fd()");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (event_queue_fd_readwrite_to_read(uttr->queue, uttp->fd)) {
|
||||
uwsgi_error("uwsgi_tuntap_peer_enqueue()/event_queue_fd_write_to_read()");
|
||||
uwsgi_tuntap_error(uttp, "uwsgi_tuntap_peer_enqueue()/event_queue_fd_write_to_read()");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -324,7 +334,7 @@ int uwsgi_tuntap_peer_enqueue(struct uwsgi_tuntap_router *uttr, struct uwsgi_tun
|
||||
retry:
|
||||
if (!uttp->wait_for_write) {
|
||||
if (event_queue_fd_read_to_readwrite(uttr->queue, uttp->fd)) {
|
||||
uwsgi_error("uwsgi_tuntap_peer_enqueue()/event_queue_fd_read_to_write()");
|
||||
uwsgi_tuntap_error(uttp, "uwsgi_tuntap_peer_enqueue()/event_queue_fd_read_to_write()");
|
||||
return -1;
|
||||
}
|
||||
uttp->wait_for_write = 1;
|
||||
|
||||
@@ -116,3 +116,5 @@ int uwsgi_tuntap_register_addr(struct uwsgi_tuntap_router *, struct uwsgi_tuntap
|
||||
|
||||
void uwsgi_tuntap_peer_send_rules(int, struct uwsgi_tuntap_peer *);
|
||||
int uwsgi_tuntap_peer_rules_check(struct uwsgi_tuntap_router *, struct uwsgi_tuntap_peer *, char *, size_t, int);
|
||||
#define uwsgi_tuntap_error(x, y) uwsgi_tuntap_error_do(x, y, __FILE__, __LINE__)
|
||||
void uwsgi_tuntap_error_do(struct uwsgi_tuntap_peer *, char *, char *, int);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "common.h"
|
||||
|
||||
extern struct uwsgi_tuntap utt;
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
int uwsgi_tuntap_peer_rules_check(struct uwsgi_tuntap_router *uttr, struct uwsgi_tuntap_peer *uttp, char *pkt, size_t len, int direction) {
|
||||
if (uttp->rules_cnt == 0) return 0;
|
||||
@@ -51,7 +52,25 @@ int uwsgi_tuntap_peer_rules_check(struct uwsgi_tuntap_router *uttr, struct uwsgi
|
||||
sin.sin_port = rule->target_port;
|
||||
sin.sin_addr.s_addr = rule->target;
|
||||
if (sendto(uttr->gateway_fd, pkt, len, 0, (struct sockaddr *) &sin, sizeof(struct sockaddr_in)) < 0) {
|
||||
uwsgi_error("uwsgi_tuntap_route_check()/sendto()");
|
||||
if (uwsgi_is_again()) {
|
||||
// suspend and retry
|
||||
struct pollfd pfd;
|
||||
memset(&pfd, 0, sizeof(struct pollfd));
|
||||
pfd.fd = uttr->gateway_fd;
|
||||
pfd.events = POLLOUT;
|
||||
int ret = poll(&pfd, 1, uwsgi.socket_timeout * 1000);
|
||||
if (ret > 0) {
|
||||
if (sendto(uttr->gateway_fd, pkt, len, 0, (struct sockaddr *) &sin, sizeof(struct sockaddr_in)) < 0) {
|
||||
uwsgi_tuntap_error(uttp,"uwsgi_tuntap_route_check()/sendto()");
|
||||
}
|
||||
}
|
||||
else {
|
||||
uwsgi_tuntap_error(uttp,"uwsgi_tuntap_route_check()/poll()");
|
||||
}
|
||||
}
|
||||
else {
|
||||
uwsgi_tuntap_error(uttp,"uwsgi_tuntap_route_check()/sendto()");
|
||||
}
|
||||
}
|
||||
}
|
||||
return 2;
|
||||
@@ -305,7 +324,7 @@ void uwsgi_tuntap_peer_send_rules(int fd, struct uwsgi_tuntap_peer *peer) {
|
||||
*slash = 0;
|
||||
}
|
||||
if (inet_pton(AF_INET, argv[1], &utpr.src) != 1) {
|
||||
uwsgi_error("uwsgi_tuntap_peer_send_rules()/inet_pton()");
|
||||
uwsgi_tuntap_error(peer, "uwsgi_tuntap_peer_send_rules()/inet_pton()");
|
||||
exit(1);
|
||||
}
|
||||
if (slash) *slash = '/';
|
||||
@@ -317,7 +336,7 @@ void uwsgi_tuntap_peer_send_rules(int fd, struct uwsgi_tuntap_peer *peer) {
|
||||
*slash = 0;
|
||||
}
|
||||
if (inet_pton(AF_INET, argv[2], &utpr.dst) != 1) {
|
||||
uwsgi_error("uwsgi_tuntap_peer_send_rules()/inet_pton()");
|
||||
uwsgi_tuntap_error(peer, "uwsgi_tuntap_peer_send_rules()/inet_pton()");
|
||||
exit(1);
|
||||
}
|
||||
if (slash) *slash = '/';
|
||||
@@ -352,7 +371,7 @@ void uwsgi_tuntap_peer_send_rules(int fd, struct uwsgi_tuntap_peer *peer) {
|
||||
}
|
||||
*colon = 0;
|
||||
if (inet_pton(AF_INET, argv[4], &utpr.target) != 1) {
|
||||
uwsgi_error("uwsgi_tuntap_peer_send_rules()/inet_pton()");
|
||||
uwsgi_tuntap_error(peer, "uwsgi_tuntap_peer_send_rules()/inet_pton()");
|
||||
exit(1);
|
||||
}
|
||||
*colon = ':';
|
||||
@@ -370,7 +389,7 @@ void uwsgi_tuntap_peer_send_rules(int fd, struct uwsgi_tuntap_peer *peer) {
|
||||
size_t len = ub->pos;
|
||||
uwsgi_buffer_destroy(ub);
|
||||
if (write(fd,peer->rules, len) != (ssize_t)len) {
|
||||
uwsgi_error("uwsgi_tuntap_peer_send_rules()/write()");
|
||||
uwsgi_tuntap_error(peer, "uwsgi_tuntap_peer_send_rules()/write()");
|
||||
exit(1);
|
||||
}
|
||||
return;
|
||||
|
||||
+11
-4
@@ -117,6 +117,13 @@ static void *uwsgi_tuntap_loop(void *arg) {
|
||||
uwsgi_error("uwsgi_tuntap_loop()/read()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// check for full write buffer
|
||||
if (uttp->write_buf_pktsize + 4 + rlen > utt.buffer_size) {
|
||||
uttp->dropped++;
|
||||
continue;
|
||||
}
|
||||
|
||||
uint16_t pktsize = rlen;
|
||||
char *ptr = uttp->write_buf + uttp->write_buf_pktsize;
|
||||
memcpy(ptr + 4, uttr->buf, rlen);
|
||||
@@ -126,7 +133,7 @@ static void *uwsgi_tuntap_loop(void *arg) {
|
||||
ptr[3] = 0;
|
||||
uttp->write_buf_pktsize+= pktsize+4;
|
||||
if (uwsgi_tuntap_peer_enqueue(uttr, uttp)) {
|
||||
uwsgi_log("server disconnected...\n");
|
||||
uwsgi_log_verbose("tuntap server disconnected...\n");
|
||||
exit(1);
|
||||
}
|
||||
continue;
|
||||
@@ -137,7 +144,7 @@ static void *uwsgi_tuntap_loop(void *arg) {
|
||||
// read from the client
|
||||
if (!uttp->wait_for_write) {
|
||||
if (uwsgi_tuntap_peer_dequeue(uttr, uttp, 0)) {
|
||||
uwsgi_log("server disconnected...\n");
|
||||
uwsgi_log_verbose("tuntap server disconnected...\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
@@ -149,7 +156,7 @@ static void *uwsgi_tuntap_loop(void *arg) {
|
||||
|
||||
// write to the client
|
||||
if (uwsgi_tuntap_peer_enqueue(uttr, uttp)) {
|
||||
uwsgi_log("server disconnected...\n");
|
||||
uwsgi_log_verbose("tuntap server disconnected...\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
@@ -507,7 +514,7 @@ void tuntaprouter_send_stats(struct uwsgi_tuntap_router *uttr) {
|
||||
ssize_t res = write(client_fd, us->base + pos, remains);
|
||||
if (res <= 0) {
|
||||
if (res < 0) {
|
||||
uwsgi_error("write()");
|
||||
uwsgi_error("tuntaprouter_send_stats()/write()");
|
||||
}
|
||||
goto end0;
|
||||
}
|
||||
|
||||
@@ -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) = @_;
|
||||
@@ -55,6 +59,10 @@ my $app = sub {
|
||||
uwsgi::signal(17);
|
||||
uwsgi::signal(30);
|
||||
|
||||
my ($package, $filename, $line) = caller;
|
||||
die "Expecting reasonable caller() return values, not [$package, $filename, $line]"
|
||||
unless $package eq 'main' and $filename =~ /\btest\.psgi$/s and $line == 0;
|
||||
|
||||
if ($env->{'psgix.cleanup'}) {
|
||||
print "cleanup supported\n";
|
||||
push @{$env->{'psgix.cleanup.handlers'}}, $one;
|
||||
|
||||
@@ -20,11 +20,13 @@ push @tests, ['1', 'HELLO', "oHELLOo_three_four"];
|
||||
push @tests, ['3', 'HELLO', "oneHELLOthree_four"];
|
||||
push @tests, ['30', 'HELLO', "one_two_three_four\0\0\0\0\0\0\0\0\0\0\0\0HELLO"];
|
||||
|
||||
@ARGV or die "You must provide a host to test on, e.g. localhost:8080";
|
||||
|
||||
foreach(@tests) {
|
||||
print "testing: offset(".$_->[0].") body(".$_->[1].")\n";
|
||||
my $req = "POST /?".$base." HTTP/1.0\r\nContent-Length: ".length($_->[1])."\r\nuWSGI-Offset: ".$_->[0]."\r\n\r\n".$_->[1];
|
||||
|
||||
my $s = IO::Socket::INET->new(PeerAddr => $ARGV[0]);
|
||||
my $s = IO::Socket::INET->new(PeerAddr => $ARGV[0]) or die "PANIC: Unable to construct socket";
|
||||
$s->send($req);
|
||||
|
||||
my $response = '';
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
sub {
|
||||
my $env = shift;
|
||||
|
||||
my $cl = $env->{CONTENT_LENGTH};
|
||||
$env->{'psgi.input'}->seek(0,0);
|
||||
my $content = '';
|
||||
while ($cl) {
|
||||
$env->{'psgi.input'}->read(my $chunk, $cl < 8192 ? $cl : 8192);
|
||||
my $read = length $chunk;
|
||||
$cl -= $read;
|
||||
$content .= $chunk;
|
||||
}
|
||||
|
||||
return [200, [], [ "Your content was: <$content>" ]];
|
||||
};
|
||||
|
||||
__END__
|
||||
|
||||
This is a trival test that prints out a POST request, it's here to
|
||||
test a regression introduced in 2.0-103-gf041d10 where doing reads
|
||||
without offsets, e.g.:
|
||||
|
||||
$ http_proxy= curl -d '{ "what": "ever" }' http://localhost:8080/
|
||||
Your content was: $VAR1 = '{ "what": "ever" }';
|
||||
|
||||
Would result in:
|
||||
|
||||
Use of uninitialized value in subroutine entry at
|
||||
/home/v-perlbrew/perl5/perlbrew/perls/perl-5.19.6/lib/site_perl/5.19.6/Plack/Request.pm
|
||||
line 280.
|
||||
|
||||
Which is due to this commit having a one-off error in counting stack
|
||||
items.
|
||||
|
||||
$ git bisect good
|
||||
f041d1095ddf7541c4b275e16d2ed3355a8e2be9 is the first bad commit
|
||||
commit f041d1095ddf7541c4b275e16d2ed3355a8e2be9
|
||||
Author: Unbit <info@unbit.it>
|
||||
Date: Wed Feb 5 11:21:01 2014 +0100
|
||||
|
||||
perl refactoring
|
||||
|
||||
:040000 040000 98a25406b7edb9bd0b9be8bbcd351a99e7ce2d33 0087e3ca4b6bd65a087fade65d43a56085298ef0 M plugins
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
sub {
|
||||
my $env = shift;
|
||||
|
||||
return sub {
|
||||
my $responder = shift;
|
||||
my $writer = $responder->([ 200, [ 'Content-Type', 'text/plain' ]]);
|
||||
sleep 3;
|
||||
$writer->write("hello\n");
|
||||
sleep 3;
|
||||
$writer->write("world\n");
|
||||
$writer->close;
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
__END__
|
||||
|
||||
Making a request to this will give you:
|
||||
|
||||
$ date; curl -s -N -D - 'http://localhost:8080'
|
||||
Sat Mar 15 14:08:25 UTC 2014
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: text/plain
|
||||
|
||||
hello
|
||||
world
|
||||
|
||||
And monitoring it with tcpflow shows how the output (including
|
||||
headers) is flushed right away:
|
||||
|
||||
$ sudo tcpflow -i lo -c port 8080 | perl -pe 's/^/localtime . " "/ge'
|
||||
Sat Mar 15 14:09:08 2014 127.000.000.001.55058-127.000.000.001.08080: GET / HTTP/1.1
|
||||
Sat Mar 15 14:09:08 2014 User-Agent: curl/7.35.0
|
||||
Sat Mar 15 14:09:08 2014 Host: localhost:8080
|
||||
Sat Mar 15 14:09:08 2014 Accept: */*
|
||||
Sat Mar 15 14:09:08 2014
|
||||
Sat Mar 15 14:09:08 2014
|
||||
Sat Mar 15 14:09:08 2014 127.000.000.001.08080-127.000.000.001.55058: HTTP/1.1 200 OK
|
||||
Sat Mar 15 14:09:08 2014 Content-Type: text/plain
|
||||
Sat Mar 15 14:09:08 2014
|
||||
Sat Mar 15 14:09:08 2014
|
||||
Sat Mar 15 14:09:11 2014 127.000.000.001.08080-127.000.000.001.55058: hello
|
||||
Sat Mar 15 14:09:11 2014
|
||||
Sat Mar 15 14:09:14 2014 127.000.000.001.08080-127.000.000.001.55058: world
|
||||
Sat Mar 15 14:09:14 2014
|
||||
+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-03-17'
|
||||
s.summary = "uWSGI"
|
||||
s.description = "The uWSGI server for Ruby/Rack"
|
||||
s.authors = ["Unbit"]
|
||||
|
||||
+20
-1
@@ -1,6 +1,6 @@
|
||||
# uWSGI build system
|
||||
|
||||
uwsgi_version = '2.0.1'
|
||||
uwsgi_version = '2.0.3'
|
||||
|
||||
import os
|
||||
import re
|
||||
@@ -367,6 +367,15 @@ def build_uwsgi(uc, print_only=False, gcll=None):
|
||||
if len(kv) > 1:
|
||||
p = kv[1]
|
||||
p = p.strip()
|
||||
if p.startswith('http://') or p.startswith('https://') or p.startswith('git://') or p.startswith('ssh://'):
|
||||
git_dir = p.split('/').pop()
|
||||
if not os.path.isdir(git_dir):
|
||||
if os.system('git clone %s' % p) != 0:
|
||||
sys.exit(1)
|
||||
else:
|
||||
if os.system('cd %s ; git pull' % git_dir) != 0:
|
||||
sys.exit(1)
|
||||
p = git_dir
|
||||
path = os.path.abspath(p)
|
||||
else:
|
||||
p = kv[0]
|
||||
@@ -1275,6 +1284,16 @@ def build_plugin(path, uc, cflags, ldflags, libs, name = None):
|
||||
|
||||
up = {}
|
||||
|
||||
if path.startswith('http://') or path.startswith('https://') or path.startswith('git://') or path.startswith('ssh://'):
|
||||
git_dir = path.split('/').pop()
|
||||
if not os.path.isdir(git_dir):
|
||||
if os.system('git clone %s' % path) != 0:
|
||||
sys.exit(1)
|
||||
else:
|
||||
if os.system('cd %s ; git pull' % git_dir) != 0:
|
||||
sys.exit(1)
|
||||
path = os.path.abspath(git_dir)
|
||||
|
||||
if os.path.isfile(path):
|
||||
bname = os.path.basename(path)
|
||||
# override path
|
||||
|
||||
Reference in New Issue
Block a user