mirror of
https://github.com/clearlinux/uwsgi.git
synced 2026-10-04 16:08:31 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
41b6005d30 | ||
|
|
497f7efa55 | ||
|
|
ad7ca0b098 | ||
|
|
1d591c95f2 | ||
|
|
d3daca0b16 | ||
|
|
bae1ade00a | ||
|
|
fd663aedbd | ||
|
|
6b9ce2d755 | ||
|
|
bd2728b391 | ||
|
|
dc250fd7b5 | ||
|
|
0a9345b8d4 | ||
|
|
db509f2d38 | ||
|
|
b12c39607d | ||
|
|
224260ce3e | ||
|
|
5f86d9522f | ||
|
|
a0fafe7847 | ||
|
|
daeaf1b231 | ||
|
|
fbc0a2775f | ||
|
|
d3c89a3f63 | ||
|
|
cd43a0d12d | ||
|
|
f06df71bfc | ||
|
|
eab2472dd0 | ||
|
|
87a2f3585c | ||
|
|
c257a9aa98 | ||
|
|
43aebe2d66 | ||
|
|
309115d611 | ||
|
|
5881d41b2b | ||
|
|
9fe4b7b14a | ||
|
|
930c19210a | ||
|
|
5beb170cfd | ||
|
|
a13103d851 | ||
|
|
bc5a86694f | ||
|
|
812685096b | ||
|
|
f70c070a0f | ||
|
|
accf622ffc | ||
|
|
04173869ee | ||
|
|
509a3c5cd4 | ||
|
|
81ad3a916d | ||
|
|
3f93a0b8e4 | ||
|
|
4408b655a4 | ||
|
|
71a6b8a304 | ||
|
|
7e9069eabf | ||
|
|
6c77dd0e38 | ||
|
|
27e506c72a | ||
|
|
bea68191e3 | ||
|
|
9b207d8a62 | ||
|
|
68d5b2de3b | ||
|
|
3a62573005 | ||
|
|
1c6dd42318 | ||
|
|
73ad0677bd | ||
|
|
15b2cf0712 | ||
|
|
0da0fa211a | ||
|
|
a8ecd71ffd | ||
|
|
ea0a95a441 | ||
|
|
6ac6e58bf7 | ||
|
|
f2c7addb73 | ||
|
|
fff5fa536b | ||
|
|
95825c9b99 | ||
|
|
1e84fcf880 | ||
|
|
0f742a72bf | ||
|
|
fd96a02576 | ||
|
|
77ca76428d | ||
|
|
9ea8f4f07c | ||
|
|
9ffc311177 | ||
|
|
4f89a350aa | ||
|
|
8f18c77587 | ||
|
|
371cafef94 | ||
|
|
89c31e9280 | ||
|
|
418d784148 | ||
|
|
c146275e9b | ||
|
|
eff23382c2 | ||
|
|
d566469c63 | ||
|
|
e008ce5d56 | ||
|
|
9d21c99183 | ||
|
|
7e80927317 | ||
|
|
6664e7120b | ||
|
|
687aabd30b | ||
|
|
fab656c635 | ||
|
|
72c31dab7a | ||
|
|
f19a301b73 | ||
|
|
19a19a8a67 | ||
|
|
d9c9f41624 | ||
|
|
dc97853f9f | ||
|
|
b089774c36 | ||
|
|
f8a271a027 | ||
|
|
ef12aaf13c | ||
|
|
a559361a30 | ||
|
|
6aad281441 | ||
|
|
7604c67018 | ||
|
|
afc962709f | ||
|
|
c11e0654a0 | ||
|
|
6e4f47cc76 | ||
|
|
20c9f0ef40 | ||
|
|
ef3c8a5bd9 | ||
|
|
76d0438fee | ||
|
|
18fd338908 | ||
|
|
2b35e95706 | ||
|
|
4761146599 | ||
|
|
3924cc639e | ||
|
|
5f09de0469 | ||
|
|
4f0e3fb79f | ||
|
|
05b6baf173 | ||
|
|
149823aac4 | ||
|
|
85d86dc10e | ||
|
|
e97d921909 | ||
|
|
c5e20bf4da | ||
|
|
a09d25ccaa | ||
|
|
bf01cea062 | ||
|
|
b6459be3e4 | ||
|
|
d42788c17b | ||
|
|
872730c116 | ||
|
|
6fce0aee84 | ||
|
|
e3d8a02614 | ||
|
|
b58696399e | ||
|
|
519c9f58b3 | ||
|
|
2c77c5c639 | ||
|
|
fb9e5a1891 | ||
|
|
5aa7d1a79f | ||
|
|
bc3442ba29 | ||
|
|
3061e36089 | ||
|
|
4f8c41cf61 | ||
|
|
b0065c379e | ||
|
|
57f71c974d | ||
|
|
b820fefbbd | ||
|
|
5f759f0d26 | ||
|
|
f7eb9ed1cd | ||
|
|
3a82732b19 | ||
|
|
d74e826f71 | ||
|
|
c846a9b388 | ||
|
|
001e4b6e39 | ||
|
|
a51a396f47 | ||
|
|
17965ea870 | ||
|
|
8a032b41ec | ||
|
|
a489cfc2c1 | ||
|
|
3b32672ff9 | ||
|
|
858131ba57 | ||
|
|
8a8d2f8675 | ||
|
|
9d37725323 | ||
|
|
e973492267 | ||
|
|
105a68bce9 | ||
|
|
0587a0ca53 | ||
|
|
d4b259d5e0 | ||
|
|
9e591c587f | ||
|
|
e7cce7b785 | ||
|
|
3285b224c2 | ||
|
|
e4a4942980 | ||
|
|
6f671936fc | ||
|
|
7d1d992d58 | ||
|
|
2bba4cf15a | ||
|
|
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 |
@@ -7,6 +7,7 @@
|
||||
|
||||
/uwsgi
|
||||
/uwsgibuild.*
|
||||
/core/config_py.c
|
||||
|
||||
/t/ring/target
|
||||
|
||||
|
||||
@@ -26,3 +26,5 @@ Natanael Copa
|
||||
Roberto Leandrini
|
||||
Ryan Petrello
|
||||
Danila Shtan <danila@shtan.ru>
|
||||
Ævar Arnfjörð Bjarmason
|
||||
Yu Zhao (getcwd)
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
main_plugin = python,asyncio,greenlet
|
||||
inherit = base
|
||||
+26
-27
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -363,6 +363,19 @@ void uwsgi_alarm_thread_start() {
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_alarm_trigger_uai(struct uwsgi_alarm_instance *uai, char *msg, size_t len) {
|
||||
struct iovec iov[2];
|
||||
iov[0].iov_base = &uai;
|
||||
iov[0].iov_len = sizeof(long);
|
||||
iov[1].iov_base = msg;
|
||||
iov[1].iov_len = len;
|
||||
|
||||
// now send the message to the alarm thread
|
||||
if (writev(uwsgi.alarm_thread->pipe[0], iov, 2) != (ssize_t) (len+sizeof(long))) {
|
||||
uwsgi_error("[uwsgi-alarm-error] uwsgi_alarm_trigger()/writev()");
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef UWSGI_PCRE
|
||||
// check if a log should raise an alarm
|
||||
void uwsgi_alarm_log_check(char *msg, size_t len) {
|
||||
@@ -372,7 +385,14 @@ void uwsgi_alarm_log_check(char *msg, size_t len) {
|
||||
while (ual) {
|
||||
if (uwsgi_regexp_match(ual->pattern, ual->pattern_extra, msg, len) >= 0) {
|
||||
if (!ual->negate) {
|
||||
uwsgi_alarm_log_run(ual, msg, len);
|
||||
struct uwsgi_alarm_ll *uall = ual->alarms;
|
||||
while (uall) {
|
||||
if (uwsgi.alarm_cheap)
|
||||
uwsgi_alarm_trigger_uai(uall->alarm, msg, len);
|
||||
else
|
||||
uwsgi_alarm_run(uall->alarm, msg, len);
|
||||
uall = uall->next;
|
||||
}
|
||||
}
|
||||
else {
|
||||
break;
|
||||
@@ -397,18 +417,6 @@ void uwsgi_alarm_run(struct uwsgi_alarm_instance *uai, char *msg, size_t len) {
|
||||
uai->last_msg_size = len;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_PCRE
|
||||
// call the alarms mapped to a log line
|
||||
void uwsgi_alarm_log_run(struct uwsgi_alarm_log *ual, char *msg, size_t len) {
|
||||
struct uwsgi_alarm_ll *uall = ual->alarms;
|
||||
while (uall) {
|
||||
uwsgi_alarm_run(uall->alarm, msg, len);
|
||||
uall = uall->next;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// this is the api function workers,mules and whatever you want can call from code
|
||||
void uwsgi_alarm_trigger(char *alarm_instance_name, char *msg, size_t len) {
|
||||
if (!uwsgi.alarm_thread) return;
|
||||
@@ -416,16 +424,7 @@ void uwsgi_alarm_trigger(char *alarm_instance_name, char *msg, size_t len) {
|
||||
struct uwsgi_alarm_instance *uai = uwsgi_alarm_get_instance(alarm_instance_name);
|
||||
if (!uai) return;
|
||||
|
||||
struct iovec iov[2];
|
||||
iov[0].iov_base = &uai;
|
||||
iov[0].iov_len = sizeof(long);
|
||||
iov[1].iov_base = msg;
|
||||
iov[1].iov_len = len;
|
||||
|
||||
// now send the message to the alarm thread
|
||||
if (writev(uwsgi.alarm_thread->pipe[0], iov, 2) != (ssize_t) (len+sizeof(long))) {
|
||||
uwsgi_error("[uwsgi-alarm-error] uwsgi_alarm_trigger()/writev()");
|
||||
}
|
||||
uwsgi_alarm_trigger_uai(uai, msg, len);
|
||||
}
|
||||
|
||||
struct uwsgi_alarm_fd *uwsgi_add_alarm_fd(int fd, char *alarm, size_t buf_len, char *msg, size_t msg_len) {
|
||||
|
||||
+141
-33
@@ -472,6 +472,38 @@ uint32_t uwsgi_cache_exists2(struct uwsgi_cache *uc, char *key, uint16_t keylen)
|
||||
return uwsgi_cache_get_index(uc, key, keylen);
|
||||
}
|
||||
|
||||
static void lru_remove_item(struct uwsgi_cache *uc, uint64_t index)
|
||||
{
|
||||
struct uwsgi_cache_item *prev, *next, *curr = cache_item(index);
|
||||
|
||||
if (curr->lru_next) {
|
||||
next = cache_item(curr->lru_next);
|
||||
next->lru_prev = curr->lru_prev;
|
||||
} else
|
||||
uc->lru_tail = curr->lru_prev;
|
||||
|
||||
if (curr->lru_prev) {
|
||||
prev = cache_item(curr->lru_prev);
|
||||
prev->lru_next = curr->lru_next;
|
||||
} else
|
||||
uc->lru_head = curr->lru_next;
|
||||
}
|
||||
|
||||
static void lru_add_item(struct uwsgi_cache *uc, uint64_t index)
|
||||
{
|
||||
struct uwsgi_cache_item *prev, *curr = cache_item(index);
|
||||
|
||||
if (uc->lru_tail) {
|
||||
prev = cache_item(uc->lru_tail);
|
||||
prev->lru_next = index;
|
||||
} else
|
||||
uc->lru_head = index;
|
||||
|
||||
curr->lru_next = 0;
|
||||
curr->lru_prev = uc->lru_tail;
|
||||
uc->lru_tail = index;
|
||||
}
|
||||
|
||||
char *uwsgi_cache_get2(struct uwsgi_cache *uc, char *key, uint16_t keylen, uint64_t * valsize) {
|
||||
|
||||
uint64_t index = uwsgi_cache_get_index(uc, key, keylen);
|
||||
@@ -481,6 +513,10 @@ char *uwsgi_cache_get2(struct uwsgi_cache *uc, char *key, uint16_t keylen, uint6
|
||||
if (uci->flags & UWSGI_CACHE_FLAG_UNGETTABLE)
|
||||
return NULL;
|
||||
*valsize = uci->valsize;
|
||||
if (uc->purge_lru) {
|
||||
lru_remove_item(uc, index);
|
||||
lru_add_item(uc, index);
|
||||
}
|
||||
uci->hits++;
|
||||
uc->hits++;
|
||||
return uc->data + (uci->first_block * uc->blocksize);
|
||||
@@ -520,6 +556,10 @@ char *uwsgi_cache_get3(struct uwsgi_cache *uc, char *key, uint16_t keylen, uint6
|
||||
*valsize = uci->valsize;
|
||||
if (expires)
|
||||
*expires = uci->expires;
|
||||
if (uc->purge_lru) {
|
||||
lru_remove_item(uc, index);
|
||||
lru_add_item(uc, index);
|
||||
}
|
||||
uci->hits++;
|
||||
uc->hits++;
|
||||
return uc->data + (uci->first_block * uc->blocksize);
|
||||
@@ -588,6 +628,10 @@ int uwsgi_cache_del2(struct uwsgi_cache *uc, char *key, uint16_t keylen, uint64_
|
||||
// reset hashtable entry
|
||||
uc->hashtable[uci->hash % uc->hashsize] = 0;
|
||||
}
|
||||
|
||||
if (uc->purge_lru)
|
||||
lru_remove_item(uc, index);
|
||||
|
||||
uc->n_items--;
|
||||
}
|
||||
|
||||
@@ -666,9 +710,17 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v
|
||||
index = uwsgi_cache_get_index(uc, key, keylen);
|
||||
if (!index) {
|
||||
if (!uc->unused_blocks_stack_ptr) {
|
||||
uwsgi_log("*** DANGER cache \"%s\" is FULL !!! ***\n", uc->name);
|
||||
if (!uc->ignore_full) {
|
||||
if (uc->purge_lru)
|
||||
uwsgi_log("LRU item will be purged from cache \"%s\"\n", uc->name);
|
||||
else
|
||||
uwsgi_log("*** DANGER cache \"%s\" is FULL !!! ***\n", uc->name);
|
||||
}
|
||||
uc->full++;
|
||||
goto end;
|
||||
if (uc->purge_lru && uc->lru_head)
|
||||
uwsgi_cache_del2(uc, NULL, 0, uc->lru_head, UWSGI_CACHE_FLAG_LOCAL);
|
||||
if (!uc->unused_blocks_stack_ptr)
|
||||
goto end;
|
||||
}
|
||||
|
||||
index = uc->unused_blocks_stack[uc->unused_blocks_stack_ptr];
|
||||
@@ -681,7 +733,8 @@ 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);
|
||||
if (uci->first_block == 0xffffffffffffffffLLU) {
|
||||
uwsgi_log("*** DANGER cache \"%s\" is FULL !!! ***\n", uc->name);
|
||||
if (!uc->ignore_full)
|
||||
uwsgi_log("*** DANGER cache \"%s\" is FULL !!! ***\n", uc->name);
|
||||
uc->full++;
|
||||
uc->unused_blocks_stack_ptr++;
|
||||
goto end;
|
||||
@@ -696,9 +749,13 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v
|
||||
uc->blocks_bitmap_pos = uci->first_block + needed_blocks;
|
||||
}
|
||||
}
|
||||
if (expires && !(flags & UWSGI_CACHE_FLAG_ABSEXPIRE)) {
|
||||
if (uc->purge_lru)
|
||||
lru_add_item(uc, index);
|
||||
else if (expires && !(flags & UWSGI_CACHE_FLAG_ABSEXPIRE)) {
|
||||
now = uwsgi_now();
|
||||
expires += now;
|
||||
if (!uc->next_scan || uc->next_scan > expires)
|
||||
uc->next_scan = expires;
|
||||
}
|
||||
uci->expires = expires;
|
||||
uci->hash = uc->hash->func(key, keylen);
|
||||
@@ -763,9 +820,16 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v
|
||||
}
|
||||
else if (flags & UWSGI_CACHE_FLAG_UPDATE) {
|
||||
uci = cache_item(index);
|
||||
if (expires && !(flags & UWSGI_CACHE_FLAG_ABSEXPIRE) && !(flags & UWSGI_CACHE_FLAG_FIXEXPIRE)) {
|
||||
now = uwsgi_now();
|
||||
expires += now;
|
||||
if (!(flags & UWSGI_CACHE_FLAG_FIXEXPIRE)) {
|
||||
if (uc->purge_lru) {
|
||||
lru_remove_item(uc, index);
|
||||
lru_add_item(uc, index);
|
||||
} else if (expires && !(flags & UWSGI_CACHE_FLAG_ABSEXPIRE)) {
|
||||
now = uwsgi_now();
|
||||
expires += now;
|
||||
if (!uc->next_scan || uc->next_scan > expires)
|
||||
uc->next_scan = expires;
|
||||
}
|
||||
uci->expires = expires;
|
||||
}
|
||||
if (uc->blocks_bitmap) {
|
||||
@@ -773,7 +837,8 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v
|
||||
uint64_t old_first_block = uci->first_block;
|
||||
uci->first_block = uwsgi_cache_find_free_blocks(uc, vallen);
|
||||
if (uci->first_block == 0xffffffffffffffffLLU) {
|
||||
uwsgi_log("*** DANGER cache \"%s\" is FULL !!! ***\n", uc->name);
|
||||
if (!uc->ignore_full)
|
||||
uwsgi_log("*** DANGER cache \"%s\" is FULL !!! ***\n", uc->name);
|
||||
uc->full++;
|
||||
uci->first_block = old_first_block;
|
||||
goto end;
|
||||
@@ -983,39 +1048,66 @@ void *cache_udp_server_loop(void *ucache) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static uint64_t cache_sweeper_free_items(struct uwsgi_cache *uc) {
|
||||
uint64_t i;
|
||||
uint64_t freed_items = 0;
|
||||
|
||||
if (uc->no_expire || uc->purge_lru)
|
||||
return 0;
|
||||
|
||||
uwsgi_rlock(uc->lock);
|
||||
if (!uc->next_scan || uc->next_scan > (uint64_t)uwsgi.current_time) {
|
||||
uwsgi_rwunlock(uc->lock);
|
||||
return 0;
|
||||
}
|
||||
uwsgi_rwunlock(uc->lock);
|
||||
|
||||
// skip the first slot
|
||||
for (i = 1; i < uc->max_items; i++) {
|
||||
struct uwsgi_cache_item *uci = cache_item(i);
|
||||
|
||||
uwsgi_wlock(uc->lock);
|
||||
// we reset next scan time first, then we find the least
|
||||
// expiration time from those that are NOT expired yet.
|
||||
if (i == 1)
|
||||
uc->next_scan = 0;
|
||||
|
||||
if (uci->expires) {
|
||||
if (uci->expires <= (uint64_t)uwsgi.current_time) {
|
||||
uwsgi_cache_del2(uc, NULL, 0, i, UWSGI_CACHE_FLAG_LOCAL);
|
||||
freed_items++;
|
||||
} else if (!uc->next_scan || uc->next_scan > uci->expires) {
|
||||
uc->next_scan = uci->expires;
|
||||
}
|
||||
}
|
||||
uwsgi_rwunlock(uc->lock);
|
||||
}
|
||||
|
||||
return freed_items;
|
||||
}
|
||||
|
||||
static void *cache_sweeper_loop(void *ucache) {
|
||||
|
||||
uint64_t i;
|
||||
// block all signals
|
||||
sigset_t smask;
|
||||
sigfillset(&smask);
|
||||
pthread_sigmask(SIG_BLOCK, &smask, NULL);
|
||||
|
||||
struct uwsgi_cache *uc = (struct uwsgi_cache *) ucache;
|
||||
|
||||
if (!uwsgi.cache_expire_freq)
|
||||
uwsgi.cache_expire_freq = 3;
|
||||
|
||||
// remove expired cache items TODO use rb_tree timeouts
|
||||
for (;;) {
|
||||
struct uwsgi_cache *uc;
|
||||
|
||||
for (uc = (struct uwsgi_cache *)ucache; uc; uc = uc->next) {
|
||||
uint64_t freed_items = cache_sweeper_free_items(uc);
|
||||
if (uwsgi.cache_report_freed_items && freed_items)
|
||||
uwsgi_log("freed %llu items for cache \"%s\"\n", (unsigned long long)freed_items, uc->name);
|
||||
}
|
||||
|
||||
sleep(uwsgi.cache_expire_freq);
|
||||
uint64_t freed_items = 0;
|
||||
// skip the first slot
|
||||
for (i = 1; i < uc->max_items; i++) {
|
||||
uwsgi_wlock(uc->lock);
|
||||
struct uwsgi_cache_item *uci = cache_item(i);
|
||||
if (uci->expires) {
|
||||
if (uci->expires < (uint64_t) uwsgi.current_time) {
|
||||
uwsgi_cache_del2(uc, NULL, 0, i, UWSGI_CACHE_FLAG_LOCAL);
|
||||
freed_items++;
|
||||
}
|
||||
}
|
||||
uwsgi_rwunlock(uc->lock);
|
||||
}
|
||||
if (uwsgi.cache_report_freed_items && freed_items > 0) {
|
||||
uwsgi_log("freed %llu items for cache \"%s\"\n", (unsigned long long) freed_items, uc->name);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -1035,16 +1127,21 @@ void uwsgi_cache_sync_all() {
|
||||
|
||||
void uwsgi_cache_start_sweepers() {
|
||||
struct uwsgi_cache *uc = uwsgi.caches;
|
||||
|
||||
if (uwsgi.cache_no_expire)
|
||||
return;
|
||||
|
||||
while(uc) {
|
||||
pthread_t cache_sweeper;
|
||||
if (!uwsgi.cache_no_expire && !uc->no_expire) {
|
||||
if (pthread_create(&cache_sweeper, NULL, cache_sweeper_loop, (void *) uc)) {
|
||||
if (!uc->no_expire && !uc->purge_lru) {
|
||||
if (pthread_create(&cache_sweeper, NULL, cache_sweeper_loop, uwsgi.caches)) {
|
||||
uwsgi_error("pthread_create()");
|
||||
uwsgi_log("unable to run the sweeper for cache \"%s\" !!!\n", uc->name);
|
||||
uwsgi_log("unable to run the sweeper!!!\n");
|
||||
}
|
||||
else {
|
||||
uwsgi_log("sweeper thread enabled for cache \"%s\"\n", uc->name);
|
||||
uwsgi_log("sweeper thread enabled\n");
|
||||
}
|
||||
break;
|
||||
}
|
||||
uc = uc->next;
|
||||
}
|
||||
@@ -1121,6 +1218,8 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) {
|
||||
char *c_bitmap = NULL;
|
||||
char *c_use_last_modified = NULL;
|
||||
char *c_math_initial = NULL;
|
||||
char *c_ignore_full = NULL;
|
||||
char *c_purge_lru = NULL;
|
||||
|
||||
if (uwsgi_kvlist_parse(arg, strlen(arg), ',', '=',
|
||||
"name", &c_name,
|
||||
@@ -1148,6 +1247,9 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) {
|
||||
"bitmap", &c_bitmap,
|
||||
"lastmod", &c_use_last_modified,
|
||||
"math_initial", &c_math_initial,
|
||||
"ignore_full", &c_ignore_full,
|
||||
"purge_lru", &c_purge_lru,
|
||||
"lru", &c_purge_lru,
|
||||
NULL)) {
|
||||
uwsgi_log("unable to parse cache definition\n");
|
||||
exit(1);
|
||||
@@ -1195,6 +1297,7 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) {
|
||||
uc->max_item_size = uc->blocksize * uc->blocks;
|
||||
}
|
||||
if (c_use_last_modified) uc->use_last_modified = 1;
|
||||
if (c_ignore_full) uc->ignore_full = 1;
|
||||
|
||||
if (c_math_initial) uc->math_initial = strtol(c_math_initial, NULL, 10);
|
||||
|
||||
@@ -1229,6 +1332,8 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) {
|
||||
}
|
||||
}
|
||||
|
||||
if (c_purge_lru)
|
||||
uc->purge_lru = 1;
|
||||
}
|
||||
|
||||
uwsgi_cache_init(uc);
|
||||
@@ -1484,7 +1589,10 @@ char *uwsgi_cache_magic_get(char *key, uint16_t keylen, uint64_t *vallen, uint64
|
||||
|
||||
// we have a local cache !!!
|
||||
if (uc) {
|
||||
uwsgi_rlock(uc->lock);
|
||||
if (uc->purge_lru)
|
||||
uwsgi_wlock(uc->lock);
|
||||
else
|
||||
uwsgi_rlock(uc->lock);
|
||||
char *value = uwsgi_cache_get3(uc, key, keylen, vallen, expires);
|
||||
if (!value) {
|
||||
uwsgi_rwunlock(uc->lock);
|
||||
|
||||
@@ -816,3 +816,19 @@ char *uwsgi_manage_placeholder(char *key) {
|
||||
|
||||
return current_value;
|
||||
}
|
||||
|
||||
void uwsgi_opt_resolve(char *opt, char *value, void *foo) {
|
||||
char *equal = strchr(value, '=');
|
||||
if (!equal) {
|
||||
uwsgi_log("invalid resolve syntax, must be placeholder=domain\n");
|
||||
exit(1);
|
||||
}
|
||||
char *ip = uwsgi_resolve_ip(equal+1);
|
||||
if (!ip) {
|
||||
uwsgi_log("unable to resolve name %s\n", equal+1);
|
||||
uwsgi_error("uwsgi_resolve_ip()");
|
||||
exit(1);
|
||||
}
|
||||
char *new_opt = uwsgi_concat2n(value, (equal-value)+1, ip, strlen(ip));
|
||||
uwsgi_opt_set_placeholder(opt, new_opt, (void *) 1);
|
||||
}
|
||||
|
||||
+811
-585
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
|
||||
@@ -485,6 +485,60 @@ static int uwsgi_hook_callret(char *arg) {
|
||||
return func();
|
||||
}
|
||||
|
||||
static int uwsgi_hook_rpc(char *arg) {
|
||||
|
||||
int ret = -1;
|
||||
size_t i, argc = 0;
|
||||
char **rargv = uwsgi_split_quoted(arg, strlen(arg), " \t", &argc);
|
||||
if (!argc) goto end;
|
||||
if (argc > 256) goto destroy;
|
||||
|
||||
char *argv[256];
|
||||
uint16_t argvs[256];
|
||||
|
||||
char *node = NULL;
|
||||
char *func = rargv[0];
|
||||
|
||||
char *at = strchr(func, '@');
|
||||
if (at) {
|
||||
*at = 0;
|
||||
node = at + 1;
|
||||
}
|
||||
|
||||
for(i=0;i<(argc-1);i++) {
|
||||
size_t a_len = strlen(rargv[i+1]);
|
||||
if (a_len > 0xffff) goto destroy;
|
||||
argv[i] = rargv[i+1] ;
|
||||
argvs[i] = a_len;
|
||||
}
|
||||
|
||||
uint64_t size = 0;
|
||||
// response must be always freed
|
||||
char *response = uwsgi_do_rpc(node, func, argc-1, argv, argvs, &size);
|
||||
if (response) {
|
||||
if (at) *at = '@';
|
||||
uwsgi_log("[rpc result from \"%s\"] %.*s\n", rargv[0], size, response);
|
||||
free(response);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
destroy:
|
||||
for(i=0;i<argc;i++) {
|
||||
free(rargv[i]);
|
||||
}
|
||||
end:
|
||||
free(rargv);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int uwsgi_hook_retryrpc(char *arg) {
|
||||
for(;;) {
|
||||
int ret = uwsgi_hook_rpc(arg);
|
||||
if (!ret) break;
|
||||
sleep(2);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void uwsgi_register_base_hooks() {
|
||||
uwsgi_register_hook("cd", uwsgi_hook_chdir);
|
||||
@@ -523,6 +577,9 @@ void uwsgi_register_base_hooks() {
|
||||
|
||||
uwsgi_register_hook("alarm", uwsgi_hook_alarm);
|
||||
|
||||
uwsgi_register_hook("rpc", uwsgi_hook_rpc);
|
||||
uwsgi_register_hook("retryrpc", uwsgi_hook_retryrpc);
|
||||
|
||||
// for testing
|
||||
uwsgi_register_hook("exit", uwsgi_hook_exit);
|
||||
uwsgi_register_hook("print", uwsgi_hook_print);
|
||||
@@ -561,6 +618,22 @@ void uwsgi_hooks_run(struct uwsgi_string_list *l, char *phase, int fatal) {
|
||||
|
||||
int ret = uh->func(colon+1);
|
||||
if (fatal && ret != 0) {
|
||||
uwsgi_log_verbose("FATAL hook failed, destroying instance\n");
|
||||
if (uwsgi.master_process) {
|
||||
if (uwsgi.workers) {
|
||||
if (uwsgi.workers[0].pid == getpid()) {
|
||||
kill_them_all(0);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
if (kill(uwsgi.workers[0].pid, SIGINT)) {
|
||||
uwsgi_error("uwsgi_hooks_run()/kill()");
|
||||
exit(1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
+4
-3
@@ -3,9 +3,9 @@
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
struct http_status_codes {
|
||||
const char key[3];
|
||||
const char *message;
|
||||
int message_size;
|
||||
const char key[3];
|
||||
const char *message;
|
||||
int message_size;
|
||||
};
|
||||
|
||||
/* statistically ordered */
|
||||
@@ -113,6 +113,7 @@ void uwsgi_init_default() {
|
||||
uwsgi.log_master_bufsize = 8192;
|
||||
|
||||
uwsgi.worker_reload_mercy = 60;
|
||||
uwsgi.mule_reload_mercy = 60;
|
||||
|
||||
uwsgi.max_vars = MAX_VARS;
|
||||
uwsgi.vec_size = 4 + 1 + (4 * MAX_VARS);
|
||||
|
||||
+12
-6
@@ -477,13 +477,19 @@ void uwsgi_check_logrotate(void) {
|
||||
|
||||
int need_rotation = 0;
|
||||
int need_reopen = 0;
|
||||
off_t logsize;
|
||||
|
||||
if (uwsgi.log_master) {
|
||||
uwsgi.shared->logsize = lseek(uwsgi.original_log_fd, 0, SEEK_CUR);
|
||||
logsize = lseek(uwsgi.original_log_fd, 0, SEEK_CUR);
|
||||
}
|
||||
else {
|
||||
uwsgi.shared->logsize = lseek(2, 0, SEEK_CUR);
|
||||
logsize = lseek(2, 0, SEEK_CUR);
|
||||
}
|
||||
if (logsize < 0) {
|
||||
uwsgi_error("uwsgi_check_logrotate()/lseek()");
|
||||
return;
|
||||
}
|
||||
uwsgi.shared->logsize = logsize;
|
||||
|
||||
if (uwsgi.log_maxsize > 0 && (uint64_t) uwsgi.shared->logsize > uwsgi.log_maxsize) {
|
||||
need_rotation = 1;
|
||||
@@ -917,7 +923,7 @@ struct uwsgi_logger *uwsgi_get_logger_from_id(char *id) {
|
||||
struct uwsgi_logger *ul = uwsgi.choosen_logger;
|
||||
|
||||
while (ul) {
|
||||
if (!strcmp(ul->id, id)) {
|
||||
if (ul->id && !strcmp(ul->id, id)) {
|
||||
return ul;
|
||||
}
|
||||
ul = ul->next;
|
||||
@@ -1839,7 +1845,7 @@ static char *uwsgi_log_encoder_json(struct uwsgi_log_encoder *ule, char *msg, si
|
||||
if (!uwsgi_strncmp(usl->value, usl->len, "msg", 3)) {
|
||||
size_t msg_len = len;
|
||||
if (msg[len-1] == '\n') msg_len--;
|
||||
char *e_json = uwsgi_malloc(msg_len * 2);
|
||||
char *e_json = uwsgi_malloc((msg_len * 2)+1);
|
||||
escape_json(msg, msg_len, e_json);
|
||||
if (uwsgi_buffer_append(ub, e_json, strlen(e_json))){
|
||||
free(e_json);
|
||||
@@ -1848,7 +1854,7 @@ static char *uwsgi_log_encoder_json(struct uwsgi_log_encoder *ule, char *msg, si
|
||||
free(e_json);
|
||||
}
|
||||
else if (!uwsgi_strncmp(usl->value, usl->len, "msgnl", 5)) {
|
||||
char *e_json = uwsgi_malloc(len * 2);
|
||||
char *e_json = uwsgi_malloc((len * 2)+1);
|
||||
escape_json(msg, len, e_json);
|
||||
if (uwsgi_buffer_append(ub, e_json, strlen(e_json))){
|
||||
free(e_json);
|
||||
@@ -1869,7 +1875,7 @@ static char *uwsgi_log_encoder_json(struct uwsgi_log_encoder *ule, char *msg, si
|
||||
int strftime_len = strftime(sftime, 64, buf, localtime(&now));
|
||||
free(buf);
|
||||
if (strftime_len > 0) {
|
||||
char *e_json = uwsgi_malloc(strftime_len * 2);
|
||||
char *e_json = uwsgi_malloc((strftime_len * 2)+1);
|
||||
escape_json(sftime, strftime_len, e_json);
|
||||
if (uwsgi_buffer_append(ub, e_json, strlen(e_json))){
|
||||
free(e_json);
|
||||
|
||||
@@ -135,6 +135,15 @@ void uwsgi_master_check_mercy() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < uwsgi.mules_cnt; i++) {
|
||||
if (uwsgi.mules[i].pid > 0 && uwsgi.mules[i].cursed_at) {
|
||||
if (uwsgi_now() > uwsgi.mules[i].no_mercy_at) {
|
||||
uwsgi_log_verbose("mule %d (pid: %d) is taking too much time to die...NO MERCY !!!\n", i + 1, uwsgi.mules[i].pid);
|
||||
uwsgi_curse_mule(i, SIGKILL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -907,6 +916,7 @@ int master_loop(char **argv, char **environ) {
|
||||
for (i = 0; i < uwsgi.mules_cnt; i++) {
|
||||
if (uwsgi.mules[i].pid == diedpid) {
|
||||
uwsgi_log("mule %d (pid: %d) annihilated\n", i + 1, (int) diedpid);
|
||||
uwsgi.mules[i].pid = 0;
|
||||
goto next;
|
||||
}
|
||||
}
|
||||
@@ -954,6 +964,11 @@ next:
|
||||
|
||||
if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_FAILED_APP_CODE) {
|
||||
uwsgi_log("OOPS ! failed loading app in worker %d (pid %d) :( trying again...\n", thewid, (int) diedpid);
|
||||
if (uwsgi.lazy_apps && uwsgi.need_app) {
|
||||
uwsgi_log_verbose("need-app requested, destroying the instance...\n");
|
||||
kill_them_all(0);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_DE_HIJACKED_CODE) {
|
||||
uwsgi_log("...restoring worker %d (pid: %d)...\n", thewid, (int) diedpid);
|
||||
@@ -969,6 +984,10 @@ next:
|
||||
reap_them_all(0);
|
||||
continue;
|
||||
}
|
||||
else if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_GO_CHEAP_CODE) {
|
||||
uwsgi_log("worker %d asked for cheap mode (pid: %d)...\n", thewid, (int) diedpid);
|
||||
uwsgi.workers[thewid].cheaped = 1;
|
||||
}
|
||||
else if (uwsgi.workers[thewid].manage_next_request) {
|
||||
if (WIFSIGNALED(waitpid_status)) {
|
||||
uwsgi_log("DAMN ! worker %d (pid: %d) died, killed by signal %d :( trying respawn ...\n", thewid, (int) diedpid, (int) WTERMSIG(waitpid_status));
|
||||
|
||||
@@ -25,6 +25,11 @@ int uwsgi_master_check_reload(char **argv) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
for(i=0;i<uwsgi.mules_cnt;i++) {
|
||||
if (uwsgi.mules[i].pid > 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
uwsgi_reload(argv);
|
||||
// never here (unless in shared library mode)
|
||||
return -1;
|
||||
|
||||
+26
-13
@@ -24,6 +24,15 @@ void uwsgi_curse(int wid, int sig) {
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_curse_mule(int mid, int sig) {
|
||||
uwsgi.mules[mid].cursed_at = uwsgi_now();
|
||||
uwsgi.mules[mid].no_mercy_at = uwsgi.mules[mid].cursed_at + uwsgi.mule_reload_mercy;
|
||||
|
||||
if (sig) {
|
||||
(void) kill(uwsgi.mules[mid].pid, sig);
|
||||
}
|
||||
}
|
||||
|
||||
static void uwsgi_signal_spoolers(int signum) {
|
||||
|
||||
struct uwsgi_spooler *uspool = uwsgi.spoolers;
|
||||
@@ -53,15 +62,6 @@ void uwsgi_destroy_processes() {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO mules can be programmed to be gracefully reloaded
|
||||
for (i = 0; i < uwsgi.mules_cnt; i++) {
|
||||
if (uwsgi.mules[i].pid > 0) {
|
||||
kill(uwsgi.mules[i].pid, SIGKILL);
|
||||
waitpid(uwsgi.mules[i].pid, &waitpid_status, 0);
|
||||
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);
|
||||
@@ -412,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...) */
|
||||
@@ -788,7 +796,7 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
|
||||
|
||||
// allocate 2x the size of original command
|
||||
// in case we need to escape all chars
|
||||
char *cmd = uwsgi_malloc(strlen(ud->command)*2);
|
||||
char *cmd = uwsgi_malloc((strlen(ud->command)*2)+1);
|
||||
escape_json(ud->command, strlen(ud->command), cmd);
|
||||
if (uwsgi_stats_keyval_comma(us, "cmd", cmd)) {
|
||||
free(cmd);
|
||||
@@ -905,7 +913,7 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (uwsgi.has_metrics) {
|
||||
if (uwsgi.has_metrics && !uwsgi.stats_no_metrics) {
|
||||
if (uwsgi_stats_key(us, "metrics"))
|
||||
goto end;
|
||||
|
||||
@@ -1137,6 +1145,8 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
|
||||
if (uwsgi_stats_list_close(us))
|
||||
goto end;
|
||||
|
||||
if (uwsgi.stats_no_cores) goto nocores;
|
||||
|
||||
if (uwsgi_stats_comma(us))
|
||||
goto end;
|
||||
|
||||
@@ -1198,9 +1208,12 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
|
||||
if (uwsgi_stats_list_close(us))
|
||||
goto end;
|
||||
|
||||
nocores:
|
||||
|
||||
if (uwsgi_stats_object_close(us))
|
||||
goto end;
|
||||
|
||||
|
||||
if (i < uwsgi.numproc - 1) {
|
||||
if (uwsgi_stats_comma(us))
|
||||
goto end;
|
||||
@@ -1276,7 +1289,7 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
|
||||
if (uwsgi_stats_keyslong_comma(us, "week", (long long) ucron->week))
|
||||
goto end;
|
||||
|
||||
char *cmd = uwsgi_malloc(strlen(ucron->command)*2);
|
||||
char *cmd = uwsgi_malloc((strlen(ucron->command)*2)+1);
|
||||
escape_json(ucron->command, strlen(ucron->command), cmd);
|
||||
if (uwsgi_stats_keyval_comma(us, "command", cmd)) {
|
||||
free(cmd);
|
||||
|
||||
+27
-2
@@ -321,6 +321,7 @@ struct uwsgi_metric *uwsgi_register_keyval_metric(char *arg) {
|
||||
char *m_initial_value = NULL;
|
||||
char *m_children = NULL;
|
||||
char *m_alias = NULL;
|
||||
char *m_reset_after_push = NULL;
|
||||
|
||||
if (!strchr(arg, '=')) {
|
||||
m_name = uwsgi_str(arg);
|
||||
@@ -340,6 +341,7 @@ struct uwsgi_metric *uwsgi_register_keyval_metric(char *arg) {
|
||||
"arg3n", &m_arg3n,
|
||||
"children", &m_children,
|
||||
"alias", &m_alias,
|
||||
"reset_after_push", &m_reset_after_push,
|
||||
NULL)) {
|
||||
uwsgi_log("invalid metric keyval syntax: %s\n", arg);
|
||||
exit(1);
|
||||
@@ -381,6 +383,10 @@ struct uwsgi_metric *uwsgi_register_keyval_metric(char *arg) {
|
||||
struct uwsgi_metric* um = uwsgi_register_metric(m_name, m_oid, type, collector, NULL, freq, NULL);
|
||||
um->initial_value = initial_value;
|
||||
|
||||
if (m_reset_after_push){
|
||||
um->reset_after_push = 1;
|
||||
}
|
||||
|
||||
if (m_children) {
|
||||
char *p, *ctx = NULL;
|
||||
uwsgi_foreach_token(m_children, ";", p, ctx) {
|
||||
@@ -427,6 +433,7 @@ struct uwsgi_metric *uwsgi_register_keyval_metric(char *arg) {
|
||||
if (m_initial_value) free(m_initial_value);
|
||||
if (m_children) free(m_children);
|
||||
if (m_alias) free(m_alias);
|
||||
if (m_reset_after_push) free(m_reset_after_push);
|
||||
return um;
|
||||
}
|
||||
|
||||
@@ -613,7 +620,7 @@ struct uwsgi_metric *uwsgi_metric_find_by_asn(char *asn, size_t len) {
|
||||
}\
|
||||
if (!um) return -1;\
|
||||
if (um->collector || um->type == UWSGI_METRIC_ALIAS) return -1;\
|
||||
uwsgi_rlock(uwsgi.metrics_lock)
|
||||
uwsgi_wlock(uwsgi.metrics_lock)
|
||||
|
||||
int uwsgi_metric_set(char *name, char *oid, int64_t value) {
|
||||
um_op;
|
||||
@@ -694,6 +701,22 @@ int64_t uwsgi_metric_getn(char *name, size_t nlen, char *oid, size_t olen) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
int uwsgi_metric_set_max(char *name, char *oid, int64_t value) {
|
||||
um_op;
|
||||
if (value > *um->value)
|
||||
*um->value = value;
|
||||
uwsgi_rwunlock(uwsgi.metrics_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_metric_set_min(char *name, char *oid, int64_t value) {
|
||||
um_op;
|
||||
if ((value > um->initial_value || 0) && value < *um->value)
|
||||
*um->value = value;
|
||||
uwsgi_rwunlock(uwsgi.metrics_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define uwsgi_metric_name(f, n) ret = snprintf(buf, 4096, f, n); if (ret <= 1 || ret >= 4096) { uwsgi_log("unable to register metric name %s\n", f); exit(1);}
|
||||
#define uwsgi_metric_name2(f, n, n2) ret = snprintf(buf, 4096, f, n, n2); if (ret <= 1 || ret >= 4096) { uwsgi_log("unable to register metric name %s\n", f); exit(1);}
|
||||
|
||||
@@ -768,9 +791,11 @@ void uwsgi_setup_metrics() {
|
||||
struct uwsgi_metric *vsz = uwsgi_register_metric(buf, buf2, UWSGI_METRIC_GAUGE, "ptr", &uwsgi.workers[i].vsz_size, 0, NULL);
|
||||
if (i > 0) uwsgi_metric_add_child(total_vsz, vsz);
|
||||
|
||||
// skip core metrics for core 0
|
||||
// skip core metrics for worker 0
|
||||
if (i == 0) continue;
|
||||
|
||||
if (uwsgi.metrics_no_cores) continue;
|
||||
|
||||
int j;
|
||||
for(j=0;j<uwsgi.cores;j++) {
|
||||
uwsgi_metric_name2("worker.%d.core.%d.requests", i, j) ; uwsgi_metric_oid2("3.%d.2.%d.1", i, j);
|
||||
|
||||
+9
-6
@@ -43,7 +43,7 @@ void uwsgi_mule(int id) {
|
||||
#endif
|
||||
|
||||
signal(SIGALRM, SIG_IGN);
|
||||
signal(SIGHUP, SIG_IGN);
|
||||
signal(SIGHUP, end_me);
|
||||
signal(SIGINT, end_me);
|
||||
signal(SIGTERM, end_me);
|
||||
signal(SIGUSR1, SIG_IGN);
|
||||
@@ -329,11 +329,13 @@ next:
|
||||
}
|
||||
}
|
||||
|
||||
int ret = poll(mulepoll, count + farms_count, timeout);
|
||||
if (ret <= 0) {
|
||||
uwsgi_error("poll");
|
||||
int ret = -1;
|
||||
retry:
|
||||
ret = poll(mulepoll, count + farms_count, timeout);
|
||||
if (ret < 0) {
|
||||
uwsgi_error("uwsgi_mule_get_msg()/poll()");
|
||||
}
|
||||
else {
|
||||
else if (ret > 0 ) {
|
||||
if (mulepoll[0].revents & POLLIN) {
|
||||
len = read(uwsgi.mules[uwsgi.muleid - 1].queue_pipe[1], message, buffer_size);
|
||||
}
|
||||
@@ -353,7 +355,7 @@ next:
|
||||
if (interesting_fd > -1) {
|
||||
len = read(interesting_fd, &uwsgi_signal, 1);
|
||||
if (len <= 0) {
|
||||
if (len < 0 && (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK)) goto clear;
|
||||
if (uwsgi_is_again()) goto retry;
|
||||
uwsgi_log_verbose("uWSGI mule %d braying: my master died, i will follow him...\n", uwsgi.muleid);
|
||||
end_me(0);
|
||||
}
|
||||
@@ -380,6 +382,7 @@ next:
|
||||
}
|
||||
|
||||
if (len < 0) {
|
||||
if (uwsgi_is_again()) goto retry;
|
||||
uwsgi_error("read()");
|
||||
goto clear;
|
||||
}
|
||||
|
||||
@@ -237,6 +237,7 @@ static void uwsgi_offload_loop(struct uwsgi_thread *ut) {
|
||||
void *events = event_queue_alloc(uwsgi.offload_threads_events);
|
||||
|
||||
for (;;) {
|
||||
// TODO make timeout tunable
|
||||
int nevents = event_queue_wait_multi(ut->queue, -1, events, uwsgi.offload_threads_events);
|
||||
for (i = 0; i < nevents; i++) {
|
||||
int interesting_fd = event_queue_interesting_fd(events, i);
|
||||
@@ -456,6 +457,13 @@ static int u_offload_transfer_do(struct uwsgi_thread *ut, struct uwsgi_offload_r
|
||||
// write event (or just connected)
|
||||
case 1:
|
||||
if (fd == uor->fd) {
|
||||
// maybe we want only a connection...
|
||||
if (uor->ubuf->pos == 0) {
|
||||
uor->status = 2;
|
||||
if (event_queue_add_fd_read(ut->queue, uor->s)) return -1;
|
||||
if (event_queue_fd_write_to_read(ut->queue, uor->fd)) return -1;
|
||||
return 0;
|
||||
}
|
||||
rlen = write(uor->fd, uor->ubuf->buf + uor->written, uor->ubuf->pos-uor->written);
|
||||
if (rlen > 0) {
|
||||
uor->written += rlen;
|
||||
|
||||
+101
-1
@@ -583,6 +583,39 @@ static int uwsgi_router_break(struct uwsgi_route *ur, char *arg) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_router_return_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route)
|
||||
{
|
||||
|
||||
if (route->data_len < 3)
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
uint16_t status_msg_len = 0;
|
||||
const char *status_msg = uwsgi_http_status_msg(route->data, &status_msg_len);
|
||||
|
||||
if (!status_msg)
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
|
||||
char *buf = uwsgi_concat3n(route->data, route->data_len, " ", 1, (char *) status_msg, status_msg_len);
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, buf, route->data_len + 1 + status_msg_len))
|
||||
goto end;
|
||||
if (uwsgi_response_add_content_type(wsgi_req, "text/plain", 10))
|
||||
goto end;
|
||||
if (uwsgi_response_add_content_length(wsgi_req, status_msg_len))
|
||||
goto end;
|
||||
uwsgi_response_write_body_do(wsgi_req, (char *) status_msg, status_msg_len);
|
||||
|
||||
end:
|
||||
free(buf);
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
}
|
||||
|
||||
static int uwsgi_router_return(struct uwsgi_route *ur, char *arg)
|
||||
{
|
||||
ur->func = uwsgi_router_return_func;
|
||||
ur->data = arg;
|
||||
ur->data_len = strlen(arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// simple math router
|
||||
static int uwsgi_router_simple_math_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
|
||||
@@ -943,6 +976,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) {
|
||||
@@ -1072,6 +1119,32 @@ static int uwsgi_router_seturi(struct uwsgi_route *ur, char *arg) {
|
||||
ur->data_len = strlen(arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// setremoteaddr route
|
||||
static int uwsgi_router_setremoteaddr_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
|
||||
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
|
||||
|
||||
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len);
|
||||
if (!ub) return UWSGI_ROUTE_BREAK;
|
||||
char *ptr = uwsgi_req_append(wsgi_req, "REMOTE_ADDR", 11, ub->buf, ub->pos);
|
||||
if (!ptr) {
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
}
|
||||
wsgi_req->remote_addr = ptr;
|
||||
wsgi_req->remote_addr_len = ub->pos;
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
static int uwsgi_router_setremoteaddr(struct uwsgi_route *ur, char *arg) {
|
||||
ur->func = uwsgi_router_setremoteaddr_func;
|
||||
ur->data = arg;
|
||||
ur->data_len = strlen(arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// setdocroot route
|
||||
static int uwsgi_router_setdocroot_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
|
||||
@@ -1145,6 +1218,26 @@ static int uwsgi_router_setscheme(struct uwsgi_route *ur, char *arg) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// setmodifiers
|
||||
static int uwsgi_router_setmodifier1_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
wsgi_req->uh->modifier1 = ur->custom;
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
static int uwsgi_router_setmodifier1(struct uwsgi_route *ur, char *arg) {
|
||||
ur->func = uwsgi_router_setmodifier1_func;
|
||||
ur->custom = atoi(arg);
|
||||
return 0;
|
||||
}
|
||||
static int uwsgi_router_setmodifier2_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
wsgi_req->uh->modifier2 = ur->custom;
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
static int uwsgi_router_setmodifier2(struct uwsgi_route *ur, char *arg) {
|
||||
ur->func = uwsgi_router_setmodifier2_func;
|
||||
ur->custom = atoi(arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// setuser route
|
||||
static int uwsgi_router_setuser_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
@@ -1670,7 +1763,7 @@ static char *uwsgi_route_var_mime(struct wsgi_request *wsgi_req, char *key, uint
|
||||
char *var_value = uwsgi_get_var(wsgi_req, key, keylen, &var_vallen);
|
||||
if (var_value) {
|
||||
size_t mime_type_len = 0;
|
||||
char *ret = uwsgi_get_mime_type(key, keylen, &mime_type_len);
|
||||
ret = uwsgi_get_mime_type(var_value, var_vallen, &mime_type_len);
|
||||
if (ret) *vallen = mime_type_len;
|
||||
}
|
||||
return ret;
|
||||
@@ -1727,6 +1820,8 @@ void uwsgi_register_embedded_routers() {
|
||||
uwsgi_register_router("continue", uwsgi_router_continue);
|
||||
uwsgi_register_router("last", uwsgi_router_continue);
|
||||
uwsgi_register_router("break", uwsgi_router_break);
|
||||
uwsgi_register_router("return", uwsgi_router_return);
|
||||
uwsgi_register_router("break-with-status", uwsgi_router_return);
|
||||
uwsgi_register_router("log", uwsgi_router_log);
|
||||
uwsgi_register_router("donotlog", uwsgi_router_donotlog);
|
||||
uwsgi_register_router("logvar", uwsgi_router_logvar);
|
||||
@@ -1737,6 +1832,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);
|
||||
@@ -1748,12 +1844,16 @@ void uwsgi_register_embedded_routers() {
|
||||
uwsgi_register_router("setscriptname", uwsgi_router_setscriptname);
|
||||
uwsgi_register_router("setmethod", uwsgi_router_setmethod);
|
||||
uwsgi_register_router("seturi", uwsgi_router_seturi);
|
||||
uwsgi_register_router("setremoteaddr", uwsgi_router_setremoteaddr);
|
||||
uwsgi_register_router("setpathinfo", uwsgi_router_setpathinfo);
|
||||
uwsgi_register_router("setdocroot", uwsgi_router_setdocroot);
|
||||
uwsgi_register_router("setscheme", uwsgi_router_setscheme);
|
||||
uwsgi_register_router("setprocname", uwsgi_router_setprocname);
|
||||
uwsgi_register_router("alarm", uwsgi_router_alarm);
|
||||
|
||||
uwsgi_register_router("setmodifier1", uwsgi_router_setmodifier1);
|
||||
uwsgi_register_router("setmodifier2", uwsgi_router_setmodifier2);
|
||||
|
||||
uwsgi_register_router("+", uwsgi_router_simple_math_plus);
|
||||
uwsgi_register_router("-", uwsgi_router_simple_math_minus);
|
||||
uwsgi_register_router("*", uwsgi_router_simple_math_multiply);
|
||||
|
||||
+5
-1
@@ -104,8 +104,12 @@ char *uwsgi_do_rpc(char *node, char *func, uint8_t argc, char *argv[], uint16_t
|
||||
|
||||
if (node == NULL || !strcmp(node, "")) {
|
||||
// allocate the whole buffer
|
||||
if (!uwsgi.rpc_table) {
|
||||
uwsgi_log("local rpc subsystem is still not initialized !!!\n");
|
||||
return NULL;
|
||||
}
|
||||
*len = uwsgi_rpc(func, argc, argv, argvs, &buffer);
|
||||
if (*buffer)
|
||||
if (buffer)
|
||||
return buffer;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+63
-6
@@ -229,8 +229,11 @@ int uwsgi_sharedarea_wait(int id, int freq, int timeout) {
|
||||
uwsgi_rlock(sa->lock);
|
||||
uint64_t updates = sa->updates;
|
||||
uwsgi_rwunlock(sa->lock);
|
||||
while(timeout == 0 || (timeout > 0 && (waiting/1000) >= timeout)) {
|
||||
uwsgi.wait_milliseconds_hook(freq);
|
||||
while(timeout == 0 || waiting == 0 || (timeout > 0 && waiting > 0 && (waiting/1000) < timeout)) {
|
||||
if (uwsgi.wait_milliseconds_hook(freq)) {
|
||||
uwsgi_rwunlock(sa->lock);
|
||||
return -1;
|
||||
}
|
||||
waiting += freq;
|
||||
// lock sa
|
||||
uwsgi_rlock(sa->lock);
|
||||
@@ -266,6 +269,27 @@ static struct uwsgi_sharedarea *announce_sa(struct uwsgi_sharedarea *sa) {
|
||||
return sa;
|
||||
}
|
||||
|
||||
|
||||
struct uwsgi_sharedarea *uwsgi_sharedarea_init_fd(int fd, uint64_t len, off_t offset) {
|
||||
int id = uwsgi_sharedarea_new_id();
|
||||
uwsgi.sharedareas[id] = uwsgi_calloc_shared(sizeof(struct uwsgi_sharedarea));
|
||||
uwsgi.sharedareas[id]->area = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset);
|
||||
if (uwsgi.sharedareas[id]->area == MAP_FAILED) {
|
||||
uwsgi_error("uwsgi_sharedarea_init_fd()/mmap()");
|
||||
exit(1);
|
||||
}
|
||||
uwsgi.sharedareas[id]->id = id;
|
||||
uwsgi.sharedareas[id]->fd = fd;
|
||||
uwsgi.sharedareas[id]->pages = len / uwsgi.page_size;
|
||||
if (len % uwsgi.page_size != 0) uwsgi.sharedareas[id]->pages++;
|
||||
uwsgi.sharedareas[id]->max_pos = len-1;
|
||||
char *id_str = uwsgi_num2str(id);
|
||||
uwsgi.sharedareas[id]->lock = uwsgi_rwlock_init(uwsgi_concat2("sharedarea", id_str));
|
||||
free(id_str);
|
||||
return announce_sa(uwsgi.sharedareas[id]);
|
||||
}
|
||||
|
||||
|
||||
struct uwsgi_sharedarea *uwsgi_sharedarea_init(int pages) {
|
||||
int id = uwsgi_sharedarea_new_id();
|
||||
uwsgi.sharedareas[id] = uwsgi_calloc_shared(uwsgi.page_size * (pages + 1));
|
||||
@@ -301,24 +325,41 @@ struct uwsgi_sharedarea *uwsgi_sharedarea_init_keyval(char *arg) {
|
||||
char *s_fd = NULL;
|
||||
char *s_ptr = NULL;
|
||||
char *s_size = NULL;
|
||||
char *s_offset = NULL;
|
||||
if (uwsgi_kvlist_parse(arg, strlen(arg), ',', '=',
|
||||
"pages", &s_pages,
|
||||
"file", &s_file,
|
||||
"fd", &s_fd,
|
||||
"ptr", &s_ptr,
|
||||
"size", &s_size,
|
||||
"offset", &s_offset,
|
||||
NULL)) {
|
||||
uwsgi_log("invalid sharedarea keyval syntax\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uint64_t len = 0;
|
||||
off_t offset = 0;
|
||||
int pages = 0;
|
||||
if (s_size) {
|
||||
len = uwsgi_n64(s_size);
|
||||
if (strlen(s_size) > 2 && s_size[0] == '0' && s_size[1] == 'x') {
|
||||
len = strtoul(s_size+2, NULL, 16);
|
||||
}
|
||||
else {
|
||||
len = uwsgi_n64(s_size);
|
||||
}
|
||||
pages = len / uwsgi.page_size;
|
||||
if (len % uwsgi.page_size != 0) pages++;
|
||||
}
|
||||
|
||||
if (s_offset) {
|
||||
if (strlen(s_offset) > 2 && s_offset[0] == '0' && s_offset[1] == 'x') {
|
||||
offset = strtoul(s_offset+2, NULL, 16);
|
||||
}
|
||||
else {
|
||||
offset = uwsgi_n64(s_offset);
|
||||
}
|
||||
}
|
||||
|
||||
if (s_pages) {
|
||||
pages = atoi(s_pages);
|
||||
@@ -326,27 +367,43 @@ struct uwsgi_sharedarea *uwsgi_sharedarea_init_keyval(char *arg) {
|
||||
|
||||
char *area = NULL;
|
||||
struct uwsgi_sharedarea *sa = NULL;
|
||||
|
||||
int fd = -1;
|
||||
if (s_file) {
|
||||
fd = open(s_file, O_RDWR|O_SYNC);
|
||||
if (fd < 0) {
|
||||
uwsgi_error_open(s_file);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
else if (s_fd) {
|
||||
fd = atoi(s_fd);
|
||||
}
|
||||
else if (s_ptr) {
|
||||
}
|
||||
|
||||
if (pages) {
|
||||
if (!area) {
|
||||
sa = uwsgi_sharedarea_init(pages);
|
||||
if (fd > -1) {
|
||||
sa = uwsgi_sharedarea_init_fd(fd, len, offset);
|
||||
}
|
||||
else if (area) {
|
||||
sa = uwsgi_sharedarea_init_ptr(area, len);
|
||||
}
|
||||
else {
|
||||
uwsgi_sharedarea_init_ptr(area, len);
|
||||
sa = uwsgi_sharedarea_init(pages);
|
||||
}
|
||||
}
|
||||
else {
|
||||
uwsgi_log("you need to set a size for a sharedarea !!! [%s]\n", arg);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (s_pages) free(s_pages);
|
||||
if (s_file) free(s_file);
|
||||
if (s_fd) free(s_fd);
|
||||
if (s_ptr) free(s_ptr);
|
||||
if (s_size) free(s_size);
|
||||
if (s_offset) free(s_offset);
|
||||
|
||||
return sa;
|
||||
}
|
||||
|
||||
+25
-7
@@ -1733,13 +1733,6 @@ void uwsgi_bind_sockets() {
|
||||
uwsgi_sock = uwsgi_sock->next;
|
||||
}
|
||||
|
||||
|
||||
if (uwsgi.chown_socket) {
|
||||
if (!uwsgi.master_as_root) {
|
||||
uwsgi_as_root();
|
||||
}
|
||||
}
|
||||
|
||||
int zero_used = 0;
|
||||
uwsgi_sock = uwsgi.sockets;
|
||||
while (uwsgi_sock) {
|
||||
@@ -1760,6 +1753,24 @@ void uwsgi_bind_sockets() {
|
||||
uwsgi_sock->fd = 0;
|
||||
uwsgi_sock->bound = 1;
|
||||
uwsgi_log("uwsgi socket %d inherited UNIX address %s fd 0\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name);
|
||||
if (!uwsgi.is_a_reload) {
|
||||
if (uwsgi.chown_socket) {
|
||||
uwsgi_chown(uwsgi_sock->name, uwsgi.chown_socket);
|
||||
}
|
||||
if (uwsgi.chmod_socket) {
|
||||
if (uwsgi.chmod_socket_value) {
|
||||
if (chmod(uwsgi_sock->name, uwsgi.chmod_socket_value) != 0) {
|
||||
uwsgi_error("inherit fd0: chmod()");
|
||||
}
|
||||
}
|
||||
else {
|
||||
uwsgi_log("chmod() fd0 socket to 666 for lazy and brave users\n");
|
||||
if (chmod(uwsgi_sock->name, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) != 0) {
|
||||
uwsgi_error("inherit fd0: chmod()");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
uwsgi_sock = uwsgi_new_socket(uwsgi_getsockname(0));
|
||||
@@ -1794,6 +1805,13 @@ void uwsgi_bind_sockets() {
|
||||
|
||||
stdin_done:
|
||||
|
||||
if (uwsgi.chown_socket) {
|
||||
if (!uwsgi.master_as_root) {
|
||||
uwsgi_as_root();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// check for auto_port socket
|
||||
uwsgi_sock = uwsgi.sockets;
|
||||
while (uwsgi_sock) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
+11
-7
@@ -243,19 +243,23 @@ SSL_CTX *uwsgi_ssl_new_server_context(char *name, char *crt, char *key, char *ci
|
||||
DH *dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
|
||||
BIO_free(bio);
|
||||
if (dh) {
|
||||
SSL_CTX_set_options(ctx, SSL_OP_SINGLE_DH_USE);
|
||||
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_options(ctx, SSL_OP_SINGLE_ECDH_USE);
|
||||
SSL_CTX_set_tmp_ecdh(ctx, ecdh);
|
||||
EC_KEY_free(ecdh);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (crt_need_free) free(crt);
|
||||
|
||||
|
||||
@@ -459,6 +459,8 @@ int uwsgi_real_file_serve(struct wsgi_request *wsgi_req, char *real_filename, si
|
||||
uwsgi_log("[uwsgi-fileserve] file %s found\n", real_filename);
|
||||
#endif
|
||||
|
||||
// static file - don't update avg_rt after request
|
||||
wsgi_req->do_not_account_avg_rt = 1;
|
||||
|
||||
size_t fsize = st->st_size;
|
||||
if (wsgi_req->range_to) {
|
||||
|
||||
+6
-15
@@ -551,25 +551,16 @@ struct uwsgi_stats_pusher *uwsgi_register_stats_pusher(char *name, void (*func)
|
||||
static void stats_dump_var(char *k, uint16_t kl, char *v, uint16_t vl, void *data) {
|
||||
struct uwsgi_stats *us = (struct uwsgi_stats *) data;
|
||||
if (us->dirty) return;
|
||||
uint16_t i;
|
||||
// replace " with '
|
||||
for(i=0;i<kl;i++) {
|
||||
if (k[i] == '"') {
|
||||
k[i] = '\'';
|
||||
}
|
||||
}
|
||||
for(i=0;i<vl;i++) {
|
||||
if (v[i] == '"') {
|
||||
v[i] = '\'';
|
||||
}
|
||||
}
|
||||
char *var = uwsgi_concat3n(k, kl, "=", 1, v,vl);
|
||||
if (uwsgi_stats_str(us, var)) {
|
||||
char *escaped_var = uwsgi_malloc(((kl+vl+1)*2)+1);
|
||||
escape_json(var, strlen(var), escaped_var);
|
||||
free(var);
|
||||
if (uwsgi_stats_str(us, escaped_var)) {
|
||||
us->dirty = 1;
|
||||
free(var);
|
||||
free(escaped_var);
|
||||
return;
|
||||
}
|
||||
free(var);
|
||||
free(escaped_var);
|
||||
if (uwsgi_stats_comma(us)) {
|
||||
us->dirty = 1;
|
||||
}
|
||||
|
||||
@@ -427,6 +427,8 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
|
||||
uwsgi_log("[uwsgi-subscription for pid %d] invalid (sniffed ?) packet sent for slot: %.*s node: %.*s unix_check: %lu\n", (int) uwsgi.mypid, usr->keylen, usr->key, usr->address_len, usr->address, (unsigned long) usr->unix_check);
|
||||
return NULL;
|
||||
}
|
||||
// eventually the packet could be upgraded to sni...
|
||||
uwsgi_subscription_sni_check(current_slot, usr);
|
||||
#endif
|
||||
// remove death mark and update cores and load
|
||||
node->death_mark = 0;
|
||||
|
||||
+15
-5
@@ -1051,10 +1051,11 @@ void uwsgi_close_request(struct wsgi_request *wsgi_req) {
|
||||
uint64_t end_of_request = uwsgi_micros();
|
||||
wsgi_req->end_of_request = end_of_request;
|
||||
|
||||
tmp_rt = wsgi_req->end_of_request - wsgi_req->start_of_request;
|
||||
|
||||
uwsgi.workers[uwsgi.mywid].running_time += tmp_rt;
|
||||
uwsgi.workers[uwsgi.mywid].avg_response_time = (uwsgi.workers[uwsgi.mywid].avg_response_time + tmp_rt) / 2;
|
||||
if (!wsgi_req->do_not_account_avg_rt) {
|
||||
tmp_rt = wsgi_req->end_of_request - wsgi_req->start_of_request;
|
||||
uwsgi.workers[uwsgi.mywid].running_time += tmp_rt;
|
||||
uwsgi.workers[uwsgi.mywid].avg_response_time = (uwsgi.workers[uwsgi.mywid].avg_response_time + tmp_rt) / 2;
|
||||
}
|
||||
|
||||
// get memory usage
|
||||
if (uwsgi.logging_options.memory_report == 1 || uwsgi.force_get_memusage) {
|
||||
@@ -3155,6 +3156,10 @@ void escape_json(char *src, size_t len, char *dst) {
|
||||
*ptr++ = '\\';
|
||||
*ptr++ = '"';
|
||||
}
|
||||
else if (src[i] == '\\') {
|
||||
*ptr++ = '\\';
|
||||
*ptr++ = '\\';
|
||||
}
|
||||
else {
|
||||
*ptr++ = src[i];
|
||||
}
|
||||
@@ -3752,7 +3757,7 @@ static void *uwsgi_thread_run(void *arg) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct uwsgi_thread *uwsgi_thread_new(void (*func) (struct uwsgi_thread *)) {
|
||||
struct uwsgi_thread *uwsgi_thread_new_with_data(void (*func) (struct uwsgi_thread *), void *data) {
|
||||
|
||||
struct uwsgi_thread *ut = uwsgi_calloc(sizeof(struct uwsgi_thread));
|
||||
|
||||
@@ -3769,6 +3774,7 @@ struct uwsgi_thread *uwsgi_thread_new(void (*func) (struct uwsgi_thread *)) {
|
||||
uwsgi_socket_nb(ut->pipe[1]);
|
||||
|
||||
ut->func = func;
|
||||
ut->data = data;
|
||||
|
||||
pthread_attr_init(&ut->tattr);
|
||||
pthread_attr_setdetachstate(&ut->tattr, PTHREAD_CREATE_DETACHED);
|
||||
@@ -3788,6 +3794,10 @@ error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct uwsgi_thread *uwsgi_thread_new(void (*func) (struct uwsgi_thread *)) {
|
||||
return uwsgi_thread_new_with_data(func, NULL);
|
||||
}
|
||||
|
||||
int uwsgi_kvlist_parse(char *src, size_t len, char list_separator, char kv_separator, ...) {
|
||||
size_t i;
|
||||
va_list ap;
|
||||
|
||||
+48
-5
@@ -101,6 +101,8 @@ static struct uwsgi_option uwsgi_base_options[] = {
|
||||
{"declare-option", required_argument, 0, "declare a new uWSGI custom option", uwsgi_opt_add_custom_option, NULL, UWSGI_OPT_IMMEDIATE},
|
||||
{"declare-option2", required_argument, 0, "declare a new uWSGI custom option (non-immediate)", uwsgi_opt_add_custom_option, NULL, 0},
|
||||
|
||||
{"resolve", required_argument, 0, "place the result of a dns query in the specified placeholder, sytax: placeholder=name (immediate option)", uwsgi_opt_resolve, NULL, UWSGI_OPT_IMMEDIATE},
|
||||
|
||||
{"for", required_argument, 0, "(opt logic) for cycle", uwsgi_opt_logic, (void *) uwsgi_logic_opt_for, UWSGI_OPT_IMMEDIATE},
|
||||
{"for-glob", required_argument, 0, "(opt logic) for cycle (expand glob)", uwsgi_opt_logic, (void *) uwsgi_logic_opt_for_glob, UWSGI_OPT_IMMEDIATE},
|
||||
{"for-times", required_argument, 0, "(opt logic) for cycle (expand the specified num to a list starting from 1)", uwsgi_opt_logic, (void *) uwsgi_logic_opt_for_times, UWSGI_OPT_IMMEDIATE},
|
||||
@@ -219,6 +221,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
|
||||
{"emperor-on-demand-exec", required_argument, 0, "use the output of the specified command as on demand socket name (the vassal name is passed as the only argument)", uwsgi_opt_set_str, &uwsgi.emperor_on_demand_exec, 0},
|
||||
{"emperor-extra-extension", required_argument, 0, "allows the specified extension in the Emperor (vassal will be called with --config)", uwsgi_opt_add_string_list, &uwsgi.emperor_extra_extension, 0},
|
||||
{"emperor-extra-ext", required_argument, 0, "allows the specified extension in the Emperor (vassal will be called with --config)", uwsgi_opt_add_string_list, &uwsgi.emperor_extra_extension, 0},
|
||||
{"emperor-no-blacklist", no_argument, 0, "disable Emperor blacklisting subsystem", uwsgi_opt_true, &uwsgi.emperor_no_blacklist, 0},
|
||||
#if defined(__linux__) && !defined(OBSOLETE_LINUX_KERNEL)
|
||||
{"emperor-use-clone", required_argument, 0, "use clone() instead of fork() passing the specified unshare() flags", uwsgi_opt_set_unshare, &uwsgi.emperor_clone, 0},
|
||||
#endif
|
||||
@@ -243,6 +246,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
|
||||
|
||||
{"reload-mercy", required_argument, 0, "set the maximum time (in seconds) we wait for workers and other processes to die during reload/shutdown", uwsgi_opt_set_int, &uwsgi.reload_mercy, 0},
|
||||
{"worker-reload-mercy", required_argument, 0, "set the maximum time (in seconds) a worker can take to reload/shutdown (default is 60)", uwsgi_opt_set_int, &uwsgi.worker_reload_mercy, 0},
|
||||
{"mule-reload-mercy", required_argument, 0, "set the maximum time (in seconds) a mule can take to reload/shutdown (default is 60)", uwsgi_opt_set_int, &uwsgi.mule_reload_mercy, 0},
|
||||
{"exit-on-reload", no_argument, 0, "force exit even if a reload is requested", uwsgi_opt_true, &uwsgi.exit_on_reload, 0},
|
||||
{"die-on-term", no_argument, 0, "exit instead of brutal reload on SIGTERM", uwsgi_opt_true, &uwsgi.die_on_term, 0},
|
||||
{"force-gateway", no_argument, 0, "force the spawn of the first registered gateway without a master", uwsgi_opt_true, &uwsgi.force_gateway, 0},
|
||||
@@ -560,6 +564,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
|
||||
{"metrics-dir-restore", no_argument, 0, "restore last value taken from the metrics dir", uwsgi_opt_true, &uwsgi.metrics_dir_restore, UWSGI_OPT_METRICS|UWSGI_OPT_MASTER},
|
||||
{"metric-dir", required_argument, 0, "export metrics as text files to the specified directory", uwsgi_opt_set_str, &uwsgi.metrics_dir, UWSGI_OPT_METRICS|UWSGI_OPT_MASTER},
|
||||
{"metric-dir-restore", no_argument, 0, "restore last value taken from the metrics dir", uwsgi_opt_true, &uwsgi.metrics_dir_restore, UWSGI_OPT_METRICS|UWSGI_OPT_MASTER},
|
||||
{"metrics-no-cores", no_argument, 0, "disable generation of cores-related metrics", uwsgi_opt_true, &uwsgi.metrics_no_cores, UWSGI_OPT_METRICS|UWSGI_OPT_MASTER},
|
||||
|
||||
{"udp", required_argument, 0, "run the udp server on the specified address", uwsgi_opt_set_str, &uwsgi.udp_socket, UWSGI_OPT_MASTER},
|
||||
{"stats", required_argument, 0, "enable the stats server on the specified address", uwsgi_opt_set_str, &uwsgi.stats, UWSGI_OPT_MASTER},
|
||||
@@ -570,6 +575,8 @@ static struct uwsgi_option uwsgi_base_options[] = {
|
||||
{"stats-push", required_argument, 0, "push the stats json to the specified destination", uwsgi_opt_add_string_list, &uwsgi.requested_stats_pushers, UWSGI_OPT_MASTER|UWSGI_OPT_METRICS},
|
||||
{"stats-pusher-default-freq", required_argument, 0, "set the default frequency of stats pushers", uwsgi_opt_set_int, &uwsgi.stats_pusher_default_freq, UWSGI_OPT_MASTER},
|
||||
{"stats-pushers-default-freq", required_argument, 0, "set the default frequency of stats pushers", uwsgi_opt_set_int, &uwsgi.stats_pusher_default_freq, UWSGI_OPT_MASTER},
|
||||
{"stats-no-cores", no_argument, 0, "disable generation of cores-related stats", uwsgi_opt_true, &uwsgi.stats_no_cores, UWSGI_OPT_MASTER},
|
||||
{"stats-no-metrics", no_argument, 0, "do not include metrics in stats output", uwsgi_opt_true, &uwsgi.stats_no_metrics, UWSGI_OPT_MASTER},
|
||||
{"multicast", required_argument, 0, "subscribe to specified multicast group", uwsgi_opt_set_str, &uwsgi.multicast_group, UWSGI_OPT_MASTER},
|
||||
{"multicast-ttl", required_argument, 0, "set multicast ttl", uwsgi_opt_set_int, &uwsgi.multicast_ttl, 0},
|
||||
{"multicast-loop", required_argument, 0, "set multicast loop (default 1)", uwsgi_opt_set_int, &uwsgi.multicast_loop, 0},
|
||||
@@ -672,6 +679,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
|
||||
{"use-abort", no_argument, 0, "call abort() on segfault/fpe, could be useful for generating a core dump", uwsgi_opt_true, &uwsgi.use_abort, 0},
|
||||
|
||||
{"alarm", required_argument, 0, "create a new alarm, syntax: <alarm> <plugin:args>", uwsgi_opt_add_string_list, &uwsgi.alarm_list, UWSGI_OPT_MASTER},
|
||||
{"alarm-cheap", required_argument, 0, "use main alarm thread rather than create dedicated threads for curl-based alarms", uwsgi_opt_true, &uwsgi.alarm_cheap, 0},
|
||||
{"alarm-freq", required_argument, 0, "tune the anti-loop alam system (default 3 seconds)", uwsgi_opt_set_int, &uwsgi.alarm_freq, 0},
|
||||
{"alarm-fd", required_argument, 0, "raise the specified alarm when an fd is read for read (by default it reads 1 byte, set 8 for eventfd)", uwsgi_opt_add_string_list, &uwsgi.alarm_fd_list, UWSGI_OPT_MASTER},
|
||||
{"alarm-segfault", required_argument, 0, "raise the specified alarm when the segmentation fault handler is executed", uwsgi_opt_add_string_list, &uwsgi.alarm_segfault, UWSGI_OPT_MASTER},
|
||||
@@ -1247,6 +1255,11 @@ void kill_them_all(int signum) {
|
||||
uwsgi_curse(i, SIGINT);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < uwsgi.mules_cnt; i++) {
|
||||
if (uwsgi.mules[i].pid > 0) {
|
||||
uwsgi_curse_mule(i, SIGINT);
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_destroy_processes();
|
||||
}
|
||||
@@ -1268,6 +1281,11 @@ void gracefully_kill_them_all(int signum) {
|
||||
uwsgi_curse(i, SIGHUP);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < uwsgi.mules_cnt; i++) {
|
||||
if (uwsgi.mules[i].pid > 0) {
|
||||
uwsgi_curse_mule(i, SIGHUP);
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_destroy_processes();
|
||||
}
|
||||
@@ -1309,6 +1327,12 @@ void grace_them_all(int signum) {
|
||||
uwsgi_curse(i, SIGHUP);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < uwsgi.mules_cnt; i++) {
|
||||
if (uwsgi.mules[i].pid > 0) {
|
||||
uwsgi_curse_mule(i, SIGHUP);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_nuclear_blast() {
|
||||
@@ -1355,6 +1379,11 @@ void reap_them_all(int signum) {
|
||||
if (uwsgi.workers[i].pid > 0)
|
||||
uwsgi_curse(i, SIGTERM);
|
||||
}
|
||||
for (i = 0; i < uwsgi.mules_cnt; i++) {
|
||||
if (uwsgi.mules[i].pid > 0) {
|
||||
uwsgi_curse_mule(i, SIGTERM);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void harakiri() {
|
||||
@@ -1555,21 +1584,25 @@ next:
|
||||
}
|
||||
}
|
||||
|
||||
void signal_pidfile(int sig, char *filename) {
|
||||
int signal_pidfile(int sig, char *filename) {
|
||||
|
||||
int ret = 0;
|
||||
size_t size = 0;
|
||||
|
||||
char *buffer = uwsgi_open_and_read(filename, &size, 1, NULL);
|
||||
|
||||
if (size > 0) {
|
||||
if (kill((pid_t) atoi(buffer), sig)) {
|
||||
uwsgi_error("kill()");
|
||||
uwsgi_error("signal_pidfile()/kill()");
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
uwsgi_log("error: invalid pidfile\n");
|
||||
ret = -1;
|
||||
}
|
||||
free(buffer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*static*/ void uwsgi_command_signal(char *opt) {
|
||||
@@ -2198,7 +2231,7 @@ void uwsgi_setup(int argc, char *argv[], char *envp[]) {
|
||||
uwsgi_opt_flock(NULL, uwsgi.flock_wait2, NULL);
|
||||
|
||||
// setup master logging
|
||||
if (uwsgi.log_master && !uwsgi.daemonize2)
|
||||
if (uwsgi.log_master && !uwsgi.daemonize2 && uwsgi.logfile)
|
||||
uwsgi_setup_log_master();
|
||||
|
||||
// setup offload engines
|
||||
@@ -2480,7 +2513,11 @@ int uwsgi_start(void *v_argv) {
|
||||
|
||||
if (uwsgi.logto2) {
|
||||
if (!uwsgi.is_a_reload || uwsgi.log_reopen) {
|
||||
int setup_log = 0;
|
||||
if (!uwsgi.logfile) setup_log = 1; // logto() will replace uwsgi.logfile and we need to check it later
|
||||
logto(uwsgi.logto2);
|
||||
if (setup_log)
|
||||
uwsgi_setup_log_master();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3663,6 +3700,13 @@ void uwsgi_init_all_apps() {
|
||||
if (uwsgi.need_app) {
|
||||
if (!uwsgi.lazy)
|
||||
uwsgi_log("*** no app loaded. GAME OVER ***\n");
|
||||
if (uwsgi.lazy_apps) {
|
||||
if (uwsgi.master_process) {
|
||||
if (kill(uwsgi.workers[0].pid, SIGINT)) {
|
||||
uwsgi_error("kill()");
|
||||
}
|
||||
}
|
||||
}
|
||||
exit(UWSGI_FAILED_APP_CODE);
|
||||
}
|
||||
else {
|
||||
@@ -4193,8 +4237,7 @@ void uwsgi_opt_pidfile_signal(char *opt, char *pidfile, void *sig) {
|
||||
|
||||
long *signum_fake_ptr = (long *) sig;
|
||||
int signum = (long) signum_fake_ptr;
|
||||
signal_pidfile(signum, pidfile);
|
||||
exit(0);
|
||||
exit(signal_pidfile(signum, pidfile));
|
||||
}
|
||||
|
||||
void uwsgi_opt_load_dl(char *opt, char *value, void *none) {
|
||||
|
||||
+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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -271,12 +271,11 @@ static void uwsgi_airbrake_loop(struct uwsgi_thread *ut) {
|
||||
}
|
||||
|
||||
static void uwsgi_airbrake_init(struct uwsgi_alarm_instance *uai) {
|
||||
struct uwsgi_thread *ut = uwsgi_thread_new(uwsgi_airbrake_loop);
|
||||
if (!ut) return;
|
||||
uai->data_ptr = ut;
|
||||
struct uwsgi_airbrake_config *uacc = uwsgi_calloc(sizeof(struct uwsgi_airbrake_config));
|
||||
uacc->arg = uai->arg;
|
||||
ut->data = uacc;
|
||||
struct uwsgi_thread *ut = uwsgi_thread_new_with_data(uwsgi_airbrake_loop, uacc);
|
||||
if (!ut) return;
|
||||
uai->data_ptr = ut;
|
||||
}
|
||||
|
||||
static void uwsgi_airbrake_func(struct uwsgi_alarm_instance *uai, char *msg, size_t len) {
|
||||
|
||||
@@ -3,9 +3,18 @@
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
struct uwsgi_alarm_curl {
|
||||
CURL *curl;
|
||||
struct uwsgi_thread *ut;
|
||||
int pos;
|
||||
int blen;
|
||||
char *body;
|
||||
int hlen;
|
||||
char hdr[];
|
||||
};
|
||||
|
||||
struct uwsgi_alarm_curl_config {
|
||||
int first;
|
||||
char *arg;
|
||||
char *url;
|
||||
char *subject;
|
||||
char *to;
|
||||
};
|
||||
@@ -17,7 +26,7 @@ struct uwsgi_alarm_curl_opt {
|
||||
};
|
||||
|
||||
|
||||
#ifdef CURLOPT_MAIL_RCPT
|
||||
#ifdef CURLPROTO_SMTP
|
||||
static void uwsgi_alarm_curl_to(CURL *curl, CURLoption option, char *arg, struct uwsgi_alarm_curl_config *uacc) {
|
||||
uacc->to = arg;
|
||||
struct curl_slist *list = NULL;
|
||||
@@ -29,6 +38,7 @@ static void uwsgi_alarm_curl_to(CURL *curl, CURLoption option, char *arg, struct
|
||||
p = strtok_r(NULL, ",", &ctx);
|
||||
}
|
||||
curl_easy_setopt(curl, option, list);
|
||||
free(items);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -44,16 +54,33 @@ static void uwsgi_alarm_curl_set_subject(CURL *curl, CURLoption option, char *ar
|
||||
uacc->subject = arg;
|
||||
}
|
||||
|
||||
static struct uwsgi_alarm_curl_opt uaco[] = {
|
||||
{"url", CURLOPT_URL, NULL},
|
||||
#ifdef CURLOPT_MAIL_RCPT
|
||||
{"mail_to", CURLOPT_MAIL_RCPT, uwsgi_alarm_curl_to },
|
||||
static void uwsgi_alarm_curl_url(CURL *curl, CURLoption option, char *arg, struct uwsgi_alarm_curl_config *uacc)
|
||||
{
|
||||
#ifndef CURLPROTO_SMTP
|
||||
if (!uwsgi_strnicmp(arg, 4, "smtp", 4)) {
|
||||
uwsgi_error("Please update libcurl to use SMTP protocol.\n");
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
#ifdef CURLOPT_MAIL_FROM
|
||||
uacc->url = arg;
|
||||
curl_easy_setopt(curl, option, arg);
|
||||
}
|
||||
|
||||
static void uwsgi_alarm_curl_ssl_insecure(CURL *curl, CURLoption option, char *arg, struct uwsgi_alarm_curl_config *uacc)
|
||||
{
|
||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
|
||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
|
||||
}
|
||||
|
||||
static struct uwsgi_alarm_curl_opt uaco[] = {
|
||||
{"url", CURLOPT_URL, uwsgi_alarm_curl_url},
|
||||
#ifdef CURLPROTO_SMTP
|
||||
{"mail_to", CURLOPT_MAIL_RCPT, uwsgi_alarm_curl_to},
|
||||
{"mail_from", CURLOPT_MAIL_FROM, NULL},
|
||||
#endif
|
||||
{"subject", 0, uwsgi_alarm_curl_set_subject},
|
||||
{"ssl", CURLOPT_USE_SSL, uwsgi_alarm_curl_ssl},
|
||||
{"ssl_insecure", 0, uwsgi_alarm_curl_ssl_insecure},
|
||||
{"auth_user", CURLOPT_USERNAME, NULL},
|
||||
{"auth_pass", CURLOPT_PASSWORD, NULL},
|
||||
{"method", CURLOPT_CUSTOMREQUEST, NULL},
|
||||
@@ -65,14 +92,10 @@ static struct uwsgi_alarm_curl_opt uaco[] = {
|
||||
static void uwsgi_alarm_curl_setopt(CURL *curl, char *opt, struct uwsgi_alarm_curl_config *uacc) {
|
||||
struct uwsgi_alarm_curl_opt *o = uaco;
|
||||
char *equal = strchr(opt,'=');
|
||||
if (!equal) {
|
||||
if (!uacc->first) {
|
||||
curl_easy_setopt(curl, CURLOPT_URL, opt);
|
||||
uacc->first = 1;
|
||||
}
|
||||
if (!equal && !uacc->url) {
|
||||
uwsgi_alarm_curl_url(curl, CURLOPT_URL, opt, uacc);
|
||||
return;
|
||||
}
|
||||
uacc->first = 1;
|
||||
*equal = 0;
|
||||
while(o->name) {
|
||||
if (!strcmp(o->name, opt)) {
|
||||
@@ -82,91 +105,137 @@ static void uwsgi_alarm_curl_setopt(CURL *curl, char *opt, struct uwsgi_alarm_cu
|
||||
else {
|
||||
curl_easy_setopt(curl, o->option, equal+1);
|
||||
}
|
||||
goto end;
|
||||
break;
|
||||
}
|
||||
o++;
|
||||
}
|
||||
end:
|
||||
*equal = '=';
|
||||
}
|
||||
|
||||
static size_t uwsgi_alarm_curl_read_callback(void *ptr, size_t size, size_t nmemb, void *userp) {
|
||||
struct uwsgi_thread *ut = (struct uwsgi_thread *) userp;
|
||||
struct uwsgi_alarm_curl *uac = userp;
|
||||
size_t full_size = size * nmemb;
|
||||
size_t remains = ut->len - ut->pos;
|
||||
struct uwsgi_alarm_curl_config *uacc = ut->data;
|
||||
int remains = full_size;
|
||||
|
||||
if (remains == 0) return 0;
|
||||
|
||||
if (ut->custom0 == 0) {
|
||||
size_t newline = 0;
|
||||
size_t required = 1;
|
||||
char *addr = ptr;
|
||||
if (uacc->to) required += 4 + strlen(uacc->to) + 1;
|
||||
if (uacc->subject) required += 9 + strlen(uacc->subject) + 1;
|
||||
if (required > full_size) goto skip;
|
||||
|
||||
|
||||
if (uacc->to) {
|
||||
memcpy(addr, "To: ", 4); addr+=4;
|
||||
memcpy(addr, uacc->to, strlen(uacc->to)); addr += strlen(uacc->to);
|
||||
*addr ++= '\n';
|
||||
newline = 1;
|
||||
if (uac->pos < uac->hlen) {
|
||||
if (remains > uac->hlen - uac->pos) {
|
||||
memcpy(ptr, uac->hdr + uac->pos, uac->hlen - uac->pos);
|
||||
ptr += uac->hlen - uac->pos;
|
||||
remains -= uac->hlen - uac->pos;
|
||||
uac->pos = uac->hlen;
|
||||
} else {
|
||||
memcpy(ptr, uac->hdr + uac->pos, remains);
|
||||
uac->pos += remains;
|
||||
return full_size;
|
||||
}
|
||||
|
||||
if (uacc->subject) {
|
||||
memcpy(addr, "Subject: ", 9); addr+=9;
|
||||
memcpy(addr, uacc->subject, strlen(uacc->subject)); addr += strlen(uacc->subject);
|
||||
*addr ++= '\n';
|
||||
newline = 1;
|
||||
}
|
||||
skip:
|
||||
if (newline > 0) {
|
||||
*addr = '\n';
|
||||
}
|
||||
ut->custom0 = 1;
|
||||
return required;
|
||||
}
|
||||
|
||||
if (full_size < remains) {
|
||||
remains = full_size;
|
||||
if (remains > uac->blen + uac->hlen - uac->pos) {
|
||||
memcpy(ptr, uac->body + uac->pos - uac->hlen, uac->blen + uac->hlen - uac->pos);
|
||||
remains -= uac->blen + uac->hlen - uac->pos;
|
||||
uac->pos = uac->blen + uac->hlen;
|
||||
return full_size - remains;
|
||||
}
|
||||
|
||||
memcpy(ptr, ut->buf + ut->pos, remains);
|
||||
ut->pos += remains;
|
||||
|
||||
return remains;
|
||||
memcpy(ptr, uac->body + uac->pos - uac->hlen, remains);
|
||||
uac->pos += remains;
|
||||
return full_size;
|
||||
}
|
||||
|
||||
static void uwsgi_alarm_curl_loop(struct uwsgi_thread *ut) {
|
||||
int interesting_fd;
|
||||
ut->buf = uwsgi_malloc(uwsgi.log_master_bufsize);
|
||||
static struct uwsgi_alarm_curl *uwsgi_alarm_curl_alloc(struct uwsgi_alarm_curl_config *uacc)
|
||||
{
|
||||
char *addr;
|
||||
struct uwsgi_alarm_curl *uac;
|
||||
size_t required = 0;
|
||||
|
||||
if (uacc->to) required += 4 + strlen(uacc->to) + 2;
|
||||
if (uacc->subject) required += 9 + strlen(uacc->subject) + 2;
|
||||
if (required)
|
||||
required += 2; /* newline between MIME header and body */
|
||||
|
||||
uac = uwsgi_malloc(sizeof(*uac) + required);
|
||||
uac->hlen = required;
|
||||
addr = uac->hdr;
|
||||
|
||||
if (uacc->to) {
|
||||
memcpy(addr, "To: ", 4); addr += 4;
|
||||
memcpy(addr, uacc->to, strlen(uacc->to)); addr += strlen(uacc->to);
|
||||
*addr++ = '\r';
|
||||
*addr++ = '\n';
|
||||
}
|
||||
|
||||
if (uacc->subject) {
|
||||
memcpy(addr, "Subject: ", 9); addr += 9;
|
||||
memcpy(addr, uacc->subject, strlen(uacc->subject)); addr += strlen(uacc->subject);
|
||||
*addr++ = '\r';
|
||||
*addr++ = '\n';
|
||||
}
|
||||
|
||||
if (required) {
|
||||
*addr++ = '\r';
|
||||
*addr = '\n';
|
||||
}
|
||||
|
||||
return uac;
|
||||
}
|
||||
|
||||
static struct uwsgi_alarm_curl *uwsgi_alarm_curl_init_curl(struct uwsgi_alarm_instance *uai) {
|
||||
CURL *curl = curl_easy_init();
|
||||
// ARGH !!!
|
||||
if (!curl) return;
|
||||
if (!curl) {
|
||||
uwsgi_error("Failed to initialize libcurl.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, uwsgi.socket_timeout);
|
||||
curl_easy_setopt(curl, CURLOPT_TIMEOUT, uwsgi.socket_timeout);
|
||||
curl_easy_setopt(curl, CURLOPT_READFUNCTION, uwsgi_alarm_curl_read_callback);
|
||||
curl_easy_setopt(curl, CURLOPT_READDATA, ut);
|
||||
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
|
||||
curl_easy_setopt(curl, CURLOPT_POST, 1L);
|
||||
struct curl_slist *expect = NULL; expect = curl_slist_append(expect, "Expect:");
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, expect);
|
||||
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
|
||||
|
||||
struct uwsgi_alarm_curl_config *uacc = (struct uwsgi_alarm_curl_config *) ut->data;
|
||||
char *opts = uwsgi_str(uacc->arg);
|
||||
struct uwsgi_alarm_curl_config uacc;
|
||||
memset(&uacc, 0, sizeof(uacc));
|
||||
char *opts = uwsgi_str(uai->arg);
|
||||
|
||||
// fill curl options
|
||||
char *ctx = NULL;
|
||||
char *p = strtok_r(opts, ";", &ctx);
|
||||
while(p) {
|
||||
uwsgi_alarm_curl_setopt(curl, uwsgi_str(p), uacc);
|
||||
uwsgi_alarm_curl_setopt(curl, p, &uacc);
|
||||
p = strtok_r(NULL, ";", &ctx);
|
||||
}
|
||||
|
||||
if (!uacc.url) {
|
||||
uwsgi_error("An URL is required to trigger curl-based alarm.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
struct uwsgi_alarm_curl *uac = uwsgi_alarm_curl_alloc(&uacc);
|
||||
curl_easy_setopt(curl, CURLOPT_READDATA, uac);
|
||||
free(opts);
|
||||
uac->curl = curl;
|
||||
uai->data_ptr = uac;
|
||||
|
||||
return uac;
|
||||
}
|
||||
|
||||
static void uwsgi_alarm_curl_call_curl(struct uwsgi_alarm_curl *uac, char *msg, int len)
|
||||
{
|
||||
uac->pos = 0;
|
||||
uac->body = msg;
|
||||
uac->blen = len;
|
||||
curl_easy_setopt(uac->curl, CURLOPT_INFILESIZE, uac->hlen + uac->blen);
|
||||
CURLcode res = curl_easy_perform(uac->curl);
|
||||
if (res != CURLE_OK)
|
||||
uwsgi_log_alarm("-curl] curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
|
||||
}
|
||||
|
||||
static void uwsgi_alarm_curl_loop(struct uwsgi_thread *ut) {
|
||||
int interesting_fd;
|
||||
struct uwsgi_alarm_curl *uac = uwsgi_alarm_curl_init_curl(ut->data);
|
||||
uac->ut = ut;
|
||||
ut->buf = uwsgi_malloc(uwsgi.log_master_bufsize);
|
||||
for(;;) {
|
||||
int ret = event_queue_wait(ut->queue, -1, &interesting_fd);
|
||||
if (ret < 0) return;
|
||||
@@ -174,31 +243,26 @@ static void uwsgi_alarm_curl_loop(struct uwsgi_thread *ut) {
|
||||
if (interesting_fd != ut->pipe[1]) continue;
|
||||
ssize_t rlen = read(ut->pipe[1], ut->buf, uwsgi.log_master_bufsize);
|
||||
if (rlen <= 0) continue;
|
||||
ut->pos = 0;
|
||||
ut->len = (size_t) rlen;
|
||||
ut->custom0 = 0;
|
||||
curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t) ut->len);
|
||||
CURLcode res = curl_easy_perform(curl);
|
||||
if (res != CURLE_OK) {
|
||||
uwsgi_log_alarm("-curl] curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
|
||||
}
|
||||
|
||||
uwsgi_alarm_curl_call_curl(uac, ut->buf, rlen);
|
||||
}
|
||||
}
|
||||
|
||||
static void uwsgi_alarm_curl_init(struct uwsgi_alarm_instance *uai) {
|
||||
struct uwsgi_thread *ut = uwsgi_thread_new(uwsgi_alarm_curl_loop);
|
||||
if (!ut) return;
|
||||
uai->data_ptr = ut;
|
||||
struct uwsgi_alarm_curl_config *uacc = uwsgi_calloc(sizeof(struct uwsgi_alarm_curl_config));
|
||||
uacc->arg = uai->arg;
|
||||
ut->data = uacc;
|
||||
if (uwsgi.alarm_cheap)
|
||||
uwsgi_alarm_curl_init_curl(uai);
|
||||
else
|
||||
uwsgi_thread_new_with_data(uwsgi_alarm_curl_loop, uai);
|
||||
}
|
||||
|
||||
// pipe the message into the thread;
|
||||
static void uwsgi_alarm_curl_func(struct uwsgi_alarm_instance *uai, char *msg, size_t len) {
|
||||
struct uwsgi_thread *ut = (struct uwsgi_thread *) uai->data_ptr;
|
||||
ut->rlen = write(ut->pipe[0], msg, len);
|
||||
struct uwsgi_alarm_curl *uac = uai->data_ptr;
|
||||
if (uwsgi.alarm_cheap)
|
||||
uwsgi_alarm_curl_call_curl(uac, msg, len);
|
||||
else {
|
||||
struct uwsgi_thread *ut = uac->ut;
|
||||
ut->rlen = write(ut->pipe[0], msg, len);
|
||||
}
|
||||
}
|
||||
|
||||
static void uwsgi_alarm_curl_load(void) {
|
||||
|
||||
@@ -4,10 +4,9 @@ void uwsgi_alarm_xmpp_loop(struct uwsgi_thread *);
|
||||
|
||||
static void uwsgi_alarm_xmpp_init(struct uwsgi_alarm_instance *uai) {
|
||||
|
||||
struct uwsgi_thread *ut = uwsgi_thread_new(uwsgi_alarm_xmpp_loop);
|
||||
struct uwsgi_thread *ut = uwsgi_thread_new_with_data(uwsgi_alarm_xmpp_loop, uai->arg);
|
||||
if (!ut) return;
|
||||
uai->data_ptr = ut;
|
||||
ut->data = uai->arg;
|
||||
}
|
||||
|
||||
// pipe the message into the thread;
|
||||
|
||||
@@ -0,0 +1,378 @@
|
||||
#include "../python/uwsgi_python.h"
|
||||
|
||||
/*
|
||||
|
||||
python >= 3.4 asyncio (PEP 3156) loop engine
|
||||
|
||||
EXPERIMENTAL !!!
|
||||
|
||||
Author: Roberto De Ioris
|
||||
|
||||
*/
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
extern struct uwsgi_python up;
|
||||
|
||||
static struct uwsgi_asyncio {
|
||||
PyObject *mod;
|
||||
PyObject *loop;
|
||||
PyObject *request;
|
||||
PyObject *hook_fd;
|
||||
PyObject *hook_timeout;
|
||||
PyObject *hook_fix;
|
||||
} uasyncio;
|
||||
|
||||
#define free_req_queue uwsgi.async_queue_unused_ptr++; uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = wsgi_req
|
||||
|
||||
static void uwsgi_opt_setup_asyncio(char *opt, char *value, void *null) {
|
||||
|
||||
// set async mode
|
||||
uwsgi_opt_set_int(opt, value, &uwsgi.async);
|
||||
if (uwsgi.socket_timeout < 30) {
|
||||
uwsgi.socket_timeout = 30;
|
||||
}
|
||||
// set loop engine
|
||||
uwsgi.loop = "asyncio";
|
||||
|
||||
}
|
||||
|
||||
static struct uwsgi_option asyncio_options[] = {
|
||||
{"asyncio", required_argument, 0, "a shortcut enabling asyncio loop engine with the specified number of async cores and optimal parameters", uwsgi_opt_setup_asyncio, NULL, UWSGI_OPT_THREADS},
|
||||
{0, 0, 0, 0, 0, 0, 0},
|
||||
|
||||
};
|
||||
|
||||
static void gil_asyncio_get() {
|
||||
pthread_setspecific(up.upt_gil_key, (void *) PyGILState_Ensure());
|
||||
}
|
||||
|
||||
static void gil_asyncio_release() {
|
||||
PyGILState_Release((PyGILState_STATE) pthread_getspecific(up.upt_gil_key));
|
||||
}
|
||||
|
||||
static int uwsgi_asyncio_wait_read_hook(int fd, int timeout) {
|
||||
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
|
||||
if (PyObject_CallMethod(uasyncio.loop, "add_reader", "iOl", fd, uasyncio.hook_fd,(long) wsgi_req) == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
PyObject *ob_timeout = PyObject_CallMethod(uasyncio.loop, "call_later", "iOl", timeout, uasyncio.hook_timeout, (long)wsgi_req);
|
||||
if (!ob_timeout) {
|
||||
if (PyObject_CallMethod(uasyncio.loop, "remove_reader", "i", fd) == NULL) PyErr_Print();
|
||||
goto error;
|
||||
}
|
||||
// back to loop
|
||||
if (uwsgi.schedule_to_main) uwsgi.schedule_to_main(wsgi_req);
|
||||
// back from loop
|
||||
|
||||
if (PyObject_CallMethod(uasyncio.loop, "remove_reader", "i", fd) == NULL) PyErr_Print();
|
||||
if (PyObject_CallMethod(ob_timeout, "cancel", NULL) == NULL) PyErr_Print();
|
||||
|
||||
Py_DECREF(ob_timeout);
|
||||
|
||||
if (wsgi_req->async_timed_out) return 0;
|
||||
|
||||
return 1;
|
||||
|
||||
error:
|
||||
PyErr_Print();
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int uwsgi_asyncio_wait_write_hook(int fd, int timeout) {
|
||||
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
|
||||
if (PyObject_CallMethod(uasyncio.loop, "add_writer", "iOl", fd, uasyncio.hook_fd,(long) wsgi_req) == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
PyObject *ob_timeout = PyObject_CallMethod(uasyncio.loop, "call_later", "iOl", timeout, uasyncio.hook_timeout, (long)wsgi_req);
|
||||
if (!ob_timeout) {
|
||||
if (PyObject_CallMethod(uasyncio.loop, "remove_writer", "i", fd) == NULL) PyErr_Print();
|
||||
goto error;
|
||||
}
|
||||
// back to loop
|
||||
if (uwsgi.schedule_to_main) {
|
||||
uwsgi.schedule_to_main(wsgi_req);
|
||||
}
|
||||
// back from loop
|
||||
|
||||
if (PyObject_CallMethod(uasyncio.loop, "remove_writer", "i", fd) == NULL) PyErr_Print();
|
||||
if (PyObject_CallMethod(ob_timeout, "cancel", NULL) == NULL) PyErr_Print();
|
||||
|
||||
Py_DECREF(ob_timeout);
|
||||
|
||||
if (wsgi_req->async_timed_out) return 0;
|
||||
|
||||
return 1;
|
||||
|
||||
error:
|
||||
PyErr_Print();
|
||||
return -1;
|
||||
}
|
||||
|
||||
static PyObject *py_uwsgi_asyncio_request(PyObject *self, PyObject *args) {
|
||||
long wsgi_req_ptr = 0;
|
||||
int timed_out = 0;
|
||||
if (!PyArg_ParseTuple(args, "l|i:uwsgi_asyncio_request", &wsgi_req_ptr, &timed_out)) {
|
||||
uwsgi_log_verbose("[BUG] invalid arguments for asyncio callback !!!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
struct wsgi_request *wsgi_req = (struct wsgi_request *) wsgi_req_ptr;
|
||||
uwsgi.wsgi_req = wsgi_req;
|
||||
|
||||
PyObject *ob_timeout = (PyObject *) wsgi_req->async_timeout;
|
||||
if (PyObject_CallMethod(ob_timeout, "cancel", NULL) == NULL) PyErr_Print();
|
||||
Py_DECREF(ob_timeout);
|
||||
// avoid mess when closing the request
|
||||
wsgi_req->async_timeout = NULL;
|
||||
|
||||
if (timed_out > 0) {
|
||||
if (PyObject_CallMethod(uasyncio.loop, "remove_reader", "i", wsgi_req->fd) == NULL) PyErr_Print();
|
||||
goto end;
|
||||
}
|
||||
|
||||
int status = wsgi_req->socket->proto(wsgi_req);
|
||||
if (status > 0) {
|
||||
ob_timeout = PyObject_CallMethod(uasyncio.loop, "call_later", "iOli", uwsgi.socket_timeout, uasyncio.request, wsgi_req_ptr, 1);
|
||||
if (!ob_timeout) {
|
||||
if (PyObject_CallMethod(uasyncio.loop, "remove_reader", "i", wsgi_req->fd) == NULL) PyErr_Print();
|
||||
goto end;
|
||||
}
|
||||
// trick for reference counting
|
||||
wsgi_req->async_timeout = (struct uwsgi_rb_timer *) ob_timeout;
|
||||
goto again;
|
||||
}
|
||||
|
||||
if (PyObject_CallMethod(uasyncio.loop, "remove_reader", "i", wsgi_req->fd) == NULL) {
|
||||
PyErr_Print();
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (status == 0) {
|
||||
// we call this two time... overengineering :(
|
||||
uwsgi.async_proto_fd_table[wsgi_req->fd] = NULL;
|
||||
uwsgi.schedule_to_req();
|
||||
goto again;
|
||||
}
|
||||
|
||||
end:
|
||||
uwsgi.async_proto_fd_table[wsgi_req->fd] = NULL;
|
||||
uwsgi_close_request(uwsgi.wsgi_req);
|
||||
free_req_queue;
|
||||
again:
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
|
||||
static PyObject *py_uwsgi_asyncio_accept(PyObject *self, PyObject *args) {
|
||||
long uwsgi_sock_ptr = 0;
|
||||
if (!PyArg_ParseTuple(args, "l:uwsgi_asyncio_accept", &uwsgi_sock_ptr)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct wsgi_request *wsgi_req = find_first_available_wsgi_req();
|
||||
|
||||
if (wsgi_req == NULL) {
|
||||
uwsgi_async_queue_is_full(uwsgi_now());
|
||||
goto end;
|
||||
}
|
||||
|
||||
uwsgi.wsgi_req = wsgi_req;
|
||||
struct uwsgi_socket *uwsgi_sock = (struct uwsgi_socket *) uwsgi_sock_ptr;
|
||||
|
||||
// fill wsgi_request structure
|
||||
wsgi_req_setup(wsgi_req, wsgi_req->async_id, uwsgi_sock );
|
||||
|
||||
// mark core as used
|
||||
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].in_request = 1;
|
||||
|
||||
// accept the connection (since uWSGI 1.5 all of the sockets are non-blocking)
|
||||
if (wsgi_req_simple_accept(wsgi_req, uwsgi_sock->fd)) {
|
||||
// in case of errors (or thundering herd, just reset it)
|
||||
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].in_request = 0;
|
||||
free_req_queue;
|
||||
goto end;
|
||||
}
|
||||
|
||||
wsgi_req->start_of_request = uwsgi_micros();
|
||||
wsgi_req->start_of_request_in_sec = wsgi_req->start_of_request/1000000;
|
||||
|
||||
// enter harakiri mode
|
||||
if (uwsgi.harakiri_options.workers > 0) {
|
||||
set_harakiri(uwsgi.harakiri_options.workers);
|
||||
}
|
||||
|
||||
uwsgi.async_proto_fd_table[wsgi_req->fd] = wsgi_req;
|
||||
|
||||
// add callback for protocol
|
||||
if (PyObject_CallMethod(uasyncio.loop, "add_reader", "iOl", wsgi_req->fd, uasyncio.request, (long) wsgi_req) == NULL) {
|
||||
free_req_queue;
|
||||
PyErr_Print();
|
||||
}
|
||||
|
||||
// add timeout
|
||||
PyObject *ob_timeout = PyObject_CallMethod(uasyncio.loop, "call_later", "iOli", uwsgi.socket_timeout, uasyncio.request, (long)wsgi_req, 1);
|
||||
if (!ob_timeout) {
|
||||
if (PyObject_CallMethod(uasyncio.loop, "remove_reader", "i", wsgi_req->fd) == NULL) PyErr_Print();
|
||||
free_req_queue;
|
||||
}
|
||||
else {
|
||||
// trick for reference counting
|
||||
wsgi_req->async_timeout = (struct uwsgi_rb_timer *) ob_timeout;
|
||||
}
|
||||
end:
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
PyObject *py_uwsgi_asyncio_hook_fd(PyObject *self, PyObject *args) {
|
||||
long wsgi_req_ptr = 0;
|
||||
if (!PyArg_ParseTuple(args, "l:uwsgi_asyncio_hook_fd", &wsgi_req_ptr)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uwsgi.wsgi_req = (struct wsgi_request *) wsgi_req_ptr;
|
||||
uwsgi.schedule_to_req();
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
PyObject *py_uwsgi_asyncio_hook_timeout(PyObject *self, PyObject *args) {
|
||||
long wsgi_req_ptr = 0;
|
||||
if (!PyArg_ParseTuple(args, "l", &wsgi_req_ptr)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uwsgi.wsgi_req = (struct wsgi_request *) wsgi_req_ptr;
|
||||
uwsgi.wsgi_req->async_timed_out = 1;
|
||||
uwsgi.schedule_to_req();
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
PyObject *py_uwsgi_asyncio_hook_fix(PyObject *self, PyObject *args) {
|
||||
long wsgi_req_ptr = 0;
|
||||
if (!PyArg_ParseTuple(args, "l", &wsgi_req_ptr)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uwsgi.wsgi_req = (struct wsgi_request *) wsgi_req_ptr;
|
||||
uwsgi.schedule_to_req();
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
|
||||
PyMethodDef uwsgi_asyncio_accept_def[] = { {"uwsgi_asyncio_accept", py_uwsgi_asyncio_accept, METH_VARARGS, ""} };
|
||||
PyMethodDef uwsgi_asyncio_request_def[] = { {"uwsgi_asyncio_request", py_uwsgi_asyncio_request, METH_VARARGS, ""} };
|
||||
PyMethodDef uwsgi_asyncio_hook_fd_def[] = { {"uwsgi_asyncio_hook_fd", py_uwsgi_asyncio_hook_fd, METH_VARARGS, ""} };
|
||||
PyMethodDef uwsgi_asyncio_hook_timeout_def[] = { {"uwsgi_asyncio_hook_timeout", py_uwsgi_asyncio_hook_timeout, METH_VARARGS, ""} };
|
||||
PyMethodDef uwsgi_asyncio_hook_fix_def[] = { {"uwsgi_asyncio_hook_fix", py_uwsgi_asyncio_hook_fix, METH_VARARGS, ""} };
|
||||
|
||||
static void uwsgi_asyncio_schedule_fix(struct wsgi_request *wsgi_req) {
|
||||
PyObject *cb = PyObject_CallMethod(uasyncio.loop, "call_soon", "Ol", uasyncio.hook_fix, (long) wsgi_req);
|
||||
if (!cb) goto error;
|
||||
Py_DECREF(cb);
|
||||
return;
|
||||
|
||||
error:
|
||||
PyErr_Print();
|
||||
}
|
||||
|
||||
static void asyncio_loop() {
|
||||
|
||||
if (!uwsgi.has_threads && uwsgi.mywid == 1) {
|
||||
uwsgi_log("!!! Running asyncio without threads IS NOT recommended, enable them with --enable-threads !!!\n");
|
||||
}
|
||||
|
||||
if (uwsgi.socket_timeout < 30) {
|
||||
uwsgi_log("!!! Running asyncio with a socket-timeout lower than 30 seconds is not recommended, tune it with --socket-timeout !!!\n");
|
||||
}
|
||||
|
||||
if (!uwsgi.async_waiting_fd_table)
|
||||
uwsgi.async_waiting_fd_table = uwsgi_calloc(sizeof(struct wsgi_request *) * uwsgi.max_fd);
|
||||
if (!uwsgi.async_proto_fd_table)
|
||||
uwsgi.async_proto_fd_table = uwsgi_calloc(sizeof(struct wsgi_request *) * uwsgi.max_fd);
|
||||
|
||||
// get the GIL
|
||||
UWSGI_GET_GIL
|
||||
|
||||
up.gil_get = gil_asyncio_get;
|
||||
up.gil_release = gil_asyncio_release;
|
||||
|
||||
uwsgi.wait_write_hook = uwsgi_asyncio_wait_write_hook;
|
||||
uwsgi.wait_read_hook = uwsgi_asyncio_wait_read_hook;
|
||||
|
||||
uwsgi.schedule_fix = uwsgi_asyncio_schedule_fix;
|
||||
|
||||
if (uwsgi.async < 2) {
|
||||
uwsgi_log("the asyncio loop engine requires async mode (--async <n>)\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!uwsgi.schedule_to_main) {
|
||||
uwsgi_log("*** DANGER *** asyncio mode without coroutine/greenthread engine loaded !!!\n");
|
||||
}
|
||||
|
||||
PyObject *asyncio = PyImport_ImportModule("asyncio");
|
||||
if (!asyncio) uwsgi_pyexit;
|
||||
|
||||
uasyncio.mod = asyncio;
|
||||
|
||||
uasyncio.loop = PyObject_CallMethod(asyncio, "get_event_loop", NULL);
|
||||
if (!uasyncio.loop) uwsgi_pyexit;
|
||||
|
||||
// main greenlet waiting for connection (one greenlet per-socket)
|
||||
PyObject *asyncio_accept = PyCFunction_New(uwsgi_asyncio_accept_def, NULL);
|
||||
Py_INCREF(asyncio_accept);
|
||||
|
||||
uasyncio.request = PyCFunction_New(uwsgi_asyncio_request_def, NULL);
|
||||
if (!uasyncio.request) uwsgi_pyexit;
|
||||
|
||||
uasyncio.hook_fd = PyCFunction_New(uwsgi_asyncio_hook_fd_def, NULL);
|
||||
if (!uasyncio.hook_fd) uwsgi_pyexit;
|
||||
uasyncio.hook_timeout = PyCFunction_New(uwsgi_asyncio_hook_timeout_def, NULL);
|
||||
if (!uasyncio.hook_timeout) uwsgi_pyexit;
|
||||
uasyncio.hook_fix = PyCFunction_New(uwsgi_asyncio_hook_fix_def, NULL);
|
||||
if (!uasyncio.hook_fix) uwsgi_pyexit;
|
||||
|
||||
Py_INCREF(uasyncio.request);
|
||||
Py_INCREF(uasyncio.hook_fd);
|
||||
Py_INCREF(uasyncio.hook_timeout);
|
||||
Py_INCREF(uasyncio.hook_fix);
|
||||
|
||||
// call add_handler on each socket
|
||||
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
|
||||
while(uwsgi_sock) {
|
||||
if (PyObject_CallMethod(uasyncio.loop, "add_reader", "iOl", uwsgi_sock->fd, asyncio_accept, (long) uwsgi_sock) == NULL) {
|
||||
uwsgi_pyexit;
|
||||
}
|
||||
uwsgi_sock = uwsgi_sock->next;
|
||||
}
|
||||
|
||||
if (PyObject_CallMethod(uasyncio.loop, "run_forever", NULL) == NULL) {
|
||||
uwsgi_pyexit;
|
||||
}
|
||||
|
||||
// never here ?
|
||||
}
|
||||
|
||||
static void asyncio_init() {
|
||||
uwsgi_register_loop( (char *) "asyncio", asyncio_loop);
|
||||
}
|
||||
|
||||
|
||||
struct uwsgi_plugin asyncio_plugin = {
|
||||
.name = "asyncio",
|
||||
.options = asyncio_options,
|
||||
.on_load = asyncio_init,
|
||||
};
|
||||
@@ -0,0 +1,8 @@
|
||||
from distutils import sysconfig
|
||||
|
||||
NAME='asyncio'
|
||||
CFLAGS = ['-I' + sysconfig.get_python_inc(), '-I' + sysconfig.get_python_inc(plat_specific=True)]
|
||||
LDFLAGS = []
|
||||
LIBS = []
|
||||
|
||||
GCC_LIST = ['asyncio']
|
||||
@@ -380,6 +380,11 @@ metrics_loop:
|
||||
uwsgi_rlock(uwsgi.metrics_lock);
|
||||
wok = carbon_write(fd, "%s%s.%s.%.*s %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, um->name_len, um->name, (unsigned long long) *um->value, (unsigned long long) now);
|
||||
uwsgi_rwunlock(uwsgi.metrics_lock);
|
||||
if (um->reset_after_push){
|
||||
uwsgi_wlock(uwsgi.metrics_lock);
|
||||
*um->value = um->initial_value;
|
||||
uwsgi_rwunlock(uwsgi.metrics_lock);
|
||||
}
|
||||
if (!wok) goto clear;
|
||||
um = um->next;
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ struct corerouter_peer *uwsgi_cr_peer_add(struct corerouter_session *cs) {
|
||||
if (!bufsize) bufsize = uwsgi.page_size;
|
||||
peers->in = uwsgi_buffer_new(bufsize);
|
||||
// add timeout
|
||||
peers->current_timeout = cs->corerouter->socket_timeout;
|
||||
peers->timeout = cr_add_timeout(cs->corerouter, peers);
|
||||
peers->prev = old_peers;
|
||||
|
||||
@@ -582,8 +583,8 @@ struct corerouter_session *corerouter_alloc_session(struct uwsgi_corerouter *ucr
|
||||
cs->corerouter = ucr;
|
||||
cs->ugs = ugs;
|
||||
|
||||
// set initial timeout
|
||||
peer->timeout = cr_add_timeout(ucr, ucr->cr_table[new_connection]);
|
||||
// set initial timeout (could be overridden)
|
||||
peer->current_timeout = ucr->socket_timeout;
|
||||
|
||||
ucr->active_sessions++;
|
||||
|
||||
@@ -622,6 +623,10 @@ struct corerouter_session *corerouter_alloc_session(struct uwsgi_corerouter *ucr
|
||||
corerouter_close_session(ucr, cs);
|
||||
cs = NULL;
|
||||
}
|
||||
else {
|
||||
// truly set the timeout
|
||||
peer->timeout = cr_add_timeout(ucr, ucr->cr_table[new_connection]);
|
||||
}
|
||||
|
||||
return cs;
|
||||
}
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
#define COREROUTER_STATUS_RECV_HDR 2
|
||||
#define COREROUTER_STATUS_RESPONSE 3
|
||||
|
||||
#define cr_add_timeout(u, x) uwsgi_add_rb_timer(u->timeouts, uwsgi_now()+u->socket_timeout, x)
|
||||
#define cr_add_timeout_fast(u, x, t) uwsgi_add_rb_timer(u->timeouts, t+u->socket_timeout, x)
|
||||
#define cr_add_timeout(u, x) uwsgi_add_rb_timer(u->timeouts, uwsgi_now()+x->current_timeout, x)
|
||||
#define cr_add_timeout_fast(u, x, t) uwsgi_add_rb_timer(u->timeouts, t+x->current_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 == x->session->main_peer) ? (x->session->peers ? x->session->peers->key_len: 0) : x->key_len, (x == x->session->main_peer) ? (x->session->peers ? x->session->peers->key: "") : x->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 == x->session->main_peer) ? (x->session->peers ? x->session->peers->key_len: 0) : x->key_len, (x == x->session->main_peer) ? (x->session->peers ? x->session->peers->key: "") : x->key, x->session->client_address, x->session->client_port, __VA_ARGS__)
|
||||
|
||||
#define cr_try_again if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {\
|
||||
errno = EINPROGRESS;\
|
||||
@@ -188,6 +188,8 @@ struct corerouter_peer {
|
||||
|
||||
struct corerouter_peer *prev;
|
||||
struct corerouter_peer *next;
|
||||
|
||||
int current_timeout;
|
||||
};
|
||||
|
||||
struct uwsgi_corerouter {
|
||||
|
||||
+6
-24
@@ -66,32 +66,14 @@ SV * coroae_coro_new(CV *block) {
|
||||
}
|
||||
|
||||
static int coroae_wait_milliseconds(int timeout) {
|
||||
int ret = -1;
|
||||
dSP;
|
||||
ENTER;
|
||||
SAVETMPS;
|
||||
PUSHMARK(SP);
|
||||
XPUSHs(newSVnv(((double)timeout)/1000.0));
|
||||
PUTBACK;
|
||||
call_pv("Coro::AnyEvent::sleep", G_SCALAR|G_EVAL);
|
||||
SPAGAIN;
|
||||
if(SvTRUE(ERRSV)) {
|
||||
uwsgi_log("[uwsgi-perl error] %s", SvPV_nolen(ERRSV));
|
||||
}
|
||||
else {
|
||||
SV *p_ret = POPs;
|
||||
if (SvTRUE(p_ret)) {
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
PUTBACK;
|
||||
FREETMPS;
|
||||
LEAVE;
|
||||
|
||||
return ret;
|
||||
char buf[256];
|
||||
double d = ((double)timeout)/1000.0;
|
||||
int ret = snprintf(buf, 256, "Coro::AnyEvent::sleep %f", d);
|
||||
if (ret <= 0 || ret > 256) return -1;
|
||||
perl_eval_pv(buf, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int coroae_wait_fd_read(int fd, int timeout) {
|
||||
int ret = 0;
|
||||
dSP;
|
||||
|
||||
@@ -10,6 +10,10 @@ struct uwsgi_emperor_mongodb_state {
|
||||
char *address;
|
||||
char *collection;
|
||||
char *json;
|
||||
char *database;
|
||||
char *username;
|
||||
char *password;
|
||||
char *predigest;
|
||||
};
|
||||
|
||||
|
||||
@@ -20,7 +24,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;
|
||||
@@ -29,9 +33,17 @@ extern "C" void uwsgi_imperial_monitor_mongodb(struct uwsgi_emperor_scanner *ues
|
||||
// connect
|
||||
c.connect(uems->address);
|
||||
|
||||
if (uems->database && uems->username && uems->password) {
|
||||
std::string err;
|
||||
if (c.auth(uems->database, uems->username, uems->password, err, uems->predigest ? false : true) == false) {
|
||||
uwsgi_log_verbose("[emperor-mongodb] unable to authenticate to db %s: %s\n", uems->database, err.c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 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 +52,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 +74,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 +90,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
|
||||
@@ -121,3 +136,40 @@ done:
|
||||
uwsgi_log("[emperor] enabled emperor MongoDB monitor for %s on collection %s\n", uems->address, uems->collection);
|
||||
}
|
||||
|
||||
// setup a new mongodb imperial monitor (keyval based)
|
||||
extern "C" void uwsgi_imperial_monitor_mongodb_init2(struct uwsgi_emperor_scanner *ues) {
|
||||
|
||||
// allocate a new state
|
||||
ues->data = uwsgi_calloc(sizeof(struct uwsgi_emperor_mongodb_state));
|
||||
size_t arg_len = strlen(ues->arg);
|
||||
struct uwsgi_emperor_mongodb_state *uems = (struct uwsgi_emperor_mongodb_state *) ues->data;
|
||||
|
||||
// parse args/ set defaults
|
||||
uems->address = (char *) "127.0.0.1:27017";
|
||||
uems->collection = (char *) "uwsgi.emperor.vassals";
|
||||
uems->json = (char *) "";
|
||||
char *args = NULL;
|
||||
if (arg_len <= 11) goto done;
|
||||
args = ues->arg+11;
|
||||
if (uwsgi_kvlist_parse(args, strlen(args), ',', '=',
|
||||
"addr", &uems->address,
|
||||
"address", &uems->address,
|
||||
"server", &uems->address,
|
||||
"collection", &uems->collection,
|
||||
"coll", &uems->collection,
|
||||
"json", &uems->json,
|
||||
"database", &uems->database,
|
||||
"db", &uems->database,
|
||||
"username", &uems->username,
|
||||
"password", &uems->password,
|
||||
"predigest", &uems->predigest,
|
||||
NULL)) {
|
||||
|
||||
uwsgi_log("[emperor-mongodb] invalid keyval syntax !\n");
|
||||
exit(1);
|
||||
}
|
||||
done:
|
||||
uwsgi_log("[emperor] enabled emperor MongoDB monitor for %s on collection %s\n", uems->address, uems->collection);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
|
||||
void uwsgi_imperial_monitor_mongodb(struct uwsgi_emperor_scanner *);
|
||||
void uwsgi_imperial_monitor_mongodb_init(struct uwsgi_emperor_scanner *);
|
||||
void uwsgi_imperial_monitor_mongodb_init2(struct uwsgi_emperor_scanner *);
|
||||
|
||||
void emperor_mongodb_init(void) {
|
||||
uwsgi_register_imperial_monitor("mongodb", uwsgi_imperial_monitor_mongodb_init, uwsgi_imperial_monitor_mongodb);
|
||||
uwsgi_register_imperial_monitor("mongodb2", uwsgi_imperial_monitor_mongodb_init2, uwsgi_imperial_monitor_mongodb);
|
||||
}
|
||||
|
||||
struct uwsgi_plugin emperor_mongodb_plugin = {
|
||||
|
||||
@@ -345,6 +345,9 @@ static void gil_gevent_release() {
|
||||
|
||||
static void gevent_loop() {
|
||||
|
||||
// ensure SIGPIPE is ignored
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
if (!uwsgi.has_threads && uwsgi.mywid == 1) {
|
||||
uwsgi_log("!!! Running gevent without threads IS NOT recommended, enable them with --enable-threads !!!\n");
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
extern struct uwsgi_server uwsgi;
|
||||
extern struct uwsgi_python up;
|
||||
|
||||
#define is_not_python(x) strcmp(uwsgi.p[x]->name, "python")
|
||||
|
||||
struct ugreenlet {
|
||||
int enabled;
|
||||
PyObject *callable;
|
||||
@@ -69,7 +71,7 @@ static void greenlet_schedule_to_req() {
|
||||
}
|
||||
|
||||
// call it in the main core
|
||||
if (uwsgi.p[modifier1]->suspend) {
|
||||
if (is_not_python(modifier1) && uwsgi.p[modifier1]->suspend) {
|
||||
uwsgi.p[modifier1]->suspend(NULL);
|
||||
}
|
||||
|
||||
@@ -81,7 +83,7 @@ static void greenlet_schedule_to_req() {
|
||||
}
|
||||
Py_DECREF(ret);
|
||||
|
||||
if (uwsgi.p[modifier1]->resume) {
|
||||
if (is_not_python(modifier1) && uwsgi.p[modifier1]->resume) {
|
||||
uwsgi.p[modifier1]->resume(NULL);
|
||||
}
|
||||
|
||||
@@ -93,7 +95,7 @@ static void greenlet_schedule_to_main(struct wsgi_request *wsgi_req) {
|
||||
// ensure gil
|
||||
UWSGI_GET_GIL
|
||||
|
||||
if (uwsgi.p[wsgi_req->uh->modifier1]->suspend) {
|
||||
if (is_not_python(wsgi_req->uh->modifier1) && uwsgi.p[wsgi_req->uh->modifier1]->suspend) {
|
||||
uwsgi.p[wsgi_req->uh->modifier1]->suspend(wsgi_req);
|
||||
}
|
||||
PyObject *ret = PyGreenlet_Switch(ugl.main, NULL, NULL);
|
||||
@@ -103,7 +105,7 @@ static void greenlet_schedule_to_main(struct wsgi_request *wsgi_req) {
|
||||
exit(1);
|
||||
}
|
||||
Py_DECREF(ret);
|
||||
if (uwsgi.p[wsgi_req->uh->modifier1]->resume) {
|
||||
if (is_not_python(wsgi_req->uh->modifier1) && uwsgi.p[wsgi_req->uh->modifier1]->resume) {
|
||||
uwsgi.p[wsgi_req->uh->modifier1]->resume(wsgi_req);
|
||||
}
|
||||
uwsgi.wsgi_req = wsgi_req;
|
||||
|
||||
@@ -42,6 +42,10 @@ struct uwsgi_http {
|
||||
|
||||
int server_name_as_http_host;
|
||||
|
||||
int headers_timeout;
|
||||
int connect_timeout;
|
||||
int manage_source;
|
||||
int enable_proxy_protocol;
|
||||
};
|
||||
|
||||
struct http_session {
|
||||
@@ -154,7 +158,7 @@ void hr_session_ssl_close(struct corerouter_session *);
|
||||
ssize_t hr_ssl_read(struct corerouter_peer *);
|
||||
ssize_t hr_ssl_write(struct corerouter_peer *);
|
||||
|
||||
int hr_https_add_vars(struct http_session *, struct uwsgi_buffer *);
|
||||
int hr_https_add_vars(struct http_session *, struct corerouter_peer *, struct uwsgi_buffer *);
|
||||
void hr_setup_ssl(struct http_session *, struct uwsgi_gateway_socket *);
|
||||
|
||||
#endif
|
||||
|
||||
+165
-49
@@ -60,43 +60,59 @@ struct uwsgi_option http_options[] = {
|
||||
{"http-buffer-size", required_argument, 0, "set internal buffer size (default: page size)", uwsgi_opt_set_64bit, &uhttp.cr.buffer_size, 0},
|
||||
|
||||
{"http-server-name-as-http-host", required_argument, 0, "force SERVER_NAME to HTTP_HOST", uwsgi_opt_true, &uhttp.server_name_as_http_host, 0},
|
||||
{"http-headers-timeout", required_argument, 0, "set internal http socket timeout for headers", uwsgi_opt_set_int, &uhttp.headers_timeout, 0},
|
||||
{"http-connect-timeout", required_argument, 0, "set internal http socket timeout for backend connections", uwsgi_opt_set_int, &uhttp.connect_timeout, 0},
|
||||
|
||||
{"http-manage-source", no_argument, 0, "manage the SOURCE HTTP method placing the session in raw mode", uwsgi_opt_true, &uhttp.manage_source, 0},
|
||||
{"http-enable-proxy-protocol", optional_argument, 0, "manage PROXY protocol requests", uwsgi_opt_true, &uhttp.enable_proxy_protocol, 0},
|
||||
{0, 0, 0, 0, 0, 0, 0},
|
||||
};
|
||||
|
||||
int http_add_uwsgi_header(struct corerouter_peer *peer, char *hh, uint16_t hhlen) {
|
||||
static void http_set_timeout(struct corerouter_peer *peer, int timeout) {
|
||||
if (peer->current_timeout == timeout) return;
|
||||
peer->current_timeout = timeout;
|
||||
peer->timeout = corerouter_reset_timeout(peer->session->corerouter, peer);
|
||||
}
|
||||
|
||||
static char * http_header_to_cgi(char *hh, size_t hhlen, size_t *keylen, size_t *vallen, int *has_prefix) {
|
||||
size_t i;
|
||||
char *val = hh;
|
||||
int status = 0;
|
||||
for (i = 0; i < hhlen; i++) {
|
||||
if (!status) {
|
||||
hh[i] = toupper((int) hh[i]);
|
||||
if (hh[i] == '-')
|
||||
hh[i] = '_';
|
||||
if (hh[i] == ':') {
|
||||
status = 1;
|
||||
*keylen = i;
|
||||
}
|
||||
}
|
||||
else if (status == 1 && hh[i] != ' ') {
|
||||
status = 2;
|
||||
val += i;
|
||||
*vallen+=1;
|
||||
}
|
||||
else if (status == 2) {
|
||||
*vallen+=1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(*keylen))
|
||||
return NULL;
|
||||
|
||||
if (uwsgi_strncmp("CONTENT_LENGTH", 14, hh, *keylen) && uwsgi_strncmp("CONTENT_TYPE", 12, hh, *keylen)) {
|
||||
*has_prefix = 0x02;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static int http_add_uwsgi_header(struct corerouter_peer *peer, char *hh, size_t keylen, char *val, size_t vallen, int prefix) {
|
||||
|
||||
struct uwsgi_buffer *out = peer->out;
|
||||
struct http_session *hr = (struct http_session *) peer->session;
|
||||
|
||||
int i;
|
||||
int status = 0;
|
||||
char *val = hh;
|
||||
uint16_t keylen = 0, vallen = 0;
|
||||
int prefix = 0;
|
||||
|
||||
for (i = 0; i < hhlen; i++) {
|
||||
if (!status) {
|
||||
hh[i] = toupper((int) hh[i]);
|
||||
if (hh[i] == '-')
|
||||
hh[i] = '_';
|
||||
if (hh[i] == ':') {
|
||||
status = 1;
|
||||
keylen = i;
|
||||
}
|
||||
}
|
||||
else if (status == 1 && hh[i] != ' ') {
|
||||
status = 2;
|
||||
val += i;
|
||||
vallen++;
|
||||
}
|
||||
else if (status == 2) {
|
||||
vallen++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!keylen)
|
||||
return -1;
|
||||
|
||||
if (hr->websockets) {
|
||||
if (!uwsgi_strncmp("UPGRADE", 7, hh, keylen)) {
|
||||
if (!uwsgi_strnicmp(val, vallen, "websocket", 9)) {
|
||||
@@ -137,10 +153,14 @@ int http_add_uwsgi_header(struct corerouter_peer *peer, char *hh, uint16_t hhlen
|
||||
}
|
||||
|
||||
else if (!uwsgi_strncmp("CONNECTION", 10, hh, keylen)) {
|
||||
if (!uwsgi_strnicmp(val, vallen, "close", 5)) {
|
||||
if (!uwsgi_strnicmp(val, vallen, "close", 5) || !uwsgi_strnicmp(val, vallen, "upgrade", 7)) {
|
||||
hr->session.can_keepalive = 0;
|
||||
}
|
||||
}
|
||||
else if (peer->key == uwsgi.hostname && hr->raw_body && !uwsgi_strncmp("ICE_URL", 7, hh, keylen)) {
|
||||
peer->key = val;
|
||||
peer->key_len = vallen;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_ZLIB
|
||||
else if (uhttp.auto_gzip && !uwsgi_strncmp("ACCEPT_ENCODING", 15, hh, keylen)) {
|
||||
@@ -151,11 +171,7 @@ int http_add_uwsgi_header(struct corerouter_peer *peer, char *hh, uint16_t hhlen
|
||||
#endif
|
||||
|
||||
done:
|
||||
|
||||
if (uwsgi_strncmp("CONTENT_TYPE", 12, hh, keylen) && uwsgi_strncmp("CONTENT_LENGTH", 14, hh, keylen)) {
|
||||
keylen += 5;
|
||||
prefix = 1;
|
||||
}
|
||||
if (prefix) keylen += 5;
|
||||
|
||||
if (uwsgi_buffer_u16le(out, keylen)) return -1;
|
||||
|
||||
@@ -163,7 +179,7 @@ done:
|
||||
if (uwsgi_buffer_append(out, "HTTP_", 5)) return -1;
|
||||
}
|
||||
|
||||
if (uwsgi_buffer_append(out, hh, keylen - (prefix * 5))) return -1;
|
||||
if (uwsgi_buffer_append(out, hh, keylen - (prefix ? 5 : 0))) return -1;
|
||||
|
||||
if (uwsgi_buffer_u16le(out, vallen)) return -1;
|
||||
if (uwsgi_buffer_append(out, val, vallen)) return -1;
|
||||
@@ -180,6 +196,14 @@ int http_headers_parse(struct corerouter_peer *peer) {
|
||||
char *watermark = ptr + hr->headers_size;
|
||||
char *base = ptr;
|
||||
char *query_string = NULL;
|
||||
char *proxy_src = NULL;
|
||||
char *proxy_dst = NULL;
|
||||
char *proxy_src_port = NULL;
|
||||
char *proxy_dst_port = NULL;
|
||||
uint16_t proxy_src_len = 0;
|
||||
uint16_t proxy_dst_len = 0;
|
||||
uint16_t proxy_src_port_len = 0;
|
||||
uint16_t proxy_dst_port_len = 0;
|
||||
|
||||
peer->out = uwsgi_buffer_new(uwsgi.page_size);
|
||||
// force this buffer to be destroyed as soon as possibile
|
||||
@@ -192,10 +216,19 @@ int http_headers_parse(struct corerouter_peer *peer) {
|
||||
struct uwsgi_buffer *out = peer->out;
|
||||
int found = 0;
|
||||
|
||||
if (uwsgi.enable_proxy_protocol || uhttp.enable_proxy_protocol) {
|
||||
ptr = proxy1_parse(ptr, watermark, &proxy_src, &proxy_src_len, &proxy_dst, &proxy_dst_len, &proxy_src_port, &proxy_src_port_len, &proxy_dst_port, &proxy_dst_port_len);
|
||||
base = ptr;
|
||||
}
|
||||
|
||||
// REQUEST_METHOD
|
||||
while (ptr < watermark) {
|
||||
if (*ptr == ' ') {
|
||||
if (uwsgi_buffer_append_keyval(out, "REQUEST_METHOD", 14, base, ptr - base)) return -1;
|
||||
// on SOURCE METHOD, force raw body
|
||||
if (uhttp.manage_source && !uwsgi_strncmp(base, ptr - base, "SOURCE", 6)) {
|
||||
hr->raw_body = 1;
|
||||
}
|
||||
ptr++;
|
||||
found = 1;
|
||||
break;
|
||||
@@ -315,16 +348,27 @@ int http_headers_parse(struct corerouter_peer *peer) {
|
||||
}
|
||||
|
||||
#ifdef UWSGI_SSL
|
||||
if (hr_https_add_vars(hr, out)) return -1;
|
||||
if (hr_https_add_vars(hr, peer, out)) return -1;
|
||||
#endif
|
||||
|
||||
// REMOTE_ADDR
|
||||
if (uwsgi_buffer_append_keyval(out, "REMOTE_ADDR", 11, peer->session->client_address, strlen(peer->session->client_address))) return -1;
|
||||
if (uwsgi_buffer_append_keyval(out, "REMOTE_PORT", 11, peer->session->client_port, strlen(peer->session->client_port))) return -1;
|
||||
if (proxy_src) {
|
||||
if (uwsgi_buffer_append_keyval(out, "REMOTE_ADDR", 11, proxy_src, proxy_src_len)) return -1;
|
||||
if (proxy_src_port) {
|
||||
if (uwsgi_buffer_append_keyval(out, "REMOTE_PORT", 11, proxy_src_port, proxy_src_port_len)) return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (uwsgi_buffer_append_keyval(out, "REMOTE_ADDR", 11, peer->session->client_address, strlen(peer->session->client_address))) return -1;
|
||||
if (uwsgi_buffer_append_keyval(out, "REMOTE_PORT", 11, peer->session->client_port, strlen(peer->session->client_port))) return -1;
|
||||
}
|
||||
|
||||
//HEADERS
|
||||
base = ptr;
|
||||
|
||||
struct uwsgi_string_list *headers = NULL, *usl = NULL;
|
||||
|
||||
while (ptr < watermark) {
|
||||
if (*ptr == '\r') {
|
||||
if (ptr + 1 >= watermark)
|
||||
@@ -345,13 +389,53 @@ int http_headers_parse(struct corerouter_peer *peer) {
|
||||
hr->send_expect_100 = 1;
|
||||
}
|
||||
}
|
||||
if (http_add_uwsgi_header(peer, base, ptr - base)) return -1;
|
||||
|
||||
size_t key_len = 0, value_len = 0;
|
||||
int has_prefix = 0;
|
||||
// last line, do not waste time
|
||||
if (ptr - base == 0) break;
|
||||
char *value = http_header_to_cgi(base, ptr - base, &key_len, &value_len, &has_prefix);
|
||||
if (!value) goto clear;
|
||||
usl = uwsgi_string_list_has_item(headers, base, key_len);
|
||||
// there is already a HTTP header with the same name, let's merge them
|
||||
if (usl) {
|
||||
char *old_value = usl->custom_ptr;
|
||||
usl->custom_ptr = uwsgi_concat3n(old_value, (size_t) usl->custom, ", ", 2, value, value_len);
|
||||
usl->custom += 2 + value_len;
|
||||
if (usl->custom2 & 0x01) free(old_value);
|
||||
usl->custom2 |= 0x01;
|
||||
}
|
||||
else {
|
||||
// add an entry
|
||||
usl = uwsgi_string_new_list(&headers, NULL);
|
||||
usl->value = base;
|
||||
usl->len = key_len;
|
||||
usl->custom_ptr = value;
|
||||
usl->custom = value_len;
|
||||
usl->custom2 = has_prefix;
|
||||
}
|
||||
ptr++;
|
||||
base = ptr + 1;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
|
||||
usl = headers;
|
||||
int broken = 0;
|
||||
while(usl) {
|
||||
if (!broken) {
|
||||
if (http_add_uwsgi_header(peer, usl->value, usl->len, usl->custom_ptr, (size_t) usl->custom, usl->custom2 & 0x02)) broken = 1;
|
||||
}
|
||||
if (usl->custom2 & 0x01) {
|
||||
free(usl->custom_ptr);
|
||||
}
|
||||
struct uwsgi_string_list *tmp_usl = usl;
|
||||
usl = usl->next;
|
||||
free(tmp_usl);
|
||||
}
|
||||
|
||||
if (broken) return -1;
|
||||
|
||||
struct uwsgi_string_list *hv = uhttp.http_vars;
|
||||
while (hv) {
|
||||
char *equal = strchr(hv->value, '=');
|
||||
@@ -363,6 +447,18 @@ int http_headers_parse(struct corerouter_peer *peer) {
|
||||
|
||||
return 0;
|
||||
|
||||
clear:
|
||||
usl = headers;
|
||||
while(usl) {
|
||||
if (usl->custom2 & 0x01) {
|
||||
free(usl->custom_ptr);
|
||||
}
|
||||
struct uwsgi_string_list *tmp_usl = usl;
|
||||
usl = usl->next;
|
||||
free(tmp_usl);
|
||||
}
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -446,6 +542,7 @@ ssize_t hr_write(struct corerouter_peer *main_peer) {
|
||||
return 0;
|
||||
}
|
||||
if (main_peer->session->connect_peer_after_write) {
|
||||
http_set_timeout(main_peer->session->connect_peer_after_write, uhttp.connect_timeout);
|
||||
cr_connect(main_peer->session->connect_peer_after_write, hr_instance_connected);
|
||||
main_peer->session->connect_peer_after_write = NULL;
|
||||
return len;
|
||||
@@ -459,6 +556,9 @@ ssize_t hr_write(struct corerouter_peer *main_peer) {
|
||||
ssize_t hr_instance_connected(struct corerouter_peer* peer) {
|
||||
|
||||
cr_peer_connected(peer, "hr_instance_connected()");
|
||||
|
||||
// set the default timeout
|
||||
http_set_timeout(peer, uhttp.cr.socket_timeout);
|
||||
|
||||
// we are connected, we cannot retry anymore
|
||||
peer->can_retry = 0;
|
||||
@@ -523,10 +623,7 @@ ssize_t hr_instance_read(struct corerouter_peer *peer) {
|
||||
hr->has_gzip = 0;
|
||||
#endif
|
||||
if (uhttp.keepalive > 1) {
|
||||
int orig_timeout = peer->session->corerouter->socket_timeout;
|
||||
peer->session->corerouter->socket_timeout = uhttp.keepalive;
|
||||
peer->session->main_peer->timeout = corerouter_reset_timeout(peer->session->corerouter, peer->session->main_peer);
|
||||
peer->session->corerouter->socket_timeout = orig_timeout;
|
||||
http_set_timeout(peer->session->main_peer, uhttp.keepalive);
|
||||
}
|
||||
}
|
||||
#ifdef UWSGI_ZLIB
|
||||
@@ -655,6 +752,9 @@ ssize_t http_parse(struct corerouter_peer *main_peer) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ensure the headers timeout is honoured
|
||||
http_set_timeout(main_peer, uhttp.headers_timeout);
|
||||
|
||||
// read until \r\n\r\n is found
|
||||
size_t j;
|
||||
size_t len = main_peer->in->pos;
|
||||
@@ -729,6 +829,13 @@ ssize_t http_parse(struct corerouter_peer *main_peer) {
|
||||
if (uwsgi_buffer_append(new_peer->out, main_peer->in->buf + hr->headers_size + 1, hr->remains)) return -1;
|
||||
}
|
||||
|
||||
if (hr->websockets > 2 && hr->websocket_key_len > 0) {
|
||||
hr->raw_body = 1;
|
||||
}
|
||||
|
||||
// on raw body, ensure keepalive is disabled
|
||||
if (hr->raw_body) hr->session.can_keepalive = 0;
|
||||
|
||||
if (hr->session.can_keepalive && hr->content_length == 0) {
|
||||
main_peer->disabled = 1;
|
||||
// stop reading from the client
|
||||
@@ -740,10 +847,12 @@ ssize_t http_parse(struct corerouter_peer *main_peer) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (hr->websockets > 2 && hr->websocket_key_len > 0) {
|
||||
hr->raw_body = 1;
|
||||
}
|
||||
|
||||
new_peer->can_retry = 1;
|
||||
// reset main timeout
|
||||
http_set_timeout(main_peer, uhttp.cr.socket_timeout);
|
||||
// set peer timeout
|
||||
http_set_timeout(new_peer, uhttp.connect_timeout);
|
||||
cr_connect(new_peer, hr_instance_connected);
|
||||
break;
|
||||
}
|
||||
@@ -830,12 +939,17 @@ static int hr_retry(struct corerouter_peer *peer) {
|
||||
|
||||
retry:
|
||||
// start async connect (again)
|
||||
http_set_timeout(peer, uhttp.connect_timeout);
|
||||
cr_connect(peer, hr_instance_connected);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int http_alloc_session(struct uwsgi_corerouter *ucr, struct uwsgi_gateway_socket *ugs, struct corerouter_session *cs, struct sockaddr *sa, socklen_t s_len) {
|
||||
|
||||
if (!uhttp.headers_timeout) uhttp.headers_timeout = uhttp.cr.socket_timeout;
|
||||
if (!uhttp.connect_timeout) uhttp.connect_timeout = uhttp.cr.socket_timeout;
|
||||
|
||||
// set the retry hook
|
||||
cs->retry = hr_retry;
|
||||
struct http_session *hr = (struct http_session *) cs;
|
||||
@@ -845,6 +959,9 @@ int http_alloc_session(struct uwsgi_corerouter *ucr, struct uwsgi_gateway_socket
|
||||
// default hook
|
||||
cs->main_peer->last_hook_read = hr_read;
|
||||
|
||||
// headers timeout
|
||||
cs->main_peer->current_timeout = uhttp.headers_timeout;
|
||||
|
||||
if (uhttp.raw_body) {
|
||||
hr->raw_body = 1;
|
||||
}
|
||||
@@ -906,7 +1023,6 @@ int http_init() {
|
||||
uhttp.cr.socket_num = 0;
|
||||
}
|
||||
uwsgi_corerouter_init((struct uwsgi_corerouter *) &uhttp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -166,10 +166,17 @@ void uwsgi_opt_http_to_https(char *opt, char *value, void *cr) {
|
||||
ucr->has_sockets++;
|
||||
}
|
||||
|
||||
int hr_https_add_vars(struct http_session *hr, struct uwsgi_buffer *out) {
|
||||
int hr_https_add_vars(struct http_session *hr, struct corerouter_peer *peer, struct uwsgi_buffer *out) {
|
||||
// HTTPS (adapted from nginx)
|
||||
if (hr->session.ugs->mode == UWSGI_HTTP_SSL) {
|
||||
if (uwsgi_buffer_append_keyval(out, "HTTPS", 5, "on", 2)) return -1;
|
||||
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
|
||||
const char *servername = SSL_get_servername(hr->ssl, TLSEXT_NAMETYPE_host_name);
|
||||
if (servername) {
|
||||
peer->key = (char *) servername;
|
||||
peer->key_len = strlen(servername);
|
||||
}
|
||||
#endif
|
||||
hr->ssl_client_cert = SSL_get_peer_certificate(hr->ssl);
|
||||
if (hr->ssl_client_cert) {
|
||||
X509_NAME *name = X509_get_subject_name(hr->ssl_client_cert);
|
||||
|
||||
@@ -59,6 +59,7 @@ int http_response_parse(struct http_session *hr, struct uwsgi_buffer *ub, size_t
|
||||
uint32_t h_len = 0;
|
||||
|
||||
int has_size = 0;
|
||||
int has_connection = 0;
|
||||
|
||||
for(i=next;i<len;i++) {
|
||||
if (key) {
|
||||
@@ -73,6 +74,7 @@ int http_response_parse(struct http_session *hr, struct uwsgi_buffer *ub, size_t
|
||||
if (hr->session.can_keepalive) {
|
||||
#endif
|
||||
if (!uwsgi_strnicmp(key, colon-key, "Connection", 10)) {
|
||||
has_connection = 1;
|
||||
if (!uwsgi_strnicmp(colon+2, h_len-((colon-key)+2), "close", 5)) {
|
||||
goto end;
|
||||
}
|
||||
@@ -169,6 +171,10 @@ int http_response_parse(struct http_session *hr, struct uwsgi_buffer *ub, size_t
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
// avoid iOS making mess...
|
||||
if (!has_connection) {
|
||||
if (uwsgi_buffer_insert(ub, len-2, "Connection: close\r\n", 19)) return -1;
|
||||
}
|
||||
hr->session.can_keepalive = 0;
|
||||
}
|
||||
}
|
||||
|
||||
+46
-5
@@ -180,8 +180,10 @@ struct uwsgi_buffer *spdy_http_to_spdy(char *buf, size_t len, uint32_t *hh) {
|
||||
if (!key) return ub;
|
||||
|
||||
uint32_t h_len = 0;
|
||||
|
||||
// headers (key lowercase...)
|
||||
// merge header values and ensure keys are all lowercase
|
||||
struct uwsgi_string_list *hr=NULL, *usl=NULL;
|
||||
char *line_value;
|
||||
size_t line_key_len, line_value_len;
|
||||
for(i=next;i<len;i++) {
|
||||
if (key) {
|
||||
if (buf[i] == '\r' || buf[i] == '\n') {
|
||||
@@ -192,10 +194,37 @@ struct uwsgi_buffer *spdy_http_to_spdy(char *buf, size_t len, uint32_t *hh) {
|
||||
// tolower !!!
|
||||
size_t j;
|
||||
for(j=0;j<h_len;j++) {
|
||||
key[j] = tolower((int) key[j]);
|
||||
// don't lowercase values, only keys
|
||||
if (key[j] == ':') break;
|
||||
key[j] = tolower((int) key[j]);
|
||||
}
|
||||
line_key_len = colon - key;
|
||||
key[line_key_len] = 0;
|
||||
line_value_len = h_len - 2 - line_key_len;
|
||||
line_value = uwsgi_strncopy(colon+2, line_value_len);
|
||||
if (hr) {
|
||||
// check if we already store values for this key
|
||||
usl = uwsgi_string_list_has_item(hr, key, line_key_len);
|
||||
if (usl) {
|
||||
// we have this key, append new value
|
||||
char *oldval = usl->custom_ptr;
|
||||
usl->custom_ptr = uwsgi_concat3n(usl->custom_ptr, usl->custom, "\0", 1, line_value, line_value_len);
|
||||
usl->custom = usl->custom + 1 + line_value_len;
|
||||
free(oldval);
|
||||
}
|
||||
else {
|
||||
// this key is new
|
||||
usl = uwsgi_string_new_list(&hr, key);
|
||||
usl->custom_ptr = line_value;
|
||||
usl->custom = line_value_len;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// this is first key
|
||||
usl = uwsgi_string_new_list(&hr, key);
|
||||
usl->custom_ptr = line_value;
|
||||
usl->custom = line_value_len;
|
||||
}
|
||||
if (uwsgi_buffer_append_keyval32(ub, key, colon-key, colon+2, h_len-((colon-key)+2))) goto end;
|
||||
*hh+=1;
|
||||
key = NULL;
|
||||
h_len = 0;
|
||||
}
|
||||
@@ -210,6 +239,18 @@ struct uwsgi_buffer *spdy_http_to_spdy(char *buf, size_t len, uint32_t *hh) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// append all merged header lines to buffer and free memory
|
||||
struct uwsgi_string_list *ohr;
|
||||
while (hr) {
|
||||
if (uwsgi_buffer_append_keyval32(ub, hr->value, hr->len, hr->custom_ptr, hr->custom)) goto end;
|
||||
*hh+=1;
|
||||
ohr = hr;
|
||||
hr = hr->next;
|
||||
free(ohr->custom_ptr);
|
||||
free(ohr);
|
||||
}
|
||||
|
||||
return ub;
|
||||
|
||||
end:
|
||||
|
||||
@@ -811,8 +811,25 @@ static int uwsgi_lua_request(struct wsgi_request *wsgi_req) {
|
||||
lua_pushnil(L);
|
||||
while(lua_next(L, -3) != 0) {
|
||||
http = lua_tolstring(L, -2, &slen);
|
||||
http2 = lua_tolstring(L, -1, &slen2);
|
||||
uwsgi_response_add_header(wsgi_req, (char *) http, slen, (char *) http2, slen2);
|
||||
|
||||
if (lua_type(L, -1) == LUA_TTABLE) {
|
||||
for (i = 1; /*empty*/ ; ++i) {
|
||||
lua_rawgeti(L, -1, i);
|
||||
|
||||
if (lua_isnil(L, -1)) {
|
||||
lua_pop(L, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
http2 = lua_tolstring(L, -1, &slen2);
|
||||
uwsgi_response_add_header(wsgi_req, (char *) http, slen, (char *) http2, slen2);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
http2 = lua_tolstring(L, -1, &slen2);
|
||||
uwsgi_response_add_header(wsgi_req, (char *) http, slen, (char *) http2, slen2);
|
||||
}
|
||||
lua_pop(L, 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
#include "php.h"
|
||||
#include "SAPI.h"
|
||||
#include "php_main.h"
|
||||
#include "php_variables.h"
|
||||
|
||||
#include "ext/standard/php_smart_str.h"
|
||||
#include "ext/standard/info.h"
|
||||
|
||||
#include "ext/session/php_session.h"
|
||||
|
||||
#include <uwsgi.h>
|
||||
|
||||
@@ -1,12 +1,4 @@
|
||||
#include "php.h"
|
||||
#include "SAPI.h"
|
||||
#include "php_main.h"
|
||||
#include "php_variables.h"
|
||||
|
||||
#include "ext/standard/php_smart_str.h"
|
||||
#include "ext/standard/info.h"
|
||||
|
||||
#include "../../uwsgi.h"
|
||||
#include "common.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
@@ -233,8 +225,9 @@ void uwsgi_php_set(char *opt) {
|
||||
uwsgi_sapi_module.ini_entries[uphp.ini_size] = 0;
|
||||
}
|
||||
|
||||
// future implementation...
|
||||
extern ps_module ps_mod_uwsgi;
|
||||
PHP_MINIT_FUNCTION(uwsgi_php_minit) {
|
||||
php_session_register_module(&ps_mod_uwsgi);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
@@ -341,7 +334,7 @@ PHP_FUNCTION(uwsgi_cache_set) {
|
||||
RETURN_NULL();
|
||||
}
|
||||
|
||||
if (uwsgi_cache_magic_set(key, keylen, value, vallen, expires, 0, cache)) {
|
||||
if (!uwsgi_cache_magic_set(key, keylen, value, vallen, expires, 0, cache)) {
|
||||
RETURN_TRUE;
|
||||
}
|
||||
RETURN_NULL();
|
||||
@@ -363,7 +356,7 @@ PHP_FUNCTION(uwsgi_cache_update) {
|
||||
RETURN_NULL();
|
||||
}
|
||||
|
||||
if (uwsgi_cache_magic_set(key, keylen, value, vallen, expires, UWSGI_CACHE_FLAG_UPDATE, cache)) {
|
||||
if (!uwsgi_cache_magic_set(key, keylen, value, vallen, expires, UWSGI_CACHE_FLAG_UPDATE, cache)) {
|
||||
RETURN_TRUE;
|
||||
}
|
||||
RETURN_NULL();
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
#include "common.h"
|
||||
|
||||
PS_OPEN_FUNC(uwsgi) {
|
||||
PS_SET_MOD_DATA((char *)save_path);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
PS_CLOSE_FUNC(uwsgi) {
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
PS_READ_FUNC(uwsgi) {
|
||||
char *cache = PS_GET_MOD_DATA();
|
||||
uint64_t valsize = 0;
|
||||
char *value = uwsgi_cache_magic_get((char *)key, strlen(key), &valsize, NULL, cache);
|
||||
if (!value) return FAILURE;
|
||||
char *new_val = emalloc(valsize);
|
||||
memcpy(new_val, value, valsize);
|
||||
free(value);
|
||||
*val = new_val;
|
||||
*vallen = valsize;
|
||||
return SUCCESS;
|
||||
|
||||
}
|
||||
|
||||
PS_WRITE_FUNC(uwsgi) {
|
||||
char *cache = PS_GET_MOD_DATA();
|
||||
if (vallen == 0) return SUCCESS;
|
||||
if (!uwsgi_cache_magic_set((char *)key, strlen(key), (char *)val, vallen, 0, UWSGI_CACHE_FLAG_UPDATE, cache)) {
|
||||
return SUCCESS;
|
||||
}
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
PS_DESTROY_FUNC(uwsgi) {
|
||||
char *cache = PS_GET_MOD_DATA();
|
||||
if (!uwsgi_cache_magic_del((char *)key, strlen(key), cache)) {
|
||||
return SUCCESS;
|
||||
}
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
PS_GC_FUNC(uwsgi) {
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
ps_module ps_mod_uwsgi = {
|
||||
PS_MOD(uwsgi)
|
||||
};
|
||||
|
||||
@@ -25,4 +25,4 @@ phplibdir = os.environ.get('UWSGICONFIG_PHPLIBDIR')
|
||||
if phplibdir:
|
||||
LIBS.append('-Wl,-rpath=%s' % phplibdir)
|
||||
|
||||
GCC_LIST = ['php_plugin']
|
||||
GCC_LIST = ['php_plugin', 'session']
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -370,12 +370,16 @@ int init_psgi_app(struct wsgi_request *wsgi_req, char *app, uint16_t app_len, Pe
|
||||
// uperl.embedding as an argument so we won't execute
|
||||
// BEGIN blocks in app_name twice.
|
||||
{
|
||||
char *perl_init_arg[] = { "", "-e", "0" };
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -768,6 +768,9 @@ XS(XS_sharedarea_wait) {
|
||||
id = SvIV(ST(0));
|
||||
if (items > 1) {
|
||||
freq = SvIV(ST(1));
|
||||
if (items > 2) {
|
||||
timeout = SvIV(ST(2));
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi_sharedarea_wait(id, freq, timeout)) {
|
||||
@@ -955,6 +958,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 +1040,7 @@ void init_perl_embedded_module() {
|
||||
|
||||
psgi_xs(spooler);
|
||||
psgi_xs(spool);
|
||||
|
||||
psgi_xs(add_var);
|
||||
|
||||
}
|
||||
|
||||
@@ -168,6 +168,8 @@ struct uwsgi_option uwsgi_python_options[] = {
|
||||
{"py-sharedarea", required_argument, 0, "create a sharedarea from a python bytearray object of the specified size", uwsgi_opt_add_string_list, &up.sharedarea, 0},
|
||||
#endif
|
||||
|
||||
{"py-call-osafterfork", no_argument, 0, "enable child processes running cpython to trap OS signals", uwsgi_opt_true, &up.call_osafterfork, 0},
|
||||
|
||||
{0, 0, 0, 0, 0, 0, 0},
|
||||
};
|
||||
|
||||
@@ -197,6 +199,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 +259,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");
|
||||
}
|
||||
@@ -369,6 +379,11 @@ void uwsgi_python_post_fork() {
|
||||
UWSGI_GET_GIL
|
||||
}
|
||||
|
||||
// reset python signal flags so child processes can trap signals
|
||||
if (up.call_osafterfork) {
|
||||
PyOS_AfterFork();
|
||||
}
|
||||
|
||||
uwsgi_python_reset_random_seed();
|
||||
|
||||
// call the post_fork_hook
|
||||
|
||||
@@ -4,6 +4,29 @@ 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_micros(PyObject * self, PyObject * args) {
|
||||
return PyLong_FromUnsignedLongLong(uwsgi_micros());
|
||||
}
|
||||
|
||||
static PyObject *py_uwsgi_signal_wait(PyObject * self, PyObject * args) {
|
||||
|
||||
struct wsgi_request *wsgi_req = py_current_wsgi_req();
|
||||
@@ -1403,7 +1426,7 @@ PyObject *py_uwsgi_sharedarea_inc64(PyObject * self, PyObject * args) {
|
||||
uint64_t pos = 0;
|
||||
int64_t value = 1;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "il|l:sharedarea_inc64", &id, &pos, &value)) {
|
||||
if (!PyArg_ParseTuple(args, "iL|l:sharedarea_inc64", &id, &pos, &value)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1420,12 +1443,56 @@ PyObject *py_uwsgi_sharedarea_inc64(PyObject * self, PyObject * args) {
|
||||
|
||||
}
|
||||
|
||||
PyObject *py_uwsgi_sharedarea_write32(PyObject * self, PyObject * args) {
|
||||
int id;
|
||||
uint64_t pos = 0;
|
||||
int32_t value = 0;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "iLI:sharedarea_write32", &id, &pos, &value)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
UWSGI_RELEASE_GIL
|
||||
int ret = uwsgi_sharedarea_write32(id, pos, &value);
|
||||
UWSGI_GET_GIL
|
||||
|
||||
if (ret) {
|
||||
return PyErr_Format(PyExc_ValueError, "error calling uwsgi_sharedarea_write32()");
|
||||
}
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
PyObject *py_uwsgi_sharedarea_write16(PyObject * self, PyObject * args) {
|
||||
int id;
|
||||
uint64_t pos = 0;
|
||||
int16_t value = 0;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "iLI:sharedarea_write16", &id, &pos, &value)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
UWSGI_RELEASE_GIL
|
||||
int ret = uwsgi_sharedarea_write16(id, pos, &value);
|
||||
UWSGI_GET_GIL
|
||||
|
||||
if (ret) {
|
||||
return PyErr_Format(PyExc_ValueError, "error calling uwsgi_sharedarea_write16()");
|
||||
}
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
|
||||
|
||||
PyObject *py_uwsgi_sharedarea_write64(PyObject * self, PyObject * args) {
|
||||
int id;
|
||||
uint64_t pos = 0;
|
||||
int64_t value = 0;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "ill:sharedarea_write64", &id, &pos, &value)) {
|
||||
if (!PyArg_ParseTuple(args, "iLL:sharedarea_write64", &id, &pos, &value)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1447,7 +1514,7 @@ PyObject *py_uwsgi_sharedarea_write(PyObject * self, PyObject * args) {
|
||||
char *value;
|
||||
Py_ssize_t value_len = 0;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "ils#:sharedarea_write", &id, &pos, &value, &value_len)) {
|
||||
if (!PyArg_ParseTuple(args, "iLs#:sharedarea_write", &id, &pos, &value, &value_len)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1547,7 +1614,7 @@ PyObject *py_uwsgi_sharedarea_write8(PyObject * self, PyObject * args) {
|
||||
uint64_t pos = 0;
|
||||
int8_t value;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "ilb:sharedarea_write8", &id, &pos, &value)) {
|
||||
if (!PyArg_ParseTuple(args, "iLb:sharedarea_write8", &id, &pos, &value)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1569,7 +1636,7 @@ PyObject *py_uwsgi_sharedarea_read64(PyObject * self, PyObject * args) {
|
||||
uint64_t pos = 0;
|
||||
int64_t value;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "il:sharedarea_read64", &id, &pos)) {
|
||||
if (!PyArg_ParseTuple(args, "iL:sharedarea_read64", &id, &pos)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1581,16 +1648,59 @@ PyObject *py_uwsgi_sharedarea_read64(PyObject * self, PyObject * args) {
|
||||
return PyErr_Format(PyExc_ValueError, "error calling uwsgi_sharedarea_read64()");
|
||||
}
|
||||
|
||||
return PyLong_FromLong(value);
|
||||
return PyLong_FromLongLong(value);
|
||||
|
||||
}
|
||||
|
||||
PyObject *py_uwsgi_sharedarea_read32(PyObject * self, PyObject * args) {
|
||||
int id;
|
||||
uint64_t pos = 0;
|
||||
int32_t value;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "iL:sharedarea_read32", &id, &pos)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
UWSGI_RELEASE_GIL
|
||||
int ret = uwsgi_sharedarea_read32(id, pos, &value);
|
||||
UWSGI_GET_GIL
|
||||
|
||||
if (ret) {
|
||||
return PyErr_Format(PyExc_ValueError, "error calling uwsgi_sharedarea_read32()");
|
||||
}
|
||||
|
||||
return PyInt_FromLong(value);
|
||||
|
||||
}
|
||||
|
||||
PyObject *py_uwsgi_sharedarea_read16(PyObject * self, PyObject * args) {
|
||||
int id;
|
||||
uint64_t pos = 0;
|
||||
int16_t value;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "iL:sharedarea_read16", &id, &pos)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
UWSGI_RELEASE_GIL
|
||||
int ret = uwsgi_sharedarea_read16(id, pos, &value);
|
||||
UWSGI_GET_GIL
|
||||
|
||||
if (ret) {
|
||||
return PyErr_Format(PyExc_ValueError, "error calling uwsgi_sharedarea_read16()");
|
||||
}
|
||||
|
||||
return PyInt_FromLong(value);
|
||||
|
||||
}
|
||||
|
||||
|
||||
PyObject *py_uwsgi_sharedarea_read8(PyObject * self, PyObject * args) {
|
||||
int id;
|
||||
uint64_t pos = 0;
|
||||
int8_t byte;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "il:sharedarea_read8", &id, &pos)) {
|
||||
if (!PyArg_ParseTuple(args, "iL:sharedarea_read8", &id, &pos)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1610,7 +1720,7 @@ PyObject *py_uwsgi_sharedarea_read(PyObject * self, PyObject * args) {
|
||||
uint64_t pos = 0;
|
||||
uint64_t len = 0;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "il|l:sharedarea_read", &id, &pos, &len)) {
|
||||
if (!PyArg_ParseTuple(args, "iL|L:sharedarea_read", &id, &pos, &len)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -2417,6 +2527,10 @@ static PyMethodDef uwsgi_advanced_methods[] = {
|
||||
|
||||
{"ready_fd", py_uwsgi_ready_fd, METH_VARARGS, ""},
|
||||
|
||||
{"add_var", py_uwsgi_add_var, METH_VARARGS, ""},
|
||||
|
||||
{"micros", py_uwsgi_micros, METH_VARARGS, ""},
|
||||
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
@@ -2432,6 +2546,10 @@ static PyMethodDef uwsgi_sa_methods[] = {
|
||||
{"sharedarea_writelong", py_uwsgi_sharedarea_write64, METH_VARARGS, ""},
|
||||
{"sharedarea_read64", py_uwsgi_sharedarea_read64, METH_VARARGS, ""},
|
||||
{"sharedarea_write64", py_uwsgi_sharedarea_write64, METH_VARARGS, ""},
|
||||
{"sharedarea_read32", py_uwsgi_sharedarea_read32, METH_VARARGS, ""},
|
||||
{"sharedarea_write32", py_uwsgi_sharedarea_write32, METH_VARARGS, ""},
|
||||
{"sharedarea_read16", py_uwsgi_sharedarea_read16, METH_VARARGS, ""},
|
||||
{"sharedarea_write16", py_uwsgi_sharedarea_write16, METH_VARARGS, ""},
|
||||
{"sharedarea_inclong", py_uwsgi_sharedarea_inc64, METH_VARARGS, ""},
|
||||
{"sharedarea_inc64", py_uwsgi_sharedarea_inc64, METH_VARARGS, ""},
|
||||
{"sharedarea_rlock", py_uwsgi_sharedarea_rlock, METH_VARARGS, ""},
|
||||
@@ -3164,6 +3282,40 @@ PyObject *py_uwsgi_metric_get(PyObject * self, PyObject * args) {
|
||||
return PyLong_FromLongLong(value);
|
||||
}
|
||||
|
||||
PyObject *py_uwsgi_metric_set_max(PyObject * self, PyObject * args) {
|
||||
char *key;
|
||||
int64_t value = 1;
|
||||
if (!PyArg_ParseTuple(args, "s|l:metric_set_max", &key, &value)) return NULL;
|
||||
|
||||
UWSGI_RELEASE_GIL
|
||||
if (uwsgi_metric_set_max(key, NULL, value)) {
|
||||
UWSGI_GET_GIL
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
UWSGI_GET_GIL
|
||||
Py_INCREF(Py_True);
|
||||
return Py_True;
|
||||
|
||||
}
|
||||
|
||||
PyObject *py_uwsgi_metric_set_min(PyObject * self, PyObject * args) {
|
||||
char *key;
|
||||
int64_t value = 1;
|
||||
if (!PyArg_ParseTuple(args, "s|l:metric_set_min", &key, &value)) return NULL;
|
||||
|
||||
UWSGI_RELEASE_GIL
|
||||
if (uwsgi_metric_set_min(key, NULL, value)) {
|
||||
UWSGI_GET_GIL
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
UWSGI_GET_GIL
|
||||
Py_INCREF(Py_True);
|
||||
return Py_True;
|
||||
|
||||
}
|
||||
|
||||
|
||||
static PyMethodDef uwsgi_metrics_methods[] = {
|
||||
{"metric_inc", py_uwsgi_metric_inc, METH_VARARGS, ""},
|
||||
@@ -3172,6 +3324,8 @@ static PyMethodDef uwsgi_metrics_methods[] = {
|
||||
{"metric_div", py_uwsgi_metric_div, METH_VARARGS, ""},
|
||||
{"metric_get", py_uwsgi_metric_get, METH_VARARGS, ""},
|
||||
{"metric_set", py_uwsgi_metric_set, METH_VARARGS, ""},
|
||||
{"metric_set_max", py_uwsgi_metric_set_max, METH_VARARGS, ""},
|
||||
{"metric_set_min", py_uwsgi_metric_set_min, METH_VARARGS, ""},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
|
||||
@@ -197,6 +197,8 @@ struct uwsgi_python {
|
||||
PyObject *raw_callable;
|
||||
|
||||
struct uwsgi_string_list *sharedarea;
|
||||
|
||||
int call_osafterfork;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
static int uwsgi_routing_func_http(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
|
||||
struct uwsgi_buffer *ub = NULL;
|
||||
|
||||
// mark a route request
|
||||
wsgi_req->via = UWSGI_VIA_ROUTE;
|
||||
@@ -24,9 +26,14 @@ static int uwsgi_routing_func_http(struct wsgi_request *wsgi_req, struct uwsgi_r
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// convert the wsgi_request to an http proxy request
|
||||
struct uwsgi_buffer *ub = uwsgi_to_http(wsgi_req, ur->data2, ur->data2_len, ub_url ? ub_url->buf : NULL, ub_url ? ub_url->pos : 0);
|
||||
if (ur->custom & 0x02) {
|
||||
ub = uwsgi_buffer_new(uwsgi.page_size);
|
||||
}
|
||||
else {
|
||||
ub = uwsgi_to_http(wsgi_req, ur->data2, ur->data2_len, ub_url ? ub_url->buf : NULL, ub_url ? ub_url->pos : 0);
|
||||
}
|
||||
|
||||
if (!ub) {
|
||||
if (ub_url) uwsgi_buffer_destroy(ub_url);
|
||||
uwsgi_log("unable to generate http request for %s\n", ub_addr->buf);
|
||||
@@ -46,11 +53,12 @@ static int uwsgi_routing_func_http(struct wsgi_request *wsgi_req, struct uwsgi_r
|
||||
uwsgi_buffer_destroy(ub_addr);
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
wsgi_req->post_pos += wsgi_req->proto_parser_remains;
|
||||
wsgi_req->proto_parser_remains = 0;
|
||||
}
|
||||
|
||||
// ok now if have offload threads, directly use them
|
||||
if (!wsgi_req->post_file && !ur->custom && wsgi_req->socket->can_offload) {
|
||||
if (!wsgi_req->post_file && !(ur->custom & 0x01) && wsgi_req->socket->can_offload) {
|
||||
// append buffered body
|
||||
if (uwsgi.post_buffering > 0 && wsgi_req->post_cl > 0) {
|
||||
if (uwsgi_buffer_append(ub, wsgi_req->post_buffering_buf, wsgi_req->post_cl)) {
|
||||
@@ -60,6 +68,14 @@ static int uwsgi_routing_func_http(struct wsgi_request *wsgi_req, struct uwsgi_r
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
}
|
||||
|
||||
// if we have a CONNECT request, let's confirm it to the client
|
||||
if (ur->custom & 0x02) {
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, "200 Connection established", 26)) goto end;
|
||||
// no need to check for return value
|
||||
uwsgi_response_write_headers_do(wsgi_req);
|
||||
}
|
||||
|
||||
if (!uwsgi_offload_request_net_do(wsgi_req, ub_addr->buf, ub)) {
|
||||
wsgi_req->via = UWSGI_VIA_OFFLOAD;
|
||||
wsgi_req->status = 202;
|
||||
@@ -72,6 +88,7 @@ static int uwsgi_routing_func_http(struct wsgi_request *wsgi_req, struct uwsgi_r
|
||||
uwsgi_log("error routing request to http server %s\n", ub_addr->buf);
|
||||
}
|
||||
|
||||
end:
|
||||
uwsgi_buffer_destroy(ub);
|
||||
uwsgi_buffer_destroy(ub_addr);
|
||||
|
||||
@@ -102,15 +119,27 @@ static int uwsgi_router_http(struct uwsgi_route *ur, char *args) {
|
||||
}
|
||||
|
||||
static int uwsgi_router_proxyhttp(struct uwsgi_route *ur, char *args) {
|
||||
ur->custom = 1;
|
||||
ur->custom = 0x1;
|
||||
return uwsgi_router_http(ur, args);
|
||||
}
|
||||
|
||||
static int uwsgi_router_proxyhttp_connect(struct uwsgi_route *ur, char *args) {
|
||||
ur->custom = 0x1|0x02;
|
||||
return uwsgi_router_http(ur, args);
|
||||
}
|
||||
|
||||
static int uwsgi_router_http_connect(struct uwsgi_route *ur, char *args) {
|
||||
ur->custom = 0x02;
|
||||
return uwsgi_router_http(ur, args);
|
||||
}
|
||||
|
||||
|
||||
static void router_http_register(void) {
|
||||
|
||||
uwsgi_register_router("http", uwsgi_router_http);
|
||||
uwsgi_register_router("proxyhttp", uwsgi_router_proxyhttp);
|
||||
uwsgi_register_router("httpconnect", uwsgi_router_http_connect);
|
||||
uwsgi_register_router("proxyhttpconnect", uwsgi_router_proxyhttp_connect);
|
||||
}
|
||||
|
||||
struct uwsgi_plugin router_http_plugin = {
|
||||
|
||||
@@ -18,6 +18,8 @@ struct uwsgi_router_file_conf {
|
||||
char *mime;
|
||||
|
||||
char *no_cl;
|
||||
|
||||
char *no_headers;
|
||||
};
|
||||
|
||||
int uwsgi_routing_func_static(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
@@ -38,6 +40,7 @@ int uwsgi_routing_func_file(struct wsgi_request *wsgi_req, struct uwsgi_route *u
|
||||
char buf[32768];
|
||||
struct stat st;
|
||||
int ret = UWSGI_ROUTE_BREAK;
|
||||
size_t remains = 0;
|
||||
|
||||
struct uwsgi_router_file_conf *urfc = (struct uwsgi_router_file_conf *) ur->data2;
|
||||
|
||||
@@ -61,6 +64,11 @@ int uwsgi_routing_func_file(struct wsgi_request *wsgi_req, struct uwsgi_route *u
|
||||
struct uwsgi_buffer *ub_s = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urfc->status, urfc->status_len);
|
||||
if (!ub_s) goto end2;
|
||||
|
||||
// static file - don't update avg_rt after request
|
||||
wsgi_req->do_not_account_avg_rt = 1;
|
||||
|
||||
if (urfc->no_headers) goto send;
|
||||
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, ub_s->buf, ub_s->pos)) {
|
||||
uwsgi_buffer_destroy(ub_s);
|
||||
goto end2;
|
||||
@@ -82,8 +90,10 @@ int uwsgi_routing_func_file(struct wsgi_request *wsgi_req, struct uwsgi_route *u
|
||||
else {
|
||||
if (uwsgi_response_add_content_type(wsgi_req, urfc->content_type, urfc->content_type_len)) goto end2;
|
||||
}
|
||||
|
||||
send:
|
||||
|
||||
size_t remains = st.st_size;
|
||||
remains = st.st_size;
|
||||
while(remains) {
|
||||
ssize_t rlen = read(fd, buf, UMIN(32768, remains));
|
||||
if (rlen <= 0) goto end2;
|
||||
@@ -125,6 +135,11 @@ int uwsgi_routing_func_sendfile(struct wsgi_request *wsgi_req, struct uwsgi_rout
|
||||
struct uwsgi_buffer *ub_s = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urfc->status, urfc->status_len);
|
||||
if (!ub_s) goto end2;
|
||||
|
||||
// static file - don't update avg_rt after request
|
||||
wsgi_req->do_not_account_avg_rt = 1;
|
||||
|
||||
if (urfc->no_headers) goto send;
|
||||
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, ub_s->buf, ub_s->pos)) {
|
||||
uwsgi_buffer_destroy(ub_s);
|
||||
goto end2;
|
||||
@@ -145,6 +160,8 @@ int uwsgi_routing_func_sendfile(struct wsgi_request *wsgi_req, struct uwsgi_rout
|
||||
if (uwsgi_response_add_content_type(wsgi_req, urfc->content_type, urfc->content_type_len)) goto end2;
|
||||
}
|
||||
|
||||
send:
|
||||
|
||||
if (!wsgi_req->headers_sent) {
|
||||
if (uwsgi_response_write_headers_do(wsgi_req)) goto end2;
|
||||
}
|
||||
@@ -188,6 +205,11 @@ int uwsgi_routing_func_fastfile(struct wsgi_request *wsgi_req, struct uwsgi_rout
|
||||
struct uwsgi_buffer *ub_s = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urfc->status, urfc->status_len);
|
||||
if (!ub_s) goto end2;
|
||||
|
||||
// static file - don't update avg_rt after request
|
||||
wsgi_req->do_not_account_avg_rt = 1;
|
||||
|
||||
if (urfc->no_headers) goto send;
|
||||
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, ub_s->buf, ub_s->pos)) {
|
||||
uwsgi_buffer_destroy(ub_s);
|
||||
goto end2;
|
||||
@@ -208,6 +230,8 @@ int uwsgi_routing_func_fastfile(struct wsgi_request *wsgi_req, struct uwsgi_rout
|
||||
if (uwsgi_response_add_content_type(wsgi_req, urfc->content_type, urfc->content_type_len)) goto end2;
|
||||
}
|
||||
|
||||
send:
|
||||
|
||||
if (!wsgi_req->headers_sent) {
|
||||
if (uwsgi_response_write_headers_do(wsgi_req)) goto end2;
|
||||
}
|
||||
@@ -256,6 +280,7 @@ static int uwsgi_router_file(struct uwsgi_route *ur, char *args) {
|
||||
"no_cl", &urfc->no_cl,
|
||||
"no_content_length", &urfc->no_cl,
|
||||
"mime", &urfc->mime,
|
||||
"no_headers", &urfc->no_headers,
|
||||
NULL)) {
|
||||
uwsgi_log("invalid file route syntax: %s\n", args);
|
||||
return -1;
|
||||
|
||||
@@ -35,7 +35,13 @@ static int uwsgi_routing_func_uwsgi_remote(struct wsgi_request *wsgi_req, struct
|
||||
|
||||
struct uwsgi_header *uh = (struct uwsgi_header *) ur->data;
|
||||
char *addr = ur->data + sizeof(struct uwsgi_header);
|
||||
|
||||
|
||||
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
|
||||
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
|
||||
|
||||
struct uwsgi_buffer *ub_addr = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, addr, strlen(addr));
|
||||
if (!ub_addr) return UWSGI_ROUTE_BREAK;
|
||||
|
||||
// mark a route request
|
||||
wsgi_req->via = UWSGI_VIA_ROUTE;
|
||||
|
||||
@@ -54,6 +60,7 @@ static int uwsgi_routing_func_uwsgi_remote(struct wsgi_request *wsgi_req, struct
|
||||
if (uwsgi_buffer_append(ub, wsgi_req->proto_parser_remains_buf, wsgi_req->proto_parser_remains)) {
|
||||
goto end;
|
||||
}
|
||||
wsgi_req->post_pos += wsgi_req->proto_parser_remains;
|
||||
wsgi_req->proto_parser_remains = 0;
|
||||
}
|
||||
|
||||
@@ -65,18 +72,20 @@ static int uwsgi_routing_func_uwsgi_remote(struct wsgi_request *wsgi_req, struct
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
if (!uwsgi_offload_request_net_do(wsgi_req, addr, ub)) {
|
||||
if (!uwsgi_offload_request_net_do(wsgi_req, ub_addr->buf, ub)) {
|
||||
wsgi_req->via = UWSGI_VIA_OFFLOAD;
|
||||
wsgi_req->status = 202;
|
||||
uwsgi_buffer_destroy(ub_addr);
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi_proxy_nb(wsgi_req, addr, ub, remains, uwsgi.socket_timeout)) {
|
||||
uwsgi_log("error routing request to uwsgi server %s\n", addr);
|
||||
if (uwsgi_proxy_nb(wsgi_req, ub_addr->buf, ub, remains, uwsgi.socket_timeout)) {
|
||||
uwsgi_log("error routing request to uwsgi server %s\n", ub_addr->buf);
|
||||
}
|
||||
end:
|
||||
uwsgi_buffer_destroy(ub);
|
||||
uwsgi_buffer_destroy(ub_addr);
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
|
||||
}
|
||||
|
||||
@@ -150,6 +150,11 @@ static void rrdtool_push(struct uwsgi_stats_pusher_instance *uspi, time_t now, c
|
||||
uwsgi_rlock(uwsgi.metrics_lock);
|
||||
int ret = snprintf(buf, 1024, "N:%lld", (long long) (*um->value));
|
||||
uwsgi_rwunlock(uwsgi.metrics_lock);
|
||||
if (um->reset_after_push){
|
||||
uwsgi_wlock(uwsgi.metrics_lock);
|
||||
*um->value = um->initial_value;
|
||||
uwsgi_rwunlock(uwsgi.metrics_lock);
|
||||
}
|
||||
if (ret < 3 || ret >= 1024) {
|
||||
uwsgi_log("unable to update rrdtool metric for %s\n", um->name);
|
||||
goto next;
|
||||
|
||||
@@ -92,6 +92,11 @@ static void stats_pusher_socket(struct uwsgi_stats_pusher_instance *uspi, time_t
|
||||
uwsgi_rlock(uwsgi.metrics_lock);
|
||||
socket_send_metric(ub, uspi, um);
|
||||
uwsgi_rwunlock(uwsgi.metrics_lock);
|
||||
if (um->reset_after_push){
|
||||
uwsgi_wlock(uwsgi.metrics_lock);
|
||||
*um->value = um->initial_value;
|
||||
uwsgi_rwunlock(uwsgi.metrics_lock);
|
||||
}
|
||||
um = um->next;
|
||||
}
|
||||
uwsgi_buffer_destroy(ub);
|
||||
|
||||
@@ -95,6 +95,11 @@ static void stats_pusher_statsd(struct uwsgi_stats_pusher_instance *uspi, time_t
|
||||
statsd_send_metric(ub, uspi, um->name, um->name_len, *um->value, "|m");
|
||||
}
|
||||
uwsgi_rwunlock(uwsgi.metrics_lock);
|
||||
if (um->reset_after_push){
|
||||
uwsgi_wlock(uwsgi.metrics_lock);
|
||||
*um->value = um->initial_value;
|
||||
uwsgi_rwunlock(uwsgi.metrics_lock);
|
||||
}
|
||||
um = um->next;
|
||||
}
|
||||
uwsgi_buffer_destroy(ub);
|
||||
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
|
||||
@@ -326,6 +326,11 @@ static void tornado_loop() {
|
||||
uwsgi_log("!!! Running tornado with a socket-timeout lower than 30 seconds is not recommended, tune it with --socket-timeout !!!\n");
|
||||
}
|
||||
|
||||
if (!uwsgi.async_waiting_fd_table)
|
||||
uwsgi.async_waiting_fd_table = uwsgi_calloc(sizeof(struct wsgi_request *) * uwsgi.max_fd);
|
||||
if (!uwsgi.async_proto_fd_table)
|
||||
uwsgi.async_proto_fd_table = uwsgi_calloc(sizeof(struct wsgi_request *) * uwsgi.max_fd);
|
||||
|
||||
// get the GIL
|
||||
UWSGI_GET_GIL
|
||||
|
||||
|
||||
+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;
|
||||
}
|
||||
|
||||
@@ -94,6 +94,13 @@ static void stats_pusher_zabbix(struct uwsgi_stats_pusher_instance *uspi, time_t
|
||||
if (uwsgi_buffer_append(zn->ub, "\",\"value\":\"", 11)) { error = 1; goto end;}
|
||||
if (uwsgi_buffer_num64(zn->ub, *um->value)) { error = 1; goto end;}
|
||||
if (uwsgi_buffer_append(zn->ub, "\"}", 2)) { error = 1; goto end;}
|
||||
if (um->reset_after_push){
|
||||
uwsgi_rwunlock(uwsgi.metrics_lock);
|
||||
uwsgi_wlock(uwsgi.metrics_lock);
|
||||
*um->value = um->initial_value;
|
||||
uwsgi_rwunlock(uwsgi.metrics_lock);
|
||||
uwsgi_rlock(uwsgi.metrics_lock);
|
||||
}
|
||||
um = um->next;
|
||||
if (um) {
|
||||
if (uwsgi_buffer_append(zn->ub, ",", 1)) { error = 1; goto end;}
|
||||
|
||||
+178
-149
@@ -8,12 +8,12 @@ extern struct uwsgi_server uwsgi;
|
||||
|
||||
struct fcgi_record {
|
||||
uint8_t version;
|
||||
uint8_t type;
|
||||
uint8_t req1;
|
||||
uint8_t req0;
|
||||
uint8_t type;
|
||||
uint8_t req1;
|
||||
uint8_t req0;
|
||||
uint8_t cl1;
|
||||
uint8_t cl0;
|
||||
uint8_t pad;
|
||||
uint8_t pad;
|
||||
uint8_t reserved;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
@@ -24,39 +24,45 @@ int fastcgi_to_uwsgi(struct wsgi_request *wsgi_req, char *buf, size_t len) {
|
||||
uint8_t octet;
|
||||
uint32_t keylen, vallen;
|
||||
for (j = 0; j < len; j++) {
|
||||
octet = (uint8_t) buf[j];
|
||||
if (octet > 127) {
|
||||
if (j + 4 >= len) return -1;
|
||||
octet = (uint8_t) buf[j];
|
||||
if (octet > 127) {
|
||||
if (j + 4 >= len)
|
||||
return -1;
|
||||
keylen = uwsgi_be32(&buf[j]) ^ 0x80000000;
|
||||
j += 4;
|
||||
j += 4;
|
||||
}
|
||||
else {
|
||||
if (j+1 >= len) return -1;
|
||||
if (j + 1 >= len)
|
||||
return -1;
|
||||
keylen = octet;
|
||||
j++;
|
||||
}
|
||||
octet = (uint8_t) buf[j];
|
||||
if (octet > 127) {
|
||||
if (j + 4 >= len) return -1;
|
||||
octet = (uint8_t) buf[j];
|
||||
if (octet > 127) {
|
||||
if (j + 4 >= len)
|
||||
return -1;
|
||||
vallen = uwsgi_be32(&buf[j]) ^ 0x80000000;
|
||||
j += 4;
|
||||
j += 4;
|
||||
}
|
||||
else {
|
||||
if (j+1 >= len) return -1;
|
||||
if (j + 1 >= len)
|
||||
return -1;
|
||||
vallen = octet;
|
||||
j++;
|
||||
}
|
||||
|
||||
if (j + (keylen + vallen) > len) {
|
||||
if (j + (keylen + vallen) > len) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (keylen > 0xffff || vallen > 0xffff) return -1;
|
||||
if (keylen > 0xffff || vallen > 0xffff)
|
||||
return -1;
|
||||
uint16_t pktsize = proto_base_add_uwsgi_var(wsgi_req, buf + j, keylen, buf + j + keylen, vallen);
|
||||
if (pktsize == 0) return -1;
|
||||
wsgi_req->uh->pktsize += pktsize;
|
||||
if (pktsize == 0)
|
||||
return -1;
|
||||
wsgi_req->uh->pktsize += pktsize;
|
||||
// -1 here as the for() will increment j again
|
||||
j += (keylen + vallen) - 1;
|
||||
j += (keylen + vallen) - 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -66,7 +72,7 @@ int fastcgi_to_uwsgi(struct wsgi_request *wsgi_req, char *buf, size_t len) {
|
||||
/*
|
||||
|
||||
each fastcgi packet is composed by a header and a body
|
||||
the parser rebuild a whole packet until it find a 0 PARAMS or a STDIN one
|
||||
the parser rebuild a whole packet until it finds a 0 STDIN
|
||||
|
||||
*/
|
||||
|
||||
@@ -78,38 +84,40 @@ int uwsgi_proto_fastcgi_parser(struct wsgi_request *wsgi_req) {
|
||||
wsgi_req->proto_parser_buf_size = uwsgi.buffer_size;
|
||||
}
|
||||
|
||||
ssize_t len = read(wsgi_req->fd, wsgi_req->proto_parser_buf + wsgi_req->proto_parser_pos, wsgi_req->proto_parser_buf_size - wsgi_req->proto_parser_pos);
|
||||
ssize_t len = read(wsgi_req->fd, wsgi_req->proto_parser_buf + wsgi_req->proto_parser_pos, wsgi_req->proto_parser_buf_size - wsgi_req->proto_parser_pos);
|
||||
if (len > 0) {
|
||||
goto parse;
|
||||
}
|
||||
}
|
||||
if (len < 0) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
|
||||
return UWSGI_AGAIN;
|
||||
}
|
||||
uwsgi_error("uwsgi_proto_fastcgi_parser()");
|
||||
return -1;
|
||||
}
|
||||
// mute on 0 len...
|
||||
if (wsgi_req->proto_parser_pos > 0) {
|
||||
uwsgi_error("uwsgi_proto_fastcgi_parser()");
|
||||
}
|
||||
return -1;
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
|
||||
return UWSGI_AGAIN;
|
||||
}
|
||||
uwsgi_error("uwsgi_proto_fastcgi_parser()");
|
||||
return -1;
|
||||
}
|
||||
// mute on 0 len...
|
||||
if (wsgi_req->proto_parser_pos > 0) {
|
||||
uwsgi_error("uwsgi_proto_fastcgi_parser()");
|
||||
}
|
||||
return -1;
|
||||
parse:
|
||||
wsgi_req->proto_parser_pos += len;
|
||||
// ok let's see what we need to do
|
||||
for(;;) {
|
||||
for (;;) {
|
||||
if (wsgi_req->proto_parser_pos >= sizeof(struct fcgi_record)) {
|
||||
struct fcgi_record *fr = (struct fcgi_record *) wsgi_req->proto_parser_buf;
|
||||
uint16_t fcgi_len = uwsgi_be16((char *)&fr->cl1);
|
||||
uint16_t fcgi_len = uwsgi_be16((char *) &fr->cl1);
|
||||
uint32_t fcgi_all_len = sizeof(struct fcgi_record) + fcgi_len + fr->pad;
|
||||
uint8_t fcgi_type = fr->type;
|
||||
uint8_t *sid = (uint8_t *) &wsgi_req->stream_id;
|
||||
uint8_t *sid = (uint8_t *) & wsgi_req->stream_id;
|
||||
sid[0] = fr->req0;
|
||||
sid[1] = fr->req1;
|
||||
// if STDIN, end of the loop
|
||||
if (fcgi_type == 5) {
|
||||
wsgi_req->uh->modifier1 = uwsgi.fastcgi_modifier1;
|
||||
wsgi_req->uh->modifier2 = uwsgi.fastcgi_modifier2;
|
||||
// does the request stream ended ?
|
||||
if (fcgi_len == 0) wsgi_req->proto_parser_eof = 1;
|
||||
return UWSGI_OK;
|
||||
}
|
||||
// if we have a full packet, parse it and reset the memory
|
||||
@@ -122,12 +130,6 @@ parse:
|
||||
}
|
||||
memmove(wsgi_req->proto_parser_buf, wsgi_req->proto_parser_buf + fcgi_all_len, wsgi_req->proto_parser_pos - fcgi_all_len);
|
||||
wsgi_req->proto_parser_pos -= fcgi_all_len;
|
||||
// end of PARAMS
|
||||
if (fcgi_type == 4 && fcgi_len == 0) {
|
||||
wsgi_req->uh->modifier1 = uwsgi.fastcgi_modifier1;
|
||||
wsgi_req->uh->modifier2 = uwsgi.fastcgi_modifier2;
|
||||
return UWSGI_OK;
|
||||
}
|
||||
}
|
||||
else if (fcgi_all_len > wsgi_req->proto_parser_buf_size - wsgi_req->proto_parser_pos) {
|
||||
char *tmp_buf = realloc(wsgi_req->proto_parser_buf, wsgi_req->proto_parser_buf_size + fcgi_all_len - (wsgi_req->proto_parser_buf_size - wsgi_req->proto_parser_pos));
|
||||
@@ -152,33 +154,41 @@ parse:
|
||||
}
|
||||
|
||||
|
||||
ssize_t uwsgi_proto_fastcgi_read_body(struct wsgi_request *wsgi_req, char *buf, size_t len) {
|
||||
ssize_t uwsgi_proto_fastcgi_read_body(struct wsgi_request * wsgi_req, char *buf, size_t len) {
|
||||
int has_read = 0;
|
||||
if (wsgi_req->proto_parser_remains > 0) {
|
||||
size_t remains = UMIN(wsgi_req->proto_parser_remains, len);
|
||||
memcpy(buf, wsgi_req->proto_parser_remains_buf, remains);
|
||||
wsgi_req->proto_parser_remains -= remains;
|
||||
wsgi_req->proto_parser_remains_buf += remains;
|
||||
size_t remains = UMIN(wsgi_req->proto_parser_remains, len);
|
||||
memcpy(buf, wsgi_req->proto_parser_remains_buf, remains);
|
||||
wsgi_req->proto_parser_remains -= remains;
|
||||
wsgi_req->proto_parser_remains_buf += remains;
|
||||
// we consumed all of the body, we can safely move the memory
|
||||
if (wsgi_req->proto_parser_remains == 0 && wsgi_req->proto_parser_move) {
|
||||
memmove(wsgi_req->proto_parser_buf, wsgi_req->proto_parser_buf + wsgi_req->proto_parser_move, wsgi_req->proto_parser_pos);
|
||||
if (wsgi_req->proto_parser_remains == 0 && wsgi_req->proto_parser_move) {
|
||||
memmove(wsgi_req->proto_parser_buf, wsgi_req->proto_parser_buf + wsgi_req->proto_parser_move, wsgi_req->proto_parser_pos);
|
||||
wsgi_req->proto_parser_move = 0;
|
||||
}
|
||||
return remains;
|
||||
}
|
||||
}
|
||||
return remains;
|
||||
}
|
||||
|
||||
// if we already have seen eof, return 0
|
||||
if (wsgi_req->proto_parser_eof) return 0;
|
||||
|
||||
ssize_t rlen;
|
||||
|
||||
for(;;) {
|
||||
if (wsgi_req->proto_parser_pos >= sizeof(struct fcgi_record)) {
|
||||
struct fcgi_record *fr = (struct fcgi_record *) wsgi_req->proto_parser_buf;
|
||||
uint16_t fcgi_len = uwsgi_be16((char *)&fr->cl1);
|
||||
for (;;) {
|
||||
if (wsgi_req->proto_parser_pos >= sizeof(struct fcgi_record)) {
|
||||
struct fcgi_record *fr = (struct fcgi_record *) wsgi_req->proto_parser_buf;
|
||||
uint16_t fcgi_len = uwsgi_be16((char *) &fr->cl1);
|
||||
uint32_t fcgi_all_len = sizeof(struct fcgi_record) + fcgi_len + fr->pad;
|
||||
uint8_t fcgi_type = fr->type;
|
||||
// if we have a full packet, parse it and reset the memory
|
||||
if (wsgi_req->proto_parser_pos >= fcgi_all_len) {
|
||||
// STDIN ? (ignore other types)
|
||||
if (fcgi_type == 5) {
|
||||
uint8_t fcgi_type = fr->type;
|
||||
// if we have a full packet, parse it and reset the memory
|
||||
if (wsgi_req->proto_parser_pos >= fcgi_all_len) {
|
||||
// STDIN ? (ignore other types)
|
||||
if (fcgi_type == 5) {
|
||||
// EOF ?
|
||||
if (fcgi_len == 0) {
|
||||
wsgi_req->proto_parser_eof = 1;
|
||||
return 0;
|
||||
}
|
||||
// copy data to the buf
|
||||
size_t remains = UMIN(fcgi_len, len);
|
||||
memcpy(buf, wsgi_req->proto_parser_buf + sizeof(struct fcgi_record), remains);
|
||||
@@ -187,45 +197,46 @@ ssize_t uwsgi_proto_fastcgi_read_body(struct wsgi_request *wsgi_req, char *buf,
|
||||
wsgi_req->proto_parser_remains_buf = wsgi_req->proto_parser_buf + sizeof(struct fcgi_record) + remains;
|
||||
// we consumed all of the body, we can safely move the memory
|
||||
if (wsgi_req->proto_parser_remains == 0) {
|
||||
memmove(wsgi_req->proto_parser_buf, wsgi_req->proto_parser_buf + fcgi_all_len, wsgi_req->proto_parser_pos - fcgi_all_len);
|
||||
memmove(wsgi_req->proto_parser_buf, wsgi_req->proto_parser_buf + fcgi_all_len, wsgi_req->proto_parser_pos - fcgi_all_len);
|
||||
}
|
||||
else {
|
||||
// postpone memory move
|
||||
wsgi_req->proto_parser_move = fcgi_all_len;
|
||||
}
|
||||
wsgi_req->proto_parser_pos -= fcgi_all_len;
|
||||
wsgi_req->proto_parser_pos -= fcgi_all_len;
|
||||
return remains;
|
||||
}
|
||||
memmove(wsgi_req->proto_parser_buf, wsgi_req->proto_parser_buf + fcgi_all_len, wsgi_req->proto_parser_pos - fcgi_all_len);
|
||||
wsgi_req->proto_parser_pos -= fcgi_all_len;
|
||||
}
|
||||
else if (fcgi_all_len > wsgi_req->proto_parser_buf_size - wsgi_req->proto_parser_pos) {
|
||||
char *tmp_buf = realloc(wsgi_req->proto_parser_buf, wsgi_req->proto_parser_buf_size + fcgi_all_len - (wsgi_req->proto_parser_buf_size - wsgi_req->proto_parser_pos));
|
||||
if (!tmp_buf) {
|
||||
uwsgi_error("uwsgi_proto_fastcgi_read_body()/realloc()");
|
||||
return -1;
|
||||
}
|
||||
wsgi_req->proto_parser_buf = tmp_buf;
|
||||
wsgi_req->proto_parser_buf_size += fcgi_all_len - (wsgi_req->proto_parser_buf_size - wsgi_req->proto_parser_pos);
|
||||
}
|
||||
if (!has_read) goto gather;
|
||||
memmove(wsgi_req->proto_parser_buf, wsgi_req->proto_parser_buf + fcgi_all_len, wsgi_req->proto_parser_pos - fcgi_all_len);
|
||||
wsgi_req->proto_parser_pos -= fcgi_all_len;
|
||||
}
|
||||
else if (fcgi_all_len > wsgi_req->proto_parser_buf_size - wsgi_req->proto_parser_pos) {
|
||||
char *tmp_buf = realloc(wsgi_req->proto_parser_buf, wsgi_req->proto_parser_buf_size + fcgi_all_len - (wsgi_req->proto_parser_buf_size - wsgi_req->proto_parser_pos));
|
||||
if (!tmp_buf) {
|
||||
uwsgi_error("uwsgi_proto_fastcgi_read_body()/realloc()");
|
||||
return -1;
|
||||
}
|
||||
wsgi_req->proto_parser_buf = tmp_buf;
|
||||
wsgi_req->proto_parser_buf_size += fcgi_all_len - (wsgi_req->proto_parser_buf_size - wsgi_req->proto_parser_pos);
|
||||
}
|
||||
if (!has_read)
|
||||
goto gather;
|
||||
errno = EAGAIN;
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
}
|
||||
else {
|
||||
gather:
|
||||
rlen = read(wsgi_req->fd, wsgi_req->proto_parser_buf + wsgi_req->proto_parser_pos, wsgi_req->proto_parser_buf_size - wsgi_req->proto_parser_pos);
|
||||
rlen = read(wsgi_req->fd, wsgi_req->proto_parser_buf + wsgi_req->proto_parser_pos, wsgi_req->proto_parser_buf_size - wsgi_req->proto_parser_pos);
|
||||
if (rlen > 0) {
|
||||
has_read = 1;
|
||||
wsgi_req->proto_parser_pos += rlen;
|
||||
continue;
|
||||
}
|
||||
return rlen;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
|
||||
}
|
||||
|
||||
// write a STDOUT packet
|
||||
@@ -233,12 +244,12 @@ int uwsgi_proto_fastcgi_write(struct wsgi_request *wsgi_req, char *buf, size_t l
|
||||
|
||||
// fastcgi packets are limited to 64k
|
||||
if (wsgi_req->proto_parser_status == 0) {
|
||||
uint16_t fcgi_len = UMIN(len-wsgi_req->write_pos, 0xffff);
|
||||
uint16_t fcgi_len = UMIN(len - wsgi_req->write_pos, 0xffff);
|
||||
wsgi_req->proto_parser_status = fcgi_len;
|
||||
struct fcgi_record fr;
|
||||
fr.version = 1;
|
||||
fr.type = 6;
|
||||
uint8_t *sid = (uint8_t *) &wsgi_req->stream_id;
|
||||
uint8_t *sid = (uint8_t *) & wsgi_req->stream_id;
|
||||
fr.req1 = sid[1];
|
||||
fr.req0 = sid[0];
|
||||
fr.pad = 0;
|
||||
@@ -250,25 +261,42 @@ int uwsgi_proto_fastcgi_write(struct wsgi_request *wsgi_req, char *buf, size_t l
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t wlen = write(wsgi_req->fd, buf+wsgi_req->write_pos, wsgi_req->proto_parser_status);
|
||||
if (wlen > 0) {
|
||||
wsgi_req->write_pos += wlen;
|
||||
ssize_t wlen = write(wsgi_req->fd, buf + wsgi_req->write_pos, wsgi_req->proto_parser_status);
|
||||
if (wlen > 0) {
|
||||
wsgi_req->write_pos += wlen;
|
||||
wsgi_req->proto_parser_status -= wlen;
|
||||
if (wsgi_req->write_pos == len) {
|
||||
return UWSGI_OK;
|
||||
}
|
||||
return UWSGI_AGAIN;
|
||||
}
|
||||
if (wlen < 0) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
|
||||
return UWSGI_AGAIN;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
if (wsgi_req->write_pos == len) {
|
||||
return UWSGI_OK;
|
||||
}
|
||||
return UWSGI_AGAIN;
|
||||
}
|
||||
if (wlen < 0) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
|
||||
return UWSGI_AGAIN;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_proto_fastcgi_close(struct wsgi_request *wsgi_req) {
|
||||
// before sending the END_REQUEST and closing the connection we need to check for EOF
|
||||
if (!wsgi_req->proto_parser_eof) {
|
||||
// we use a custom tiny buffer, all the data will be discarded...
|
||||
char buf[4096];
|
||||
for(;;) {
|
||||
ssize_t rlen = uwsgi_proto_fastcgi_read_body(wsgi_req, buf, 4096);
|
||||
if (rlen < 0) {
|
||||
if (uwsgi_is_again()) {
|
||||
int ret = uwsgi.wait_read_hook(wsgi_req->fd, uwsgi.socket_timeout);
|
||||
if (ret <= 0) goto end;
|
||||
continue;
|
||||
}
|
||||
goto end;
|
||||
}
|
||||
if (rlen == 0) break;
|
||||
}
|
||||
}
|
||||
// special case here, we run in void context, so we need to wait directly here
|
||||
char end_request[24];
|
||||
memcpy(end_request, FCGI_END_REQUEST, 24);
|
||||
@@ -279,69 +307,70 @@ void uwsgi_proto_fastcgi_close(struct wsgi_request *wsgi_req) {
|
||||
end_request[10] = sid[1];
|
||||
end_request[11] = sid[0];
|
||||
(void) uwsgi_write_true_nb(wsgi_req->fd, end_request, 24, uwsgi.socket_timeout);
|
||||
end:
|
||||
uwsgi_proto_base_close(wsgi_req);
|
||||
}
|
||||
|
||||
int uwsgi_proto_fastcgi_sendfile(struct wsgi_request *wsgi_req, int fd, size_t pos, size_t len) {
|
||||
|
||||
// fastcgi packets are limited to 64k
|
||||
if (wsgi_req->proto_parser_status == 0) {
|
||||
uint16_t fcgi_len = (uint16_t) UMIN(len-wsgi_req->write_pos, 0xffff);
|
||||
wsgi_req->proto_parser_status = fcgi_len;
|
||||
struct fcgi_record fr;
|
||||
fr.version = 1;
|
||||
fr.type = 6;
|
||||
uint8_t *sid = (uint8_t *) &wsgi_req->stream_id;
|
||||
fr.req1 = sid[1];
|
||||
fr.req0 = sid[0];
|
||||
fr.pad = 0;
|
||||
fr.reserved = 0;
|
||||
fr.cl0 = (uint8_t) (fcgi_len & 0xff);
|
||||
fr.cl1 = (uint8_t) ((fcgi_len >> 8) & 0xff);
|
||||
if (uwsgi_write_true_nb(wsgi_req->fd, (char *) &fr, sizeof(struct fcgi_record), uwsgi.socket_timeout)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (wsgi_req->proto_parser_status == 0) {
|
||||
uint16_t fcgi_len = (uint16_t) UMIN(len - wsgi_req->write_pos, 0xffff);
|
||||
wsgi_req->proto_parser_status = fcgi_len;
|
||||
struct fcgi_record fr;
|
||||
fr.version = 1;
|
||||
fr.type = 6;
|
||||
uint8_t *sid = (uint8_t *) & wsgi_req->stream_id;
|
||||
fr.req1 = sid[1];
|
||||
fr.req0 = sid[0];
|
||||
fr.pad = 0;
|
||||
fr.reserved = 0;
|
||||
fr.cl0 = (uint8_t) (fcgi_len & 0xff);
|
||||
fr.cl1 = (uint8_t) ((fcgi_len >> 8) & 0xff);
|
||||
if (uwsgi_write_true_nb(wsgi_req->fd, (char *) &fr, sizeof(struct fcgi_record), uwsgi.socket_timeout)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t wlen = uwsgi_sendfile_do(wsgi_req->fd, fd, pos+wsgi_req->write_pos, wsgi_req->proto_parser_status);
|
||||
if (wlen > 0) {
|
||||
wsgi_req->write_pos += wlen;
|
||||
ssize_t wlen = uwsgi_sendfile_do(wsgi_req->fd, fd, pos + wsgi_req->write_pos, wsgi_req->proto_parser_status);
|
||||
if (wlen > 0) {
|
||||
wsgi_req->write_pos += wlen;
|
||||
wsgi_req->proto_parser_status -= wlen;
|
||||
if (wsgi_req->write_pos == len) {
|
||||
return UWSGI_OK;
|
||||
}
|
||||
return UWSGI_AGAIN;
|
||||
}
|
||||
if (wlen < 0) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
|
||||
return UWSGI_AGAIN;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
if (wsgi_req->write_pos == len) {
|
||||
return UWSGI_OK;
|
||||
}
|
||||
return UWSGI_AGAIN;
|
||||
}
|
||||
if (wlen < 0) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
|
||||
return UWSGI_AGAIN;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void uwsgi_proto_fastcgi_setup(struct uwsgi_socket *uwsgi_sock) {
|
||||
uwsgi_sock->proto = uwsgi_proto_fastcgi_parser;
|
||||
uwsgi_sock->proto_accept = uwsgi_proto_base_accept;
|
||||
uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_cgi_prepare_headers;
|
||||
uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header;
|
||||
uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers;
|
||||
uwsgi_sock->proto_read_body = uwsgi_proto_fastcgi_read_body;
|
||||
uwsgi_sock->proto_write = uwsgi_proto_fastcgi_write;
|
||||
uwsgi_sock->proto_write_headers = uwsgi_proto_fastcgi_write;
|
||||
uwsgi_sock->proto_sendfile = uwsgi_proto_fastcgi_sendfile;
|
||||
uwsgi_sock->proto_close = uwsgi_proto_fastcgi_close;
|
||||
uwsgi_sock->proto = uwsgi_proto_fastcgi_parser;
|
||||
uwsgi_sock->proto_accept = uwsgi_proto_base_accept;
|
||||
uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_cgi_prepare_headers;
|
||||
uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header;
|
||||
uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers;
|
||||
uwsgi_sock->proto_read_body = uwsgi_proto_fastcgi_read_body;
|
||||
uwsgi_sock->proto_write = uwsgi_proto_fastcgi_write;
|
||||
uwsgi_sock->proto_write_headers = uwsgi_proto_fastcgi_write;
|
||||
uwsgi_sock->proto_sendfile = uwsgi_proto_fastcgi_sendfile;
|
||||
uwsgi_sock->proto_close = uwsgi_proto_fastcgi_close;
|
||||
}
|
||||
|
||||
void uwsgi_proto_fastcgi_nph_setup(struct uwsgi_socket *uwsgi_sock) {
|
||||
uwsgi_sock->proto = uwsgi_proto_fastcgi_parser;
|
||||
uwsgi_sock->proto_accept = uwsgi_proto_base_accept;
|
||||
uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_prepare_headers;
|
||||
uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header;
|
||||
uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers;
|
||||
uwsgi_sock->proto_read_body = uwsgi_proto_fastcgi_read_body;
|
||||
uwsgi_sock->proto_write = uwsgi_proto_fastcgi_write;
|
||||
uwsgi_sock->proto_write_headers = uwsgi_proto_fastcgi_write;
|
||||
uwsgi_sock->proto_sendfile = uwsgi_proto_fastcgi_sendfile;
|
||||
uwsgi_sock->proto_close = uwsgi_proto_fastcgi_close;
|
||||
uwsgi_sock->proto = uwsgi_proto_fastcgi_parser;
|
||||
uwsgi_sock->proto_accept = uwsgi_proto_base_accept;
|
||||
uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_prepare_headers;
|
||||
uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header;
|
||||
uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers;
|
||||
uwsgi_sock->proto_read_body = uwsgi_proto_fastcgi_read_body;
|
||||
uwsgi_sock->proto_write = uwsgi_proto_fastcgi_write;
|
||||
uwsgi_sock->proto_write_headers = uwsgi_proto_fastcgi_write;
|
||||
uwsgi_sock->proto_sendfile = uwsgi_proto_fastcgi_sendfile;
|
||||
uwsgi_sock->proto_close = uwsgi_proto_fastcgi_close;
|
||||
}
|
||||
|
||||
+111
-46
@@ -4,52 +4,55 @@
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
static uint16_t http_add_uwsgi_header(struct wsgi_request *wsgi_req, char *hh, int hhlen) {
|
||||
static char * http_header_to_cgi(char *hh, size_t hhlen, size_t *keylen, size_t *vallen, int *has_prefix) {
|
||||
size_t i;
|
||||
char *val = hh;
|
||||
int status = 0;
|
||||
for (i = 0; i < hhlen; i++) {
|
||||
if (!status) {
|
||||
hh[i] = toupper((int) hh[i]);
|
||||
if (hh[i] == '-')
|
||||
hh[i] = '_';
|
||||
if (hh[i] == ':') {
|
||||
status = 1;
|
||||
*keylen = i;
|
||||
}
|
||||
}
|
||||
else if (status == 1 && hh[i] != ' ') {
|
||||
status = 2;
|
||||
val += i;
|
||||
*vallen+=1;
|
||||
}
|
||||
else if (status == 2) {
|
||||
*vallen+=1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(*keylen))
|
||||
return NULL;
|
||||
|
||||
if (uwsgi_strncmp("CONTENT_LENGTH", 14, hh, *keylen) && uwsgi_strncmp("CONTENT_TYPE", 12, hh, *keylen)) {
|
||||
*has_prefix = 0x02;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static uint16_t http_add_uwsgi_header(struct wsgi_request *wsgi_req, char *hh, size_t hhlen, char *hv, size_t hvlen, int has_prefix) {
|
||||
|
||||
char *buffer = wsgi_req->buffer + wsgi_req->uh->pktsize;
|
||||
char *watermark = wsgi_req->buffer + uwsgi.buffer_size;
|
||||
|
||||
int i;
|
||||
int status = 0;
|
||||
char *val = hh;
|
||||
uint16_t keylen = 0, vallen = 0;
|
||||
int prefix = 0;
|
||||
char *ptr = buffer;
|
||||
size_t keylen = hhlen;
|
||||
|
||||
for (i = 0; i < hhlen; i++) {
|
||||
if (!status) {
|
||||
hh[i] = toupper((int) hh[i]);
|
||||
if (hh[i] == '-')
|
||||
hh[i] = '_';
|
||||
if (hh[i] == ':') {
|
||||
status = 1;
|
||||
keylen = i;
|
||||
}
|
||||
}
|
||||
else if (status == 1 && hh[i] != ' ') {
|
||||
status = 2;
|
||||
val += i;
|
||||
vallen++;
|
||||
}
|
||||
else if (status == 2) {
|
||||
vallen++;
|
||||
}
|
||||
}
|
||||
if (has_prefix) keylen += 5;
|
||||
|
||||
if (!keylen)
|
||||
return 0;
|
||||
|
||||
if (uwsgi_strncmp("CONTENT_LENGTH", 14, hh, keylen) && uwsgi_strncmp("CONTENT_TYPE", 12, hh, keylen)) {
|
||||
keylen += 5;
|
||||
prefix = 1;
|
||||
}
|
||||
|
||||
if (buffer + keylen + vallen + 2 + 2 >= watermark) {
|
||||
if (prefix) {
|
||||
uwsgi_log("[WARNING] unable to add HTTP_%.*s=%.*s to uwsgi packet, consider increasing buffer size\n", keylen, hh, vallen, val);
|
||||
if (buffer + keylen + hvlen + 2 + 2 >= watermark) {
|
||||
if (has_prefix) {
|
||||
uwsgi_log("[WARNING] unable to add HTTP_%.*s=%.*s to uwsgi packet, consider increasing buffer size\n", keylen, hh, hvlen, hv);
|
||||
}
|
||||
else {
|
||||
uwsgi_log("[WARNING] unable to add %.*s=%.*s to uwsgi packet, consider increasing buffer size\n", keylen, hh, vallen, val);
|
||||
uwsgi_log("[WARNING] unable to add %.*s=%.*s to uwsgi packet, consider increasing buffer size\n", keylen, hh, hvlen, hv);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -58,7 +61,7 @@ static uint16_t http_add_uwsgi_header(struct wsgi_request *wsgi_req, char *hh, i
|
||||
*ptr++ = (uint8_t) (keylen & 0xff);
|
||||
*ptr++ = (uint8_t) ((keylen >> 8) & 0xff);
|
||||
|
||||
if (prefix) {
|
||||
if (has_prefix) {
|
||||
memcpy(ptr, "HTTP_", 5);
|
||||
ptr += 5;
|
||||
memcpy(ptr, hh, keylen - 5);
|
||||
@@ -69,14 +72,14 @@ static uint16_t http_add_uwsgi_header(struct wsgi_request *wsgi_req, char *hh, i
|
||||
ptr += keylen;
|
||||
}
|
||||
|
||||
*ptr++ = (uint8_t) (vallen & 0xff);
|
||||
*ptr++ = (uint8_t) ((vallen >> 8) & 0xff);
|
||||
memcpy(ptr, val, vallen);
|
||||
*ptr++ = (uint8_t) (hvlen & 0xff);
|
||||
*ptr++ = (uint8_t) ((hvlen >> 8) & 0xff);
|
||||
memcpy(ptr, hv, hvlen);
|
||||
|
||||
return 2 + keylen + 2 + vallen;
|
||||
return 2 + keylen + 2 + hvlen;
|
||||
}
|
||||
|
||||
static char *proxy1_parse(char *ptr, char *watermark, char **src, uint16_t *src_len, char **dst, uint16_t *dst_len, char **src_port, uint16_t *src_port_len, char **dst_port, uint16_t *dst_port_len) {
|
||||
char *proxy1_parse(char *ptr, char *watermark, char **src, uint16_t *src_len, char **dst, uint16_t *dst_len, char **src_port, uint16_t *src_port_len, char **dst_port, uint16_t *dst_port_len) {
|
||||
// check for PROXY header
|
||||
if (watermark - ptr > 6) {
|
||||
if (memcmp(ptr, "PROXY ", 6)) return ptr;
|
||||
@@ -301,9 +304,15 @@ static int http_parse(struct wsgi_request *wsgi_req, char *watermark) {
|
||||
}
|
||||
}
|
||||
|
||||
if (wsgi_req->https_len > 0) {
|
||||
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "HTTPS", 5, wsgi_req->https, wsgi_req->https_len);
|
||||
}
|
||||
|
||||
//HEADERS
|
||||
base = ptr;
|
||||
|
||||
struct uwsgi_string_list *headers = NULL, *usl = NULL;
|
||||
|
||||
while (ptr < watermark) {
|
||||
if (*ptr == '\r') {
|
||||
if (ptr + 1 >= watermark)
|
||||
@@ -317,15 +326,71 @@ static int http_parse(struct wsgi_request *wsgi_req, char *watermark) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
wsgi_req->uh->pktsize += http_add_uwsgi_header(wsgi_req, base, ptr - base);
|
||||
size_t key_len = 0, value_len = 0;
|
||||
int has_prefix = 0;
|
||||
// last line, do not waste time
|
||||
if (ptr - base == 0) break;
|
||||
char *value = http_header_to_cgi(base, ptr - base, &key_len, &value_len, &has_prefix);
|
||||
if (!value) {
|
||||
uwsgi_log_verbose("invalid HTTP request\n");
|
||||
goto clear;
|
||||
}
|
||||
usl = uwsgi_string_list_has_item(headers, base, key_len);
|
||||
// there is already a HTTP header with the same name, let's merge them
|
||||
if (usl) {
|
||||
char *old_value = usl->custom_ptr;
|
||||
usl->custom_ptr = uwsgi_concat3n(old_value, (size_t) usl->custom, ", ", 2, value, value_len);
|
||||
usl->custom += 2 + value_len;
|
||||
if (usl->custom2 & 0x01) free(old_value);
|
||||
usl->custom2 |= 0x01;
|
||||
}
|
||||
else {
|
||||
// add an entry
|
||||
usl = uwsgi_string_new_list(&headers, NULL);
|
||||
usl->value = base;
|
||||
usl->len = key_len;
|
||||
usl->custom_ptr = value;
|
||||
usl->custom = value_len;
|
||||
usl->custom2 = has_prefix;
|
||||
}
|
||||
ptr++;
|
||||
base = ptr + 1;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
usl = headers;
|
||||
int broken = 0;
|
||||
while(usl) {
|
||||
if (!broken) {
|
||||
uint16_t old_pktsize = wsgi_req->uh->pktsize;
|
||||
wsgi_req->uh->pktsize += http_add_uwsgi_header(wsgi_req, usl->value, usl->len, usl->custom_ptr, (size_t) usl->custom, usl->custom2 & 0x02);
|
||||
// if the packet remains unchanged, the buffer is full, mark the request as broken
|
||||
if (old_pktsize == wsgi_req->uh->pktsize) {
|
||||
broken = 1;
|
||||
}
|
||||
}
|
||||
if (usl->custom2 & 0x01) {
|
||||
free(usl->custom_ptr);
|
||||
}
|
||||
struct uwsgi_string_list *tmp_usl = usl;
|
||||
usl = usl->next;
|
||||
free(tmp_usl);
|
||||
}
|
||||
|
||||
return broken;
|
||||
|
||||
clear:
|
||||
usl = headers;
|
||||
while(usl) {
|
||||
if (usl->custom2 & 0x01) {
|
||||
free(usl->custom_ptr);
|
||||
}
|
||||
struct uwsgi_string_list *tmp_usl = usl;
|
||||
usl = usl->next;
|
||||
free(tmp_usl);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -9,4 +9,5 @@ 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
|
||||
cache2 = name=items_lru,items=3,blocksize=20,purge_lru=1
|
||||
pyrun = t/cachebitmap.py
|
||||
|
||||
+11
-1
@@ -5,7 +5,7 @@ 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']
|
||||
__caches__ = ['items_1', 'items_2', 'items_3', 'items_4', 'items_17', 'items_4_10', 'items_1_100000', 'items_non_bitmap', 'items_lru']
|
||||
|
||||
def setUp(self):
|
||||
for cache in self.__caches__:
|
||||
@@ -103,4 +103,14 @@ class BitmapTest(unittest.TestCase):
|
||||
self.assertIsNone(uwsgi.cache_set('KEY', 'X' * 21, 0, 'items_non_bitmap'))
|
||||
self.assertTrue(uwsgi.cache_set('KEY', 'X' * 20, 0, 'items_non_bitmap'))
|
||||
|
||||
def test_lru(self):
|
||||
self.assertTrue(uwsgi.cache_set('KEY1', 'X' * 20, 0, 'items_lru'))
|
||||
self.assertTrue(uwsgi.cache_set('KEY2', 'X' * 20, 0, 'items_lru'))
|
||||
self.assertTrue(uwsgi.cache_set('KEY3', 'Y' * 20, 0, 'items_lru'))
|
||||
self.assertIsNone(uwsgi.cache_get('KEY1', 'items_lru'))
|
||||
second_item = uwsgi.cache_get('KEY3', 'items_lru')
|
||||
for i in range(4,100):
|
||||
self.assertTrue(uwsgi.cache_set('KEY%d' % i, 'Y' * 20, 0, 'items_lru'))
|
||||
self.assertIsNone(uwsgi.cache_get('KEY%d' % (i-2), 'items_lru'))
|
||||
|
||||
unittest.main()
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
function hello(wsapi_env)
|
||||
local headers = { ["Content-type"] = "text/html", ["set-cookie"] = {"foo=bar", "bar=baz"} }
|
||||
local function hello_text()
|
||||
coroutine.yield("<html><body>")
|
||||
coroutine.yield("<p>Hello Wsapi!</p>")
|
||||
coroutine.yield("<p>PATH_INFO: " .. wsapi_env.PATH_INFO .. "</p>")
|
||||
coroutine.yield("<p>SCRIPT_NAME: " .. wsapi_env.SCRIPT_NAME .. "</p>")
|
||||
coroutine.yield("<p>QUERY_STRING: " .. wsapi_env.QUERY_STRING .. "</p>")
|
||||
coroutine.yield("</body></html>")
|
||||
end
|
||||
return 200, headers, coroutine.wrap(hello_text)
|
||||
end
|
||||
|
||||
return hello
|
||||
@@ -59,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;
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
use v5.10.0;
|
||||
use strict;
|
||||
use warnings;
|
||||
use Time::HiRes qw(sleep);
|
||||
use autodie qw(:all);
|
||||
|
||||
my $psgi = $ARGV[0] || 't/perl/test_hello.psgi';
|
||||
|
||||
for my $use_thunder_lock (0,1) {
|
||||
for my $cpu_multiplier (1,2,4,8,16,32,64) {
|
||||
my $procs = 16 * $cpu_multiplier;
|
||||
my $desc = sprintf "%3d procs %2s/TL", $procs, ($use_thunder_lock ? "w" : "wo");
|
||||
my $tl_cl = $use_thunder_lock ? "--thunder-lock --lock-engine ipcsem --ftok $psgi" : "";
|
||||
|
||||
#say STDERR "Now testing $desc";
|
||||
system q[for p in $(ps auxf|grep uwsgi.*--disable-logging|grep -v grep|awk '{print $2}'); do kill $p; done];
|
||||
system qq[./uwsgi --http 127.0.0.1:8080 --processes $procs --psgi $psgi --disable-logging $tl_cl >/dev/null 2>&1 &];
|
||||
sleep 0.5;
|
||||
chomp(my $ab = qx[http_proxy= ab -n 10000 -c 32 http://localhost:8080/ 2>&1]);
|
||||
my ($seconds) = $ab =~ m[Time taken for tests:\s+([0-9.]+) seconds];
|
||||
say STDERR "$seconds\t$desc";
|
||||
system q[for p in $(ps auxf|grep uwsgi.*--disable-logging|grep -v grep|awk '{print $2}'); do kill $p; done];
|
||||
sleep 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
__END__
|
||||
$ perl t/perl/test_benchmark.pl t/perl/test_sleepy.psgi
|
||||
7.128 16 procs wo/TL
|
||||
3.547 32 procs wo/TL
|
||||
2.038 64 procs wo/TL
|
||||
2.880 128 procs wo/TL
|
||||
4.578 256 procs wo/TL
|
||||
8.199 512 procs wo/TL
|
||||
13.379 1024 procs wo/TL
|
||||
7.123 16 procs w/TL
|
||||
3.559 32 procs w/TL
|
||||
2.036 64 procs w/TL
|
||||
1.972 128 procs w/TL
|
||||
2.026 256 procs w/TL
|
||||
2.172 512 procs w/TL
|
||||
2.412 1024 procs w/TL
|
||||
|
||||
$ perl t/perl/test_benchmark.pl t/perl/test_hello.psgi
|
||||
1.392 16 procs wo/TL
|
||||
1.743 32 procs wo/TL
|
||||
2.374 64 procs wo/TL
|
||||
3.530 128 procs wo/TL
|
||||
4.984 256 procs wo/TL
|
||||
8.258 512 procs wo/TL
|
||||
9.343 1024 procs wo/TL
|
||||
1.134 16 procs w/TL
|
||||
1.284 32 procs w/TL
|
||||
1.152 64 procs w/TL
|
||||
1.084 128 procs w/TL
|
||||
1.286 256 procs w/TL
|
||||
1.559 512 procs w/TL
|
||||
1.537 1024 procs w/TL
|
||||
@@ -0,0 +1,8 @@
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
sub {
|
||||
my $env = shift;
|
||||
|
||||
return [200, [], [ "Hello, world!" ]];
|
||||
}
|
||||
@@ -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,20 @@
|
||||
use strict;
|
||||
use warnings;
|
||||
use Time::HiRes qw(usleep);
|
||||
|
||||
sub {
|
||||
my $env = shift;
|
||||
|
||||
die "PANIC: We are expecting to support psgix.cleanup" unless $env->{'psgix.cleanup'};
|
||||
my $msleep = 2 * 1000 + int rand 7 * 1000; # 2..10ms
|
||||
my $csleep = 2 * 1000 + int rand 7 * 1000; # 2..10ms
|
||||
|
||||
push @{$env->{'psgix.cleanup.handlers'}} => sub { usleep($csleep) };
|
||||
usleep($msleep);
|
||||
|
||||
return [
|
||||
200,
|
||||
[],
|
||||
[ "Responding. Slept $msleep us in the main phase, sleeping $csleep us in the cleanup phase" ],
|
||||
];
|
||||
}
|
||||
@@ -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,4 +1,4 @@
|
||||
#!./uwsgi --http-socket :9090 --gevent 100 --module tests.websocket_chat --gevent-monkey-patch
|
||||
#!./uwsgi --http-socket :9090 --gevent 100 --module tests.websockets_chat --gevent-monkey-patch
|
||||
import uwsgi
|
||||
import time
|
||||
import gevent.select
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
#!./uwsgi --http-socket :9090 --asyncio 100 --module tests.websockets_chat_asyncio --greenlet
|
||||
import uwsgi
|
||||
import asyncio
|
||||
import asyncio_redis
|
||||
import time
|
||||
import greenlet
|
||||
|
||||
class GreenFuture(asyncio.Future):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.greenlet = greenlet.getcurrent()
|
||||
self.add_done_callback(lambda f: f.greenlet.switch())
|
||||
|
||||
def result(self):
|
||||
while True:
|
||||
if self.done():
|
||||
return super().result()
|
||||
self.greenlet.parent.switch()
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def redis_open(f):
|
||||
connection = yield from asyncio_redis.Connection.create(host='localhost', port=6379)
|
||||
f.set_result(connection)
|
||||
f.greenlet.switch()
|
||||
|
||||
@asyncio.coroutine
|
||||
def redis_subscribe(f):
|
||||
connection = yield from asyncio_redis.Connection.create(host='localhost', port=6379)
|
||||
subscriber = yield from connection.start_subscribe()
|
||||
yield from subscriber.subscribe([ 'foobar' ])
|
||||
f.set_result(subscriber)
|
||||
f.greenlet.switch()
|
||||
|
||||
def ws_recv_msg(g):
|
||||
g.has_ws_msg = True
|
||||
g.switch()
|
||||
|
||||
@asyncio.coroutine
|
||||
def redis_wait(subscriber, f):
|
||||
reply = yield from subscriber.next_published()
|
||||
f.set_result(reply.value)
|
||||
f.greenlet.switch()
|
||||
|
||||
@asyncio.coroutine
|
||||
def redis_publish(connection, msg):
|
||||
yield from connection.publish('foobar', msg.decode('utf-8'))
|
||||
|
||||
def application(env, sr):
|
||||
|
||||
ws_scheme = 'ws'
|
||||
if 'HTTPS' in env or env['wsgi.url_scheme'] == 'https':
|
||||
ws_scheme = 'wss'
|
||||
|
||||
if env['PATH_INFO'] == '/':
|
||||
sr('200 OK', [('Content-Type','text/html')])
|
||||
return ("""
|
||||
<html>
|
||||
<head>
|
||||
<script language="Javascript">
|
||||
var s = new WebSocket("%s://%s/foobar/");
|
||||
s.onopen = function() {
|
||||
alert("connected !!!");
|
||||
s.send("ciao");
|
||||
};
|
||||
s.onmessage = function(e) {
|
||||
var bb = document.getElementById('blackboard')
|
||||
var html = bb.innerHTML;
|
||||
bb.innerHTML = html + '<br/>' + e.data;
|
||||
};
|
||||
|
||||
s.onerror = function(e) {
|
||||
alert(e);
|
||||
}
|
||||
|
||||
s.onclose = function(e) {
|
||||
alert("connection closed");
|
||||
}
|
||||
|
||||
function invia() {
|
||||
var value = document.getElementById('testo').value;
|
||||
s.send(value);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>WebSocket</h1>
|
||||
<input type="text" id="testo"/>
|
||||
<input type="button" value="invia" onClick="invia();"/>
|
||||
<div id="blackboard" style="width:640px;height:480px;background-color:black;color:white;border: solid 2px red;overflow:auto">
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
""" % (ws_scheme, env['HTTP_HOST'])).encode()
|
||||
elif env['PATH_INFO'] == '/favicon.ico':
|
||||
return b""
|
||||
elif env['PATH_INFO'] == '/foobar/':
|
||||
uwsgi.websocket_handshake()
|
||||
print("websockets...")
|
||||
# a future for waiting for redis connection
|
||||
f = GreenFuture()
|
||||
asyncio.Task(redis_subscribe(f))
|
||||
# the result() method will switch greenlets if needed
|
||||
subscriber = f.result()
|
||||
|
||||
# open another redis connection for publishing messages
|
||||
f0 = GreenFuture()
|
||||
t = asyncio.Task(redis_open(f0))
|
||||
connection = f0.result()
|
||||
|
||||
myself = greenlet.getcurrent()
|
||||
myself.has_ws_msg = False
|
||||
# start monitoring websocket events
|
||||
asyncio.get_event_loop().add_reader(uwsgi.connection_fd(), ws_recv_msg, myself)
|
||||
|
||||
# add a 4 seconds timer to manage ping/pong
|
||||
asyncio.get_event_loop().call_later(4, ws_recv_msg, myself)
|
||||
|
||||
# add a coroutine for redis messages
|
||||
f = GreenFuture()
|
||||
asyncio.Task(redis_wait(subscriber, f))
|
||||
|
||||
# switch again
|
||||
f.greenlet.parent.switch()
|
||||
|
||||
while True:
|
||||
# any redis message in the queue ?
|
||||
if f.done():
|
||||
msg = f.result()
|
||||
uwsgi.websocket_send("[%s] %s" % (time.time(), msg))
|
||||
# restart coroutine
|
||||
f = GreenFuture()
|
||||
asyncio.Task(redis_wait(subscriber, f))
|
||||
if myself.has_ws_msg:
|
||||
myself.has_ws_msg = False
|
||||
msg = uwsgi.websocket_recv_nb()
|
||||
if msg:
|
||||
asyncio.Task(redis_publish(connection, msg))
|
||||
# switch again
|
||||
f.greenlet.parent.switch()
|
||||
+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-26'
|
||||
s.date = '2014-06-01'
|
||||
s.summary = "uWSGI"
|
||||
s.description = "The uWSGI server for Ruby/Rack"
|
||||
s.authors = ["Unbit"]
|
||||
|
||||
@@ -765,6 +765,10 @@ struct uwsgi_cache_item {
|
||||
uint64_t prev;
|
||||
// next same-hash item
|
||||
uint64_t next;
|
||||
// previous lru item
|
||||
uint64_t lru_prev;
|
||||
// next lru item
|
||||
uint64_t lru_next;
|
||||
// key characters follows...
|
||||
char key[];
|
||||
} __attribute__ ((__packed__));
|
||||
@@ -819,6 +823,13 @@ struct uwsgi_cache {
|
||||
struct uwsgi_lock_item *lock;
|
||||
|
||||
struct uwsgi_cache *next;
|
||||
|
||||
int ignore_full;
|
||||
|
||||
uint64_t next_scan;
|
||||
int purge_lru;
|
||||
uint64_t lru_head;
|
||||
uint64_t lru_tail;
|
||||
};
|
||||
|
||||
struct uwsgi_option {
|
||||
@@ -886,6 +897,7 @@ struct uwsgi_opt {
|
||||
#define UWSGI_EXCEPTION_CODE 5
|
||||
#define UWSGI_QUIET_CODE 29
|
||||
#define UWSGI_BRUTAL_RELOAD_CODE 31
|
||||
#define UWSGI_GO_CHEAP_CODE 15
|
||||
|
||||
#define MAX_VARS 64
|
||||
|
||||
@@ -1555,6 +1567,11 @@ struct wsgi_request {
|
||||
#ifdef UWSGI_SSL
|
||||
SSL *ssl;
|
||||
#endif
|
||||
|
||||
// do not update avg_rt after request
|
||||
int do_not_account_avg_rt;
|
||||
// used for protocol parsers requiring EOF signaling
|
||||
int proto_parser_eof;
|
||||
};
|
||||
|
||||
|
||||
@@ -2695,6 +2712,17 @@ struct uwsgi_server {
|
||||
char *notify_socket;
|
||||
int notify_socket_fd;
|
||||
char *subscription_notify_socket;
|
||||
|
||||
//uWSGI 2.0.5
|
||||
|
||||
int mule_reload_mercy;
|
||||
int alarm_cheap;
|
||||
|
||||
int emperor_no_blacklist;
|
||||
int metrics_no_cores;
|
||||
int stats_no_cores;
|
||||
int stats_no_metrics;
|
||||
|
||||
};
|
||||
|
||||
struct uwsgi_rpc {
|
||||
@@ -2928,6 +2956,9 @@ struct uwsgi_mule {
|
||||
time_t user_harakiri;
|
||||
|
||||
char name[0xff];
|
||||
|
||||
time_t cursed_at;
|
||||
time_t no_mercy_at;
|
||||
};
|
||||
|
||||
struct uwsgi_mule_farm {
|
||||
@@ -2995,6 +3026,7 @@ void spooler(struct uwsgi_spooler *);
|
||||
pid_t spooler_start(struct uwsgi_spooler *);
|
||||
|
||||
void uwsgi_curse(int, int);
|
||||
void uwsgi_curse_mule(int, int);
|
||||
void uwsgi_destroy_processes(void);
|
||||
|
||||
void set_harakiri(int);
|
||||
@@ -3760,6 +3792,8 @@ int uwsgi_logic_opt_if_plugin(char *, char *);
|
||||
int uwsgi_logic_opt_if_not_plugin(char *, char *);
|
||||
|
||||
|
||||
void uwsgi_opt_resolve(char *, char *, void *);
|
||||
|
||||
#ifdef UWSGI_CAP
|
||||
void uwsgi_opt_set_cap(char *, char *, void *);
|
||||
void uwsgi_opt_set_emperor_cap(char *, char *, void *);
|
||||
@@ -4044,6 +4078,7 @@ void emperor_stop(struct uwsgi_instance *);
|
||||
void emperor_curse(struct uwsgi_instance *);
|
||||
void emperor_respawn(struct uwsgi_instance *, time_t);
|
||||
void emperor_add(struct uwsgi_emperor_scanner *, char *, time_t, char *, uint32_t, uid_t, gid_t, char *);
|
||||
void emperor_back_to_ondemand(struct uwsgi_instance *);
|
||||
|
||||
void uwsgi_exec_command_with_args(char *);
|
||||
|
||||
@@ -4131,7 +4166,6 @@ char *uwsgi_elf_section(char *, char *, size_t *);
|
||||
|
||||
void uwsgi_alarm_log_check(char *, size_t);
|
||||
void uwsgi_alarm_run(struct uwsgi_alarm_instance *, char *, size_t);
|
||||
void uwsgi_alarm_log_run(struct uwsgi_alarm_log *, char *, size_t);
|
||||
void uwsgi_register_alarm(char *, void (*)(struct uwsgi_alarm_instance *), void (*)(struct uwsgi_alarm_instance *, char *, size_t));
|
||||
void uwsgi_register_embedded_alarms();
|
||||
void uwsgi_alarms_init();
|
||||
@@ -4157,6 +4191,7 @@ struct uwsgi_thread {
|
||||
void (*func) (struct uwsgi_thread *);
|
||||
};
|
||||
struct uwsgi_thread *uwsgi_thread_new(void (*)(struct uwsgi_thread *));
|
||||
struct uwsgi_thread *uwsgi_thread_new_with_data(void (*)(struct uwsgi_thread *), void *data);
|
||||
|
||||
struct uwsgi_offload_request {
|
||||
// the request socket
|
||||
@@ -4409,6 +4444,7 @@ int uwsgi_exceptions_catch(struct wsgi_request *);
|
||||
uint64_t uwsgi_worker_exceptions(int);
|
||||
struct uwsgi_exception_handler *uwsgi_register_exception_handler(char *, int (*)(struct uwsgi_exception_handler_instance *, char *, size_t));
|
||||
|
||||
char *proxy1_parse(char *ptr, char *watermark, char **src, uint16_t *src_len, char **dst, uint16_t *dst_len, char **src_port, uint16_t *src_port_len, char **dst_port, uint16_t *dst_port_len);
|
||||
void uwsgi_async_queue_is_full(time_t);
|
||||
char *uwsgi_get_header(struct wsgi_request *, char *, uint16_t, uint16_t *);
|
||||
|
||||
@@ -4651,6 +4687,9 @@ struct uwsgi_metric {
|
||||
struct uwsgi_metric_threshold *thresholds;
|
||||
|
||||
struct uwsgi_metric *next;
|
||||
|
||||
// allow to reset metrics after each push
|
||||
uint8_t reset_after_push;
|
||||
};
|
||||
|
||||
struct uwsgi_metric_child {
|
||||
@@ -4668,6 +4707,8 @@ int uwsgi_metric_mul(char *, char *, int64_t);
|
||||
int uwsgi_metric_div(char *, char *, int64_t);
|
||||
int64_t uwsgi_metric_get(char *, char *);
|
||||
int64_t uwsgi_metric_getn(char *, size_t, char *, size_t);
|
||||
int uwsgi_metric_set_max(char *, char *, int64_t);
|
||||
int uwsgi_metric_set_min(char *, char *, int64_t);
|
||||
|
||||
struct uwsgi_metric_collector *uwsgi_register_metric_collector(char *, int64_t (*)(struct uwsgi_metric *));
|
||||
struct uwsgi_metric *uwsgi_register_metric(char *, char *, uint8_t, char *, void *, uint32_t, void *);
|
||||
@@ -4695,6 +4736,7 @@ void uwsgi_sharedareas_init();
|
||||
|
||||
struct uwsgi_sharedarea *uwsgi_sharedarea_init(int);
|
||||
struct uwsgi_sharedarea *uwsgi_sharedarea_init_ptr(char *, uint64_t);
|
||||
struct uwsgi_sharedarea *uwsgi_sharedarea_init_fd(int, uint64_t, off_t);
|
||||
|
||||
int64_t uwsgi_sharedarea_read(int, uint64_t, char *, uint64_t);
|
||||
int uwsgi_sharedarea_write(int, uint64_t, char *, uint64_t);
|
||||
|
||||
+28
-9
@@ -1,6 +1,6 @@
|
||||
# uWSGI build system
|
||||
|
||||
uwsgi_version = '2.0.2'
|
||||
uwsgi_version = '2.0.5'
|
||||
|
||||
import os
|
||||
import re
|
||||
@@ -331,6 +331,13 @@ def build_uwsgi(uc, print_only=False, gcll=None):
|
||||
uwsgi_config_py = uwsgi_config_py_content.encode('hex')
|
||||
open('core/config_py.c', 'w').write('char *uwsgi_config_py = "%s";\n' % uwsgi_config_py);
|
||||
gcc_list.append('core/config_py')
|
||||
|
||||
additional_sources = os.environ.get('UWSGI_ADDITIONAL_SOURCES')
|
||||
if not additional_sources:
|
||||
additional_sources = uc.get('additional_sources')
|
||||
if additional_sources:
|
||||
for item in additional_sources.split(','):
|
||||
gcc_list.append(item)
|
||||
|
||||
cflags.append('-DUWSGI_CFLAGS=\\"%s\\"' % uwsgi_cflags)
|
||||
cflags.append('-DUWSGI_BUILD_DATE="\\"%s\\""' % time.strftime("%d %B %Y %H:%M:%S"))
|
||||
@@ -367,6 +374,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]
|
||||
@@ -510,13 +526,6 @@ def build_uwsgi(uc, print_only=False, gcll=None):
|
||||
for ef in binary_list:
|
||||
gcc_list.append("%s.o" % ef)
|
||||
|
||||
additional_sources = os.environ.get('UWSGI_ADDITIONAL_SOURCES')
|
||||
if not additional_sources:
|
||||
additional_sources = uc.get('additional_sources')
|
||||
if additional_sources:
|
||||
for item in additional_sources.split(','):
|
||||
gcc_list.append(item)
|
||||
|
||||
if compile_queue:
|
||||
for t in thread_compilers:
|
||||
compile_queue.put((None, None))
|
||||
@@ -1049,7 +1058,7 @@ class uConf(object):
|
||||
|
||||
self.embed_config = None
|
||||
|
||||
if uwsgi_os == 'Linux':
|
||||
if uwsgi_os not in ('Darwin',):
|
||||
self.embed_config = os.environ.get('UWSGI_EMBED_CONFIG')
|
||||
if not self.embed_config:
|
||||
self.embed_config = self.get('embed_config')
|
||||
@@ -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