Compare commits

...
47 Commits
Author SHA1 Message Date
Unbit b0159ea23b prepare for 2.0.2 2014-02-26 17:06:47 +01:00
Unbit d3493df032 do not expode if Devel::StackTrace is missing 2014-02-26 17:06:21 +01:00
Unbit 757c76b569 fix -bash in perl hooks 2014-02-26 12:12:41 +01:00
Unbit 30eebfd335 better perl do usage and --perl-no-plack flag 2014-02-26 12:07:00 +01:00
Unbit c5d7d30439 try to better address #553 2014-02-26 11:39:00 +01:00
unbit 04bc3e117d Merge pull request #553 from avar/avar/do-not-run-psgi-begin-blocks-twice
perl: Don't run BEGIN blocks twice in the provided *.psgi
2014-02-26 08:24:11 +01:00
Ævar Arnfjörð Bjarmason 3480c30674 perl: Don't run BEGIN blocks twice in the provided *.psgi
The psgi loaded was calling perl_parse() with the script ostensibly to
set up xsinit.

However it would also call perl_parse() with the path to our *.psgi
file, whith the result that any BEGIN block in the *.psgi file would be
run twice, but anything outside BEGIN blocks would only run once.

This means that any code within explicit BEGIN blocks will run twice,
and any "use" statement in the *.psgi file will run its import() routine
twice, but due to the module being in %INC already we won't actually
compile things twice.

The previous behavior dates all the way back to the initial introduction
of the PSGI plugin in 299fd9c.

Then when support for local::lib was added in 7cbe751 we initially did a
perl_eval_pv() of a "use" statement like I'm doing here again now, but
later on in 1561dd3 changed it to call perl_parse with the commit
message "another PSGI loading fix".

Since there's no info on what that fixed or what was broken before I
have no idea if I'm introducing a regression here, but I don't see why
this way of loding local::lib shouldn't work, and it correctly munges
@INC for me when I try it.

We may still have this bug in the remaining perl_parse() calls that
remain for supporting "preinit" and "mule".

I haven't tested those modes (I don't use them), but when we load the
Perl apps we should only perl_parse() once with -e1, and then
perl_eval_pv() to actually load the application. We should not call
perl_parse() on code that we're just about to perl_eval_pv(), or we'll
run into this bug.

To test this just run:

    ./uwsgi --http 127.0.0.1:8080 --psgi ./t/perl/test.psgi

It'll no longer PANIC on the BEGIN block being run twice now, at least
in that simplistic non-"preinit" non-"mule" mode.
2014-02-25 18:07:42 +00:00
Unbit a7e6dfc469 fixed python 3 on old compilers, fixes #551 2014-02-25 07:05:46 +01:00
Unbit 5e276b43ad fix poll() usage in #546 2014-02-24 09:14:14 +01:00
Roberto De Ioris 9e6a21602a more cgi improvements 2014-02-22 11:40:23 +01:00
Roberto De Ioris 952c4ce854 minor fixes in non-blocking reads 2014-02-22 11:13:50 +01:00
Roberto De Ioris 951f24e711 fixed #546 2014-02-22 10:46:46 +01:00
Unbit 7bda4c9b63 allow starting in spooler mode only 2014-02-21 08:48:21 +01:00
Unbit 1b25516ced spawn spoolers if requested 2014-02-21 08:42:22 +01:00
Unbit b3020e60f9 fixed long standing bug with caches 2014-02-20 14:19:40 +01:00
Unbit 808d37f33a fixed ftime log var 2014-02-20 10:52:05 +01:00
Unbit 8c8a7f77d1 added async remote signal management 2014-02-20 10:48:30 +01:00
Unbit 3f601af740 fix end-for and end-if 2014-02-20 10:28:30 +01:00
Unbit 7b901ab81e fixed #536 2014-02-20 09:19:41 +01:00
Roberto De Ioris 930eb1e6aa fixed #541 2014-02-20 07:52:47 +01:00
Unbit 77e5931da7 avoid loop in response and error internal routing 2014-02-15 09:35:38 +01:00
Unbit 3e6ddbb3d5 added --php-exec-before/--php-exec-after 2014-02-15 08:59:56 +01:00
Unbit 623bce274a prepare for 2.0.2 2014-02-15 07:31:39 +01:00
Unbit 6c986f8082 fixed pypy execute_source usage 2014-02-15 07:30:17 +01:00
Unbit 10a02064ba Merge branch 'master' of ssh://github.com/unbit/uwsgi 2014-02-13 06:25:18 +01:00
Unbit 774f5a81a5 added --geoip-use-disk, fixes #519 2014-02-13 06:25:07 +01:00
unbit e270593cc0 Merge pull request #533 from ramm/master
typo fix
2014-02-13 06:24:13 +01:00
Unbit b559354845 more tests for bitmap cache 2014-02-13 06:16:02 +01:00
Unbit 46a2fefb04 added overlap check for cache 2014-02-13 06:06:29 +01:00
Unbit c6c9baa7b5 initial test suite for bitmap cache mode 2014-02-12 18:54:39 +01:00
Danila Shtan c37710f4c2 Add myself to contributors
as agreed at https://github.com/unbit/uwsgi/pull/530#issuecomment-34859953
2014-02-12 22:35:10 +05:00
Danila Shtan 943c20b88c typo fix 2014-02-12 22:33:40 +05:00
Unbit a442614db0 fixed #531 2014-02-12 17:00:47 +01:00
Unbit 5830af37ba restore back needed_bytes 2014-02-12 16:25:02 +01:00
unbit de4c563169 Merge pull request #530 from ramm/master
fixed bitmap allocation bugs
2014-02-12 16:22:56 +01:00
Danila Shtan 77f008e24c fix unmark interval inside cache_update 2014-02-12 18:20:39 +05:00
Danila Shtan df0bd832b4 bitmap allocation fix
fix cache_mark offset bug and change cache_unmark according to previous changes)
2014-02-12 17:36:40 +05:00
Danila Shtan 07c42c262f fix comment typos 2014-02-12 15:44:41 +05:00
Danila Shtan cb131836ae remove extra bit in bitmap_pos optimisation
looks like it was added because there was an error in counting last_byte_bit position in cache_mark_blocks()
2014-02-12 15:42:46 +05:00
Danila Shtan 2c6855a969 fix bitmap allocation 2014-02-12 15:37:44 +05:00
Roberto De Ioris 79ca1940de fixed #527 2014-02-12 06:59:24 +01:00
Roberto De Ioris d46879dca9 fixed #528 2014-02-12 06:33:47 +01:00
Roberto De Ioris 9b889f7b77 another spooler-related fix (fd leak) 2014-02-12 06:28:49 +01:00
Roberto De Ioris 1128d09187 fixed #526 2014-02-12 06:05:29 +01:00
Roberto De Ioris d3d4d04fac fixed #524 2014-02-11 06:27:01 +01:00
unbit 4a554db63b Merge pull request #521 from methane/patch-1
logpipe: Don't setsid() twice.
2014-02-10 12:02:27 +01:00
INADA Naoki 8b799b4f9f logpipe: Don't setsid() twice. 2014-02-10 20:00:50 +09:00
29 changed files with 759 additions and 416 deletions
+1
View File
@@ -25,3 +25,4 @@ Mingli Yuan
Natanael Copa
Roberto Leandrini
Ryan Petrello
Danila Shtan <danila@shtan.ru>
+18
View File
@@ -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
View File
@@ -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
View File
@@ -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);
}
+22 -3
View File
@@ -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
View File
@@ -1116,7 +1116,7 @@ static ssize_t uwsgi_lf_ltime(struct wsgi_request * wsgi_req, char **buf) {
}
static ssize_t uwsgi_lf_ftime(struct wsgi_request * wsgi_req, char **buf) {
if (!uwsgi.log_strftime) {
if (!uwsgi.logformat_strftime || !uwsgi.log_strftime) {
return uwsgi_lf_ltime(wsgi_req, buf);
}
*buf = uwsgi_malloc(64);
+23 -9
View File
@@ -43,13 +43,6 @@ void uwsgi_destroy_processes() {
uwsgi_signal_spoolers(SIGKILL);
if (uwsgi.emperor_pid >= 0) {
kill(uwsgi.emperor_pid, SIGKILL);
waitpid(uwsgi.emperor_pid, &waitpid_status, 0);
uwsgi_log("The Emperor has been buried (pid: %d)\n", (int) uwsgi.emperor_pid);
}
uwsgi_detach_daemons();
for (i = 0; i < ushared->gateways_cnt; i++) {
@@ -68,6 +61,26 @@ void uwsgi_destroy_processes() {
uwsgi_log("mule %d has been buried (pid: %d)\n", i, (int) uwsgi.mules[i].pid);
}
}
if (uwsgi.emperor_pid > 0) {
kill(uwsgi.emperor_pid, SIGINT);
time_t timeout = uwsgi_now() + (uwsgi.reload_mercy ? uwsgi.reload_mercy : 3);
// increase timeout for being more tolerant
timeout+=2;
int waitpid_status;
while (uwsgi_now() < timeout) {
pid_t diedpid = waitpid(uwsgi.emperor_pid, &waitpid_status, WNOHANG);
if (diedpid == uwsgi.emperor_pid) {
goto nomoremperor;
}
uwsgi_log("waiting for Emperor death...\n");
sleep(1);
}
kill(uwsgi.emperor_pid, SIGKILL);
waitpid(uwsgi.emperor_pid, &waitpid_status, 0);
nomoremperor:
uwsgi_log("The Emperor has been buried (pid: %d)\n", (int) uwsgi.emperor_pid);
}
}
@@ -546,9 +559,10 @@ void uwsgi_fixup_fds(int wid, int muleid, struct uwsgi_gateway *ug) {
}
}
if (uwsgi.shared->spooler_signal_pipe[0] != -1)
close(uwsgi.shared->spooler_signal_pipe[0]);
if (uwsgi.i_am_a_spooler && uwsgi.i_am_a_spooler->pid != getpid()) {
if (uwsgi.shared->spooler_signal_pipe[0] != -1)
close(uwsgi.shared->spooler_signal_pipe[0]);
if (uwsgi.shared->spooler_signal_pipe[1] != -1)
close(uwsgi.shared->spooler_signal_pipe[1]);
}
+1
View File
@@ -312,6 +312,7 @@ int uwsgi_apply_error_routes(struct wsgi_request *wsgi_req) {
int uwsgi_apply_response_routes(struct wsgi_request *wsgi_req) {
if (!uwsgi.response_routes) return 0;
if (wsgi_req->response_routes_applied) return 0;
+12 -10
View File
@@ -269,20 +269,22 @@ int uwsgi_remote_signal_send(char *addr, uint8_t sig) {
uh.pktsize = 0;
uh.modifier2 = sig;
int fd = uwsgi_connect(addr, uwsgi.socket_timeout, 0);
if (fd < 0)
return -1;
int fd = uwsgi_connect(addr, 0, 1);
if (fd < 0) return -1;
if (write(fd, (char *) &uh, 4) != 4) {
uwsgi_error("uwsgi_remote_signal_send()");
close(fd);
return -1;
}
// wait for connection
if (uwsgi.wait_write_hook(fd, uwsgi.socket_timeout) <= 0) goto end;
int ret = uwsgi_read_response(fd, &uh, uwsgi.socket_timeout, NULL);
if (uwsgi_write_true_nb(fd, (char *) &uh, 4, uwsgi.socket_timeout)) goto end;
if (uwsgi_read_whole_true_nb(fd, (char *) &uh, 4, uwsgi.socket_timeout)) goto end;
close(fd);
return ret;
return uh.modifier2;
end:
close(fd);
return -1;
}
+34 -28
View File
@@ -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
View File
@@ -1916,6 +1916,17 @@ int main(int argc, char *argv[], char *envp[]) {
return uwsgi_run();
}
static char *uwsgi_at_file_read(char *filename) {
size_t size = 0;
char *buffer = uwsgi_open_and_read(filename, &size, 1, NULL);
if (size > 1) {
if (buffer[size-2] == '\n' || buffer[size-2] == '\r') {
buffer[size-2] = 0;
}
}
return buffer;
}
void uwsgi_setup(int argc, char *argv[], char *envp[]) {
#ifdef UWSGI_AS_SHARED_LIBRARY
#ifdef __APPLE__
@@ -2113,7 +2124,7 @@ void uwsgi_setup(int argc, char *argv[], char *envp[]) {
uwsgi_apply_config_pass('$', (char *(*)(char *)) getenv);
// third pass: FILEs
uwsgi_apply_config_pass('@', uwsgi_simple_file_read);
uwsgi_apply_config_pass('@', uwsgi_at_file_read);
// last pass: REFERENCEs
uwsgi_apply_config_pass('%', uwsgi_manage_placeholder);
@@ -2772,6 +2783,7 @@ int uwsgi_start(void *v_argv) {
!uwsgi.command_mode &&
!uwsgi.daemons_cnt &&
!uwsgi.crons &&
!uwsgi.spoolers &&
!uwsgi.emperor_proxy
#ifdef __linux__
&& !uwsgi.setns_socket
@@ -2930,7 +2942,7 @@ unsafe:
}
// initialize locks and socket as soon as possible, as the master could enqueue tasks
if (uwsgi.spoolers != NULL && (uwsgi.sockets || uwsgi.loop)) {
if (uwsgi.spoolers != NULL) {
create_signal_pipe(uwsgi.shared->spooler_signal_pipe);
struct uwsgi_spooler *uspool = uwsgi.spoolers;
while (uspool) {
@@ -3068,15 +3080,13 @@ next:
if (uwsgi.spoolers != NULL && (uwsgi.sockets || uwsgi.loop)) {
struct uwsgi_spooler *uspool = uwsgi.spoolers;
while (uspool) {
if (uspool->mode == UWSGI_SPOOLER_EXTERNAL)
goto next2;
uspool->pid = spooler_start(uspool);
struct uwsgi_spooler *uspool = uwsgi.spoolers;
while (uspool) {
if (uspool->mode == UWSGI_SPOOLER_EXTERNAL)
goto next2;
uspool->pid = spooler_start(uspool);
next2:
uspool = uspool->next;
}
uspool = uspool->next;
}
if (!uwsgi.master_process) {
+31 -23
View File
@@ -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
View File
@@ -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);
}
+5 -3
View File
@@ -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);
-1
View File
@@ -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);
+19 -2
View File
@@ -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;
+2
View File
@@ -65,6 +65,8 @@ struct uwsgi_perl {
int shell_oneshot;
CV *spooler;
int no_plack;
};
void init_perl_embedded_module(void);
+46 -37
View File
@@ -313,9 +313,6 @@ int init_psgi_app(struct wsgi_request *wsgi_req, char *app, uint16_t app_len, Pe
char *app_name = uwsgi_concat2n(app, app_len, "", 0);
size_t size;
char *buf = uwsgi_open_and_read(app_name, &size, 1, NULL);
if (uwsgi_file_exists(app_name)) {
// prepare for $0 (if the file is local)
uperl.embedding[1] = app_name;
@@ -368,38 +365,30 @@ int init_psgi_app(struct wsgi_request *wsgi_req, char *app, uint16_t app_len, Pe
uperl.tmp_current_i = i;
if (uperl.locallib) {
uwsgi_log("using %s as local::lib directory\n", uperl.locallib);
uperl.embedding[1] = uwsgi_concat2("-Mlocal::lib=", uperl.locallib);
uperl.embedding[2] = app_name;
if (perl_parse(interpreters[i], xs_init, 3, uperl.embedding, NULL)) {
// what to do here ? i hope no-one will use threads with dynamic apps... but clear the whole stuff...
free(uperl.embedding[1]);
uperl.embedding[1] = app_name;
free(callables);
uwsgi_perl_free_stashes();
goto clear;
}
free(uperl.embedding[1]);
uperl.embedding[1] = app_name;
}
else {
if (perl_parse(interpreters[i], xs_init, 2, uperl.embedding, NULL)) {
// We need to initialize the interpreter to execute
// our xs_init hook, but we're *not* calling it with
// uperl.embedding as an argument so we won't execute
// BEGIN blocks in app_name twice.
{
char *perl_init_arg[] = { "", "-e", "0" };
if (perl_parse(interpreters[i], xs_init, 3, perl_init_arg, NULL)) {
// what to do here ? i hope no-one will use threads with dynamic apps... but clear the whole stuff...
free(callables);
uwsgi_perl_free_stashes();
goto clear;
}
}
}
if (uperl.locallib) {
uwsgi_log("using %s as local::lib directory\n", uperl.locallib);
char *local_lib_use = uwsgi_concat3("use local::lib qw(", uperl.locallib, ");");
perl_eval_pv(local_lib_use, 1);
free(local_lib_use);
}
perl_eval_pv("use IO::Handle;", 1);
perl_eval_pv("use IO::File;", 1);
perl_eval_pv("use IO::Socket;", 1);
perl_eval_pv("use Scalar::Util;", 1);
if (!uperl.no_die_catch) {
perl_eval_pv("use Devel::StackTrace; $SIG{__DIE__} = sub { print Devel::StackTrace->new()->as_string() };", 0);
}
if (uperl.argv_items || uperl.argv_item) {
AV *uperl_argv = GvAV(PL_argvgv);
@@ -417,12 +406,32 @@ int init_psgi_app(struct wsgi_request *wsgi_req, char *app, uint16_t app_len, Pe
}
}
SV *dollar_zero = get_sv("0", GV_ADD);
sv_setsv(dollar_zero, newSVpv(app, app_len));
callables[i] = perl_eval_pv(uwsgi_concat4("#line 1 ", app_name, "\n", buf), 0);
if (!callables[i]) {
SV *has_plack = NULL;
if (!uperl.no_plack) {
has_plack = perl_eval_pv("use Plack::Util;", 0);
}
if (!has_plack || SvTRUE(ERRSV)) {
if (!uperl.no_plack) {
uwsgi_log("Plack::Util is not installed, using \"do\" instead of \"load_psgi\"\n");
}
char *code = uwsgi_concat3("my $app = do '", app_name, "'; if ( !$app && ( my $error = $@ || $! )) { die $error; }; $app");
callables[i] = perl_eval_pv(code, 0);
free(code);
}
else {
char *code = uwsgi_concat3("Plack::Util::load_psgi '", app_name , "';");
callables[i] = perl_eval_pv(code, 0);
free(code);
}
if (!callables[i] || SvTYPE(callables[i]) == SVt_NULL || SvTRUE(ERRSV)) {
if (SvTRUE(ERRSV)) {
uwsgi_log("%s", SvPV_nolen(ERRSV));
}
uwsgi_log("unable to find PSGI function entry point.\n");
// what to do here ? i hope no-one will use threads with dynamic apps...
free(callables);
@@ -430,18 +439,16 @@ int init_psgi_app(struct wsgi_request *wsgi_req, char *app, uint16_t app_len, Pe
goto clear;
}
if (!uperl.no_die_catch) {
perl_eval_pv("use Devel::StackTrace; $SIG{__DIE__} = sub { print Devel::StackTrace->new()->as_string() };", 0);
if(SvTRUE(ERRSV)) {
uwsgi_log("%s", SvPV_nolen(ERRSV));
}
}
PERL_SET_CONTEXT(interpreters[0]);
}
free(buf);
if(SvTRUE(ERRSV)) {
uwsgi_log("%s", SvPV_nolen(ERRSV));
free(callables);
uwsgi_perl_free_stashes();
goto clear;
}
if (uwsgi_apps_cnt >= uwsgi.max_apps) {
uwsgi_log("ERROR: you cannot load more than %d apps in a worker\n", uwsgi.max_apps);
goto clear;
@@ -504,6 +511,8 @@ void uwsgi_psgi_preinit_apps() {
perl_parse(uperl.main[0], xs_init, 3, uperl.embedding, NULL);
struct uwsgi_string_list *usl;
uwsgi_foreach(usl, uperl.exec) {
SV *dollar_zero = get_sv("0", GV_ADD);
sv_setsv(dollar_zero, newSVpv(usl->value, usl->len));
uwsgi_perl_exec(usl->value);
}
}
+4
View File
@@ -44,6 +44,8 @@ struct uwsgi_option uwsgi_perl_options[] = {
{"plshell", optional_argument, 0, "run a perl interactive shell", uwsgi_opt_plshell, NULL, 0},
{"plshell-oneshot", no_argument, 0, "run a perl interactive shell (one shot)", uwsgi_opt_plshell, NULL, 0},
{"perl-no-plack", no_argument, 0, "force the use of do instead of Plack::Util::load_psgi", uwsgi_opt_true, &uperl.no_plack, 0},
{0, 0, 0, 0, 0, 0, 0},
};
@@ -705,6 +707,8 @@ void uwsgi_perl_post_fork() {
struct uwsgi_string_list *usl;
uwsgi_foreach(usl, uperl.exec_post_fork) {
SV *dollar_zero = get_sv("0", GV_ADD);
sv_setsv(dollar_zero, newSVpv(usl->value, usl->len));
uwsgi_perl_exec(usl->value);
}
+22 -25
View File
@@ -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;
}
+10
View File
@@ -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
+2 -1
View File
@@ -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)) {
+38 -2
View File
@@ -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);
+6 -5
View File
@@ -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;
}
+12
View File
@@ -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
+106
View File
@@ -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()
+4
View File
@@ -1,5 +1,9 @@
use strict;
use warnings;
BEGIN {
die "PANIC: We should only load this once" if ++$main::count_BEGIN > 1;
}
die "PANIC: We should only run this once" if ++$main::count_runs > 1;
uwsgi::register_rpc('hello', sub {
my ($one, $two, $three) = @_;
+1 -1
View File
@@ -2,7 +2,7 @@ Gem::Specification.new do |s|
s.name = 'uwsgi'
s.license = 'GPL-2'
s.version = `python -c "import uwsgiconfig as uc; print uc.uwsgi_version"`.sub(/-dev-.*/,'')
s.date = '2014-02-09'
s.date = '2014-02-26'
s.summary = "uWSGI"
s.description = "The uWSGI server for Ruby/Rack"
s.authors = ["Unbit"]
+1 -1
View File
@@ -1,6 +1,6 @@
# uWSGI build system
uwsgi_version = '2.0.1'
uwsgi_version = '2.0.2'
import os
import re