mirror of
https://github.com/clearlinux/uwsgi.git
synced 2026-10-04 16:08:31 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0f397eeb55 | ||
|
|
bf929398a9 | ||
|
|
4f8a0f753e | ||
|
|
7db5da9566 | ||
|
|
4d1389805c | ||
|
|
ee87e2b946 | ||
|
|
6356d78768 | ||
|
|
afdf7e740e | ||
|
|
51ce3ddf78 | ||
|
|
192186056e | ||
|
|
336a7febd7 | ||
|
|
63e73d1b73 | ||
|
|
a02ab9a723 | ||
|
|
95f15ab9dd | ||
|
|
5d0ea0066a | ||
|
|
9ff6b2da9b | ||
|
|
6ac7e27847 | ||
|
|
4ed1c5e747 | ||
|
|
bae3bc096f | ||
|
|
9d73683de2 | ||
|
|
f5fec0ab71 | ||
|
|
9909ab10c4 | ||
|
|
65cff01fee | ||
|
|
10190a3012 | ||
|
|
79ab696f4e | ||
|
|
cb603682e4 | ||
|
|
c986a06bf7 | ||
|
|
e2843a6cee | ||
|
|
ea1f239807 | ||
|
|
8d7618146a | ||
|
|
eb9e419bb0 | ||
|
|
f98f71ac26 | ||
|
|
03baaaebcb | ||
|
|
cbca954508 | ||
|
|
22ba6cc406 | ||
|
|
6bd172acb4 | ||
|
|
818ba4416f | ||
|
|
adff12841c | ||
|
|
480c306591 | ||
|
|
cbd1481cb7 | ||
|
|
d1c1871222 | ||
|
|
15a94b8fb0 | ||
|
|
66be54e6a7 | ||
|
|
62c85cc2eb | ||
|
|
1ae05a9ebc | ||
|
|
3457c70f30 | ||
|
|
c1ec9126da | ||
|
|
398da2fac7 | ||
|
|
47f33d6346 | ||
|
|
2cad82d537 | ||
|
|
8d06d78537 | ||
|
|
b61be000de | ||
|
|
9ca6de6e7a | ||
|
|
5c03c25e96 | ||
|
|
23843163ad | ||
|
|
8b07fbbedc | ||
|
|
5bf55220d4 | ||
|
|
0e1de3d6e8 | ||
|
|
3a7ba3675b | ||
|
|
5c0deb5bdb | ||
|
|
50dcbc2b01 | ||
|
|
90d72f7843 | ||
|
|
90ee59c70d | ||
|
|
59eda11c1b | ||
|
|
78684a424f | ||
|
|
4a936dda6e | ||
|
|
094d4b99a4 | ||
|
|
382268308e | ||
|
|
97315d27b9 | ||
|
|
26ae573b72 | ||
|
|
803c44d783 | ||
|
|
90f3f1037a | ||
|
|
ce39a751d9 | ||
|
|
ceebf7d32d | ||
|
|
8da59bf0ac | ||
|
|
d25979502a | ||
|
|
549bc3bf9f | ||
|
|
22b2f325e0 | ||
|
|
6615d1b90c | ||
|
|
8f045c4254 | ||
|
|
a4434349e5 | ||
|
|
01272be25f | ||
|
|
be0beed403 | ||
|
|
453d2abed5 | ||
|
|
57e9ccbef0 | ||
|
|
989124772b | ||
|
|
72400e4b91 | ||
|
|
900cba29a7 | ||
|
|
f177a65c1e | ||
|
|
b6baf9016d | ||
|
|
86ac6e8044 | ||
|
|
66d8fb95db | ||
|
|
22da8d9ba2 | ||
|
|
819e9c1b16 | ||
|
|
dd4b2e8bc2 | ||
|
|
e2f7ac2017 | ||
|
|
31b5cf6926 | ||
|
|
25fe3035c2 | ||
|
|
0cf56823cd | ||
|
|
c2f36968c3 | ||
|
|
a508c7f53e | ||
|
|
48de68031d | ||
|
|
81ef85af82 | ||
|
|
16b65d7dbe | ||
|
|
5a98e6511b | ||
|
|
2418f08e22 | ||
|
|
80a821bc20 | ||
|
|
378f78bd87 | ||
|
|
f010591e19 | ||
|
|
5274abdcca | ||
|
|
48f9e8c5c8 | ||
|
|
5c02117fde | ||
|
|
bc56a188f8 | ||
|
|
b6df1b22ab | ||
|
|
0fbf2dd5bb | ||
|
|
38c126d11a | ||
|
|
7dff602e5e | ||
|
|
e401f32815 | ||
|
|
12e94b70a7 | ||
|
|
884de3959c | ||
|
|
fe12325e50 | ||
|
|
bea86f3f79 | ||
|
|
7a5f3667da | ||
|
|
0813788c98 | ||
|
|
b1ca73e7f0 | ||
|
|
ebf9e9b1a3 | ||
|
|
b0abab7a1d | ||
|
|
995bb493df | ||
|
|
1b2375fc84 | ||
|
|
b7315bcb5a | ||
|
|
2c9ebdaa69 | ||
|
|
fbd9e5b4d7 | ||
|
|
b9a3425b6d | ||
|
|
d4742c611b | ||
|
|
c645a590aa | ||
|
|
275a7fe63f | ||
|
|
0ff16d8312 | ||
|
|
1cb31d6c7e | ||
|
|
8a6eb553df | ||
|
|
946af8b9ee | ||
|
|
098a1f647e | ||
|
|
c9681dc430 | ||
|
|
ff0b8b2d53 | ||
|
|
75f520d43a | ||
|
|
65209748ba | ||
|
|
cd604ef07b | ||
|
|
51da8bc531 | ||
|
|
2374ba12bd | ||
|
|
0a75aaec25 | ||
|
|
a8c286ae83 | ||
|
|
7c4caef5e7 |
@@ -2,6 +2,8 @@
|
||||
*.py[co]
|
||||
*.class
|
||||
*.jar
|
||||
*~
|
||||
*.so
|
||||
|
||||
/uwsgi
|
||||
/uwsgibuild.*
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ plugins =
|
||||
bin_name = uwsgi
|
||||
append_version =
|
||||
plugin_dir = .
|
||||
embedded_plugins = %(main_plugin)s, ping, cache, nagios, rrdtool, carbon, rpc, corerouter, fastrouter, http, ugreen, signal, syslog, rsyslog, logsocket, router_uwsgi, router_redirect, router_basicauth, zergpool, redislog, mongodblog, router_rewrite, router_http, logfile, router_cache, rawrouter, router_static, sslrouter, spooler, cheaper_busyness, symcall, transformation_tofile, transformation_gzip, transformation_chunked
|
||||
embedded_plugins = %(main_plugin)s, ping, cache, nagios, rrdtool, carbon, rpc, corerouter, fastrouter, http, ugreen, signal, syslog, rsyslog, logsocket, router_uwsgi, router_redirect, router_basicauth, zergpool, redislog, mongodblog, router_rewrite, router_http, logfile, router_cache, rawrouter, router_static, sslrouter, spooler, cheaper_busyness, symcall, transformation_tofile, transformation_gzip, transformation_chunked, transformation_offload, router_memcached, router_redis, router_hash
|
||||
as_shared_library = false
|
||||
|
||||
locking = auto
|
||||
|
||||
+9
-1
@@ -194,9 +194,15 @@ static void uwsgi_cache_load_files(struct uwsgi_cache *uc) {
|
||||
if (!uwsgi_cache_set2(uc, key, key_len, value, len, 0, 0)) {
|
||||
uwsgi_log("[cache] stored \"%.*s\" in \"%s\"\n", key_len, key, uc->name);
|
||||
}
|
||||
else {
|
||||
uwsgi_log("[cache-error] unable to store \"%.*s\" in \"%s\"\n", key_len, key, uc->name);
|
||||
}
|
||||
uwsgi_rwunlock(uc->lock);
|
||||
free(value);
|
||||
}
|
||||
else {
|
||||
uwsgi_log("[cache-error] unable to read file \"%.*s\"\n", key_len, key);
|
||||
}
|
||||
next:
|
||||
usl = usl->next;
|
||||
}
|
||||
@@ -1089,7 +1095,6 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) {
|
||||
// defaults
|
||||
uc->blocks = uc->max_items;
|
||||
uc->blocksize = UMAX16;
|
||||
uc->max_item_size = uc->blocksize;
|
||||
uc->keysize = 2048;
|
||||
uc->hashsize = UMAX16;
|
||||
uc->hash = uwsgi_hash_algo_get("djb33x");
|
||||
@@ -1097,6 +1102,9 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) {
|
||||
// customize
|
||||
if (c_blocksize) uc->blocksize = uwsgi_n64(c_blocksize);
|
||||
if (!uc->blocksize) { uwsgi_log("invalid cache blocksize for \"%s\"\n", uc->name); exit(1); }
|
||||
// set the true max size of an item
|
||||
uc->max_item_size = uc->blocksize;
|
||||
|
||||
if (c_blocks) uc->blocks = uwsgi_n64(c_blocks);
|
||||
if (!uc->blocks) { uwsgi_log("invalid cache blocks for \"%s\"\n", uc->name); exit(1); }
|
||||
if (c_hash) uc->hash = uwsgi_hash_algo_get(c_hash);
|
||||
|
||||
+160
-12
@@ -27,13 +27,22 @@ struct uwsgi_cron *uwsgi_cron_add(char *crontab) {
|
||||
exit(1);
|
||||
}
|
||||
uc->command = crontab + i;
|
||||
uc->pid = -1;
|
||||
return uc;
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_opt_add_cron(char *opt, char *value, void *foobar) {
|
||||
uwsgi_cron_add(value);
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_opt_add_unique_cron(char *opt, char *value, void *foobar) {
|
||||
struct uwsgi_cron *uc = uwsgi_cron_add(value);
|
||||
uc->unique = 1;
|
||||
}
|
||||
|
||||
|
||||
#ifdef UWSGI_SSL
|
||||
void uwsgi_opt_add_legion_cron(char *opt, char *value, void *foobar) {
|
||||
char *space = strchr(value, ' ');
|
||||
@@ -45,9 +54,140 @@ void uwsgi_opt_add_legion_cron(char *opt, char *value, void *foobar) {
|
||||
struct uwsgi_cron *uc = uwsgi_cron_add(space+1);
|
||||
uc->legion = legion;
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_opt_add_unique_legion_cron(char *opt, char *value, void *foobar) {
|
||||
char *space = strchr(value, ' ');
|
||||
if (!space) {
|
||||
uwsgi_log("invalid %s syntax, must be prefixed with a legion name\n", opt);
|
||||
exit(1);
|
||||
}
|
||||
char *legion = uwsgi_concat2n(value, space-value, "", 0);
|
||||
struct uwsgi_cron *uc = uwsgi_cron_add(space+1);
|
||||
uc->legion = legion;
|
||||
uc->unique = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void uwsgi_opt_add_cron2(char *opt, char *value, void *foobar) {
|
||||
|
||||
char *c_minute = NULL;
|
||||
char *c_hour = NULL;
|
||||
char *c_day = NULL;
|
||||
char *c_month = NULL;
|
||||
char *c_week = NULL;
|
||||
char *c_unique = NULL;
|
||||
char *c_harakiri = NULL;
|
||||
char *c_legion = NULL;
|
||||
|
||||
char *c_command = value;
|
||||
|
||||
char *space = strchr(value, ' ');
|
||||
if (space) {
|
||||
if (uwsgi_str_contains(value, space - value, '=')) {
|
||||
// --cron2 key=val command
|
||||
*space = 0;
|
||||
c_command = space + 1;
|
||||
}
|
||||
|
||||
// no point in parsing key=val list if there is none
|
||||
if (uwsgi_kvlist_parse(value, strlen(value), ',', '=',
|
||||
"minute", &c_minute,
|
||||
"hour", &c_hour,
|
||||
"day", &c_day,
|
||||
"month", &c_month,
|
||||
"week", &c_week,
|
||||
"unique", &c_unique,
|
||||
"harakiri", &c_harakiri,
|
||||
"legion", &c_legion,
|
||||
NULL)) {
|
||||
uwsgi_log("unable to parse cron definition: %s\n", value);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (uwsgi_str_contains(value, strlen(value), '=')) {
|
||||
// --cron2 key=val
|
||||
uwsgi_log("unable to parse cron definition: %s\n", value);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
struct uwsgi_cron *old_uc, *uc = uwsgi.crons;
|
||||
if (!uc) {
|
||||
uc = uwsgi_malloc(sizeof(struct uwsgi_cron));
|
||||
uwsgi.crons = uc;
|
||||
}
|
||||
else {
|
||||
old_uc = uc;
|
||||
while (uc->next) {
|
||||
uc = uc->next;
|
||||
old_uc = uc;
|
||||
}
|
||||
|
||||
old_uc->next = uwsgi_malloc(sizeof(struct uwsgi_cron));
|
||||
uc = old_uc->next;
|
||||
}
|
||||
|
||||
memset(uc, 0, sizeof(struct uwsgi_cron));
|
||||
|
||||
uc->command = c_command;
|
||||
if (!uc->command) {
|
||||
uwsgi_log("[uwsgi-cron] invalid command in cron definition: %s\n", value);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// defaults
|
||||
uc->minute = -1;
|
||||
uc->hour = -1;
|
||||
uc->day = -1;
|
||||
uc->month = -1;
|
||||
uc->week = -1;
|
||||
|
||||
uc->unique = 0;
|
||||
uc->mercy = 0;
|
||||
uc->harakiri = 0;
|
||||
uc->pid = -1;
|
||||
|
||||
#ifdef UWSGI_SSL
|
||||
uc->legion = c_legion;
|
||||
#endif
|
||||
|
||||
if (c_minute)
|
||||
uc->minute = atoi(c_minute);
|
||||
|
||||
if (c_hour)
|
||||
uc->hour = atoi(c_hour);
|
||||
|
||||
if (c_day)
|
||||
uc->day = atoi(c_day);
|
||||
|
||||
if (c_month)
|
||||
uc->month = atoi(c_month);
|
||||
|
||||
if (c_week)
|
||||
uc->week = atoi(c_week);
|
||||
|
||||
if (c_unique)
|
||||
uc->unique = atoi(c_unique);
|
||||
|
||||
if (c_harakiri) {
|
||||
if (atoi(c_harakiri)) {
|
||||
// harakiri > 0
|
||||
uc->mercy = atoi(c_harakiri);
|
||||
}
|
||||
else {
|
||||
// harakiri == 0
|
||||
uc->mercy = -1;
|
||||
}
|
||||
}
|
||||
else if (uwsgi.cron_harakiri) {
|
||||
uc->harakiri = uwsgi.cron_harakiri;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_signal_add_cron(uint8_t sig, int minute, int hour, int day, int month, int week) {
|
||||
|
||||
if (!uwsgi.master_process)
|
||||
@@ -134,15 +274,16 @@ void uwsgi_manage_command_cron(time_t now) {
|
||||
#ifdef UWSGI_SSL
|
||||
// check for legion cron
|
||||
if (current_cron->legion) {
|
||||
if (!uwsgi_legion_i_am_the_lord(current_cron->legion)) {
|
||||
current_cron = current_cron->next;
|
||||
continue;
|
||||
}
|
||||
if (!uwsgi_legion_i_am_the_lord(current_cron->legion))
|
||||
goto next;
|
||||
}
|
||||
#endif
|
||||
|
||||
int run_task = uwsgi_cron_task_needs_execution(uwsgi_cron_delta, current_cron->minute, current_cron->hour, current_cron->day, current_cron->month, current_cron->week);
|
||||
// skip unique crons that are still running
|
||||
if (current_cron->unique && current_cron->pid >= 0)
|
||||
goto next;
|
||||
|
||||
int run_task = uwsgi_cron_task_needs_execution(uwsgi_cron_delta, current_cron->minute, current_cron->hour, current_cron->day, current_cron->month, current_cron->week);
|
||||
if (run_task == 1) {
|
||||
|
||||
// date match, run command ?
|
||||
@@ -153,20 +294,27 @@ void uwsgi_manage_command_cron(time_t now) {
|
||||
current_cron->func(current_cron, now);
|
||||
}
|
||||
else {
|
||||
if (uwsgi_run_command(current_cron->command, NULL, -1) >= 0) {
|
||||
uwsgi_log_verbose("[uwsgi-cron] running %s\n", current_cron->command);
|
||||
}
|
||||
pid_t pid = uwsgi_run_command(current_cron->command, NULL, -1);
|
||||
if (pid >= 0) {
|
||||
current_cron->pid = pid;
|
||||
current_cron->started_at = now;
|
||||
uwsgi_log_verbose("[uwsgi-cron] running \"%s\" (pid %d)\n", current_cron->command, current_cron->pid);
|
||||
if (current_cron->mercy) {
|
||||
//uwsgi_cron->mercy can be negative to inform master that harakiri should be disabled for this cron
|
||||
if (current_cron->mercy > 0)
|
||||
current_cron->harakiri = now + current_cron->mercy;
|
||||
}
|
||||
else if (uwsgi.cron_harakiri)
|
||||
current_cron->harakiri = now + uwsgi.cron_harakiri;
|
||||
}
|
||||
}
|
||||
}
|
||||
current_cron->last_job = now;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
next:
|
||||
current_cron = current_cron->next;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -181,6 +181,7 @@ void uwsgi_daemons_spawn_all() {
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
ud->registered = 1;
|
||||
if (ud->pidfile) {
|
||||
int checked_pid = uwsgi_check_pidfile(ud->pidfile);
|
||||
if (checked_pid <= 0) {
|
||||
@@ -194,7 +195,6 @@ void uwsgi_daemons_spawn_all() {
|
||||
else {
|
||||
uwsgi_spawn_daemon(ud);
|
||||
}
|
||||
ud->registered = 1;
|
||||
}
|
||||
ud = ud->next;
|
||||
}
|
||||
@@ -366,7 +366,7 @@ void uwsgi_opt_add_daemon(char *opt, char *value, void *none) {
|
||||
freq = atoi(comma + 1);
|
||||
}
|
||||
command = space + 1;
|
||||
if (!strcmp(opt, "smart-attach-daemon2")) {
|
||||
if (!strcmp(opt, "smart-attach-daemon2") || !strcmp(opt, "legion-smart-attach-daemon2")) {
|
||||
daemonize = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -376,7 +376,11 @@ void *event_queue_alloc(int nevents) {
|
||||
|
||||
int event_queue_interesting_fd(void *events, int id) {
|
||||
port_event_t *pe = (port_event_t *) events;
|
||||
#ifdef PORT_SOURCE_FILE
|
||||
if (pe[id].portev_source == PORT_SOURCE_FILE || pe[id].portev_source == PORT_SOURCE_TIMER) {
|
||||
#else
|
||||
if (pe[id].portev_source == PORT_SOURCE_TIMER) {
|
||||
#endif
|
||||
return (long) pe[id].portev_user;
|
||||
}
|
||||
|
||||
@@ -464,7 +468,11 @@ int event_queue_wait(int eq, int timeout, int *interesting_fd) {
|
||||
}
|
||||
|
||||
|
||||
#ifdef PORT_SOURCE_FILE
|
||||
if (pe.portev_source == PORT_SOURCE_FILE || pe.portev_source == PORT_SOURCE_TIMER) {
|
||||
#else
|
||||
if (pe.portev_source == PORT_SOURCE_TIMER) {
|
||||
#endif
|
||||
*interesting_fd = (long) pe.portev_user;
|
||||
}
|
||||
else {
|
||||
@@ -972,6 +980,7 @@ struct uwsgi_fmon *event_queue_ack_file_monitor(int eq, int id) {
|
||||
#endif
|
||||
|
||||
#ifdef UWSGI_EVENT_FILEMONITOR_USE_PORT
|
||||
#ifdef PORT_SOURCE_FILE
|
||||
int event_queue_add_file_monitor(int eq, char *filename, int *id) {
|
||||
|
||||
struct file_obj fo;
|
||||
@@ -1032,6 +1041,14 @@ struct uwsgi_fmon *event_queue_ack_file_monitor(int eq, int id) {
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
int event_queue_add_file_monitor(int eq, char *filename, int *id) {
|
||||
return -1;
|
||||
}
|
||||
struct uwsgi_fmon *event_queue_ack_file_monitor(int eq, int id) {
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -91,6 +91,7 @@ void uwsgi_ini_config(char *file, char *magic_table[]) {
|
||||
|
||||
char *section_asked = "uwsgi";
|
||||
char *colon;
|
||||
int got_section = 0;
|
||||
|
||||
|
||||
if (uwsgi_check_scheme(file)) {
|
||||
@@ -147,6 +148,7 @@ void uwsgi_ini_config(char *file, char *magic_table[]) {
|
||||
val = ini_get_key(key);
|
||||
|
||||
if (!strcmp(section, section_asked)) {
|
||||
got_section = 1;
|
||||
ini_rstrip(key);
|
||||
val = ini_lstrip(val);
|
||||
ini_rstrip(val);
|
||||
@@ -161,6 +163,10 @@ void uwsgi_ini_config(char *file, char *magic_table[]) {
|
||||
|
||||
}
|
||||
|
||||
if (!got_section) {
|
||||
uwsgi_log("*** WARNING: Can't find section \"%s\" in INI configuration file %s ***\n", section_asked, file);
|
||||
}
|
||||
|
||||
if (colon) {
|
||||
colon[0] = ':';
|
||||
}
|
||||
|
||||
+7
-1
@@ -161,6 +161,10 @@ void uwsgi_init_default() {
|
||||
|
||||
uwsgi.empty = "";
|
||||
|
||||
#ifdef __linux__
|
||||
uwsgi.cgroup_dir_mode = "0700";
|
||||
#endif
|
||||
|
||||
uwsgi.wait_read_hook = uwsgi_simple_wait_read_hook;
|
||||
uwsgi.wait_write_hook = uwsgi_simple_wait_write_hook;
|
||||
|
||||
@@ -348,7 +352,9 @@ void uwsgi_setup_workers() {
|
||||
uwsgi.shared->signal_table = uwsgi_calloc_shared(sizeof(struct uwsgi_signal_entry) * 256 * (uwsgi.numproc + 1));
|
||||
|
||||
#ifdef UWSGI_ROUTING
|
||||
uwsgi_fixup_routes();
|
||||
uwsgi_fixup_routes(uwsgi.routes);
|
||||
uwsgi_fixup_routes(uwsgi.error_routes);
|
||||
uwsgi_fixup_routes(uwsgi.final_routes);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
+10
-2
@@ -764,10 +764,18 @@ nextlock:
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_user_lock(int lock_num) {
|
||||
int uwsgi_user_lock(int lock_num) {
|
||||
if (lock_num < 0 || lock_num > uwsgi.locks) {
|
||||
return -1;
|
||||
}
|
||||
uwsgi_lock(uwsgi.user_lock[lock_num]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void uwsgi_user_unlock(int lock_num) {
|
||||
int uwsgi_user_unlock(int lock_num) {
|
||||
if (lock_num < 0 || lock_num > uwsgi.locks) {
|
||||
return -1;
|
||||
}
|
||||
uwsgi_unlock(uwsgi.user_lock[lock_num]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -485,6 +485,18 @@ int master_loop(char **argv, char **environ) {
|
||||
usl = usl->next;
|
||||
}
|
||||
uwsgi_check_touches(uwsgi.touch_exec);
|
||||
// update signal touches
|
||||
usl = uwsgi.touch_signal;
|
||||
while(usl) {
|
||||
char *space = strchr(usl->value, ' ');
|
||||
if (space) {
|
||||
*space = 0;
|
||||
usl->len = strlen(usl->value);
|
||||
usl->custom_ptr = space + 1;
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
uwsgi_check_touches(uwsgi.touch_signal);
|
||||
|
||||
// setup cheaper algos (can be stacked)
|
||||
uwsgi.cheaper_algo = uwsgi_cheaper_algo_spare;
|
||||
@@ -706,6 +718,7 @@ int master_loop(char **argv, char **environ) {
|
||||
uwsgi_master_check_gateways_deadline();
|
||||
uwsgi_master_check_mules_deadline();
|
||||
uwsgi_master_check_spoolers_deadline();
|
||||
uwsgi_master_check_crons_deadline();
|
||||
|
||||
#ifdef __linux__
|
||||
#ifdef MADV_MERGEABLE
|
||||
@@ -768,6 +781,12 @@ int master_loop(char **argv, char **environ) {
|
||||
uwsgi_log_verbose("[uwsgi-touch-exec] running %s\n", touched);
|
||||
}
|
||||
}
|
||||
touched = uwsgi_check_touches(uwsgi.touch_signal);
|
||||
if (touched) {
|
||||
uint8_t signum = atoi(touched);
|
||||
uwsgi_route_signal(signum);
|
||||
uwsgi_log_verbose("[uwsgi-touch-signal] raising %u\n", signum);
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
@@ -789,6 +808,7 @@ int master_loop(char **argv, char **environ) {
|
||||
if (uwsgi_master_check_mules_death(diedpid)) continue;
|
||||
if (uwsgi_master_check_gateways_death(diedpid)) continue;
|
||||
if (uwsgi_master_check_daemons_death(diedpid)) continue;
|
||||
if (uwsgi_master_check_cron_death(diedpid)) continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -853,6 +873,7 @@ next:
|
||||
// ok, if we are reloading or dying, just continue the master loop
|
||||
// as soon as all of the workers have pid == 0, the action (exit, or reload) is triggered
|
||||
if (uwsgi_instance_is_reloading || uwsgi_instance_is_dying) {
|
||||
if (!uwsgi.workers[thewid].cursed_at) uwsgi.workers[thewid].cursed_at = uwsgi_now();
|
||||
uwsgi_log("worker %d buried after %d seconds\n", thewid, (int) (uwsgi_now()-uwsgi.workers[thewid].cursed_at));
|
||||
uwsgi.workers[thewid].cursed_at = 0;
|
||||
continue;
|
||||
|
||||
@@ -277,3 +277,29 @@ int uwsgi_worker_is_busy(int wid) {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_master_check_cron_death(int diedpid) {
|
||||
struct uwsgi_cron *uc = uwsgi.crons;
|
||||
while (uc) {
|
||||
if (uc->pid == (pid_t) diedpid) {
|
||||
uwsgi_log("[uwsgi-cron] command \"%s\" running with pid %d exited after %d second(s)\n", uc->command, uc->pid, uwsgi_now() - uc->started_at);
|
||||
uc->pid = -1;
|
||||
uc->started_at = 0;
|
||||
return -1;
|
||||
}
|
||||
uc = uc->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void uwsgi_master_check_crons_deadline() {
|
||||
struct uwsgi_cron *uc = uwsgi.crons;
|
||||
while (uc) {
|
||||
if (uc->pid >= 0 && uc->harakiri > 0 && uc->harakiri < (time_t) uwsgi.current_time) {
|
||||
uwsgi_log("*** HARAKIRI ON CRON \"%s\" (pid: %d) ***\n", uc->command, uc->pid);
|
||||
kill(-uc->pid, SIGKILL);
|
||||
}
|
||||
uc = uc->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+78
-1
@@ -388,6 +388,12 @@ void uwsgi_reload(char **argv) {
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.alarm_thread) {
|
||||
if (i == uwsgi.alarm_thread->queue) continue;
|
||||
if (i == uwsgi.alarm_thread->pipe[0]) continue;
|
||||
if (i == uwsgi.alarm_thread->pipe[1]) continue;
|
||||
}
|
||||
|
||||
if (uwsgi.log_master) {
|
||||
if (uwsgi.original_log_fd > -1) {
|
||||
if (i == uwsgi.original_log_fd) {
|
||||
@@ -690,8 +696,17 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
|
||||
while (ud) {
|
||||
if (uwsgi_stats_object_open(us))
|
||||
goto end;
|
||||
if (uwsgi_stats_keyval_comma(us, "cmd", ud->command))
|
||||
|
||||
// allocate 2x the size of original command
|
||||
// in case we need to escape all chars
|
||||
char *cmd = uwsgi_malloc(strlen(ud->command)*2);
|
||||
escape_json(ud->command, strlen(ud->command), cmd);
|
||||
if (uwsgi_stats_keyval_comma(us, "cmd", cmd)) {
|
||||
free(cmd);
|
||||
goto end;
|
||||
}
|
||||
free(cmd);
|
||||
|
||||
if (uwsgi_stats_keylong_comma(us, "pid", (unsigned long long) (ud->pid < 0) ? 0 : ud->pid))
|
||||
goto end;
|
||||
if (uwsgi_stats_keylong(us, "respawns", (unsigned long long) ud->respawns ? 0 : ud->respawns))
|
||||
@@ -1073,6 +1088,68 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
|
||||
goto end;
|
||||
}
|
||||
|
||||
struct uwsgi_cron *ucron = uwsgi.crons;
|
||||
if (ucron) {
|
||||
if (uwsgi_stats_comma(us))
|
||||
goto end;
|
||||
if (uwsgi_stats_key(us, "crons"))
|
||||
goto end;
|
||||
if (uwsgi_stats_list_open(us))
|
||||
goto end;
|
||||
while (ucron) {
|
||||
if (uwsgi_stats_object_open(us))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keyslong_comma(us, "minute", (long long) ucron->minute))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keyslong_comma(us, "hour", (long long) ucron->hour))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keyslong_comma(us, "day", (long long) ucron->day))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keyslong_comma(us, "month", (long long) ucron->month))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keyslong_comma(us, "week", (long long) ucron->week))
|
||||
goto end;
|
||||
|
||||
char *cmd = uwsgi_malloc(strlen(ucron->command)*2);
|
||||
escape_json(ucron->command, strlen(ucron->command), cmd);
|
||||
if (uwsgi_stats_keyval_comma(us, "command", cmd)) {
|
||||
free(cmd);
|
||||
goto end;
|
||||
}
|
||||
free(cmd);
|
||||
|
||||
if (uwsgi_stats_keylong_comma(us, "unique", (unsigned long long) ucron->unique))
|
||||
goto end;
|
||||
|
||||
#ifdef UWSGI_SSL
|
||||
if (uwsgi_stats_keyval_comma(us, "legion", ucron->legion ? ucron->legion : ""))
|
||||
goto end;
|
||||
#endif
|
||||
|
||||
if (uwsgi_stats_keyslong_comma(us, "pid", (long long) ucron->pid))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keylong(us, "started_at", (unsigned long long) ucron->started_at))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_object_close(us))
|
||||
goto end;
|
||||
|
||||
ucron = ucron->next;
|
||||
if (ucron) {
|
||||
if (uwsgi_stats_comma(us))
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
if (uwsgi_stats_list_close(us))
|
||||
goto end;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_SSL
|
||||
struct uwsgi_legion *legion = NULL;
|
||||
if (uwsgi.legions) {
|
||||
|
||||
+21
-15
@@ -77,19 +77,8 @@ void uwsgi_mule(int id) {
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_mule_run();
|
||||
|
||||
if (uwsgi.mules[id - 1].patch) {
|
||||
for (i = 0; i < 256; i++) {
|
||||
if (uwsgi.p[i]->mule) {
|
||||
if (uwsgi.p[i]->mule(uwsgi.mules[id - 1].patch) == 1) {
|
||||
// never here ?
|
||||
end_me(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_mule_handler();
|
||||
}
|
||||
else if (pid > 0) {
|
||||
uwsgi.mules[id - 1].id = id;
|
||||
@@ -98,6 +87,23 @@ void uwsgi_mule(int id) {
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_mule_run() {
|
||||
int id = uwsgi.muleid;
|
||||
int i;
|
||||
if (uwsgi.mules[id - 1].patch) {
|
||||
for (i = 0; i < 256; i++) {
|
||||
if (uwsgi.p[i]->mule) {
|
||||
if (uwsgi.p[i]->mule(uwsgi.mules[id - 1].patch) == 1) {
|
||||
// never here ?
|
||||
end_me(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_mule_handler();
|
||||
}
|
||||
|
||||
int uwsgi_farm_has_mule(struct uwsgi_farm *farm, int muleid) {
|
||||
|
||||
struct uwsgi_mule_farm *umf = farm->mules;
|
||||
@@ -410,12 +416,12 @@ void uwsgi_setup_mules_and_farms() {
|
||||
uwsgi.mules = (struct uwsgi_mule *) uwsgi_calloc_shared(sizeof(struct uwsgi_mule) * uwsgi.mules_cnt);
|
||||
|
||||
create_signal_pipe(uwsgi.shared->mule_signal_pipe);
|
||||
create_signal_pipe(uwsgi.shared->mule_queue_pipe);
|
||||
create_msg_pipe(uwsgi.shared->mule_queue_pipe, uwsgi.mule_msg_size);
|
||||
|
||||
for (i = 0; i < uwsgi.mules_cnt; i++) {
|
||||
// create the socket pipe
|
||||
create_signal_pipe(uwsgi.mules[i].signal_pipe);
|
||||
create_signal_pipe(uwsgi.mules[i].queue_pipe);
|
||||
create_msg_pipe(uwsgi.mules[i].queue_pipe, uwsgi.mule_msg_size);
|
||||
|
||||
uwsgi.mules[i].id = i + 1;
|
||||
|
||||
@@ -445,7 +451,7 @@ void uwsgi_setup_mules_and_farms() {
|
||||
|
||||
// create the socket pipe
|
||||
create_signal_pipe(uwsgi.farms[i].signal_pipe);
|
||||
create_signal_pipe(uwsgi.farms[i].queue_pipe);
|
||||
create_msg_pipe(uwsgi.farms[i].queue_pipe, uwsgi.mule_msg_size);
|
||||
|
||||
char *p = strtok(mules_list, ",");
|
||||
while (p != NULL) {
|
||||
|
||||
+150
-1
@@ -58,6 +58,39 @@ static int uwsgi_offload_enqueue(struct wsgi_request *wsgi_req, struct uwsgi_off
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
pipe offload engine:
|
||||
fd -> the file descriptor to read from
|
||||
len -> amount of data to transfer
|
||||
|
||||
*/
|
||||
|
||||
static int u_offload_pipe_prepare(struct wsgi_request *wsgi_req, struct uwsgi_offload_request *uor) {
|
||||
|
||||
if (uor->fd < 0 || !uor->len) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
memory offload engine:
|
||||
buf -> pointer to the memory to transfer (memory is freed at the end)
|
||||
len -> amount of data to transfer
|
||||
|
||||
*/
|
||||
|
||||
static int u_offload_memory_prepare(struct wsgi_request *wsgi_req, struct uwsgi_offload_request *uor) {
|
||||
|
||||
if (!uor->buf || !uor->len) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
||||
transfer offload engine:
|
||||
@@ -66,7 +99,7 @@ static int uwsgi_offload_enqueue(struct wsgi_request *wsgi_req, struct uwsgi_off
|
||||
|
||||
*/
|
||||
|
||||
int u_offload_transfer_prepare(struct wsgi_request *wsgi_req, struct uwsgi_offload_request *uor) {
|
||||
static int u_offload_transfer_prepare(struct wsgi_request *wsgi_req, struct uwsgi_offload_request *uor) {
|
||||
|
||||
if (!uor->name) {
|
||||
return -1;
|
||||
@@ -240,6 +273,39 @@ struct uwsgi_thread *uwsgi_offload_thread_start() {
|
||||
return uwsgi_thread_new(uwsgi_offload_loop);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
offload memory transfer
|
||||
|
||||
uor->len -> the size of the memory chunk
|
||||
uor->buf -> the memory to transfer
|
||||
uor->written -> written bytes
|
||||
|
||||
status: none
|
||||
|
||||
*/
|
||||
|
||||
static int u_offload_memory_do(struct uwsgi_thread *ut, struct uwsgi_offload_request *uor, int fd) {
|
||||
if (fd == -1) {
|
||||
if (event_queue_add_fd_write(ut->queue, uor->s)) return -1;
|
||||
return 0;
|
||||
}
|
||||
ssize_t rlen = write(uor->s, uor->buf + uor->written, uor->len - uor->written);
|
||||
if (rlen > 0) {
|
||||
uor->written += rlen;
|
||||
if (uor->written >= uor->len) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else if (rlen < 0) {
|
||||
uwsgi_offload_retry
|
||||
uwsgi_error("u_offload_memory_do()");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
||||
the offload task starts after having acquired the file fd
|
||||
@@ -293,6 +359,71 @@ static int u_offload_sendfile_do(struct uwsgi_thread *ut, struct uwsgi_offload_r
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
pipe offloading
|
||||
status:
|
||||
0 -> waiting for data on fd
|
||||
1 -> waiting for write to s
|
||||
*/
|
||||
|
||||
static int u_offload_pipe_do(struct uwsgi_thread *ut, struct uwsgi_offload_request *uor, int fd) {
|
||||
|
||||
ssize_t rlen;
|
||||
|
||||
// setup
|
||||
if (fd == -1) {
|
||||
event_queue_add_fd_read(ut->queue, uor->fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch(uor->status) {
|
||||
// read event from fd
|
||||
case 0:
|
||||
if (!uor->buf) {
|
||||
uor->buf = uwsgi_malloc(4096);
|
||||
}
|
||||
rlen = read(uor->fd, uor->buf, 4096);
|
||||
if (rlen > 0) {
|
||||
uor->to_write = rlen;
|
||||
uor->pos = 0;
|
||||
if (event_queue_del_fd(ut->queue, uor->fd, event_queue_read())) return -1;
|
||||
if (event_queue_add_fd_write(ut->queue, uor->s)) return -1;
|
||||
uor->status = 1;
|
||||
return 0;
|
||||
}
|
||||
if (rlen < 0) {
|
||||
uwsgi_offload_retry
|
||||
uwsgi_error("u_offload_pipe_do() -> read()");
|
||||
}
|
||||
return -1;
|
||||
// write event on s
|
||||
case 1:
|
||||
rlen = write(uor->s, uor->buf + uor->pos, uor->to_write);
|
||||
if (rlen > 0) {
|
||||
uor->to_write -= rlen;
|
||||
uor->pos += rlen;
|
||||
if (uor->to_write == 0) {
|
||||
if (event_queue_del_fd(ut->queue, uor->s, event_queue_write())) return -1;
|
||||
if (event_queue_add_fd_read(ut->queue, uor->fd)) return -1;
|
||||
uor->status = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else if (rlen < 0) {
|
||||
uwsgi_offload_retry
|
||||
uwsgi_error("u_offload_pipe_do() -> write()");
|
||||
}
|
||||
return -1;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
the offload task starts soon after the call to connect()
|
||||
|
||||
@@ -490,6 +621,8 @@ struct uwsgi_offload_engine *uwsgi_offload_register_engine(char *name, int (*pre
|
||||
void uwsgi_offload_engines_register_all() {
|
||||
uwsgi.offload_engine_sendfile = uwsgi_offload_register_engine("sendfile", u_offload_sendfile_prepare, u_offload_sendfile_do);
|
||||
uwsgi.offload_engine_transfer = uwsgi_offload_register_engine("transfer", u_offload_transfer_prepare, u_offload_transfer_do);
|
||||
uwsgi.offload_engine_memory = uwsgi_offload_register_engine("memory", u_offload_memory_prepare, u_offload_memory_do);
|
||||
uwsgi.offload_engine_pipe = uwsgi_offload_register_engine("pipe", u_offload_pipe_prepare, u_offload_pipe_do);
|
||||
}
|
||||
|
||||
int uwsgi_offload_request_sendfile_do(struct wsgi_request *wsgi_req, int fd, size_t len) {
|
||||
@@ -507,3 +640,19 @@ int uwsgi_offload_request_net_do(struct wsgi_request *wsgi_req, char *socketname
|
||||
uor.ubuf = ubuf;
|
||||
return uwsgi_offload_run(wsgi_req, &uor, NULL);
|
||||
}
|
||||
|
||||
int uwsgi_offload_request_memory_do(struct wsgi_request *wsgi_req, char *buf, size_t len) {
|
||||
struct uwsgi_offload_request uor;
|
||||
uwsgi_offload_setup(uwsgi.offload_engine_memory, &uor, wsgi_req, 1);
|
||||
uor.buf = buf;
|
||||
uor.len = len;
|
||||
return uwsgi_offload_run(wsgi_req, &uor, NULL);
|
||||
}
|
||||
|
||||
int uwsgi_offload_request_pipe_do(struct wsgi_request *wsgi_req, int fd, size_t len) {
|
||||
struct uwsgi_offload_request uor;
|
||||
uwsgi_offload_setup(uwsgi.offload_engine_pipe, &uor, wsgi_req, 1);
|
||||
uor.fd = fd;
|
||||
uor.len = len;
|
||||
return uwsgi_offload_run(wsgi_req, &uor, NULL);
|
||||
}
|
||||
|
||||
+2
-2
@@ -478,9 +478,9 @@ int uwsgi_postbuffer_do_in_disk(struct wsgi_request *wsgi_req) {
|
||||
int upload_progress_fd = -1;
|
||||
char *upload_progress_filename = NULL;
|
||||
|
||||
wsgi_req->post_file = tmpfile();
|
||||
wsgi_req->post_file = uwsgi_tmpfile();
|
||||
if (!wsgi_req->post_file) {
|
||||
uwsgi_error("uwsgi_postbuffer_do_in_disk()/tmpfile()");
|
||||
uwsgi_error("uwsgi_postbuffer_do_in_disk()/uwsgi_tmpfile()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
+148
-15
@@ -166,23 +166,34 @@ static void uwsgi_routing_reset_memory(struct wsgi_request *wsgi_req, struct uws
|
||||
|
||||
}
|
||||
|
||||
int uwsgi_apply_routes_do(struct wsgi_request *wsgi_req, char *subject, uint16_t subject_len) {
|
||||
int uwsgi_apply_routes_do(struct uwsgi_route *routes, struct wsgi_request *wsgi_req, char *subject, uint16_t subject_len) {
|
||||
|
||||
struct uwsgi_route *routes = uwsgi.routes;
|
||||
int n = -1;
|
||||
|
||||
char *orig_subject = subject;
|
||||
uint16_t orig_subject_len = subject_len;
|
||||
|
||||
uint32_t *r_goto = &wsgi_req->route_goto;
|
||||
uint32_t *r_pc = &wsgi_req->route_pc;
|
||||
|
||||
if (routes == uwsgi.error_routes) {
|
||||
r_goto = &wsgi_req->error_route_goto;
|
||||
r_pc = &wsgi_req->error_route_pc;
|
||||
}
|
||||
else if (routes == uwsgi.final_routes) {
|
||||
r_goto = &wsgi_req->final_route_goto;
|
||||
r_pc = &wsgi_req->final_route_pc;
|
||||
}
|
||||
|
||||
while (routes) {
|
||||
|
||||
if (routes->label) goto next;
|
||||
|
||||
if (wsgi_req->route_goto > 0 && wsgi_req->route_pc < wsgi_req->route_goto) {
|
||||
if (*r_goto > 0 && *r_pc < *r_goto) {
|
||||
goto next;
|
||||
}
|
||||
|
||||
wsgi_req->route_goto = 0;
|
||||
*r_goto = 0;
|
||||
|
||||
if (!routes->if_func) {
|
||||
// could be a "run"
|
||||
@@ -244,7 +255,7 @@ next:
|
||||
subject = orig_subject;
|
||||
subject_len = orig_subject_len;
|
||||
routes = routes->next;
|
||||
if (routes) wsgi_req->route_pc++;
|
||||
if (routes) *r_pc = *r_pc+1;
|
||||
}
|
||||
|
||||
return UWSGI_ROUTE_CONTINUE;
|
||||
@@ -268,9 +279,34 @@ int uwsgi_apply_routes(struct wsgi_request *wsgi_req) {
|
||||
return UWSGI_ROUTE_CONTINUE;
|
||||
}
|
||||
|
||||
return uwsgi_apply_routes_do(wsgi_req, NULL, 0);
|
||||
return uwsgi_apply_routes_do(uwsgi.routes, wsgi_req, NULL, 0);
|
||||
}
|
||||
|
||||
void uwsgi_apply_final_routes(struct wsgi_request *wsgi_req) {
|
||||
|
||||
if (!uwsgi.final_routes) return;
|
||||
|
||||
// avoid loops
|
||||
if (wsgi_req->is_routing) return;
|
||||
|
||||
wsgi_req->is_final_routing = 1;
|
||||
|
||||
uwsgi_apply_routes_do(uwsgi.final_routes, wsgi_req, NULL, 0);
|
||||
}
|
||||
|
||||
int uwsgi_apply_error_routes(struct wsgi_request *wsgi_req) {
|
||||
|
||||
if (!uwsgi.error_routes) return 0;
|
||||
|
||||
// do not forget to check it !!!
|
||||
if (wsgi_req->is_error_routing) return 0;
|
||||
|
||||
wsgi_req->is_error_routing = 1;
|
||||
|
||||
return uwsgi_apply_routes_do(uwsgi.error_routes, wsgi_req, NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
static void *uwsgi_route_get_condition_func(char *name) {
|
||||
struct uwsgi_route_condition *urc = uwsgi.route_conditions;
|
||||
while(urc) {
|
||||
@@ -282,11 +318,25 @@ static void *uwsgi_route_get_condition_func(char *name) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int uwsgi_route_condition_status(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
if (wsgi_req->status == ur->if_status) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_opt_add_route(char *opt, char *value, void *foobar) {
|
||||
|
||||
char *space = NULL;
|
||||
char *command = NULL;
|
||||
struct uwsgi_route *old_ur = NULL,*ur = uwsgi.routes;
|
||||
struct uwsgi_route *old_ur = NULL, *ur = uwsgi.routes;
|
||||
if (!uwsgi_starts_with(opt, strlen(opt), "final", 5)) {
|
||||
ur = uwsgi.final_routes;
|
||||
}
|
||||
else if (!uwsgi_starts_with(opt, strlen(opt), "error", 5)) {
|
||||
ur = uwsgi.error_routes;
|
||||
}
|
||||
uint64_t pos = 0;
|
||||
while(ur) {
|
||||
old_ur = ur;
|
||||
@@ -298,7 +348,15 @@ void uwsgi_opt_add_route(char *opt, char *value, void *foobar) {
|
||||
old_ur->next = ur;
|
||||
}
|
||||
else {
|
||||
uwsgi.routes = ur;
|
||||
if (!uwsgi_starts_with(opt, strlen(opt), "final", 5)) {
|
||||
uwsgi.final_routes = ur;
|
||||
}
|
||||
else if (!uwsgi_starts_with(opt, strlen(opt), "error", 5)) {
|
||||
uwsgi.error_routes = ur;
|
||||
}
|
||||
else {
|
||||
uwsgi.routes = ur;
|
||||
}
|
||||
}
|
||||
|
||||
ur->pos = pos;
|
||||
@@ -344,6 +402,11 @@ void uwsgi_opt_add_route(char *opt, char *value, void *foobar) {
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
else if (!strcmp(foobar, "status")) {
|
||||
ur->if_status = atoi(ur->orig_route);
|
||||
foobar = ur->orig_route;
|
||||
ur->if_func = uwsgi_route_condition_status;
|
||||
}
|
||||
|
||||
else if (!strcmp(foobar, "http_host")) {
|
||||
ur->subject = offsetof(struct wsgi_request, host);
|
||||
@@ -409,8 +472,7 @@ done:
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void uwsgi_fixup_routes() {
|
||||
struct uwsgi_route *ur = uwsgi.routes;
|
||||
void uwsgi_fixup_routes(struct uwsgi_route *ur) {
|
||||
while(ur) {
|
||||
// prepare the main pointers
|
||||
ur->ovn = uwsgi_calloc(sizeof(int) * uwsgi.cores);
|
||||
@@ -496,6 +558,21 @@ static int uwsgi_router_break(struct uwsgi_route *ur, char *arg) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// harakiri router
|
||||
static int uwsgi_router_harakiri_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route) {
|
||||
if (route->custom > 0) {
|
||||
set_user_harakiri(route->custom);
|
||||
}
|
||||
return UWSGI_ROUTE_CONTINUE;
|
||||
}
|
||||
|
||||
static int uwsgi_router_harakiri(struct uwsgi_route *ur, char *arg) {
|
||||
ur->func = uwsgi_router_harakiri_func;
|
||||
ur->custom = atoi(arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// flush response
|
||||
static int transform_flush(struct wsgi_request *wsgi_req, struct uwsgi_transformation *ut) {
|
||||
// avoid loops !!!
|
||||
@@ -609,25 +686,37 @@ static int uwsgi_router_goto_func(struct wsgi_request *wsgi_req, struct uwsgi_ro
|
||||
|
||||
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len);
|
||||
if (!ub) return UWSGI_ROUTE_BREAK;
|
||||
uint32_t *r_goto = &wsgi_req->route_goto;
|
||||
uint32_t *r_pc = &wsgi_req->route_pc;
|
||||
|
||||
// find the label
|
||||
struct uwsgi_route *routes = uwsgi.routes;
|
||||
if (wsgi_req->is_error_routing) {
|
||||
routes = uwsgi.error_routes;
|
||||
r_goto = &wsgi_req->error_route_goto;
|
||||
r_pc = &wsgi_req->error_route_pc;
|
||||
}
|
||||
else if (wsgi_req->is_final_routing) {
|
||||
routes = uwsgi.final_routes;
|
||||
r_goto = &wsgi_req->final_route_goto;
|
||||
r_pc = &wsgi_req->final_route_pc;
|
||||
}
|
||||
while(routes) {
|
||||
if (!routes->label) goto next;
|
||||
if (!uwsgi_strncmp(routes->label, routes->label_len, ub->buf, ub->pos)) {
|
||||
wsgi_req->route_goto = routes->pos;
|
||||
*r_goto = routes->pos;
|
||||
goto found;
|
||||
}
|
||||
next:
|
||||
routes = routes->next;
|
||||
}
|
||||
|
||||
wsgi_req->route_goto = ur->custom;
|
||||
*r_goto = ur->custom;
|
||||
|
||||
found:
|
||||
uwsgi_buffer_destroy(ub);
|
||||
if (wsgi_req->route_goto <= wsgi_req->route_pc) {
|
||||
wsgi_req->route_goto = 0;
|
||||
if (*r_goto <= *r_pc) {
|
||||
*r_goto = 0;
|
||||
uwsgi_log("[uwsgi-route] ERROR \"goto\" instruction can only jump forward (check your label !!!)\n");
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
}
|
||||
@@ -1291,6 +1380,14 @@ static char *uwsgi_route_var_uwsgi(struct wsgi_request *wsgi_req, char *key, uin
|
||||
uwsgi_uuid(ret);
|
||||
*vallen = 36;
|
||||
}
|
||||
else if (!uwsgi_strncmp(key, keylen, "status", 6)) {
|
||||
ret = uwsgi_num2str(wsgi_req->status);
|
||||
*vallen = strlen(ret);
|
||||
}
|
||||
else if (!uwsgi_strncmp(key, keylen, "rtime", 5)) {
|
||||
ret = uwsgi_num2str(wsgi_req->end_of_request - wsgi_req->start_of_request);
|
||||
*vallen = strlen(ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1423,6 +1520,8 @@ void uwsgi_register_embedded_routers() {
|
||||
uwsgi_register_router("flush", uwsgi_router_flush);
|
||||
uwsgi_register_router("fixcl", uwsgi_router_fixcl);
|
||||
|
||||
uwsgi_register_router("harakiri", uwsgi_router_harakiri);
|
||||
|
||||
uwsgi_register_route_condition("exists", uwsgi_route_condition_exists);
|
||||
uwsgi_register_route_condition("isfile", uwsgi_route_condition_isfile);
|
||||
uwsgi_register_route_condition("isdir", uwsgi_route_condition_isdir);
|
||||
@@ -1522,7 +1621,7 @@ struct uwsgi_route_condition *uwsgi_register_route_condition(char *name, int (*f
|
||||
|
||||
void uwsgi_routing_dump() {
|
||||
struct uwsgi_route *routes = uwsgi.routes;
|
||||
if (!routes) return;
|
||||
if (!routes) goto next;
|
||||
uwsgi_log("*** dumping internal routing table ***\n");
|
||||
while(routes) {
|
||||
if (routes->label) {
|
||||
@@ -1537,5 +1636,39 @@ void uwsgi_routing_dump() {
|
||||
routes = routes->next;
|
||||
}
|
||||
uwsgi_log("*** end of the internal routing table ***\n");
|
||||
next:
|
||||
routes = uwsgi.error_routes;
|
||||
if (!routes) goto next2;
|
||||
uwsgi_log("*** dumping internal error routing table ***\n");
|
||||
while(routes) {
|
||||
if (routes->label) {
|
||||
uwsgi_log("[rule: %llu] label: %s\n", (unsigned long long ) routes->pos, routes->label);
|
||||
}
|
||||
else if (!routes->subject_str && !routes->if_func) {
|
||||
uwsgi_log("[rule: %llu] action: %s\n", (unsigned long long ) routes->pos, routes->action);
|
||||
}
|
||||
else {
|
||||
uwsgi_log("[rule: %llu] subject: %s %s: %s%s action: %s\n", (unsigned long long ) routes->pos, routes->subject_str, routes->if_func ? "func" : "regexp", routes->if_negate ? "!" : "", routes->regexp, routes->action);
|
||||
}
|
||||
routes = routes->next;
|
||||
}
|
||||
uwsgi_log("*** end of the internal error routing table ***\n");
|
||||
next2:
|
||||
routes = uwsgi.final_routes;
|
||||
if (!routes) return;
|
||||
uwsgi_log("*** dumping internal final routing table ***\n");
|
||||
while(routes) {
|
||||
if (routes->label) {
|
||||
uwsgi_log("[rule: %llu] label: %s\n", (unsigned long long ) routes->pos, routes->label);
|
||||
}
|
||||
else if (!routes->subject_str && !routes->if_func) {
|
||||
uwsgi_log("[rule: %llu] action: %s\n", (unsigned long long ) routes->pos, routes->action);
|
||||
}
|
||||
else {
|
||||
uwsgi_log("[rule: %llu] subject: %s %s: %s%s action: %s\n", (unsigned long long ) routes->pos, routes->subject_str, routes->if_func ? "func" : "regexp", routes->if_negate ? "!" : "", routes->regexp, routes->action);
|
||||
}
|
||||
routes = routes->next;
|
||||
}
|
||||
uwsgi_log("*** end of the internal final routing table ***\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -37,3 +37,39 @@ ssize_t uwsgi_sendfile_do(int sockfd, int filefd, size_t pos, size_t len) {
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
simple non blocking sendfile implementation
|
||||
(generally used as fallback)
|
||||
*/
|
||||
|
||||
int uwsgi_simple_sendfile(struct wsgi_request *wsgi_req, int fd, size_t pos, size_t len) {
|
||||
|
||||
wsgi_req->write_pos = 0;
|
||||
|
||||
for(;;) {
|
||||
int ret = wsgi_req->socket->proto_sendfile(wsgi_req, fd, pos, len);
|
||||
if (ret < 0) {
|
||||
if (!uwsgi.ignore_write_errors) {
|
||||
uwsgi_error("uwsgi_simple_sendfile()");
|
||||
}
|
||||
wsgi_req->write_errors++;
|
||||
return -1;
|
||||
}
|
||||
if (ret == UWSGI_OK) {
|
||||
break;
|
||||
}
|
||||
ret = uwsgi_wait_write_req(wsgi_req);
|
||||
if (ret < 0) {
|
||||
wsgi_req->write_errors++;
|
||||
return -1;
|
||||
}
|
||||
if (ret == 0) {
|
||||
uwsgi_log("uwsgi_simple_sendfile() TIMEOUT !!!\n");
|
||||
wsgi_req->write_errors++;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
+4
-1
@@ -99,7 +99,10 @@ int uwsgi_register_signal(uint8_t sig, char *receiver, void *handler, uint8_t mo
|
||||
|
||||
struct uwsgi_signal_entry *use = NULL;
|
||||
|
||||
if (!uwsgi.master_process) return -1;
|
||||
if (!uwsgi.master_process) {
|
||||
uwsgi_log("you cannot register signals without a master\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (uwsgi.mywid == 0 && uwsgi.workers[0].pid != uwsgi.mypid) {
|
||||
uwsgi_log("only the master and the workers can register signal handlers\n");
|
||||
|
||||
@@ -1552,6 +1552,9 @@ void uwsgi_setup_shared_sockets() {
|
||||
shared_sock->fd = bind_to_unix(shared_sock->name, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket);
|
||||
shared_sock->family = AF_UNIX;
|
||||
uwsgi_log("uwsgi shared socket %d bound to UNIX address %s fd %d\n", uwsgi_get_shared_socket_num(shared_sock), shared_sock->name, shared_sock->fd);
|
||||
if (uwsgi.chown_socket) {
|
||||
uwsgi_chown(shared_sock->name, uwsgi.chown_socket);
|
||||
}
|
||||
}
|
||||
else {
|
||||
#ifdef AF_INET6
|
||||
|
||||
+21
-15
@@ -122,21 +122,7 @@ pid_t spooler_start(struct uwsgi_spooler * uspool) {
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi.signal_socket = uwsgi.shared->spooler_signal_pipe[1];
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
if (uwsgi.p[i]->spooler_init) {
|
||||
uwsgi.p[i]->spooler_init();
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < uwsgi.gp_cnt; i++) {
|
||||
if (uwsgi.gp[i]->spooler_init) {
|
||||
uwsgi.gp[i]->spooler_init();
|
||||
}
|
||||
}
|
||||
|
||||
spooler(uspool);
|
||||
uwsgi_spooler_run();
|
||||
}
|
||||
else if (pid > 0) {
|
||||
uwsgi_log("spawned the uWSGI spooler on dir %s with pid %d\n", uspool->dir, pid);
|
||||
@@ -145,6 +131,26 @@ pid_t spooler_start(struct uwsgi_spooler * uspool) {
|
||||
return pid;
|
||||
}
|
||||
|
||||
void uwsgi_spooler_run() {
|
||||
int i;
|
||||
struct uwsgi_spooler *uspool = uwsgi.i_am_a_spooler;
|
||||
uwsgi.signal_socket = uwsgi.shared->spooler_signal_pipe[1];
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
if (uwsgi.p[i]->spooler_init) {
|
||||
uwsgi.p[i]->spooler_init();
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < uwsgi.gp_cnt; i++) {
|
||||
if (uwsgi.gp[i]->spooler_init) {
|
||||
uwsgi.gp[i]->spooler_init();
|
||||
}
|
||||
}
|
||||
|
||||
spooler(uspool);
|
||||
}
|
||||
|
||||
void destroy_spool(char *dir, char *file) {
|
||||
|
||||
if (chdir(dir)) {
|
||||
|
||||
+12
-11
@@ -2,9 +2,9 @@
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
int uwsgi_static_want_gzip(struct wsgi_request *wsgi_req, char *filename, size_t filename_len, struct stat *st) {
|
||||
int uwsgi_static_want_gzip(struct wsgi_request *wsgi_req, char *filename, size_t *filename_len, struct stat *st) {
|
||||
// check for filename size
|
||||
if (filename_len + 4 > PATH_MAX) return 0;
|
||||
if (*filename_len + 4 > PATH_MAX) return 0;
|
||||
// check for supported encodings
|
||||
if (!uwsgi_contains_n(wsgi_req->encoding, wsgi_req->encoding_len, "gzip", 4) ) return 0;
|
||||
|
||||
@@ -14,7 +14,7 @@ int uwsgi_static_want_gzip(struct wsgi_request *wsgi_req, char *filename, size_t
|
||||
// check for dirs/prefix
|
||||
struct uwsgi_string_list *usl = uwsgi.static_gzip_dir;
|
||||
while(usl) {
|
||||
if (!uwsgi_starts_with(filename, filename_len, usl->value, usl->len)) {
|
||||
if (!uwsgi_starts_with(filename, *filename_len, usl->value, usl->len)) {
|
||||
goto gzip;
|
||||
}
|
||||
usl = usl->next;
|
||||
@@ -23,7 +23,7 @@ int uwsgi_static_want_gzip(struct wsgi_request *wsgi_req, char *filename, size_t
|
||||
// check for ext/suffix
|
||||
usl = uwsgi.static_gzip_ext;
|
||||
while(usl) {
|
||||
if (!uwsgi_strncmp(filename + (filename_len - usl->len), usl->len, usl->value, usl->len)) {
|
||||
if (!uwsgi_strncmp(filename + (*filename_len - usl->len), usl->len, usl->value, usl->len)) {
|
||||
goto gzip;
|
||||
}
|
||||
usl = usl->next;
|
||||
@@ -33,7 +33,7 @@ int uwsgi_static_want_gzip(struct wsgi_request *wsgi_req, char *filename, size_t
|
||||
// check for regexp
|
||||
struct uwsgi_regexp_list *url = uwsgi.static_gzip;
|
||||
while(url) {
|
||||
if (uwsgi_regexp_match(url->pattern, url->pattern_extra, filename, filename_len) >= 0) {
|
||||
if (uwsgi_regexp_match(url->pattern, url->pattern_extra, filename, *filename_len) >= 0) {
|
||||
goto gzip;
|
||||
}
|
||||
url = url->next;
|
||||
@@ -43,12 +43,12 @@ int uwsgi_static_want_gzip(struct wsgi_request *wsgi_req, char *filename, size_t
|
||||
|
||||
gzip:
|
||||
|
||||
memcpy(filename + filename_len, ".gz\0", 4);
|
||||
filename_len += 3;
|
||||
memcpy(filename + *filename_len, ".gz\0", 4);
|
||||
*filename_len += 3;
|
||||
|
||||
if (stat(filename, st)) {
|
||||
filename_len -= 3;
|
||||
filename[filename_len] = 0;
|
||||
*filename_len -= 3;
|
||||
filename[*filename_len] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -445,7 +445,7 @@ int uwsgi_real_file_serve(struct wsgi_request *wsgi_req, char *real_filename, si
|
||||
char *mime_type = uwsgi_get_mime_type(real_filename, real_filename_len, &mime_type_size);
|
||||
|
||||
// here we need to choose if we want the gzip variant;
|
||||
if (uwsgi_static_want_gzip(wsgi_req, real_filename, real_filename_len, st)) use_gzip = 1;
|
||||
if (uwsgi_static_want_gzip(wsgi_req, real_filename, &real_filename_len, st)) use_gzip = 1;
|
||||
|
||||
if (wsgi_req->if_modified_since_len) {
|
||||
time_t ims = parse_http_date(wsgi_req->if_modified_since, wsgi_req->if_modified_since_len);
|
||||
@@ -579,6 +579,7 @@ int uwsgi_file_serve(struct wsgi_request *wsgi_req, char *document_root, uint16_
|
||||
if (item && item_len > 0 && item_len <= PATH_MAX) {
|
||||
memcpy(real_filename, item, item_len);
|
||||
real_filename_len = item_len;
|
||||
real_filename[real_filename_len] = 0;
|
||||
uwsgi_rwunlock(uwsgi.static_cache_paths->lock);
|
||||
goto found;
|
||||
}
|
||||
@@ -644,7 +645,7 @@ safe:
|
||||
|
||||
#ifdef UWSGI_ROUTING
|
||||
// before sending the file, we need to check if some rule applies
|
||||
if (!wsgi_req->is_routing && uwsgi_apply_routes_do(wsgi_req, NULL, 0) == UWSGI_ROUTE_BREAK) {
|
||||
if (!wsgi_req->is_routing && uwsgi_apply_routes_do(uwsgi.routes, wsgi_req, NULL, 0) == UWSGI_ROUTE_BREAK) {
|
||||
return 0;
|
||||
}
|
||||
wsgi_req->routes_applied = 1;
|
||||
|
||||
@@ -132,6 +132,12 @@ void uwsgi_free_transformations(struct wsgi_request *wsgi_req) {
|
||||
if (current_ut->chunk) {
|
||||
uwsgi_buffer_destroy(current_ut->chunk);
|
||||
}
|
||||
if (current_ut->ub) {
|
||||
uwsgi_buffer_destroy(current_ut->ub);
|
||||
}
|
||||
if (current_ut->fd > -1) {
|
||||
close(current_ut->fd);
|
||||
}
|
||||
ut = ut->next;
|
||||
free(current_ut);
|
||||
}
|
||||
@@ -144,12 +150,9 @@ struct uwsgi_transformation *uwsgi_add_transformation(struct wsgi_request *wsgi_
|
||||
ut = ut->next;
|
||||
}
|
||||
|
||||
ut = uwsgi_malloc(sizeof(struct uwsgi_transformation));
|
||||
ut = uwsgi_calloc(sizeof(struct uwsgi_transformation));
|
||||
ut->func = func;
|
||||
ut->is_final = 0;
|
||||
ut->next = NULL;
|
||||
ut->chunk = NULL;
|
||||
ut->can_stream = 0;
|
||||
ut->fd = -1;
|
||||
ut->data = data;
|
||||
|
||||
if (old_ut) {
|
||||
|
||||
+117
-24
@@ -206,14 +206,20 @@ void uwsgi_set_cgroup() {
|
||||
usl = uwsgi.cgroup;
|
||||
|
||||
while (usl) {
|
||||
if (mkdir(usl->value, 0700)) {
|
||||
uwsgi_log("using Linux cgroup %s\n", usl->value);
|
||||
int mode = strtol(uwsgi.cgroup_dir_mode, 0, 8);
|
||||
if (mkdir(usl->value, mode)) {
|
||||
if (errno != EEXIST) {
|
||||
uwsgi_error("mkdir()");
|
||||
exit(1);
|
||||
}
|
||||
if (chmod(usl->value, mode)) {
|
||||
uwsgi_error("chmod()");
|
||||
exit(1);
|
||||
}
|
||||
uwsgi_log("using Linux cgroup %s with mode %o\n", usl->value, mode);
|
||||
}
|
||||
else {
|
||||
uwsgi_log("created Linux cgroup %s\n", usl->value);
|
||||
uwsgi_log("created Linux cgroup %s with mode %o\n", usl->value, mode);
|
||||
}
|
||||
|
||||
cgroup_taskfile = uwsgi_concat2(usl->value, "/tasks");
|
||||
@@ -607,6 +613,20 @@ void uwsgi_close_request(struct wsgi_request *wsgi_req) {
|
||||
uwsgi.workers[uwsgi.mywid].rss_size = rss;
|
||||
}
|
||||
|
||||
if (!wsgi_req->do_not_account) {
|
||||
uwsgi.workers[0].requests++;
|
||||
uwsgi.workers[uwsgi.mywid].requests++;
|
||||
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].requests++;
|
||||
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].write_errors += wsgi_req->write_errors;
|
||||
// this is used for MAX_REQUESTS
|
||||
uwsgi.workers[uwsgi.mywid].delta_requests++;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_ROUTING
|
||||
// apply final routes after accounting
|
||||
uwsgi_apply_final_routes(wsgi_req);
|
||||
#endif
|
||||
|
||||
// close the connection with the client
|
||||
if (!wsgi_req->fd_closed) {
|
||||
// NOTE, if we close the socket before receiving eventually sent data, socket layer will send a RST
|
||||
@@ -629,15 +649,6 @@ void uwsgi_close_request(struct wsgi_request *wsgi_req) {
|
||||
free(wsgi_req->proto_parser_buf);
|
||||
}
|
||||
|
||||
if (!wsgi_req->do_not_account) {
|
||||
uwsgi.workers[0].requests++;
|
||||
uwsgi.workers[uwsgi.mywid].requests++;
|
||||
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].requests++;
|
||||
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].write_errors += wsgi_req->write_errors;
|
||||
// this is used for MAX_REQUESTS
|
||||
uwsgi.workers[uwsgi.mywid].delta_requests++;
|
||||
}
|
||||
|
||||
// after_request hook
|
||||
if (uwsgi.p[wsgi_req->uh->modifier1]->after_request)
|
||||
uwsgi.p[wsgi_req->uh->modifier1]->after_request(wsgi_req);
|
||||
@@ -1141,7 +1152,7 @@ int uwsgi_get_app_id(struct wsgi_request *wsgi_req, char *key, uint16_t key_len,
|
||||
char *app_name = key;
|
||||
uint16_t app_name_len = key_len;
|
||||
|
||||
if (!app_name && wsgi_req) {
|
||||
if (app_name_len == 0 && wsgi_req) {
|
||||
app_name = wsgi_req->appid;
|
||||
app_name_len = wsgi_req->appid_len;
|
||||
if (app_name_len == 0) {
|
||||
@@ -1203,11 +1214,7 @@ int uwsgi_get_app_id(struct wsgi_request *wsgi_req, char *key, uint16_t key_len,
|
||||
}
|
||||
}
|
||||
|
||||
if (!uwsgi.no_default_app) {
|
||||
if (free_appname) free(app_name);
|
||||
return uwsgi.default_app;
|
||||
}
|
||||
|
||||
if (free_appname) free(app_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -2225,6 +2232,7 @@ struct uwsgi_string_list *uwsgi_string_new_list(struct uwsgi_string_list **list,
|
||||
uwsgi_string->next = NULL;
|
||||
uwsgi_string->custom = 0;
|
||||
uwsgi_string->custom2 = 0;
|
||||
uwsgi_string->custom_ptr = NULL;
|
||||
|
||||
return uwsgi_string;
|
||||
}
|
||||
@@ -3057,6 +3065,36 @@ void escape_shell_arg(char *src, size_t len, char *dst) {
|
||||
*ptr++ = 0;
|
||||
}
|
||||
|
||||
void escape_json(char *src, size_t len, char *dst) {
|
||||
|
||||
size_t i;
|
||||
char *ptr = dst;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (src[i] == '\t') {
|
||||
*ptr++ = '\\';
|
||||
*ptr++ = 't';
|
||||
}
|
||||
else if (src[i] == '\n') {
|
||||
*ptr++ = '\\';
|
||||
*ptr++ = 'n';
|
||||
}
|
||||
else if (src[i] == '\r') {
|
||||
*ptr++ = '\\';
|
||||
*ptr++ = 'r';
|
||||
}
|
||||
else if (src[i] == '"') {
|
||||
*ptr++ = '\\';
|
||||
*ptr++ = '"';
|
||||
}
|
||||
else {
|
||||
*ptr++ = src[i];
|
||||
}
|
||||
}
|
||||
|
||||
*ptr++ = 0;
|
||||
}
|
||||
|
||||
void http_url_decode(char *buf, uint16_t * len, char *dst) {
|
||||
|
||||
uint16_t i;
|
||||
@@ -3213,14 +3251,22 @@ char *uwsgi_chomp(char *str) {
|
||||
return str;
|
||||
}
|
||||
|
||||
char *uwsgi_tmpname(char *base, char *id) {
|
||||
char *template = uwsgi_concat3(base, "/", id);
|
||||
if (mkstemp(template) < 0) {
|
||||
free(template);
|
||||
return NULL;
|
||||
int uwsgi_tmpfd() {
|
||||
char *tmpdir = getenv("TMPDIR");
|
||||
if (!tmpdir) {
|
||||
tmpdir = "/tmp";
|
||||
}
|
||||
char *template = uwsgi_concat2(tmpdir, "/uwsgiXXXXXX");
|
||||
int fd = mkstemp(template);
|
||||
unlink(template);
|
||||
free(template);
|
||||
return fd;
|
||||
}
|
||||
|
||||
return template;
|
||||
FILE *uwsgi_tmpfile() {
|
||||
int fd = uwsgi_tmpfd();
|
||||
if (fd < 0) return NULL;
|
||||
return fdopen(fd, "w+");
|
||||
}
|
||||
|
||||
int uwsgi_file_to_string_list(char *filename, struct uwsgi_string_list **list) {
|
||||
@@ -3939,3 +3985,50 @@ void http_url_encode(char *buf, uint16_t *len, char *dst) {
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_takeover() {
|
||||
if (uwsgi.i_am_a_spooler) {
|
||||
uwsgi_spooler_run();
|
||||
}
|
||||
else if (uwsgi.muleid) {
|
||||
uwsgi_mule_run();
|
||||
}
|
||||
else {
|
||||
uwsgi_worker_run();
|
||||
}
|
||||
}
|
||||
|
||||
// create a message pipe
|
||||
void create_msg_pipe(int *fd, int bufsize) {
|
||||
|
||||
#if defined(SOCK_SEQPACKET) && defined(__linux__)
|
||||
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fd)) {
|
||||
#else
|
||||
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, fd)) {
|
||||
#endif
|
||||
uwsgi_error("create_msg_pipe()/socketpair()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uwsgi_socket_nb(fd[0]);
|
||||
uwsgi_socket_nb(fd[1]);
|
||||
|
||||
if (bufsize) {
|
||||
if (setsockopt(fd[0], SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(int))) {
|
||||
uwsgi_error("create_msg_pipe()/setsockopt()");
|
||||
}
|
||||
if (setsockopt(fd[0], SOL_SOCKET, SO_RCVBUF, &bufsize, sizeof(int))) {
|
||||
uwsgi_error("create_msg_pipe()/setsockopt()");
|
||||
}
|
||||
|
||||
if (setsockopt(fd[1], SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(int))) {
|
||||
uwsgi_error("create_msg_pipe()/setsockopt()");
|
||||
}
|
||||
if (setsockopt(fd[1], SOL_SOCKET, SO_RCVBUF, &bufsize, sizeof(int))) {
|
||||
uwsgi_error("create_msg_pipe()/setsockopt()");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char *uwsgi_binary_path() {
|
||||
return uwsgi.binary_path ? uwsgi.binary_path : "uwsgi";
|
||||
}
|
||||
|
||||
+73
-1
@@ -206,6 +206,9 @@ static struct uwsgi_option uwsgi_base_options[] = {
|
||||
{"help", no_argument, 'h', "show this help", uwsgi_help, NULL, UWSGI_OPT_IMMEDIATE},
|
||||
{"usage", no_argument, 'h', "show this help", uwsgi_help, NULL, UWSGI_OPT_IMMEDIATE},
|
||||
|
||||
{"print-sym", required_argument, 0, "print content of the specified binary symbol", uwsgi_print_sym, NULL, UWSGI_OPT_IMMEDIATE},
|
||||
{"print-symbol", required_argument, 0, "print content of the specified binary symbol", uwsgi_print_sym, NULL, UWSGI_OPT_IMMEDIATE},
|
||||
|
||||
{"reaper", no_argument, 'r', "call waitpid(-1,...) after each request to get rid of zombies", uwsgi_opt_dyn_true, (void *) UWSGI_OPTION_REAPER, 0},
|
||||
{"max-requests", required_argument, 'R', "reload workers after the specified amount of managed requests", uwsgi_opt_set_dyn, (void *) UWSGI_OPTION_MAX_REQUESTS, 0},
|
||||
{"min-worker-lifetime", required_argument, 0, "number of seconds worker must run before being reloaded (default is 60)", uwsgi_opt_set_dyn, (void *) UWSGI_OPTION_MIN_WORKER_LIFETIME, 0},
|
||||
@@ -258,6 +261,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
|
||||
{"mule", optional_argument, 0, "add a mule", uwsgi_opt_add_mule, NULL, UWSGI_OPT_MASTER},
|
||||
{"mules", required_argument, 0, "add the specified number of mules", uwsgi_opt_add_mules, NULL, UWSGI_OPT_MASTER},
|
||||
{"farm", required_argument, 0, "add a mule farm", uwsgi_opt_add_farm, NULL, UWSGI_OPT_MASTER},
|
||||
{"mule-msg-size", optional_argument, 0, "set mule message buffer size", uwsgi_opt_set_int, &uwsgi.mule_msg_size, UWSGI_OPT_MASTER},
|
||||
|
||||
{"signal", required_argument, 0, "send a uwsgi signal to a server", uwsgi_opt_signal, NULL, UWSGI_OPT_IMMEDIATE},
|
||||
{"signal-bufsize", required_argument, 0, "set buffer size for signal queue", uwsgi_opt_set_int, &uwsgi.signal_bufsize, 0},
|
||||
@@ -345,6 +349,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
|
||||
{"touch-logrotate", required_argument, 0, "trigger logrotation if the specified file is modified/touched", uwsgi_opt_add_string_list, &uwsgi.touch_logrotate, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER},
|
||||
{"touch-logreopen", required_argument, 0, "trigger log reopen if the specified file is modified/touched", uwsgi_opt_add_string_list, &uwsgi.touch_logreopen, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER},
|
||||
{"touch-exec", required_argument, 0, "run command when the specified file is modified/touched (syntax: file command)", uwsgi_opt_add_string_list, &uwsgi.touch_exec, UWSGI_OPT_MASTER},
|
||||
{"touch-signal", required_argument, 0, "signal when the specified file is modified/touched (syntax: file signal)", uwsgi_opt_add_string_list, &uwsgi.touch_signal, UWSGI_OPT_MASTER},
|
||||
{"propagate-touch", no_argument, 0, "over-engineering option for system with flaky signal mamagement", uwsgi_opt_true, &uwsgi.propagate_touch, 0},
|
||||
{"limit-post", required_argument, 0, "limit request body", uwsgi_opt_set_64bit, &uwsgi.limit_post, 0},
|
||||
{"no-orphans", no_argument, 0, "automatically kill workers if master dies (can be dangerous for availability)", uwsgi_opt_true, &uwsgi.no_orphans, 0},
|
||||
@@ -414,7 +419,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
|
||||
{"ssl-verbose", no_argument, 0, "be verbose about SSL errors", uwsgi_opt_true, &uwsgi.ssl_verbose, 0},
|
||||
// force master, as ssl sessions caching initialize locking early
|
||||
{"ssl-sessions-use-cache", optional_argument, 0, "use uWSGI cache for ssl sessions storage", uwsgi_opt_set_str, &uwsgi.ssl_sessions_use_cache, UWSGI_OPT_MASTER},
|
||||
{"ssl-session-use-cache", no_argument, 0, "use uWSGI cache for ssl sessions storage", uwsgi_opt_true, &uwsgi.ssl_sessions_use_cache, UWSGI_OPT_MASTER},
|
||||
{"ssl-session-use-cache", optional_argument, 0, "use uWSGI cache for ssl sessions storage", uwsgi_opt_set_str, &uwsgi.ssl_sessions_use_cache, UWSGI_OPT_MASTER},
|
||||
{"ssl-sessions-timeout", required_argument, 0, "set SSL sessions timeout (default: 300 seconds)", uwsgi_opt_set_int, &uwsgi.ssl_sessions_timeout, 0},
|
||||
{"ssl-session-timeout", required_argument, 0, "set SSL sessions timeout (default: 300 seconds)", uwsgi_opt_set_int, &uwsgi.ssl_sessions_timeout, 0},
|
||||
{"sni", required_argument, 0, "add an SNI-governed SSL context", uwsgi_opt_sni, NULL, 0},
|
||||
@@ -531,6 +536,37 @@ static struct uwsgi_option uwsgi_base_options[] = {
|
||||
{"route-if", required_argument, 0, "add a route based on condition", uwsgi_opt_add_route, "if", 0},
|
||||
{"route-if-not", required_argument, 0, "add a route based on condition (negate version)", uwsgi_opt_add_route, "if-not", 0},
|
||||
{"route-run", required_argument, 0, "always run the specified route action", uwsgi_opt_add_route, "run", 0},
|
||||
|
||||
|
||||
|
||||
{"final-route", required_argument, 0, "add a final route", uwsgi_opt_add_route, "path_info", 0},
|
||||
{"final-route-status", required_argument, 0, "add a final route for the specified status", uwsgi_opt_add_route, "status", 0},
|
||||
{"final-route-host", required_argument, 0, "add a final route based on Host header", uwsgi_opt_add_route, "http_host", 0},
|
||||
{"final-route-uri", required_argument, 0, "add a final route based on REQUEST_URI", uwsgi_opt_add_route, "request_uri", 0},
|
||||
{"final-route-qs", required_argument, 0, "add a final route based on QUERY_STRING", uwsgi_opt_add_route, "query_string", 0},
|
||||
{"final-route-remote-addr", required_argument, 0, "add a final route based on REMOTE_ADDR", uwsgi_opt_add_route, "remote_addr", 0},
|
||||
{"final-route-user-agent", required_argument, 0, "add a final route based on HTTP_USER_AGENT", uwsgi_opt_add_route, "user_agent", 0},
|
||||
{"final-route-remote-user", required_argument, 0, "add a final route based on REMOTE_USER", uwsgi_opt_add_route, "remote_user", 0},
|
||||
{"final-route-referer", required_argument, 0, "add a final route based on HTTP_REFERER", uwsgi_opt_add_route, "referer", 0},
|
||||
{"final-route-label", required_argument, 0, "add a final routing label (for use with goto)", uwsgi_opt_add_route, NULL, 0},
|
||||
{"final-route-if", required_argument, 0, "add a final route based on condition", uwsgi_opt_add_route, "if", 0},
|
||||
{"final-route-if-not", required_argument, 0, "add a final route based on condition (negate version)", uwsgi_opt_add_route, "if-not", 0},
|
||||
{"final-route-run", required_argument, 0, "always run the specified final route action", uwsgi_opt_add_route, "run", 0},
|
||||
|
||||
{"error-route", required_argument, 0, "add an error route", uwsgi_opt_add_route, "path_info", 0},
|
||||
{"error-route-status", required_argument, 0, "add an error route for the specified status", uwsgi_opt_add_route, "status", 0},
|
||||
{"error-route-host", required_argument, 0, "add an error route based on Host header", uwsgi_opt_add_route, "http_host", 0},
|
||||
{"error-route-uri", required_argument, 0, "add an error route based on REQUEST_URI", uwsgi_opt_add_route, "request_uri", 0},
|
||||
{"error-route-qs", required_argument, 0, "add an error route based on QUERY_STRING", uwsgi_opt_add_route, "query_string", 0},
|
||||
{"error-route-remote-addr", required_argument, 0, "add an error route based on REMOTE_ADDR", uwsgi_opt_add_route, "remote_addr", 0},
|
||||
{"error-route-user-agent", required_argument, 0, "add an error route based on HTTP_USER_AGENT", uwsgi_opt_add_route, "user_agent", 0},
|
||||
{"error-route-remote-user", required_argument, 0, "add an error route based on REMOTE_USER", uwsgi_opt_add_route, "remote_user", 0},
|
||||
{"error-route-referer", required_argument, 0, "add an error route based on HTTP_REFERER", uwsgi_opt_add_route, "referer", 0},
|
||||
{"error-route-label", required_argument, 0, "add an error routing label (for use with goto)", uwsgi_opt_add_route, NULL, 0},
|
||||
{"error-route-if", required_argument, 0, "add an error route based on condition", uwsgi_opt_add_route, "if", 0},
|
||||
{"error-route-if-not", required_argument, 0, "add an error route based on condition (negate version)", uwsgi_opt_add_route, "if-not", 0},
|
||||
{"error-route-run", required_argument, 0, "always run the specified error route action", uwsgi_opt_add_route, "run", 0},
|
||||
|
||||
{"router-list", no_argument, 0, "list enabled routers", uwsgi_opt_true, &uwsgi.router_list, 0},
|
||||
{"routers-list", no_argument, 0, "list enabled routers", uwsgi_opt_true, &uwsgi.router_list, 0},
|
||||
#endif
|
||||
@@ -604,6 +640,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
|
||||
#ifdef __linux__
|
||||
{"cgroup", required_argument, 0, "put the processes in the specified cgroup", uwsgi_opt_add_string_list, &uwsgi.cgroup, 0},
|
||||
{"cgroup-opt", required_argument, 0, "set value in specified cgroup option", uwsgi_opt_add_string_list, &uwsgi.cgroup_opt, 0},
|
||||
{"cgroup-dir-mode", required_argument, 0, "set permission for cgroup directory (default is 700)", uwsgi_opt_set_str, &uwsgi.cgroup_dir_mode, 0},
|
||||
{"namespace", required_argument, 0, "run in a new namespace under the specified rootfs", uwsgi_opt_set_str, &uwsgi.ns, 0},
|
||||
{"namespace-keep-mount", required_argument, 0, "keep the specified mountpoint in your namespace", uwsgi_opt_add_string_list, &uwsgi.ns_keep_mount, 0},
|
||||
{"ns", required_argument, 0, "run in a new namespace under the specified rootfs", uwsgi_opt_set_str, &uwsgi.ns, 0},
|
||||
@@ -620,9 +657,14 @@ static struct uwsgi_option uwsgi_base_options[] = {
|
||||
{"zerg-server", required_argument, 0, "enable the zerg server on the specified UNIX socket", uwsgi_opt_set_str, &uwsgi.zerg_server, UWSGI_OPT_MASTER},
|
||||
|
||||
{"cron", required_argument, 0, "add a cron task", uwsgi_opt_add_cron, NULL, UWSGI_OPT_MASTER},
|
||||
{"cron2", required_argument, 0, "add a cron task (key=val syntax)", uwsgi_opt_add_cron2, NULL, UWSGI_OPT_MASTER},
|
||||
{"unique-cron", required_argument, 0, "add a unique cron task", uwsgi_opt_add_unique_cron, NULL, UWSGI_OPT_MASTER},
|
||||
{"cron-harakiri", required_argument, 0, "set the maximum time (in seconds) we wait for cron command to complete", uwsgi_opt_set_int, &uwsgi.cron_harakiri, 0},
|
||||
#ifdef UWSGI_SSL
|
||||
{"legion-cron", required_argument, 0, "add a cron task runnable only when the instance is a lord of the specified legion", uwsgi_opt_add_legion_cron, NULL, UWSGI_OPT_MASTER},
|
||||
{"cron-legion", required_argument, 0, "add a cron task runnable only when the instance is a lord of the specified legion", uwsgi_opt_add_legion_cron, NULL, UWSGI_OPT_MASTER},
|
||||
{"unique-legion-cron", required_argument, 0, "add a unique cron task runnable only when the instance is a lord of the specified legion", uwsgi_opt_add_unique_legion_cron, NULL, UWSGI_OPT_MASTER},
|
||||
{"unique-cron-legion", required_argument, 0, "add a unique cron task runnable only when the instance is a lord of the specified legion", uwsgi_opt_add_unique_legion_cron, NULL, UWSGI_OPT_MASTER},
|
||||
#endif
|
||||
{"loop", required_argument, 0, "select the uWSGI loop engine", uwsgi_opt_set_str, &uwsgi.loop, 0},
|
||||
{"loop-list", no_argument, 0, "list enabled loop engines", uwsgi_opt_true, &uwsgi.loop_list, 0},
|
||||
@@ -2790,6 +2832,16 @@ next2:
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_worker_run();
|
||||
// never here
|
||||
_exit(0);
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_worker_run() {
|
||||
|
||||
int i;
|
||||
|
||||
if (uwsgi.lazy || uwsgi.lazy_apps) {
|
||||
uwsgi_init_all_apps();
|
||||
}
|
||||
@@ -4054,3 +4106,23 @@ void uwsgi_opt_extract(char *opt, char *address, void *foobar) {
|
||||
};
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void uwsgi_print_sym(char *opt, char *symbol, void *foobar) {
|
||||
char *sym = dlsym(RTLD_DEFAULT, symbol);
|
||||
if (sym) {
|
||||
uwsgi_log("%s", sym);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
char *symbol_start = uwsgi_concat2(symbol, "_start");
|
||||
char *symbol_end = uwsgi_concat2(symbol, "_end");
|
||||
|
||||
char *sym_s = dlsym(RTLD_DEFAULT, symbol_start);
|
||||
char *sym_e = dlsym(RTLD_DEFAULT, symbol_end);
|
||||
|
||||
if (sym_s && sym_e) {
|
||||
uwsgi_log("%.*s", sym_e - sym_s, sym_s);
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
+54
-3
@@ -76,7 +76,19 @@ int uwsgi_response_prepare_headers(struct wsgi_request *wsgi_req, char *status,
|
||||
|
||||
// reset the buffer (could be useful for rollbacks...)
|
||||
wsgi_req->headers->pos = 0;
|
||||
// reset headers count
|
||||
wsgi_req->header_cnt = 0;
|
||||
struct uwsgi_buffer *hh = NULL;
|
||||
wsgi_req->status = uwsgi_str3_num(status);
|
||||
#ifdef UWSGI_ROUTING
|
||||
// apply error routes
|
||||
if (uwsgi_apply_error_routes(wsgi_req) == UWSGI_ROUTE_BREAK) {
|
||||
// from now on ignore write body requests...
|
||||
wsgi_req->ignore_body = 1;
|
||||
return -1;
|
||||
}
|
||||
wsgi_req->is_error_routing = 0;
|
||||
#endif
|
||||
if (status_len <= 4) {
|
||||
char *new_sc = NULL;
|
||||
size_t new_sc_len = 0;
|
||||
@@ -99,7 +111,6 @@ int uwsgi_response_prepare_headers(struct wsgi_request *wsgi_req, char *status,
|
||||
if (!hh) {wsgi_req->write_errors++; return -1;}
|
||||
if (uwsgi_buffer_append(wsgi_req->headers, hh->buf, hh->pos)) goto error;
|
||||
uwsgi_buffer_destroy(hh);
|
||||
wsgi_req->status = uwsgi_str3_num(status);
|
||||
return 0;
|
||||
error:
|
||||
uwsgi_buffer_destroy(hh);
|
||||
@@ -208,6 +219,7 @@ int uwsgi_response_write_headers_do(struct wsgi_request *wsgi_req) {
|
||||
int uwsgi_response_write_body_do(struct wsgi_request *wsgi_req, char *buf, size_t len) {
|
||||
|
||||
if (wsgi_req->write_errors) return -1;
|
||||
if (wsgi_req->ignore_body) return UWSGI_OK;
|
||||
|
||||
// if the transformation chain returns 1, we are in buffering mode
|
||||
if (wsgi_req->transformed_chunk_len == 0 && wsgi_req->transformations) {
|
||||
@@ -270,8 +282,10 @@ sendbody:
|
||||
}
|
||||
|
||||
int uwsgi_response_sendfile_do(struct wsgi_request *wsgi_req, int fd, size_t pos, size_t len) {
|
||||
return uwsgi_response_sendfile_do_can_close(wsgi_req, fd, pos, len, 1);
|
||||
}
|
||||
|
||||
int can_close = 1;
|
||||
int uwsgi_response_sendfile_do_can_close(struct wsgi_request *wsgi_req, int fd, size_t pos, size_t len, int can_close) {
|
||||
|
||||
if (fd == wsgi_req->sendfile_fd) can_close = 0;
|
||||
|
||||
@@ -280,6 +294,11 @@ int uwsgi_response_sendfile_do(struct wsgi_request *wsgi_req, int fd, size_t pos
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (wsgi_req->ignore_body) {
|
||||
if (can_close) close(fd);
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
if (!wsgi_req->headers_sent) {
|
||||
int ret = uwsgi_response_write_headers_do(wsgi_req);
|
||||
if (ret == UWSGI_OK) goto sendfile;
|
||||
@@ -294,7 +313,7 @@ sendfile:
|
||||
if (len == 0) {
|
||||
struct stat st;
|
||||
if (fstat(fd, &st)) {
|
||||
uwsgi_error("fstat()");
|
||||
uwsgi_error("uwsgi_response_sendfile_do()/fstat()");
|
||||
wsgi_req->write_errors++;
|
||||
if (can_close) close(fd);
|
||||
return -1;
|
||||
@@ -389,3 +408,35 @@ int uwsgi_simple_wait_write_hook(int fd, int timeout) {
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
simplified write to client
|
||||
(generally used as fallback)
|
||||
*/
|
||||
int uwsgi_simple_write(struct wsgi_request *wsgi_req, char *buf, size_t len) {
|
||||
|
||||
wsgi_req->write_pos = 0;
|
||||
|
||||
for(;;) {
|
||||
int ret = wsgi_req->socket->proto_write(wsgi_req, buf, len);
|
||||
if (ret < 0) {
|
||||
if (!uwsgi.ignore_write_errors) {
|
||||
uwsgi_error("uwsgi_simple_write()");
|
||||
}
|
||||
wsgi_req->write_errors++;
|
||||
return -1;
|
||||
}
|
||||
if (ret == UWSGI_OK) {
|
||||
break;
|
||||
}
|
||||
ret = uwsgi_wait_write_req(wsgi_req);
|
||||
if (ret < 0) { wsgi_req->write_errors++; return -1;}
|
||||
if (ret == 0) {
|
||||
uwsgi_log("uwsgi_simple_write() TIMEOUT !!!\n");
|
||||
wsgi_req->write_errors++;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ struct uwsgi_airbrake_config {
|
||||
int first;
|
||||
char *arg;
|
||||
char *apikey;
|
||||
char *env;
|
||||
};
|
||||
|
||||
struct uwsgi_airbrake_opt {
|
||||
@@ -28,9 +29,14 @@ static void uwsgi_airbrake_set_apikey(CURL *curl, CURLoption option, char *arg,
|
||||
uacc->apikey = arg;
|
||||
}
|
||||
|
||||
static void uwsgi_airbrake_set_env(CURL *curl, CURLoption option, char *arg, struct uwsgi_airbrake_config *uacc) {
|
||||
uacc->env = arg;
|
||||
}
|
||||
|
||||
static struct uwsgi_airbrake_opt uaco[] = {
|
||||
{"url", CURLOPT_URL, NULL},
|
||||
{"apikey", 0, uwsgi_airbrake_set_apikey},
|
||||
{"env", 0, uwsgi_airbrake_set_env},
|
||||
{"ssl", CURLOPT_USE_SSL, uwsgi_airbrake_ssl},
|
||||
{"timeout", CURLOPT_TIMEOUT, uwsgi_airbrake_int},
|
||||
{"conn_timeout", CURLOPT_CONNECTTIMEOUT, uwsgi_airbrake_int},
|
||||
@@ -65,78 +71,89 @@ end:
|
||||
*equal = '=';
|
||||
}
|
||||
|
||||
static size_t uwsgi_airbrake_read_callback(void *ptr, size_t size, size_t nmemb, void *userp) {
|
||||
struct uwsgi_thread *ut = (struct uwsgi_thread *) userp;
|
||||
size_t full_size = size * nmemb;
|
||||
size_t remains = ut->len - ut->pos;
|
||||
char *uwsgi_format_airbrake_backtrace(struct uwsgi_thread *ut) {
|
||||
|
||||
if (remains == 0) return 0;
|
||||
|
||||
if (ut->custom0 == 0) {
|
||||
size_t newline = 0;
|
||||
size_t required = 1;
|
||||
char *addr = ptr;
|
||||
if (required > full_size) goto skip;
|
||||
|
||||
skip:
|
||||
if (newline > 0) {
|
||||
*addr = '\n';
|
||||
}
|
||||
ut->custom0 = 1;
|
||||
return required;
|
||||
}
|
||||
|
||||
if (full_size < remains) {
|
||||
remains = full_size;
|
||||
}
|
||||
|
||||
memcpy(ptr, ut->buf + ut->pos, remains);
|
||||
ut->pos += remains;
|
||||
|
||||
return remains;
|
||||
}
|
||||
|
||||
static void uwsgi_format_airbrake_backtrace(struct uwsgi_thread *ut, char *apikey) {
|
||||
struct uwsgi_airbrake_config *uacc = (struct uwsgi_airbrake_config *) ut->data;
|
||||
|
||||
xmlChar *xmlbuff;
|
||||
int buffersize;
|
||||
xmlDocPtr doc = NULL;
|
||||
xmlNodePtr notice_node = NULL, node = NULL, line_node = NULL, errnode = NULL;
|
||||
char *msg = uwsgi_str("uWSGI segfault");
|
||||
char *msg = NULL;
|
||||
|
||||
doc = xmlNewDoc(BAD_CAST "1.0");
|
||||
notice_node = xmlNewNode(NULL, BAD_CAST "notice");
|
||||
xmlNewProp(notice_node, BAD_CAST "version", BAD_CAST "2.3");
|
||||
xmlDocSetRootElement(doc, notice_node);
|
||||
|
||||
xmlNewChild(notice_node, NULL, BAD_CAST "api-key", BAD_CAST apikey);
|
||||
xmlNewChild(notice_node, NULL, BAD_CAST "api-key", BAD_CAST uacc->apikey);
|
||||
|
||||
node = xmlNewChild(notice_node, NULL, BAD_CAST "notifier", NULL);
|
||||
xmlNewChild(node, NULL, BAD_CAST "name", BAD_CAST "uWSGI");
|
||||
xmlNewChild(node, NULL, BAD_CAST "version", BAD_CAST UWSGI_VERSION);
|
||||
xmlNewChild(node, NULL, BAD_CAST "url", BAD_CAST "https://github.com/unbit/uwsgi");
|
||||
|
||||
// request env
|
||||
node = xmlNewChild(notice_node, NULL, BAD_CAST "request", NULL);
|
||||
node = xmlNewChild(node, NULL, BAD_CAST "cgi-data", NULL);
|
||||
|
||||
line_node = xmlNewChild(node, NULL, BAD_CAST "var", BAD_CAST UWSGI_VERSION);
|
||||
xmlNewProp(line_node, BAD_CAST "key", BAD_CAST "uwsgi_version");
|
||||
|
||||
line_node = xmlNewChild(node, NULL, BAD_CAST "var", BAD_CAST __VERSION__);
|
||||
xmlNewProp(line_node, BAD_CAST "key", BAD_CAST "compiled_with_version");
|
||||
|
||||
struct utsname uuts;
|
||||
#ifdef __sun__
|
||||
if (uname(&uuts) < 0) {
|
||||
#else
|
||||
if (uname(&uuts)) {
|
||||
#endif
|
||||
uwsgi_error("uname()");
|
||||
}
|
||||
else {
|
||||
line_node = xmlNewChild(node, NULL, BAD_CAST "var", BAD_CAST uuts.sysname);
|
||||
xmlNewProp(line_node, BAD_CAST "key", BAD_CAST "os_sysname");
|
||||
|
||||
char *os_version = uwsgi_concat3(uuts.release, "-", uuts.version);
|
||||
line_node = xmlNewChild(node, NULL, BAD_CAST "var", BAD_CAST os_version);
|
||||
xmlNewProp(line_node, BAD_CAST "key", BAD_CAST "os_version");
|
||||
free(os_version);
|
||||
|
||||
line_node = xmlNewChild(node, NULL, BAD_CAST "var", BAD_CAST uuts.machine);
|
||||
xmlNewProp(line_node, BAD_CAST "key", BAD_CAST "machine");
|
||||
|
||||
line_node = xmlNewChild(node, NULL, BAD_CAST "var", BAD_CAST uuts.nodename);
|
||||
xmlNewProp(line_node, BAD_CAST "key", BAD_CAST "nodename");
|
||||
|
||||
}
|
||||
// end request env
|
||||
|
||||
node = xmlNewChild(notice_node, NULL, BAD_CAST "server-environment", NULL);
|
||||
xmlNewChild(node, NULL, BAD_CAST "app-version", BAD_CAST UWSGI_VERSION);
|
||||
if (uacc->env) {
|
||||
xmlNewChild(node, NULL, BAD_CAST "environment-name", BAD_CAST uacc->env);
|
||||
}
|
||||
else {
|
||||
xmlNewChild(node, NULL, BAD_CAST "environment-name", BAD_CAST UWSGI_VERSION);
|
||||
}
|
||||
|
||||
errnode = xmlNewChild(notice_node, NULL, BAD_CAST "error", NULL);
|
||||
xmlNewChild(errnode, NULL, BAD_CAST "class", BAD_CAST "RuntimeError");
|
||||
node = xmlNewChild(errnode, NULL, BAD_CAST "backtrace", NULL);
|
||||
|
||||
char *p = strtok(ut->buf, "\n");
|
||||
int i = 0;
|
||||
char *ctx = NULL;
|
||||
char *text = uwsgi_str(ut->buf);
|
||||
char *p = strtok_r(text, "\n", &ctx);
|
||||
while (p) {
|
||||
// skip log messages
|
||||
if (!uwsgi_startswith(p, "***", 3))
|
||||
goto next;
|
||||
i++;
|
||||
// skip last 2 backtrace lines, real bt starts after them
|
||||
if (i <= 2) {
|
||||
goto next;
|
||||
}
|
||||
// backtrace line looks like this: uwsgi(simple_loop_run+0xc5) [0x451555]
|
||||
// we take binary/lib as filename
|
||||
// and extract method name from remaining string
|
||||
char *n = strchr(p, '(');
|
||||
if (n) {
|
||||
line_node = xmlNewChild(node, NULL, BAD_CAST "line", NULL);
|
||||
*n = 0;
|
||||
|
||||
char *pls = strchr(n+1, '+');
|
||||
@@ -144,8 +161,15 @@ static void uwsgi_format_airbrake_backtrace(struct uwsgi_thread *ut, char *apike
|
||||
*pls = 0;
|
||||
}
|
||||
|
||||
if (i == 3) {
|
||||
free(msg);
|
||||
if (!strcmp("uwsgi_backtrace", n+1) || !strcmp("what_i_am_doing", n+1)) {
|
||||
goto next;
|
||||
}
|
||||
else if (!strcmp("uwsgi_fpe", n+1)) {
|
||||
msg = uwsgi_concat4("uWSGI FPE at ", n+1, " in ", p);
|
||||
goto next;
|
||||
}
|
||||
|
||||
if (!msg) {
|
||||
if (strlen(n+1)) {
|
||||
msg = uwsgi_concat4("uWSGI segfault at ", n+1, " in ", p);
|
||||
}
|
||||
@@ -155,6 +179,12 @@ static void uwsgi_format_airbrake_backtrace(struct uwsgi_thread *ut, char *apike
|
||||
}
|
||||
}
|
||||
|
||||
// skip empty lines
|
||||
if (!p)
|
||||
goto next;
|
||||
|
||||
line_node = xmlNewChild(node, NULL, BAD_CAST "line", NULL);
|
||||
|
||||
if ((n+1)[0] == ')') {
|
||||
xmlNewProp(line_node, BAD_CAST "method", BAD_CAST "()");
|
||||
}
|
||||
@@ -164,28 +194,23 @@ static void uwsgi_format_airbrake_backtrace(struct uwsgi_thread *ut, char *apike
|
||||
|
||||
xmlNewProp(line_node, BAD_CAST "file", BAD_CAST p);
|
||||
|
||||
xmlNewProp(line_node, BAD_CAST "number", BAD_CAST "0");
|
||||
//xmlNewProp(line_node, BAD_CAST "number", BAD_CAST "0");
|
||||
}
|
||||
next:
|
||||
p = strtok(NULL, "\n");
|
||||
p = strtok_r(NULL, "\n", &ctx);
|
||||
}
|
||||
|
||||
xmlNewChild(errnode, NULL, BAD_CAST "message", BAD_CAST msg);
|
||||
|
||||
node = xmlNewChild(notice_node, NULL, BAD_CAST "server-environment", NULL);
|
||||
xmlNewChild(node, NULL, BAD_CAST "environment-name", BAD_CAST UWSGI_VERSION);
|
||||
xmlNewChild(node, NULL, BAD_CAST "app-version", BAD_CAST UWSGI_VERSION);
|
||||
|
||||
xmlDocDumpFormatMemory(doc, &xmlbuff, &buffersize, 1);
|
||||
|
||||
xmlFreeDoc(doc);
|
||||
xmlCleanupParser();
|
||||
xmlMemoryDump();
|
||||
|
||||
free(ut->buf);
|
||||
free(msg);
|
||||
ut->buf = (char *) xmlbuff;
|
||||
ut->len = strlen(ut->buf);
|
||||
free(text);
|
||||
|
||||
return (char *) xmlbuff;
|
||||
}
|
||||
|
||||
|
||||
@@ -199,7 +224,7 @@ static void uwsgi_airbrake_loop(struct uwsgi_thread *ut) {
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
|
||||
curl_easy_setopt(curl, CURLOPT_TIMEOUT, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
|
||||
curl_easy_setopt(curl, CURLOPT_READFUNCTION, uwsgi_airbrake_read_callback);
|
||||
curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
|
||||
curl_easy_setopt(curl, CURLOPT_READDATA, ut);
|
||||
curl_easy_setopt(curl, CURLOPT_POST, 1L);
|
||||
struct curl_slist *expect = NULL; expect = curl_slist_append(expect, "Expect:");
|
||||
@@ -218,7 +243,8 @@ static void uwsgi_airbrake_loop(struct uwsgi_thread *ut) {
|
||||
|
||||
for(;;) {
|
||||
int ret = event_queue_wait(ut->queue, -1, &interesting_fd);
|
||||
if (ret <= 0) continue;
|
||||
if (ret < 0) return;
|
||||
if (ret == 0) continue;
|
||||
if (interesting_fd != ut->pipe[1]) continue;
|
||||
ssize_t rlen = read(ut->pipe[1], ut->buf, uwsgi.log_master_bufsize);
|
||||
if (rlen <= 0) continue;
|
||||
@@ -226,19 +252,20 @@ static void uwsgi_airbrake_loop(struct uwsgi_thread *ut) {
|
||||
ut->len = (size_t) rlen;
|
||||
ut->custom0 = 0;
|
||||
|
||||
uwsgi_format_airbrake_backtrace(ut, uacc->apikey);
|
||||
char *notice = uwsgi_format_airbrake_backtrace(ut);
|
||||
|
||||
curl_slist_append(expect, "Accept: */*");
|
||||
curl_slist_append(expect, "Content-Type: text/xml; charset=utf-8");
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, expect);
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, ut->buf);
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, ut->len);
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, notice);
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, strlen(notice));
|
||||
|
||||
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));
|
||||
}
|
||||
free(notice);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "../../uwsgi.h"
|
||||
#include <uwsgi.h>
|
||||
#include <curl/curl.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
@@ -168,7 +168,8 @@ static void uwsgi_alarm_curl_loop(struct uwsgi_thread *ut) {
|
||||
|
||||
for(;;) {
|
||||
int ret = event_queue_wait(ut->queue, -1, &interesting_fd);
|
||||
if (ret <= 0) continue;
|
||||
if (ret < 0) return;
|
||||
if (ret == 0) continue;
|
||||
if (interesting_fd != ut->pipe[1]) continue;
|
||||
ssize_t rlen = read(ut->pipe[1], ut->buf, uwsgi.log_master_bufsize);
|
||||
if (rlen <= 0) continue;
|
||||
|
||||
@@ -214,7 +214,7 @@ static int uwsgi_cgi_parse(struct wsgi_request *wsgi_req, char *buf, size_t len)
|
||||
// "Status: NNN"
|
||||
if (header_size >= 11) {
|
||||
if (!strncasecmp("Status: ", key, 8)) {
|
||||
uwsgi_response_prepare_headers(wsgi_req, key+8, header_size - 8);
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, key+8, header_size - 8)) return -1;
|
||||
status_sent = 1;
|
||||
key = NULL;
|
||||
value = NULL;
|
||||
@@ -229,13 +229,13 @@ static int uwsgi_cgi_parse(struct wsgi_request *wsgi_req, char *buf, size_t len)
|
||||
// Location: X
|
||||
if (header_size >= 11) {
|
||||
if (!strncasecmp("Location: ", key, 10)) {
|
||||
uwsgi_response_prepare_headers(wsgi_req, "302 Found", 9);
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, "302 Found", 9)) return -1;
|
||||
status_sent = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (status_sent == 0) {
|
||||
uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6);
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) return -1;
|
||||
status_sent = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,10 +44,6 @@ struct corerouter_peer *uwsgi_cr_peer_add(struct corerouter_session *cs) {
|
||||
peers->in = uwsgi_buffer_new(uwsgi.page_size);
|
||||
// add timeout
|
||||
peers->timeout = cr_add_timeout(cs->corerouter, peers);
|
||||
// check retry
|
||||
if (cs->retry) {
|
||||
peers->can_retry = 1;
|
||||
}
|
||||
peers->prev = old_peers;
|
||||
|
||||
if (old_peers) {
|
||||
|
||||
@@ -453,7 +453,8 @@ static int amqp_wait_connection_tune(int fd) {
|
||||
static char *amqp_simple_get_frame(int fd, struct amqp_frame_header *fh) {
|
||||
|
||||
char *ptr = (char *) fh;
|
||||
ssize_t len = 0, rlen;
|
||||
size_t len = 0;
|
||||
ssize_t rlen;
|
||||
|
||||
while(len < 7) {
|
||||
rlen = recv(fd, ptr, 7-len, 0);
|
||||
|
||||
@@ -172,6 +172,9 @@ static ssize_t fr_instance_connected(struct corerouter_peer *peer) {
|
||||
|
||||
cr_peer_connected(peer, "fr_instance_connected()");
|
||||
|
||||
// we are connected, we cannot retry anymore
|
||||
peer->can_retry = 0;
|
||||
|
||||
// fix modifiers
|
||||
peer->in->buf[0] = peer->session->main_peer->modifier1;
|
||||
peer->in->buf[3] = peer->session->main_peer->modifier2;
|
||||
@@ -217,6 +220,8 @@ static ssize_t fr_recv_uwsgi_vars(struct corerouter_peer *main_peer) {
|
||||
if (new_peer->instance_address_len == 0)
|
||||
return -1;
|
||||
|
||||
new_peer->can_retry = 1;
|
||||
|
||||
cr_connect(new_peer, fr_instance_connected);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,196 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
/*
|
||||
|
||||
Soon before official Go 1.1, we understand supporting Go in a fork() heavy
|
||||
environment was not blessed by the Go community.
|
||||
|
||||
Instead of completely dropping support for Go, we studied how the gccgo project works and we
|
||||
decided it was a better approach for uWSGI.
|
||||
|
||||
This new plugin works by initializing a new "go runtime" after each fork().
|
||||
|
||||
The runtime calls the Go main function (developed by the user), and pass the whole
|
||||
uWSGI control to it.
|
||||
|
||||
the uwsgi.Run() go function directly calls the uwsgi_takeover() function (it automatically
|
||||
manages mules, spoolers and workers)
|
||||
|
||||
As well as before each core maps to a goroutine mapped to a real pthread. (goroutines called
|
||||
from your apps are native goroutines)
|
||||
|
||||
*/
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
struct uwsgi_plugin gccgo_plugin;
|
||||
|
||||
struct uwsgi_gccgo{
|
||||
struct uwsgi_string_list *libs;
|
||||
char *args;
|
||||
} ugccgo;
|
||||
|
||||
/*
|
||||
static void uwsgi_opt_setup_goroutines(char *opt, char *value, void *foobar) {
|
||||
// set async mode
|
||||
uwsgi_opt_set_int(opt, value, &uwsgi.async);
|
||||
// set loop engine
|
||||
uwsgi.loop = "goroutines";
|
||||
}
|
||||
*/
|
||||
|
||||
struct uwsgi_option uwsgi_gccgo_options[] = {
|
||||
{"go-load", required_argument, 0, "load a go shared library in the process address space, eventually patching main.main and __go_init_main", uwsgi_opt_add_string_list, &ugccgo.libs, 0},
|
||||
{"gccgo-load", required_argument, 0, "load a go shared library in the process address space, eventually patching main.main and __go_init_main", uwsgi_opt_add_string_list, &ugccgo.libs, 0},
|
||||
{"go-args", required_argument, 0, "set go commandline arguments", uwsgi_opt_set_str, &ugccgo.args, 0},
|
||||
{"gccgo-args", required_argument, 0, "set go commandline arguments", uwsgi_opt_set_str, &ugccgo.args, 0},
|
||||
// {"goroutines", required_argument, 0, "a shortcut setting optimal options for goroutine-based apps, takes the number of goroutines to spawn as argument", uwsgi_opt_setup_goroutines, NULL, UWSGI_OPT_THREADS},
|
||||
{0, 0, 0, 0, 0, 0, 0},
|
||||
|
||||
};
|
||||
|
||||
// no_split_stack is the key to avoid crashing !!!
|
||||
void* runtime_m(void) __attribute__ ((noinline, no_split_stack));
|
||||
|
||||
void runtime_check(void);
|
||||
void runtime_args(int, char **);
|
||||
void runtime_osinit(void);
|
||||
void runtime_schedinit(void);
|
||||
void *__go_go(void *, void *);
|
||||
void runtime_main(void);
|
||||
void runtime_mstart(void *);
|
||||
|
||||
extern void uwsgigo_request(void *, void *) __asm__ ("go.uwsgi.RequestHandler");
|
||||
extern void* uwsgigo_env(void *) __asm__ ("go.uwsgi.Env");
|
||||
extern void* uwsgigo_env_add(void *, void *, uint16_t, void *, uint16_t) __asm__ ("go.uwsgi.EnvAdd");
|
||||
extern void uwsgigo_run_core(int) __asm__ ("go.uwsgi.RunCore");
|
||||
extern void uwsgigo_signal_handler(void *, uint8_t) __asm__ ("go.uwsgi.SignalHandler");
|
||||
//extern void uwsgigo_loop(void) __asm__ ("go.uwsgi.Loop");
|
||||
|
||||
static void mainstart(void *arg __attribute__((unused))) {
|
||||
runtime_main();
|
||||
}
|
||||
|
||||
void uwsgigo_main_main(void) __asm__ ("main.main");
|
||||
void uwsgigo_main_init(void) __asm__ ("__go_init_main");
|
||||
|
||||
void (*uwsgigo_hook_init)(void);
|
||||
void (*uwsgigo_hook_main)(void);
|
||||
|
||||
void uwsgigo_main_init(void) {
|
||||
uwsgigo_hook_init();
|
||||
}
|
||||
|
||||
void uwsgigo_main_main(void) {
|
||||
uwsgigo_hook_main();
|
||||
}
|
||||
|
||||
int uwsgi_gccgo_helper_request_body_read(struct wsgi_request *wsgi_req, char *p, uint64_t len) {
|
||||
ssize_t rlen = 0;
|
||||
char *buf = uwsgi_request_body_read(wsgi_req, len, &rlen);
|
||||
if (buf == uwsgi.empty) {
|
||||
return 0;
|
||||
}
|
||||
else if (buf == NULL) {
|
||||
return -1;
|
||||
}
|
||||
memcpy(p, buf, rlen);
|
||||
return (int) rlen;
|
||||
}
|
||||
|
||||
int uwsgi_gccgo_helper_register_signal(uint8_t signum, char *receiver, void *handler) {
|
||||
return uwsgi_register_signal(signum, receiver, handler, gccgo_plugin.modifier1);
|
||||
}
|
||||
|
||||
static void uwsgi_gccgo_initialize() {
|
||||
struct uwsgi_string_list *usl = ugccgo.libs;
|
||||
while(usl) {
|
||||
void *handle = dlopen(usl->value, RTLD_NOW | RTLD_GLOBAL);
|
||||
if (!handle) {
|
||||
uwsgi_log("unable to open go shared library: %s\n", dlerror());
|
||||
exit(1);
|
||||
}
|
||||
uwsgi_log("[uwsgi-gccgo] loaded %s\n", usl->value);
|
||||
uwsgigo_hook_init = dlsym(handle, "__go_init_main");
|
||||
uwsgigo_hook_main = dlsym(handle, "main.main");
|
||||
usl = usl->next;
|
||||
}
|
||||
|
||||
if (!uwsgigo_hook_init || !uwsgigo_hook_main) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Go runtime initialization
|
||||
int argc = 0;
|
||||
if (ugccgo.args) {
|
||||
char *argv_list = uwsgi_str(ugccgo.args);
|
||||
char *p = strtok(argv_list, " ");
|
||||
while(p) {
|
||||
argc++;
|
||||
p = strtok(NULL, " ");
|
||||
}
|
||||
free(argv_list);
|
||||
}
|
||||
runtime_check();
|
||||
if (argc > 0) {
|
||||
char **argv = uwsgi_calloc(sizeof(char *) * (argc + 1));
|
||||
char *argv_list = uwsgi_str(ugccgo.args);
|
||||
char *p = strtok(argv_list, " ");
|
||||
int n = 0;
|
||||
while(p) {
|
||||
argv[n] = p;
|
||||
n++;
|
||||
p = strtok(NULL, " ");
|
||||
}
|
||||
runtime_args(argc, argv);
|
||||
}
|
||||
else {
|
||||
char *argv[2] = {0,0};
|
||||
runtime_args(0, argv);
|
||||
}
|
||||
runtime_osinit();
|
||||
runtime_schedinit();
|
||||
__go_go(mainstart, NULL);
|
||||
runtime_mstart(runtime_m());
|
||||
// never here
|
||||
}
|
||||
|
||||
static int uwsgi_gccgo_request(struct wsgi_request *wsgi_req) {
|
||||
/* Standard GO request */
|
||||
if (!wsgi_req->uh->pktsize) {
|
||||
uwsgi_log("Empty GO request. skip.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (uwsgi_parse_vars(wsgi_req)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
wsgi_req->async_environ = uwsgigo_env(wsgi_req);
|
||||
int i;
|
||||
for(i=0;i<wsgi_req->var_cnt;i++) {
|
||||
uwsgigo_env_add(wsgi_req->async_environ, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len, wsgi_req->hvec[i+1].iov_base, wsgi_req->hvec[i+1].iov_len);
|
||||
i++;
|
||||
}
|
||||
uwsgigo_request(wsgi_req->async_environ, wsgi_req);
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
static void uwsgi_gccgo_after_request(struct wsgi_request *wsgi_req) {
|
||||
log_request(wsgi_req);
|
||||
}
|
||||
|
||||
static int uwsgi_gccgo_signal_handler(uint8_t signum, void *handler) {
|
||||
uwsgigo_signal_handler(handler, signum);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct uwsgi_plugin gccgo_plugin = {
|
||||
.name = "gccgo",
|
||||
.modifier1 = 11,
|
||||
.options = uwsgi_gccgo_options,
|
||||
//.on_load = uwsgi_gccgo_on_load,
|
||||
.request = uwsgi_gccgo_request,
|
||||
.after_request = uwsgi_gccgo_after_request,
|
||||
.post_fork = uwsgi_gccgo_initialize,
|
||||
.signal_handler = uwsgi_gccgo_signal_handler,
|
||||
};
|
||||
@@ -0,0 +1,118 @@
|
||||
package uwsgi
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"net/http"
|
||||
"net/http/cgi"
|
||||
"io"
|
||||
)
|
||||
|
||||
|
||||
//extern uwsgi_takeover
|
||||
func uwsgi_takeover()
|
||||
//extern uwsgi_response_write_body_do
|
||||
func uwsgi_response_write_body_do(*interface{}, *byte, uint64) int
|
||||
//extern uwsgi_response_prepare_headers_int
|
||||
func uwsgi_response_prepare_headers_int(*interface{}, int) int
|
||||
//extern uwsgi_response_add_header
|
||||
func uwsgi_response_add_header(*interface{}, *byte, uint16, *byte, uint16) int
|
||||
//extern uwsgi_gccgo_helper_request_body_read
|
||||
func uwsgi_request_body_read(*interface{}, *byte, uint64) int
|
||||
//extern uwsgi_gccgo_helper_register_signal
|
||||
func uwsgi_register_signal(uint8, *byte, func(uint8)) int
|
||||
|
||||
var uwsgi_signals_gc [256]func(uint8)
|
||||
|
||||
func Env(wsgi_req *interface{}) *map[string]string {
|
||||
var env map[string]string
|
||||
env = make(map[string]string)
|
||||
return &env
|
||||
}
|
||||
|
||||
func EnvAdd(env *map[string]string, k *[65536]byte, kl uint16, v *[65536]byte, vl uint16) {
|
||||
(*env)[ string((*k)[0:kl]) ] = string((*v)[0:vl])
|
||||
}
|
||||
|
||||
type ResponseWriter struct {
|
||||
r *http.Request
|
||||
wsgi_req *interface{}
|
||||
headers http.Header
|
||||
wroteHeader bool
|
||||
}
|
||||
|
||||
func (w *ResponseWriter) Write(p []byte) (n int, err error) {
|
||||
if !w.wroteHeader {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
uwsgi_response_write_body_do(w.wsgi_req, &p[0], uint64(len(p)))
|
||||
return len(p), err
|
||||
}
|
||||
|
||||
func (w *ResponseWriter) WriteHeader(status int) {
|
||||
uwsgi_response_prepare_headers_int(w.wsgi_req, status )
|
||||
if w.headers.Get("Content-Type") == "" {
|
||||
w.headers.Set("Content-Type", "text/html; charset=utf-8")
|
||||
}
|
||||
for k := range w.headers {
|
||||
for _, v := range w.headers[k] {
|
||||
v = strings.NewReplacer("\n", " ", "\r", " ").Replace(v)
|
||||
v = strings.TrimSpace(v)
|
||||
kb := []byte(k)
|
||||
vb := []byte(v)
|
||||
uwsgi_response_add_header(w.wsgi_req, &kb[0], uint16(len(k)), &vb[0], uint16(len(v)))
|
||||
}
|
||||
}
|
||||
w.wroteHeader = true
|
||||
}
|
||||
|
||||
func (w *ResponseWriter) Header() http.Header {
|
||||
return w.headers
|
||||
}
|
||||
|
||||
|
||||
type BodyReader struct {
|
||||
wsgi_req *interface{}
|
||||
}
|
||||
|
||||
// there is no close in request body
|
||||
func (br *BodyReader) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (br *BodyReader) Read(p []byte) (n int, err error) {
|
||||
var rlen int = uwsgi_request_body_read(br.wsgi_req, &p[0], uint64(len(p)))
|
||||
if (rlen == 0) {
|
||||
err = io.EOF;
|
||||
return 0, err
|
||||
} else if (rlen == -1) {
|
||||
err = io.ErrUnexpectedEOF
|
||||
return 0, err
|
||||
}
|
||||
return rlen, err
|
||||
}
|
||||
|
||||
func RequestHandler(env *map[string]string, wsgi_req *interface{}) {
|
||||
httpReq, err := cgi.RequestFromMap(*env)
|
||||
if err == nil {
|
||||
httpReq.Body = &BodyReader{wsgi_req}
|
||||
w := ResponseWriter{httpReq, wsgi_req,http.Header{},false}
|
||||
http.DefaultServeMux.ServeHTTP(&w, httpReq)
|
||||
}
|
||||
}
|
||||
|
||||
func RegisterSignal(signum uint8, receiver string, handler func(uint8)) bool {
|
||||
var b []byte = []byte(receiver)
|
||||
if (uwsgi_register_signal(signum, &b[0], handler) < 0) {
|
||||
return false
|
||||
}
|
||||
uwsgi_signals_gc[signum] = handler
|
||||
return true
|
||||
}
|
||||
|
||||
func SignalHandler(handler func(uint8), signum uint8) {
|
||||
handler(signum)
|
||||
}
|
||||
|
||||
func Run() {
|
||||
uwsgi_takeover()
|
||||
}
|
||||
+34
-3
@@ -121,7 +121,6 @@ int http_add_uwsgi_header(struct corerouter_peer *peer, char *hh, uint16_t hhlen
|
||||
|
||||
else if (!uwsgi_strncmp("CONTENT_LENGTH", 14, hh, keylen)) {
|
||||
hr->content_length = uwsgi_str_num(val, vallen);
|
||||
hr->session.can_keepalive = 0;
|
||||
}
|
||||
|
||||
// in the future we could support chunked requests...
|
||||
@@ -183,19 +182,28 @@ int http_headers_parse(struct corerouter_peer *peer) {
|
||||
peer->out_pos = 0;
|
||||
|
||||
struct uwsgi_buffer *out = peer->out;
|
||||
int found = 0;
|
||||
|
||||
// REQUEST_METHOD
|
||||
while (ptr < watermark) {
|
||||
if (*ptr == ' ') {
|
||||
if (uwsgi_buffer_append_keyval(out, "REQUEST_METHOD", 14, base, ptr - base)) return -1;
|
||||
ptr++;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
else if (*ptr == '\r' || *ptr == '\n') break;
|
||||
ptr++;
|
||||
}
|
||||
|
||||
// ensure we have a method
|
||||
if (!found) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// REQUEST_URI / PATH_INFO / QUERY_STRING
|
||||
base = ptr;
|
||||
found = 0;
|
||||
while (ptr < watermark) {
|
||||
if (*ptr == '?' && !query_string) {
|
||||
// PATH_INFO must be url-decoded !!!
|
||||
@@ -221,13 +229,20 @@ int http_headers_parse(struct corerouter_peer *peer) {
|
||||
if (uwsgi_buffer_append_keyval(out, "QUERY_STRING", 12, query_string, ptr - query_string)) return -1;
|
||||
}
|
||||
ptr++;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
|
||||
// ensure we have a URI
|
||||
if (!found) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// SERVER_PROTOCOL
|
||||
base = ptr;
|
||||
found = 0;
|
||||
while (ptr < watermark) {
|
||||
if (*ptr == '\r') {
|
||||
if (ptr + 1 >= watermark)
|
||||
@@ -239,11 +254,17 @@ int http_headers_parse(struct corerouter_peer *peer) {
|
||||
hr->session.can_keepalive = 1;
|
||||
}
|
||||
ptr += 2;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
|
||||
// ensure we have a protocol
|
||||
if (!found) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// SCRIPT_NAME
|
||||
if (uwsgi_buffer_append_keyval(out, "SCRIPT_NAME", 11, "", 0)) return -1;
|
||||
|
||||
@@ -459,6 +480,8 @@ ssize_t hr_instance_read(struct corerouter_peer *peer) {
|
||||
struct http_session *hr = (struct http_session *) peer->session;
|
||||
ssize_t len = cr_read(peer, "hr_instance_read()");
|
||||
if (!len) {
|
||||
// disable keepalive on unread body
|
||||
if (hr->content_length) hr->session.can_keepalive = 0;
|
||||
if (hr->session.can_keepalive) {
|
||||
peer->session->main_peer->disabled = 0;
|
||||
hr->rnrn = 0;
|
||||
@@ -575,9 +598,16 @@ ssize_t http_parse(struct corerouter_peer *main_peer) {
|
||||
if (main_peer->in->pos > hr->content_length) {
|
||||
main_peer->in->pos = hr->content_length;
|
||||
hr->content_length = 0;
|
||||
// on pipeline attempt, disable keepalive
|
||||
hr->session.can_keepalive = 0;
|
||||
}
|
||||
else {
|
||||
hr->content_length -= main_peer->in->pos;
|
||||
if (hr->content_length == 0) {
|
||||
main_peer->disabled = 1;
|
||||
// stop reading from the client
|
||||
if (uwsgi_cr_set_hooks(main_peer, NULL, NULL)) return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -649,10 +679,11 @@ ssize_t http_parse(struct corerouter_peer *main_peer) {
|
||||
new_peer->out->buf[2] = (uint8_t) ((pktsize >> 8) & 0xff);
|
||||
|
||||
if (hr->remains > 0) {
|
||||
hr->session.can_keepalive = 0;
|
||||
if (hr->content_length < hr->remains) {
|
||||
hr->remains = hr->content_length;
|
||||
hr->content_length = 0;
|
||||
// we need to avoid problems with pipelined requests
|
||||
hr->session.can_keepalive = 0;
|
||||
}
|
||||
else {
|
||||
hr->content_length -= hr->remains;
|
||||
@@ -660,7 +691,7 @@ 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->session.can_keepalive) {
|
||||
if (hr->session.can_keepalive && hr->content_length == 0) {
|
||||
main_peer->disabled = 1;
|
||||
// stop reading from the client
|
||||
if (uwsgi_cr_set_hooks(main_peer, NULL, NULL)) return -1;
|
||||
|
||||
@@ -25,6 +25,7 @@ struct uwsgi_jvm {
|
||||
jclass input_stream_class;
|
||||
jclass file_class;
|
||||
jclass hashmap_class;
|
||||
jclass list_class;
|
||||
jclass set_class;
|
||||
jclass iterator_class;
|
||||
|
||||
@@ -63,6 +64,10 @@ jmethodID uwsgi_jvm_get_static_method_id_quiet(jclass, char *, char *);
|
||||
jobject uwsgi_jvm_str(char *, size_t);
|
||||
jobject uwsgi_jvm_hashmap(void);
|
||||
int uwsgi_jvm_hashmap_put(jobject, jobject, jobject);
|
||||
int uwsgi_jvm_hashmap_has(jobject, jobject);
|
||||
|
||||
jobject uwsgi_jvm_list(void);
|
||||
int uwsgi_jvm_list_add(jobject, jobject);
|
||||
|
||||
jobject uwsgi_jvm_call_object(jobject, jmethodID, ...);
|
||||
jobject uwsgi_jvm_call_object_static(jclass, jmethodID, ...);
|
||||
|
||||
@@ -215,15 +215,42 @@ JNIEXPORT jint JNICALL uwsgi_jvm_request_body_read_bytearray(JNIEnv *env, jobjec
|
||||
return rlen;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL uwsgi_jvm_request_body_readline_bytearray(JNIEnv *env, jobject o, jobject b) {
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
ssize_t rlen = 0;
|
||||
size_t len = uwsgi_jvm_array_len(b);
|
||||
char *chunk = uwsgi_request_body_readline(wsgi_req, len, &rlen);
|
||||
if (!chunk) {
|
||||
uwsgi_jvm_throw_io("error reading request body");
|
||||
return -1;
|
||||
}
|
||||
if (chunk == uwsgi.empty) {
|
||||
return -1;
|
||||
}
|
||||
char *buf = (char *) (*ujvm_env)->GetByteArrayElements(ujvm_env, b, JNI_FALSE);
|
||||
if (!buf) return -1;
|
||||
memcpy(buf, chunk, rlen);
|
||||
(*ujvm_env)->ReleaseByteArrayElements(ujvm_env, b, (jbyte *) buf, 0);
|
||||
return rlen;
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jint JNICALL uwsgi_jvm_request_body_available(JNIEnv *env, jobject o) {
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
return (jint) (wsgi_req->post_cl - wsgi_req->post_pos);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL uwsgi_jvm_request_body_seek(JNIEnv *env, jobject o, jint pos) {
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
uwsgi_request_body_seek(wsgi_req, pos);
|
||||
}
|
||||
|
||||
static JNINativeMethod uwsgi_jvm_request_body_methods[] = {
|
||||
{"read", "()I", (void *) &uwsgi_jvm_request_body_read},
|
||||
{"read", "([B)I", (void *) &uwsgi_jvm_request_body_read_bytearray},
|
||||
{"readLine", "([B)I", (void *) &uwsgi_jvm_request_body_readline_bytearray},
|
||||
{"available", "()I", (void *) &uwsgi_jvm_request_body_available},
|
||||
{"seek", "(I)V", (void *) &uwsgi_jvm_request_body_seek},
|
||||
};
|
||||
|
||||
static struct uwsgi_option uwsgi_jvm_options[] = {
|
||||
@@ -684,6 +711,23 @@ void uwsgi_jvm_local_unref(jobject obj) {
|
||||
(*ujvm_env)->DeleteLocalRef(ujvm_env, obj);
|
||||
}
|
||||
|
||||
jobject uwsgi_jvm_list() {
|
||||
// optimization
|
||||
static jmethodID mid = 0;
|
||||
|
||||
if (!mid) {
|
||||
mid = uwsgi_jvm_get_method_id(ujvm.list_class, "<init>", "()V");
|
||||
if (!mid) return NULL;
|
||||
}
|
||||
|
||||
jobject ll = (*ujvm_env)->NewObject(ujvm_env, ujvm.list_class, mid);
|
||||
if (uwsgi_jvm_exception()) {
|
||||
return NULL;
|
||||
}
|
||||
return ll;
|
||||
}
|
||||
|
||||
|
||||
jobject uwsgi_jvm_hashmap() {
|
||||
// optimization
|
||||
static jmethodID mid = 0;
|
||||
@@ -712,6 +756,18 @@ int uwsgi_jvm_hashmap_put(jobject hm, jobject key, jobject value) {
|
||||
return uwsgi_jvm_call(hm, mid, key, value);
|
||||
}
|
||||
|
||||
int uwsgi_jvm_list_add(jobject ll, jobject value) {
|
||||
// optimization
|
||||
static jmethodID mid = 0;
|
||||
|
||||
if (!mid) {
|
||||
mid = uwsgi_jvm_get_method_id(ujvm.list_class, "add", "(Ljava/lang/Object;)Z");
|
||||
if (!mid) return -1;
|
||||
}
|
||||
|
||||
return uwsgi_jvm_call(ll, mid, value);
|
||||
}
|
||||
|
||||
jobject uwsgi_jvm_hashmap_get(jobject hm, jobject key) {
|
||||
// optimization
|
||||
static jmethodID mid = 0;
|
||||
@@ -724,6 +780,21 @@ jobject uwsgi_jvm_hashmap_get(jobject hm, jobject key) {
|
||||
return uwsgi_jvm_call_object(hm, mid, key);
|
||||
}
|
||||
|
||||
int uwsgi_jvm_hashmap_has(jobject hm, jobject key) {
|
||||
// optimization
|
||||
static jmethodID mid = 0;
|
||||
|
||||
if (!mid) {
|
||||
mid = uwsgi_jvm_get_method_id(ujvm.hashmap_class, "containsKey", "(Ljava/lang/Object;)Z");
|
||||
if (!mid) return 0;
|
||||
}
|
||||
|
||||
if (uwsgi_jvm_call_bool(hm, mid, key)) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
jobject uwsgi_jvm_iterator(jobject set) {
|
||||
// optimization
|
||||
static jmethodID mid = 0;
|
||||
@@ -1010,6 +1081,9 @@ static void uwsgi_jvm_create(void) {
|
||||
ujvm.hashmap_class = uwsgi_jvm_class("java/util/HashMap");
|
||||
if (!ujvm.hashmap_class) exit(1);
|
||||
|
||||
ujvm.list_class = uwsgi_jvm_class("java/util/ArrayList");
|
||||
if (!ujvm.list_class) exit(1);
|
||||
|
||||
ujvm.set_class = uwsgi_jvm_class("java/util/Set");
|
||||
if (!ujvm.set_class) exit(1);
|
||||
|
||||
@@ -1026,6 +1100,52 @@ static void uwsgi_jvm_create(void) {
|
||||
if (!uwsgi_class) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
start filling uwsgi.opt
|
||||
*/
|
||||
jfieldID opt_fid = (*ujvm_env)->GetStaticFieldID(ujvm_env, uwsgi_class, "opt", "Ljava/util/HashMap;");
|
||||
if (uwsgi_jvm_exception()) {
|
||||
exit(1);
|
||||
}
|
||||
jobject opt_hm = uwsgi_jvm_hashmap();
|
||||
int j;
|
||||
for (j = 0; j < uwsgi.exported_opts_cnt; j++) {
|
||||
jstring j_opt_key = uwsgi_jvm_str(uwsgi.exported_opts[j]->key, 0);
|
||||
if (uwsgi_jvm_hashmap_has(opt_hm, (jobject) j_opt_key)) {
|
||||
jobject j_opt_value = uwsgi_jvm_hashmap_get(opt_hm, (jobject) j_opt_key);
|
||||
if (uwsgi_jvm_object_is_instance(j_opt_value, ujvm.list_class)) {
|
||||
if (uwsgi.exported_opts[j]->value == NULL) {
|
||||
uwsgi_jvm_list_add(j_opt_value, (jobject) 1);
|
||||
}
|
||||
else {
|
||||
uwsgi_jvm_list_add(j_opt_value, uwsgi_jvm_str(uwsgi.exported_opts[j]->value, 0));
|
||||
}
|
||||
}
|
||||
else {
|
||||
jobject ll = uwsgi_jvm_list();
|
||||
uwsgi_jvm_list_add(ll, j_opt_value);
|
||||
if (uwsgi.exported_opts[j]->value == NULL) {
|
||||
uwsgi_jvm_list_add(ll, (jobject) 1);
|
||||
}
|
||||
else {
|
||||
uwsgi_jvm_list_add(ll, uwsgi_jvm_str(uwsgi.exported_opts[j]->value, 0));
|
||||
}
|
||||
uwsgi_jvm_hashmap_put(opt_hm, j_opt_key, ll);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (uwsgi.exported_opts[j]->value == NULL) {
|
||||
uwsgi_jvm_hashmap_put(opt_hm, j_opt_key, (jobject) 1);
|
||||
}
|
||||
else {
|
||||
uwsgi_jvm_hashmap_put(opt_hm, j_opt_key, uwsgi_jvm_str(uwsgi.exported_opts[j]->value, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
(*ujvm_env)->SetStaticObjectField(ujvm_env, uwsgi_class, opt_fid, opt_hm);
|
||||
|
||||
|
||||
(*ujvm_env)->RegisterNatives(ujvm_env, uwsgi_class, uwsgi_jvm_api_methods, sizeof(uwsgi_jvm_api_methods)/sizeof(uwsgi_jvm_api_methods[0]));
|
||||
if (uwsgi_jvm_exception()) {
|
||||
exit(1);
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
public class uwsgi {
|
||||
|
||||
static HashMap<String,Object> opt;
|
||||
|
||||
public static class RequestBody extends InputStream {
|
||||
public native int read();
|
||||
public native int read(byte[] b);
|
||||
public native int readLine(byte[] b);
|
||||
public native int available();
|
||||
public native void seek(int pos);
|
||||
}
|
||||
|
||||
public interface SignalHandler {
|
||||
|
||||
@@ -9,6 +9,7 @@ struct uwsgi_jwsgi {
|
||||
char *app;
|
||||
jmethodID app_mid;
|
||||
jclass app_class;
|
||||
jobject app_instance;
|
||||
} ujwsgi;
|
||||
|
||||
static struct uwsgi_option uwsgi_jwsgi_options[] = {
|
||||
@@ -20,7 +21,16 @@ static int uwsgi_jwsgi_add_request_item(jobject hm, char *key, uint16_t key_len,
|
||||
jobject j_key = uwsgi_jvm_str(key, key_len);
|
||||
if (!j_key) return -1;
|
||||
|
||||
jobject j_value = uwsgi_jvm_str(value, value_len);
|
||||
jobject j_value = NULL;
|
||||
// avoid clobbering vars
|
||||
if (value_len > 0) {
|
||||
j_value = uwsgi_jvm_str(value, value_len);
|
||||
}
|
||||
else {
|
||||
char *tmp = uwsgi_str("");
|
||||
j_value = uwsgi_jvm_str(tmp, 0);
|
||||
free(tmp);
|
||||
}
|
||||
if (!j_value) {
|
||||
uwsgi_jvm_local_unref(j_value);
|
||||
return -1;
|
||||
@@ -72,7 +82,12 @@ static int uwsgi_jwsgi_request(struct wsgi_request *wsgi_req) {
|
||||
|
||||
if (uwsgi_jwsgi_add_request_input(hm, "jwsgi.input", 11)) goto end;
|
||||
|
||||
response = uwsgi_jvm_call_object_static(ujwsgi.app_class, ujwsgi.app_mid, hm);
|
||||
if (!ujwsgi.app_instance) {
|
||||
response = uwsgi_jvm_call_object_static(ujwsgi.app_class, ujwsgi.app_mid, hm);
|
||||
}
|
||||
else {
|
||||
response = uwsgi_jvm_call_object(ujwsgi.app_instance, ujwsgi.app_mid, hm);
|
||||
}
|
||||
if (!response) goto end;
|
||||
|
||||
if (uwsgi_jvm_array_len(response) != 3) {
|
||||
@@ -135,23 +150,31 @@ static int uwsgi_jwsgi_setup() {
|
||||
|
||||
char *app = uwsgi_str(ujwsgi.app);
|
||||
|
||||
char *method = "application";
|
||||
char *colon = strchr(app, ':');
|
||||
|
||||
if (!colon) {
|
||||
uwsgi_log("invalid JWSGI app definition, must be class:method\n");
|
||||
exit(1);
|
||||
if (colon) {
|
||||
*colon = 0;
|
||||
method = colon + 1;
|
||||
}
|
||||
|
||||
*colon = 0;
|
||||
|
||||
ujwsgi.app_class = uwsgi_jvm_class(app);
|
||||
if (!ujwsgi.app_class) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ujwsgi.app_mid = uwsgi_jvm_get_static_method_id(ujwsgi.app_class, colon+1, "(Ljava/util/HashMap;)[Ljava/lang/Object;");
|
||||
if (!ujwsgi.app_mid) {
|
||||
exit(1);
|
||||
ujwsgi.app_mid = uwsgi_jvm_get_static_method_id_quiet(ujwsgi.app_class, method, "(Ljava/util/HashMap;)[Ljava/lang/Object;");
|
||||
if (uwsgi_jvm_exception() || !ujwsgi.app_mid) {
|
||||
jmethodID mid = uwsgi_jvm_get_method_id(ujwsgi.app_class, "<init>", "()V");
|
||||
if (uwsgi_jvm_exception() || !mid) exit(1);
|
||||
ujwsgi.app_instance = (*ujvm_env)->NewObject(ujvm_env, ujwsgi.app_class, mid);
|
||||
if (uwsgi_jvm_exception() || !ujwsgi.app_instance) {
|
||||
exit(1);
|
||||
}
|
||||
ujwsgi.app_mid = uwsgi_jvm_get_method_id(ujwsgi.app_class, method, "(Ljava/util/HashMap;)[Ljava/lang/Object;");
|
||||
if (uwsgi_jvm_exception() || !ujwsgi.app_mid) {
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_log("JWSGI app \"%s\" loaded\n", ujwsgi.app);
|
||||
|
||||
@@ -547,7 +547,7 @@ static int uwsgi_mono_request(struct wsgi_request *wsgi_req) {
|
||||
pthread_mutex_lock(&umono.lock_loader);
|
||||
}
|
||||
|
||||
// check if the mean time, something changed
|
||||
// check if in the mean time, something changed
|
||||
wsgi_req->app_id = uwsgi_get_app_id(NULL, key, key_len, mono_plugin.modifier1);
|
||||
|
||||
if (wsgi_req->app_id == -1) {
|
||||
|
||||
+21
-10
@@ -394,33 +394,44 @@ int uwsgi_perl_request(struct wsgi_request *wsgi_req) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (wsgi_req->dynamic) {
|
||||
if (uwsgi.threads > 1) {
|
||||
pthread_mutex_lock(&uperl.lock_loader);
|
||||
}
|
||||
}
|
||||
|
||||
wsgi_req->app_id = uwsgi_get_app_id(wsgi_req, wsgi_req->appid, wsgi_req->appid_len, psgi_plugin.modifier1);
|
||||
// if it is -1, try to load a dynamic app
|
||||
if (wsgi_req->app_id == -1) {
|
||||
if (wsgi_req->dynamic) {
|
||||
if (uwsgi.threads > 1) {
|
||||
pthread_mutex_lock(&uperl.lock_loader);
|
||||
}
|
||||
|
||||
if (wsgi_req->script_len > 0) {
|
||||
wsgi_req->app_id = init_psgi_app(wsgi_req, wsgi_req->script, wsgi_req->script_len, NULL);
|
||||
}
|
||||
else if (wsgi_req->file_len > 0) {
|
||||
wsgi_req->app_id = init_psgi_app(wsgi_req, wsgi_req->file, wsgi_req->file_len, NULL);
|
||||
}
|
||||
|
||||
if (uwsgi.threads > 1) {
|
||||
pthread_mutex_unlock(&uperl.lock_loader);
|
||||
}
|
||||
}
|
||||
|
||||
if (wsgi_req->app_id == -1 && !uwsgi.no_default_app && uwsgi.default_app > -1) {
|
||||
if (uwsgi_apps[uwsgi.default_app].modifier1 == psgi_plugin.modifier1) {
|
||||
wsgi_req->app_id = uwsgi.default_app;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (wsgi_req->dynamic) {
|
||||
if (uwsgi.threads > 1) {
|
||||
pthread_mutex_unlock(&uperl.lock_loader);
|
||||
}
|
||||
}
|
||||
|
||||
if (wsgi_req->app_id == -1) {
|
||||
uwsgi_500(wsgi_req);
|
||||
uwsgi_log("--- unable to find perl application ---\n");
|
||||
// nothing to clear/free
|
||||
return UWSGI_OK;
|
||||
}
|
||||
}
|
||||
|
||||
struct uwsgi_app *wi = &uwsgi_apps[wsgi_req->app_id];
|
||||
wi->requests++;
|
||||
@@ -712,7 +723,7 @@ static uint16_t uwsgi_perl_rpc(void *func, uint8_t argc, char **argv, uint16_t a
|
||||
STRLEN rlen;
|
||||
SV *response = POPs;
|
||||
char *value = SvPV(response, rlen );
|
||||
ret = UMIN(UMAX16, rlen);
|
||||
ret = UMIN(UMAX16-1, rlen);
|
||||
memcpy(buffer, value, ret);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
This is a bit convoluted, but you run it (so far) this way:
|
||||
|
||||
You have to compile PyPy with strange options. I'll explain them below.
|
||||
In the pypy checkout, run:
|
||||
|
||||
./rpython/bin/rpython -Ojit --shared --gcrootfinder=shadowstack pypy/goal/targetpypystandalone
|
||||
|
||||
Options:
|
||||
|
||||
-Ojit - standard PyPy build with JIT
|
||||
--shared - as expected, creates a .so
|
||||
--gcrootfinder - on linux, the default rootfinder is asmgcc which has trouble
|
||||
with position independent code. This option is not needed
|
||||
on OS X or windows.
|
||||
|
||||
If for some strange/dangerous/wrong reason your uWSGI binary is linked with cpython you could have name collisions
|
||||
with pypy cpyext. In such crazy case you can remove cpyext support with:
|
||||
|
||||
./rpython/bin/rpython -Ojit --shared --gcrootfinder=shadowstack pypy/goal/targetpypystandalone --withoutmod-cpyext
|
||||
|
||||
By default the pypy uWSGI plugin will load the libpypy-c.so library. You should have it in the LD_LIBRARY_PATH, otherwise you can set its path
|
||||
with --pypy-lib option (pass an absolute path to it)
|
||||
|
||||
You have to specify the pypy home too, you can use the --pypy-home option or the PYPY_HOME var
|
||||
|
||||
PYPY_HOME=/home/user/pypy/lib_pypy uwsgi --pypy-lib /opt/pypy/libpypy-c.so --http-socket :9090 --pypy-wsgi werkzeug.testapp:test_app
|
||||
|
||||
|
||||
The funny part about the uWSGI pypy plugin is that it is mainly written in python. The pypy_setup.py script is linked to the plugin, but you can override
|
||||
it with the --pypy-setup option
|
||||
@@ -0,0 +1,360 @@
|
||||
/*******************************************************************
|
||||
|
||||
This is the C part of the PyPy plugin (with the main logic being in
|
||||
Python, see pypy_setup.py).
|
||||
|
||||
Idea and initial implementation by Maciej Fijalkowski
|
||||
|
||||
*******************************************************************/
|
||||
|
||||
#include <uwsgi.h>
|
||||
|
||||
struct uwsgi_pypy {
|
||||
void *handler;
|
||||
char *lib;
|
||||
char *setup;
|
||||
char *home;
|
||||
char *wsgi;
|
||||
char *wsgi_file;
|
||||
struct uwsgi_string_list *eval;
|
||||
struct uwsgi_string_list *eval_post_fork;
|
||||
struct uwsgi_string_list *exec;
|
||||
struct uwsgi_string_list *exec_post_fork;
|
||||
|
||||
struct uwsgi_string_list *pp;
|
||||
} upypy;
|
||||
|
||||
// the functions exposed by libpypy-c
|
||||
char *(*rpython_startup_code)(void);
|
||||
int (*pypy_setup_home)(char *, int);
|
||||
int (*pypy_execute_source)(char *);
|
||||
void (*pypy_thread_attach)(void);
|
||||
void (*pypy_init_threads)(void);
|
||||
|
||||
// the hooks you can override with pypy
|
||||
void (*uwsgi_pypy_hook_loader)(char *);
|
||||
void (*uwsgi_pypy_hook_file_loader)(char *);
|
||||
void (*uwsgi_pypy_hook_pythonpath)(char *);
|
||||
void (*uwsgi_pypy_hook_request)(void *, int);
|
||||
void (*uwsgi_pypy_post_fork_hook)(void);
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
struct uwsgi_plugin pypy_plugin;
|
||||
|
||||
int uwsgi_pypy_helper_masterpid() {
|
||||
if (uwsgi.master_process) {
|
||||
return uwsgi.workers[0].pid;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_pypy_helper_worker_id() {
|
||||
return uwsgi.mywid;
|
||||
}
|
||||
|
||||
int uwsgi_pypy_helper_mule_id() {
|
||||
return uwsgi.muleid;
|
||||
}
|
||||
|
||||
void uwsgi_pypy_helper_signal(int signum) {
|
||||
uwsgi_signal_send(uwsgi.signal_socket, signum);
|
||||
}
|
||||
|
||||
struct uwsgi_opt **uwsgi_pypy_helper_opts(int *n) {
|
||||
*n = uwsgi.exported_opts_cnt;
|
||||
return uwsgi.exported_opts;
|
||||
}
|
||||
|
||||
char *uwsgi_pypy_helper_version() {
|
||||
return UWSGI_VERSION;
|
||||
}
|
||||
|
||||
int uwsgi_pypy_helper_register_signal(int signum, char *kind, void *handler) {
|
||||
return uwsgi_register_signal(signum, kind, handler, pypy_plugin.modifier1);
|
||||
}
|
||||
|
||||
int uwsgi_pypy_helper_register_rpc(char *name, int argc, void *func) {
|
||||
return uwsgi_register_rpc(name, &pypy_plugin, argc, func);
|
||||
}
|
||||
|
||||
struct iovec *uwsgi_pypy_helper_environ(struct wsgi_request *wsgi_req, uint16_t *len) {
|
||||
*len = wsgi_req->var_cnt;
|
||||
return wsgi_req->hvec;
|
||||
}
|
||||
|
||||
static int uwsgi_pypy_init() {
|
||||
|
||||
size_t rlen = 0;
|
||||
char *buffer = NULL;
|
||||
|
||||
void *is_cpython_loaded = dlsym(RTLD_DEFAULT, "Py_Initialize");
|
||||
if (is_cpython_loaded) {
|
||||
uwsgi_log("!!! Loading both PyPy and CPython in the same process IS PURE EVIL AND IT IS NOT SUPPORTED !!!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (upypy.lib) {
|
||||
upypy.handler = dlopen(upypy.lib, RTLD_NOW | RTLD_GLOBAL);
|
||||
}
|
||||
else {
|
||||
if (upypy.home) {
|
||||
#ifdef __APPLE__
|
||||
char *libpath = uwsgi_concat2(upypy.home, "/libpypy-c.dylib");
|
||||
#else
|
||||
char *libpath = uwsgi_concat2(upypy.home, "/libpypy-c.so");
|
||||
#endif
|
||||
if (uwsgi_file_exists(libpath)) {
|
||||
upypy.handler = dlopen(libpath, RTLD_NOW | RTLD_GLOBAL);
|
||||
}
|
||||
free(libpath);
|
||||
}
|
||||
// fallback to standard library search path
|
||||
if (!upypy.handler) {
|
||||
#ifdef __APPLE__
|
||||
upypy.handler = dlopen("libpypy-c.dylib", RTLD_NOW | RTLD_GLOBAL);
|
||||
#else
|
||||
upypy.handler = dlopen("libpypy-c.so", RTLD_NOW | RTLD_GLOBAL);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (!upypy.handler) {
|
||||
uwsgi_log("unable to load pypy library: %s\n", dlerror());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
rpython_startup_code = dlsym(upypy.handler, "rpython_startup_code");
|
||||
if (!rpython_startup_code) {
|
||||
uwsgi_log("unable to find rpython_startup_code() symbol\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
pypy_setup_home = dlsym(upypy.handler, "pypy_setup_home");
|
||||
if (!pypy_setup_home) {
|
||||
uwsgi_log("unable to find pypy_setup_home() symbol\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
pypy_execute_source = dlsym(upypy.handler, "pypy_execute_source");
|
||||
if (!pypy_execute_source) {
|
||||
uwsgi_log("unable to find pypy_execute_source() symbol\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
pypy_thread_attach = dlsym(upypy.handler, "pypy_thread_attach");
|
||||
if (!pypy_thread_attach) {
|
||||
uwsgi_log("!!! WARNING your libpypy-c does not export pypy_thread_attach, multithreading will not work !!!\n");
|
||||
}
|
||||
|
||||
pypy_init_threads = dlsym(upypy.handler, "pypy_init_threads");
|
||||
if (!pypy_init_threads) {
|
||||
uwsgi_log("!!! WARNING your libpypy-c does not export pypy_init_threads, multithreading will not work !!!\n");
|
||||
}
|
||||
|
||||
rpython_startup_code();
|
||||
|
||||
if (!upypy.home) {
|
||||
upypy.home = getenv("PYPY_HOME");
|
||||
if (!upypy.home) {
|
||||
uwsgi_log("you have to specify a pypy home with --pypy-home\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (pypy_setup_home(upypy.home, 0)) {
|
||||
char *retry = uwsgi_concat2(upypy.home, "/lib_pypy");
|
||||
if (uwsgi_is_dir(retry)) {
|
||||
// this time we use debug
|
||||
if (!pypy_setup_home(retry, 1)) {
|
||||
free(retry);
|
||||
goto ready;
|
||||
}
|
||||
}
|
||||
uwsgi_log("unable to set pypy home to \"%s\"\n", upypy.home);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ready:
|
||||
if (upypy.setup) {
|
||||
buffer = uwsgi_open_and_read(upypy.setup, &rlen, 1, NULL);
|
||||
}
|
||||
else {
|
||||
char *start = dlsym(RTLD_DEFAULT, "uwsgi_pypy_setup_start");
|
||||
char *end = dlsym(RTLD_DEFAULT, "uwsgi_pypy_setup_end");
|
||||
if (start && end) {
|
||||
buffer = uwsgi_concat2n(start, end-start, "", 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (!buffer) {
|
||||
uwsgi_log("you have to load a pypy setup file with --pypy-setup\n");
|
||||
exit(1);
|
||||
}
|
||||
if (pypy_execute_source(buffer)) {
|
||||
exit(1);
|
||||
}
|
||||
free(buffer);
|
||||
|
||||
// add items to the pythonpath
|
||||
struct uwsgi_string_list *usl = upypy.pp;
|
||||
while(usl) {
|
||||
if (uwsgi_pypy_hook_pythonpath) {
|
||||
uwsgi_pypy_hook_pythonpath(usl->value);
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void uwsgi_pypy_preinit_apps() {
|
||||
|
||||
struct uwsgi_string_list *usl = upypy.eval;
|
||||
while(usl) {
|
||||
if (pypy_execute_source(usl->value)) {
|
||||
exit(1);
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
|
||||
usl = upypy.exec;
|
||||
while(usl) {
|
||||
size_t rlen = 0;
|
||||
char *buffer = uwsgi_open_and_read(usl->value, &rlen, 1, NULL);
|
||||
if (pypy_execute_source(buffer)) {
|
||||
exit(1);
|
||||
}
|
||||
free(buffer);
|
||||
usl = usl->next;
|
||||
}
|
||||
}
|
||||
|
||||
static int uwsgi_pypy_request(struct wsgi_request *wsgi_req) {
|
||||
/* Standard WSGI request */
|
||||
if (!wsgi_req->uh->pktsize) {
|
||||
uwsgi_log( "Empty pypy request. skip.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (uwsgi_parse_vars(wsgi_req)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (uwsgi_pypy_hook_request) {
|
||||
uwsgi_pypy_hook_request(wsgi_req, wsgi_req->async_id);
|
||||
}
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
static void uwsgi_pypy_after_request(struct wsgi_request *wsgi_req) {
|
||||
log_request(wsgi_req);
|
||||
}
|
||||
|
||||
static void uwsgi_pypy_init_apps() {
|
||||
if (uwsgi_pypy_hook_loader && upypy.wsgi) {
|
||||
uwsgi_pypy_hook_loader(upypy.wsgi);
|
||||
}
|
||||
|
||||
if (uwsgi_pypy_hook_file_loader && upypy.wsgi_file) {
|
||||
uwsgi_pypy_hook_file_loader(upypy.wsgi_file);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
static void uwsgi_pypy_atexit() {
|
||||
if (pypy_debug_file)
|
||||
fflush(pypy_debug_file);
|
||||
}
|
||||
*/
|
||||
|
||||
static struct uwsgi_option uwsgi_pypy_options[] = {
|
||||
{"pypy-lib", required_argument, 0, "set the path/name of the pypy library", uwsgi_opt_set_str, &upypy.lib, 0},
|
||||
{"pypy-setup", required_argument, 0, "set the path of the python setup script", uwsgi_opt_set_str, &upypy.setup, 0},
|
||||
{"pypy-home", required_argument, 0, "set the home of pypy library", uwsgi_opt_set_str, &upypy.home, 0},
|
||||
{"pypy-wsgi", required_argument, 0, "load a WSGI module", uwsgi_opt_set_str, &upypy.wsgi, 0},
|
||||
{"pypy-wsgi-file", required_argument, 0, "load a WSGI/mod_wsgi file", uwsgi_opt_set_str, &upypy.wsgi_file, 0},
|
||||
{"pypy-eval", required_argument, 0, "evaluate pypy code before fork()", uwsgi_opt_add_string_list, &upypy.eval, 0},
|
||||
{"pypy-eval-post-fork", required_argument, 0, "evaluate pypy code soon after fork()", uwsgi_opt_add_string_list, &upypy.eval_post_fork, 0},
|
||||
{"pypy-exec", required_argument, 0, "execute pypy code from file before fork()", uwsgi_opt_add_string_list, &upypy.exec, 0},
|
||||
{"pypy-exec-post-fork", required_argument, 0, "execute pypy code from file soon after fork()", uwsgi_opt_add_string_list, &upypy.exec_post_fork, 0},
|
||||
{"pypy-pp", required_argument, 0, "add an item to the pythonpath", uwsgi_opt_add_string_list, &upypy.pp, 0},
|
||||
{"pypy-python-path", required_argument, 0, "add an item to the pythonpath", uwsgi_opt_add_string_list, &upypy.pp, 0},
|
||||
{"pypy-pythonpath", required_argument, 0, "add an item to the pythonpath", uwsgi_opt_add_string_list, &upypy.pp, 0},
|
||||
{0, 0, 0, 0, 0, 0, 0},
|
||||
};
|
||||
|
||||
static void uwsgi_pypy_enable_threads() {
|
||||
if (pypy_init_threads) {
|
||||
pypy_init_threads();
|
||||
}
|
||||
}
|
||||
|
||||
static void uwsgi_pypy_init_thread() {
|
||||
if (pypy_thread_attach) {
|
||||
pypy_thread_attach();
|
||||
}
|
||||
}
|
||||
|
||||
static int uwsgi_pypy_signal_handler(uint8_t sig, void *handler) {
|
||||
void (*pypy_func)(int) = (void(*)(int)) handler;
|
||||
pypy_func(sig);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint16_t uwsgi_pypy_rpc(void *func, uint8_t argc, char **argv, uint16_t argvs[], char *buffer) {
|
||||
int iargvs[UMAX8];
|
||||
int i;
|
||||
int (*pypy_func)(int, char **, int*, char *) = (int (*)(int, char **, int*, char *)) func;
|
||||
// we convert 16bit to int
|
||||
for(i=0;i<argc;i++) {
|
||||
iargvs[i] = (int) argvs[i];
|
||||
}
|
||||
return pypy_func(argc, argv, iargvs, buffer);
|
||||
}
|
||||
|
||||
static void uwsgi_pypy_post_fork() {
|
||||
struct uwsgi_string_list *usl = upypy.eval_post_fork;
|
||||
while(usl) {
|
||||
if (pypy_execute_source(usl->value)) {
|
||||
exit(1);
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
usl = upypy.exec_post_fork;
|
||||
while(usl) {
|
||||
size_t rlen = 0;
|
||||
char *buffer = uwsgi_open_and_read(usl->value, &rlen, 1, NULL);
|
||||
if (pypy_execute_source(buffer)) {
|
||||
exit(1);
|
||||
}
|
||||
free(buffer);
|
||||
usl = usl->next;
|
||||
}
|
||||
|
||||
if (uwsgi_pypy_post_fork_hook) {
|
||||
uwsgi_pypy_post_fork_hook();
|
||||
}
|
||||
}
|
||||
|
||||
static void uwsgi_pypy_onload() {
|
||||
#ifdef UWSGI_PYPY_HOME
|
||||
upypy.home = UWSGI_PYPY_HOME;
|
||||
#endif
|
||||
}
|
||||
|
||||
struct uwsgi_plugin pypy_plugin = {
|
||||
.name = "pypy",
|
||||
.modifier1 = 0,
|
||||
.on_load = uwsgi_pypy_onload,
|
||||
.init = uwsgi_pypy_init,
|
||||
.request = uwsgi_pypy_request,
|
||||
.after_request = uwsgi_pypy_after_request,
|
||||
.options = uwsgi_pypy_options,
|
||||
.preinit_apps = uwsgi_pypy_preinit_apps,
|
||||
.init_apps = uwsgi_pypy_init_apps,
|
||||
.init_thread = uwsgi_pypy_init_thread,
|
||||
.signal_handler = uwsgi_pypy_signal_handler,
|
||||
.enable_threads = uwsgi_pypy_enable_threads,
|
||||
.rpc = uwsgi_pypy_rpc,
|
||||
.post_fork = uwsgi_pypy_post_fork,
|
||||
};
|
||||
@@ -0,0 +1,463 @@
|
||||
import sys
|
||||
import os
|
||||
sys.path.insert(0, '.')
|
||||
sys.path.extend(os.environ.get('PYTHONPATH','').split(os.pathsep))
|
||||
import imp
|
||||
import traceback
|
||||
|
||||
|
||||
__name__ = '__main__'
|
||||
mainmodule = type(sys)('__main__')
|
||||
sys.modules['__main__'] = mainmodule
|
||||
|
||||
import cffi
|
||||
|
||||
# this is a list holding object we do not want to be freed (like callback and handlers)
|
||||
uwsgi_gc = []
|
||||
|
||||
defines = '''
|
||||
void free(void *);
|
||||
|
||||
void (*uwsgi_pypy_hook_loader)(char *);
|
||||
void (*uwsgi_pypy_hook_file_loader)(char *);
|
||||
void (*uwsgi_pypy_hook_pythonpath)(char *);
|
||||
void (*uwsgi_pypy_hook_request)(void *, int);
|
||||
void (*uwsgi_pypy_post_fork_hook)(void);
|
||||
|
||||
struct iovec {
|
||||
char *iov_base;
|
||||
uint64_t iov_len;
|
||||
};
|
||||
|
||||
struct uwsgi_opt {
|
||||
char *key;
|
||||
char *value;
|
||||
int configured;
|
||||
};
|
||||
|
||||
char *uwsgi_binary_path();
|
||||
void uwsgi_set_processname(char *);
|
||||
void uwsgi_alarm_trigger(char *, char *, uint64_t);
|
||||
int uwsgi_signal_registered(uint8_t);
|
||||
|
||||
int uwsgi_response_write_body_do(void *, char *, uint64_t);
|
||||
int uwsgi_response_sendfile_do_can_close(void *, int, uint64_t, uint64_t, int);
|
||||
int uwsgi_response_prepare_headers(void *, char *, uint16_t);
|
||||
int uwsgi_response_add_header(void *, char *, uint16_t, char *, uint16_t);
|
||||
char *uwsgi_request_body_read(void *, uint64_t, int64_t *);
|
||||
char *uwsgi_request_body_readline(void *, uint64_t, int64_t *);
|
||||
|
||||
struct iovec *uwsgi_pypy_helper_environ(void *, uint16_t *);
|
||||
|
||||
char *uwsgi_pypy_helper_version();
|
||||
int uwsgi_pypy_helper_register_signal(int, char *, void *);
|
||||
int uwsgi_pypy_helper_register_rpc(char *, int, void *);
|
||||
void uwsgi_pypy_helper_signal(int);
|
||||
struct uwsgi_opt** uwsgi_pypy_helper_opts(int *);
|
||||
int uwsgi_pypy_helper_masterpid();
|
||||
int uwsgi_pypy_helper_worker_id();
|
||||
int uwsgi_pypy_helper_mule_id();
|
||||
|
||||
char *uwsgi_cache_magic_get(char *, uint64_t, uint64_t *, uint64_t *, char *);
|
||||
int uwsgi_cache_magic_set(char *, uint64_t, char *, uint64_t, uint64_t, uint64_t, char *);
|
||||
int uwsgi_cache_magic_del(char *, uint64_t, char *);
|
||||
int uwsgi_add_timer(uint8_t, int);
|
||||
int uwsgi_add_rb_timer(uint8_t, int, int);
|
||||
int uwsgi_add_file_monitor(uint8_t, char *);
|
||||
char *uwsgi_do_rpc(char *, char *, uint8_t, char **, uint16_t *, uint16_t *);
|
||||
int uwsgi_signal_add_cron(uint8_t, int, int, int, int, int);
|
||||
|
||||
int uwsgi_user_lock(int);
|
||||
int uwsgi_user_unlock(int);
|
||||
|
||||
'''
|
||||
|
||||
ffi = cffi.FFI()
|
||||
ffi.cdef(defines)
|
||||
lib = ffi.verify(defines)
|
||||
libc = ffi.dlopen(None)
|
||||
|
||||
"""
|
||||
this is a global object point the the WSGI callable
|
||||
it sucks, i will fix it in the near future...
|
||||
"""
|
||||
wsgi_application = None
|
||||
|
||||
|
||||
sys.argv.insert(0, ffi.string(lib.uwsgi_binary_path()))
|
||||
|
||||
|
||||
"""
|
||||
load a wsgi module
|
||||
"""
|
||||
@ffi.callback("void(char *)")
|
||||
def uwsgi_pypy_loader(module):
|
||||
global wsgi_application
|
||||
m = ffi.string(module)
|
||||
c = 'application'
|
||||
if ':' in m:
|
||||
m, c = m.split(':')
|
||||
if '.' in m:
|
||||
mod = __import__(m, None, None, '*')
|
||||
else:
|
||||
mod = __import__(m)
|
||||
wsgi_application = getattr(mod, c)
|
||||
|
||||
"""
|
||||
load a mod_wsgi compliant .wsgi file
|
||||
"""
|
||||
@ffi.callback("void(char *)")
|
||||
def uwsgi_pypy_file_loader(filename):
|
||||
global wsgi_application
|
||||
w = ffi.string(filename)
|
||||
c = 'application'
|
||||
mod = imp.load_source('uwsgi_file_wsgi', w)
|
||||
wsgi_application = getattr(mod, c)
|
||||
|
||||
"""
|
||||
.post_fork_hokk
|
||||
"""
|
||||
@ffi.callback("void()")
|
||||
def uwsgi_pypy_post_fork_hook():
|
||||
import uwsgi
|
||||
if hasattr(uwsgi, 'post_fork_hook'):
|
||||
uwsgi.post_fork_hook()
|
||||
|
||||
"""
|
||||
add an item to the pythonpath
|
||||
"""
|
||||
@ffi.callback("void(char *)")
|
||||
def uwsgi_pypy_pythonpath(item):
|
||||
path = ffi.string(item)
|
||||
sys.path.append(path)
|
||||
print "added %s to pythonpath" % path
|
||||
|
||||
|
||||
"""
|
||||
class implementing wsgi.file_wrapper
|
||||
"""
|
||||
class WSGIfilewrapper(object):
|
||||
def __init__(self, wsgi_req, f, chunksize=0):
|
||||
self.wsgi_req = wsgi_req
|
||||
self.f = f
|
||||
self.chunksize = chunksize
|
||||
if hasattr(f, 'close'):
|
||||
self.close = f.close
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
def sendfile(self):
|
||||
if hasattr(self.f, 'fileno'):
|
||||
lib.uwsgi_response_sendfile_do_can_close(self.wsgi_req, self.f.fileno(), 0, 0, 0)
|
||||
elif hasattr(self.f, 'read'):
|
||||
if self.chunksize == 0:
|
||||
chunk = self.f.read()
|
||||
if len(chunk) > 0:
|
||||
lib.uwsgi_response_write_body_do(self.wsgi_req, ffi.new("char[]", chunk), len(chunk))
|
||||
return
|
||||
while True:
|
||||
chunk = self.f.read(self.chunksize)
|
||||
if chunk is None or len(chunk) == 0:
|
||||
break
|
||||
lib.uwsgi_response_write_body_do(self.wsgi_req, ffi.new("char[]", chunk), len(chunk))
|
||||
|
||||
|
||||
"""
|
||||
class implementing wsgi.input
|
||||
"""
|
||||
class WSGIinput(object):
|
||||
def __init__(self, wsgi_req):
|
||||
self.wsgi_req = wsgi_req
|
||||
|
||||
def read(self, size=0):
|
||||
rlen = ffi.new('int64_t*')
|
||||
chunk = lib.uwsgi_request_body_read(self.wsgi_req, size, rlen)
|
||||
if chunk != ffi.NULL:
|
||||
return ffi.string(chunk, rlen[0])
|
||||
if rlen[0] < 0:
|
||||
raise IOError("error reading wsgi.input")
|
||||
raise IOError("error waiting for wsgi.input")
|
||||
|
||||
def getline(self, hint=0):
|
||||
rlen = ffi.new('int64_t*')
|
||||
chunk = lib.uwsgi_request_body_readline(self.wsgi_req, hint, rlen)
|
||||
if chunk != ffi.NULL:
|
||||
return ffi.string(chunk, rlen[0])
|
||||
if rlen[0] < 0:
|
||||
raise IOError("error reading line from wsgi.input")
|
||||
raise IOError("error waiting for line on wsgi.input")
|
||||
|
||||
def readline(self, hint=0):
|
||||
return self.getline(hint)
|
||||
|
||||
def readlines(self, hint=0):
|
||||
lines = []
|
||||
while True:
|
||||
chunk = self.getline(hint)
|
||||
if len(chunk) == 0:
|
||||
break
|
||||
lines.append(chunk)
|
||||
return lines
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
def __next__(self):
|
||||
chunk = self.getline()
|
||||
if len(chunk) == 0:
|
||||
raise StopIteration
|
||||
return chunk
|
||||
|
||||
|
||||
"""
|
||||
the WSGI request handler
|
||||
"""
|
||||
@ffi.callback("void(void *, int)")
|
||||
def uwsgi_pypy_wsgi_handler(wsgi_req, core):
|
||||
global wsgi_application
|
||||
|
||||
def writer(data):
|
||||
lib.uwsgi_response_write_body_do(wsgi_req, ffi.new("char[]", data), len(data))
|
||||
|
||||
def start_response(status, headers, exc_info=None):
|
||||
if exc_info:
|
||||
traceback.print_exception(*exc_info)
|
||||
lib.uwsgi_response_prepare_headers(wsgi_req, ffi.new("char[]", status), len(status))
|
||||
for hh in headers:
|
||||
lib.uwsgi_response_add_header(wsgi_req, ffi.new("char[]", hh[0]), len(hh[0]), ffi.new("char[]", hh[1]), len(hh[1]))
|
||||
return writer
|
||||
|
||||
environ = {}
|
||||
nv = ffi.new("uint16_t*")
|
||||
iov = lib.uwsgi_pypy_helper_environ(wsgi_req, nv)
|
||||
for i in range(0, nv[0], 2):
|
||||
environ[ffi.string(iov[i].iov_base, iov[i].iov_len)] = ffi.string(iov[i+1].iov_base, iov[i+1].iov_len)
|
||||
|
||||
environ['wsgi.version'] = (1, 0)
|
||||
scheme = 'http'
|
||||
if 'HTTPS' in environ:
|
||||
if environ['HTTPS'] in ('on', 'ON', 'On', '1', 'true', 'TRUE', 'True'):
|
||||
scheme = 'https'
|
||||
environ['wsgi.url_scheme'] = environ.get('UWSGI_SCHEME', scheme)
|
||||
environ['wsgi.input'] = WSGIinput(wsgi_req)
|
||||
environ['wsgi.errors'] = sys.stderr
|
||||
environ['wsgi.run_once'] = False
|
||||
environ['wsgi.file_wrapper'] = lambda f, chunksize=0: WSGIfilewrapper(wsgi_req, f, chunksize)
|
||||
environ['wsgi.multithread'] = True
|
||||
environ['wsgi.multiprocess'] = True
|
||||
|
||||
environ['uwsgi.core'] = core
|
||||
|
||||
response = wsgi_application(environ, start_response)
|
||||
if type(response) is str:
|
||||
writer(response)
|
||||
else:
|
||||
try:
|
||||
if isinstance(response, WSGIfilewrapper):
|
||||
response.sendfile()
|
||||
else:
|
||||
for chunk in response:
|
||||
if isinstance(chunk, WSGIfilewrapper):
|
||||
try:
|
||||
chunk.sendfile()
|
||||
finally:
|
||||
chunk.close()
|
||||
else:
|
||||
writer(chunk)
|
||||
finally:
|
||||
if hasattr(response, 'close'):
|
||||
response.close()
|
||||
|
||||
lib.uwsgi_pypy_hook_loader = uwsgi_pypy_loader
|
||||
lib.uwsgi_pypy_hook_file_loader = uwsgi_pypy_file_loader
|
||||
lib.uwsgi_pypy_hook_pythonpath = uwsgi_pypy_pythonpath
|
||||
lib.uwsgi_pypy_hook_request = uwsgi_pypy_wsgi_handler
|
||||
lib.uwsgi_pypy_post_fork_hook = uwsgi_pypy_post_fork_hook
|
||||
|
||||
"""
|
||||
Here we define the "uwsgi" virtual module
|
||||
"""
|
||||
|
||||
uwsgi = imp.new_module('uwsgi')
|
||||
sys.modules['uwsgi'] = uwsgi
|
||||
uwsgi.version = ffi.string(lib.uwsgi_pypy_helper_version())
|
||||
|
||||
|
||||
def uwsgi_pypy_uwsgi_register_signal(signum, kind, handler):
|
||||
cb = ffi.callback('void(int)', handler)
|
||||
uwsgi_gc.append(cb)
|
||||
if lib.uwsgi_pypy_helper_register_signal(signum, ffi.new("char[]", kind), cb) < 0:
|
||||
raise Exception("unable to register signal %d" % signum)
|
||||
uwsgi.register_signal = uwsgi_pypy_uwsgi_register_signal
|
||||
|
||||
|
||||
class uwsgi_pypy_RPC(object):
|
||||
def __init__(self, func):
|
||||
self.func = func
|
||||
|
||||
def __call__(self, argc, argv, argvs, buf):
|
||||
pargs = []
|
||||
for i in range(0, argc):
|
||||
pargs.append(ffi.string(argv[i], argvs[i]))
|
||||
response = self.func(*pargs)
|
||||
if len(response) > 0 and len(response) <= 65535:
|
||||
dst = ffi.buffer(buf, 65536)
|
||||
dst[:len(response)] = response
|
||||
return len(response)
|
||||
|
||||
|
||||
def uwsgi_pypy_uwsgi_register_rpc(name, func, argc=0):
|
||||
rpc_func = uwsgi_pypy_RPC(func)
|
||||
cb = ffi.callback("int(int, char*[], int[], char*)", rpc_func)
|
||||
uwsgi_gc.append(cb)
|
||||
if lib.uwsgi_pypy_helper_register_rpc(ffi.new("char[]", name), argc, cb) < 0:
|
||||
raise Exception("unable to register rpc func %s" % name)
|
||||
uwsgi.register_rpc = uwsgi_pypy_uwsgi_register_rpc
|
||||
|
||||
def uwsgi_pypy_rpc(node, func, *args):
|
||||
argc = 0
|
||||
argv = ffi.new('char*[256]')
|
||||
argvs = ffi.new('uint16_t[256]')
|
||||
rsize = ffi.new('uint16_t*')
|
||||
|
||||
for arg in args:
|
||||
if argc >= 255:
|
||||
raise Exception('invalid number of rpc arguments')
|
||||
if len(arg) >= 65535:
|
||||
raise Exception('invalid rpc argument size (must be < 65535)')
|
||||
argv[argc] = ffi.new('char[]', arg)
|
||||
argvs[argc] = len(arg)
|
||||
argc += 1
|
||||
|
||||
if node:
|
||||
c_node = ffi.new("char[]", node)
|
||||
else:
|
||||
c_node = ffi.NULL
|
||||
|
||||
response = lib.uwsgi_do_rpc(c_node, ffi.new("char[]",func), argc, argv, argvs, rsize)
|
||||
if response:
|
||||
ret = ffi.string(response, rsize[0])
|
||||
lib.free(response)
|
||||
return ret
|
||||
return None
|
||||
uwsgi.rpc = uwsgi_pypy_rpc
|
||||
|
||||
def uwsgi_pypy_call(func, *args):
|
||||
node = None
|
||||
if '@' in func:
|
||||
(func, node) = func.split('@')
|
||||
return uwsgi_pypy_rpc(node, func, *args)
|
||||
uwsgi.call = uwsgi_pypy_call
|
||||
|
||||
def uwsgi_pypy_uwsgi_signal(signum):
|
||||
lib.uwsgi_pypy_helper_signal(signum)
|
||||
uwsgi.signal = uwsgi_pypy_uwsgi_signal
|
||||
|
||||
|
||||
def uwsgi_pypy_uwsgi_cache_get(key, cache=ffi.NULL):
|
||||
vallen = ffi.new('uint64_t*')
|
||||
value = lib.uwsgi_cache_magic_get(key, len(key), vallen, ffi.NULL, cache)
|
||||
if value == ffi.NULL:
|
||||
return None
|
||||
ret = ffi.string(value, vallen[0])
|
||||
libc.free(value)
|
||||
return ret
|
||||
uwsgi.cache_get = uwsgi_pypy_uwsgi_cache_get
|
||||
|
||||
def uwsgi_pypy_uwsgi_cache_set(key, value, expires=0, cache=ffi.NULL):
|
||||
if lib.uwsgi_cache_magic_set(key, len(key), value, len(value), expires, 0, cache) < 0:
|
||||
raise Exception('unable to store item in the cache')
|
||||
uwsgi.cache_set = uwsgi_pypy_uwsgi_cache_set
|
||||
|
||||
def uwsgi_pypy_uwsgi_cache_update(key, value, expires=0, cache=ffi.NULL):
|
||||
if lib.uwsgi_cache_magic_set(key, len(key), value, len(value), expires, 1 << 1, cache) < 0:
|
||||
raise Exception('unable to store item in the cache')
|
||||
uwsgi.cache_update = uwsgi_pypy_uwsgi_cache_update
|
||||
|
||||
def uwsgi_pypy_uwsgi_cache_del(key, cache=ffi.NULL):
|
||||
if lib.uwsgi_cache_magic_del(key, len(key), cache) < 0:
|
||||
raise Exception('unable to delete item from the cache')
|
||||
uwsgi.cache_del = uwsgi_pypy_uwsgi_cache_del
|
||||
|
||||
|
||||
def uwsgi_pypy_uwsgi_add_timer(signum, secs):
|
||||
if lib.uwsgi_add_timer(signum, secs) < 0:
|
||||
raise Exception("unable to register timer")
|
||||
uwsgi.add_timer = uwsgi_pypy_uwsgi_add_timer
|
||||
|
||||
def uwsgi_pypy_uwsgi_add_rb_timer(signum, secs):
|
||||
if lib.uwsgi_add_rb_timer(signum, secs, 0) < 0:
|
||||
raise Exception("unable to register redblack timer")
|
||||
uwsgi.add_rb_timer = uwsgi_pypy_uwsgi_add_rb_timer
|
||||
|
||||
|
||||
def uwsgi_pypy_uwsgi_add_file_monitor(signum, filename):
|
||||
if lib.uwsgi_add_file_monitor(signum, ffi.new("char[]", filename)) < 0:
|
||||
raise Exception("unable to register file monitor")
|
||||
uwsgi.add_file_monitor = uwsgi_pypy_uwsgi_add_file_monitor
|
||||
|
||||
def uwsgi_pypy_lock(num):
|
||||
if lib.uwsgi_user_lock(num) < 0:
|
||||
raise Exception("invalid lock")
|
||||
uwsgi.lock = uwsgi_pypy_lock
|
||||
|
||||
def uwsgi_pypy_unlock(num):
|
||||
if lib.uwsgi_user_unlock(num) < 0:
|
||||
raise Exception("invalid lock")
|
||||
uwsgi.unlock = uwsgi_pypy_unlock
|
||||
|
||||
def uwsgi_pypy_masterpid():
|
||||
return lib.uwsgi_pypy_helper_masterpid()
|
||||
uwsgi.masterpid = uwsgi_pypy_masterpid
|
||||
|
||||
def uwsgi_pypy_worker_id():
|
||||
return lib.uwsgi_pypy_helper_worker_id()
|
||||
uwsgi.worker_id = uwsgi_pypy_worker_id
|
||||
|
||||
def uwsgi_pypy_mule_id():
|
||||
return lib.uwsgi_pypy_helper_mule_id()
|
||||
uwsgi.mule_id = uwsgi_pypy_mule_id
|
||||
|
||||
def uwsgi_pypy_signal_registered(signum):
|
||||
if lib.uwsgi_signal_registered(signum) > 0:
|
||||
return True
|
||||
return False
|
||||
uwsgi.signal_registered = uwsgi_pypy_signal_registered
|
||||
|
||||
def uwsgi_pypy_alarm(alarm, msg):
|
||||
lib.uwsgi_alarm_trigger(ffi.new('char[]', alarm), ffi.new('char[]', msg), len(msg))
|
||||
uwsgi.alarm = uwsgi_pypy_alarm
|
||||
|
||||
def uwsgi_pypy_setprocname(name):
|
||||
lib.uwsgi_set_processname(ffi.new('char[]',name))
|
||||
uwsgi.setprocname = uwsgi_pypy_setprocname
|
||||
|
||||
def uwsgi_pypy_add_cron(signum, minute, hour, day, month, week):
|
||||
if lib.uwsgi_signal_add_cron(signum, minute, hour, day, month, week) < 0:
|
||||
raise Exception("unable to register cron")
|
||||
return True
|
||||
uwsgi.add_cron = uwsgi_pypy_add_cron
|
||||
|
||||
"""
|
||||
populate uwsgi.opt
|
||||
"""
|
||||
uwsgi.opt = {}
|
||||
n_opts = ffi.new('int*')
|
||||
u_opts = lib.uwsgi_pypy_helper_opts(n_opts)
|
||||
for i in range(0, n_opts[0]):
|
||||
k = ffi.string(u_opts[i].key)
|
||||
if u_opts[i].value == ffi.NULL:
|
||||
v = True
|
||||
else:
|
||||
v = ffi.string(u_opts[i].value)
|
||||
if k in uwsgi.opt:
|
||||
if type(uwsgi.opt[k]) is list:
|
||||
uwsgi.opt[k].append(v)
|
||||
else:
|
||||
uwsgi.opt[k] = [uwsgi.opt[k], v]
|
||||
else:
|
||||
uwsgi.opt[k] = v
|
||||
|
||||
print "Initialized PyPy with Python", sys.version
|
||||
print "PyPy Home:", sys.prefix
|
||||
+10
-11
@@ -1,13 +1,12 @@
|
||||
import os,sys
|
||||
|
||||
from distutils import sysconfig
|
||||
|
||||
NAME='pypy'
|
||||
GCC_LIST = ['../python/python_plugin', '../python/pyutils', '../python/pyloader', '../python/wsgi_handlers', '../python/wsgi_headers', '../python/wsgi_subhandler',
|
||||
'../python/web3_subhandler', '../python/pump_subhandler','../python/gil', '../python/uwsgi_pymodule', '../python/profiler', '../python/symimporter']
|
||||
|
||||
CFLAGS = ['-I' + sysconfig.get_python_inc(), '-I' + sysconfig.get_python_inc(plat_specific=True) ]
|
||||
CFLAGS.append('-DUWSGI_PYPY')
|
||||
|
||||
LIBS = ['-lpypy-c']
|
||||
LDFLAGS = []
|
||||
LIBS = []
|
||||
GCC_LIST = ['pypy_plugin']
|
||||
BINARY_LIST = [ ('uwsgi_pypy_setup','pypy_setup.py')]
|
||||
CFLAGS = []
|
||||
try:
|
||||
import __pypy__
|
||||
import sys
|
||||
CFLAGS.append('-DUWSGI_PYPY_HOME="\\"%s\\""' % sys.prefix)
|
||||
except:
|
||||
pass
|
||||
|
||||
@@ -5,7 +5,7 @@ extern struct uwsgi_python up;
|
||||
|
||||
void gil_real_get() {
|
||||
//uwsgi_log("LOCK %d\n", uwsgi.mywid);
|
||||
#if !defined(PYTHREE) && !defined(UWSGI_PYPY)
|
||||
#if !defined(PYTHREE)
|
||||
PyEval_AcquireLock();
|
||||
PyThreadState_Swap((PyThreadState *) pthread_getspecific(up.upt_gil_key));
|
||||
#else
|
||||
@@ -17,7 +17,7 @@ void gil_real_get() {
|
||||
|
||||
void gil_real_release() {
|
||||
//uwsgi_log("UNLOCK %d\n", uwsgi.mywid);
|
||||
#if !defined(PYTHREE) && !defined(UWSGI_PYPY)
|
||||
#if !defined(PYTHREE)
|
||||
pthread_setspecific(up.upt_gil_key, (void *) PyThreadState_Swap(NULL));
|
||||
PyEval_ReleaseLock();
|
||||
#else
|
||||
|
||||
@@ -15,7 +15,6 @@ int PyFrame_GetLineNumber(PyFrameObject *frame) {
|
||||
|
||||
int uwsgi_python_profiler_call(PyObject *obj, PyFrameObject *frame, int what, PyObject *arg) {
|
||||
|
||||
#ifndef UWSGI_PYPY
|
||||
static uint64_t last_ts = 0;
|
||||
uint64_t now = uwsgi_micros();
|
||||
uint64_t delta = 0;
|
||||
@@ -42,14 +41,12 @@ int uwsgi_python_profiler_call(PyObject *obj, PyFrameObject *frame, int what, Py
|
||||
PyEval_GetFuncName(arg), frame->f_code->co_argcount, frame->f_code->co_stacksize);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_python_tracer(PyObject *obj, PyFrameObject *frame, int what, PyObject *arg) {
|
||||
|
||||
#ifndef UWSGI_PYPY
|
||||
static uint64_t last_ts = 0;
|
||||
uint64_t now = uwsgi_micros();
|
||||
uint64_t delta = 0;
|
||||
@@ -64,7 +61,6 @@ int uwsgi_python_tracer(PyObject *obj, PyFrameObject *frame, int what, PyObject
|
||||
last_ts = now;
|
||||
uwsgi_log("[uWSGI Python profiler %llu] file %s line %d: %s argc:%d\n", (unsigned long long)delta, PyString_AsString(frame->f_code->co_filename), PyFrame_GetLineNumber(frame), PyString_AsString(frame->f_code->co_name), frame->f_code->co_argcount);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -672,10 +672,6 @@ PyObject *uwsgi_paste_loader(void *arg1) {
|
||||
|
||||
PyObject *uwsgi_eval_loader(void *arg1) {
|
||||
|
||||
#ifdef UWSGI_PYPY
|
||||
uwsgi_log("the eval loader is currently not supported under PyPy !!!\n");
|
||||
return NULL;
|
||||
#else
|
||||
char *code = (char *) arg1;
|
||||
|
||||
PyObject *wsgi_eval_module, *wsgi_eval_callable = NULL;
|
||||
@@ -731,7 +727,6 @@ PyObject *uwsgi_eval_loader(void *arg1) {
|
||||
}
|
||||
|
||||
return wsgi_eval_callable;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -52,11 +52,7 @@ void uwsgi_opt_pyrun(char *opt, char *value, void *foobar) {
|
||||
}
|
||||
|
||||
void uwsgi_opt_pyver(char *opt, char *foo, void *bar) {
|
||||
#ifndef UWSGI_PYPY
|
||||
const char *version = Py_GetVersion();
|
||||
#else
|
||||
const char *version = PYPY_VERSION;
|
||||
#endif
|
||||
const char *space = strchr(version, ' ');
|
||||
if (space) {
|
||||
fprintf(stdout, "%.*s\n", (int) (space-version), version);
|
||||
@@ -136,9 +132,7 @@ struct uwsgi_option uwsgi_python_options[] = {
|
||||
{"ini-paste-logged", required_argument, 0, "load a paste.deploy config file containing uwsgi section (load loggers too)", uwsgi_opt_ini_paste, NULL, UWSGI_OPT_IMMEDIATE},
|
||||
{"reload-os-env", no_argument, 0, "force reload of os.environ at each request", uwsgi_opt_true, &up.reload_os_env, 0},
|
||||
#ifndef __CYGWIN__
|
||||
#ifndef UWSGI_PYPY
|
||||
{"no-site", no_argument, 0, "do not import site module", uwsgi_opt_true, &Py_NoSiteFlag, 0},
|
||||
#endif
|
||||
#endif
|
||||
{"pyshell", optional_argument, 0, "run an interactive python shell in the uWSGI environment", uwsgi_opt_pyshell, NULL, 0},
|
||||
{"pyshell-oneshot", optional_argument, 0, "run an interactive python shell in the uWSGI environment (one-shot variant)", uwsgi_opt_pyshell, NULL, 0},
|
||||
@@ -147,9 +141,8 @@ struct uwsgi_option uwsgi_python_options[] = {
|
||||
{"py", required_argument, 0, "run a python script in the uWSGI environment", uwsgi_opt_pyrun, NULL, 0},
|
||||
{"pyrun", required_argument, 0, "run a python script in the uWSGI environment", uwsgi_opt_pyrun, NULL, 0},
|
||||
|
||||
#ifndef UWSGI_PYPY
|
||||
{"py-tracebacker", required_argument, 0, "enable the uWSGI python tracebacker", uwsgi_opt_set_str, &up.tracebacker, UWSGI_OPT_THREADS|UWSGI_OPT_MASTER},
|
||||
#endif
|
||||
|
||||
{"py-auto-reload", required_argument, 0, "monitor python modules mtime to trigger reload (use only in development)", uwsgi_opt_set_int, &up.auto_reload, UWSGI_OPT_THREADS|UWSGI_OPT_MASTER},
|
||||
{"py-autoreload", required_argument, 0, "monitor python modules mtime to trigger reload (use only in development)", uwsgi_opt_set_int, &up.auto_reload, UWSGI_OPT_THREADS|UWSGI_OPT_MASTER},
|
||||
{"python-auto-reload", required_argument, 0, "monitor python modules mtime to trigger reload (use only in development)", uwsgi_opt_set_int, &up.auto_reload, UWSGI_OPT_THREADS|UWSGI_OPT_MASTER},
|
||||
@@ -183,7 +176,6 @@ PyMethodDef uwsgi_write_method[] = { {"uwsgi_write", py_uwsgi_write, METH_VARARG
|
||||
|
||||
int uwsgi_python_init() {
|
||||
|
||||
#ifndef UWSGI_PYPY
|
||||
char *pyversion = strchr(Py_GetVersion(), '\n');
|
||||
if (!pyversion) {
|
||||
uwsgi_log_initial("Python version: %s\n", Py_GetVersion());
|
||||
@@ -191,9 +183,6 @@ int uwsgi_python_init() {
|
||||
else {
|
||||
uwsgi_log_initial("Python version: %.*s %s\n", pyversion-Py_GetVersion(), Py_GetVersion(), Py_GetCompiler()+1);
|
||||
}
|
||||
#else
|
||||
uwsgi_log_initial("PyPy version: %s\n", PYPY_VERSION);
|
||||
#endif
|
||||
|
||||
if (up.home != NULL) {
|
||||
#ifdef PYTHREE
|
||||
@@ -245,9 +234,7 @@ pep405:
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef UWSGI_PYPY
|
||||
Py_OptimizeFlag = up.optimize;
|
||||
#endif
|
||||
|
||||
Py_Initialize();
|
||||
|
||||
@@ -286,9 +273,6 @@ void uwsgi_python_reset_random_seed() {
|
||||
random_seed = PyDict_GetItemString(random_dict, "seed");
|
||||
if (random_seed) {
|
||||
PyObject *random_args = PyTuple_New(1);
|
||||
#ifdef UWSGI_PYPY
|
||||
Py_INCREF(Py_None);
|
||||
#endif
|
||||
// pass no args
|
||||
PyTuple_SetItem(random_args, 0, Py_None);
|
||||
PyEval_CallObject(random_seed, random_args);
|
||||
@@ -375,13 +359,11 @@ void uwsgi_python_post_fork() {
|
||||
pthread_t par_tid;
|
||||
pthread_create(&par_tid, NULL, uwsgi_python_autoreloader_thread, NULL);
|
||||
}
|
||||
#ifndef UWSGI_PYPY
|
||||
if (up.tracebacker) {
|
||||
// spawn the tracebacker thread
|
||||
pthread_t ptb_tid;
|
||||
pthread_create(&ptb_tid, NULL, uwsgi_python_tracebacker_thread, NULL);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
UWSGI_RELEASE_GIL
|
||||
@@ -390,10 +372,6 @@ UWSGI_RELEASE_GIL
|
||||
|
||||
PyObject *uwsgi_pyimport_by_filename(char *name, char *filename) {
|
||||
|
||||
#ifdef UWSGI_PYPY
|
||||
uwsgi_log("import by filename is currently not supported on PyPy !!!\n");
|
||||
return NULL;
|
||||
#else
|
||||
FILE *pyfile;
|
||||
struct _node *py_file_node = NULL;
|
||||
PyObject *py_compiled_node, *py_file_module;
|
||||
@@ -479,7 +457,6 @@ PyObject *uwsgi_pyimport_by_filename(char *name, char *filename) {
|
||||
Py_DECREF(py_compiled_node);
|
||||
|
||||
return py_file_module;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
@@ -500,7 +477,11 @@ void init_uwsgi_vars() {
|
||||
|
||||
#ifdef PYTHREE
|
||||
// fix stdout and stderr
|
||||
PyObject *new_stdprint = PyFile_NewStdPrinter(2);
|
||||
#ifdef HAS_NO_ERRORS_IN_PyFile_FromFd
|
||||
PyObject *new_stdprint = PyFile_FromFd(2, NULL, "w", _IOLBF, NULL, NULL, 0);
|
||||
#else
|
||||
PyObject *new_stdprint = PyFile_FromFd(2, NULL, "w", _IOLBF, NULL, NULL, NULL, 0);
|
||||
#endif
|
||||
PyDict_SetItemString(pysys_dict, "stdout", new_stdprint);
|
||||
PyDict_SetItemString(pysys_dict, "__stdout__", new_stdprint);
|
||||
PyDict_SetItemString(pysys_dict, "stderr", new_stdprint);
|
||||
@@ -1067,13 +1048,11 @@ void uwsgi_python_init_apps() {
|
||||
UWSGI_GET_GIL;
|
||||
}
|
||||
|
||||
#ifndef UWSGI_PYPY
|
||||
// prepare for stack suspend/resume
|
||||
if (uwsgi.async > 1) {
|
||||
up.current_recursion_depth = uwsgi_malloc(sizeof(int)*uwsgi.async);
|
||||
up.current_frame = uwsgi_malloc(sizeof(struct _frame)*uwsgi.async);
|
||||
}
|
||||
#endif
|
||||
|
||||
// setup app loaders
|
||||
up.loaders[LOADER_DYN] = uwsgi_dyn_loader;
|
||||
@@ -1160,7 +1139,6 @@ next:
|
||||
init_uwsgi_app(LOADER_UWSGI, up.wsgi_lite, uwsgi.wsgi_req, up.main_thread, PYTHON_APP_TYPE_WSGI_LITE);
|
||||
}
|
||||
|
||||
#ifndef UWSGI_PYPY
|
||||
if (uwsgi.profiler) {
|
||||
if (!strcmp(uwsgi.profiler, "pycall")) {
|
||||
PyEval_SetProfile(uwsgi_python_profiler_call, NULL);
|
||||
@@ -1169,7 +1147,6 @@ next:
|
||||
PyEval_SetTrace(uwsgi_python_tracer, NULL);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
PyObject *uwsgi_dict = get_uwsgi_pydict("uwsgi");
|
||||
if (uwsgi_dict) {
|
||||
@@ -1425,7 +1402,6 @@ void *uwsgi_python_autoreloader_thread(void *foobar) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifndef UWSGI_PYPY
|
||||
void uwsgi_python_suspend(struct wsgi_request *wsgi_req) {
|
||||
|
||||
PyGILState_STATE pgst = PyGILState_Ensure();
|
||||
@@ -1442,7 +1418,6 @@ void uwsgi_python_suspend(struct wsgi_request *wsgi_req) {
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
char *uwsgi_python_code_string(char *id, char *code, char *function, char *key, uint16_t keylen) {
|
||||
|
||||
@@ -1637,7 +1612,6 @@ int uwsgi_python_spooler(char *filename, char *buf, uint16_t len, char *body, si
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifndef UWSGI_PYPY
|
||||
void uwsgi_python_resume(struct wsgi_request *wsgi_req) {
|
||||
|
||||
PyGILState_STATE pgst = PyGILState_Ensure();
|
||||
@@ -1654,7 +1628,6 @@ void uwsgi_python_resume(struct wsgi_request *wsgi_req) {
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
void uwsgi_python_fixup() {
|
||||
// set hacky modifier 30
|
||||
@@ -1668,7 +1641,6 @@ void uwsgi_python_hijack(void) {
|
||||
|
||||
// the pyshell will be execute only in the first worker
|
||||
|
||||
#ifndef UWSGI_PYPY
|
||||
FILE *pyfile;
|
||||
if (up.pyrun) {
|
||||
uwsgi.workers[uwsgi.mywid].hijacked = 1;
|
||||
@@ -1682,7 +1654,6 @@ void uwsgi_python_hijack(void) {
|
||||
// could be never executed
|
||||
exit(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (up.pyshell_oneshot && uwsgi.workers[uwsgi.mywid].hijacked_count > 0) {
|
||||
uwsgi.workers[uwsgi.mywid].hijacked = 0;
|
||||
@@ -1708,9 +1679,7 @@ void uwsgi_python_hijack(void) {
|
||||
else {
|
||||
PyImport_ImportModule("readline");
|
||||
|
||||
#ifndef UWSGI_PYPY
|
||||
ret = PyRun_InteractiveLoop(stdin, "uwsgi");
|
||||
#endif
|
||||
}
|
||||
if (up.pyshell_oneshot) {
|
||||
exit(UWSGI_DE_HIJACKED_CODE);
|
||||
@@ -1787,7 +1756,12 @@ void uwsgi_python_harakiri(int wid) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
# you can use this logger to offload logging to python
|
||||
# be sure to configure it to not log to stderr otherwise you will generate a loop
|
||||
import logging
|
||||
logging.basicConfig(filename='/tmp/pippo.log')
|
||||
*/
|
||||
ssize_t uwsgi_python_logger(struct uwsgi_logger *ul, char *message, size_t len) {
|
||||
if (!Py_IsInitialized()) return -1;
|
||||
|
||||
@@ -1830,13 +1804,8 @@ void uwsgi_python_on_load() {
|
||||
uwsgi_register_logger("python", uwsgi_python_logger);
|
||||
}
|
||||
|
||||
#ifndef UWSGI_PYPY
|
||||
struct uwsgi_plugin python_plugin = {
|
||||
.name = "python",
|
||||
#else
|
||||
struct uwsgi_plugin pypy_plugin = {
|
||||
.name = "pypy",
|
||||
#endif
|
||||
.alias = "python",
|
||||
.modifier1 = 0,
|
||||
.init = uwsgi_python_init,
|
||||
@@ -1858,10 +1827,8 @@ struct uwsgi_plugin pypy_plugin = {
|
||||
|
||||
.magic = uwsgi_python_magic,
|
||||
|
||||
#ifndef UWSGI_PYPY
|
||||
.suspend = uwsgi_python_suspend,
|
||||
.resume = uwsgi_python_resume,
|
||||
#endif
|
||||
|
||||
.harakiri = uwsgi_python_harakiri,
|
||||
|
||||
|
||||
@@ -10,14 +10,14 @@ int manage_python_response(struct wsgi_request *wsgi_req) {
|
||||
|
||||
char *uwsgi_python_get_exception_type(PyObject *exc) {
|
||||
char *class_name = NULL;
|
||||
#if !defined(PYTHREE) && !defined(UWSGI_PYPY)
|
||||
#if !defined(PYTHREE)
|
||||
if (PyClass_Check(exc)) {
|
||||
class_name = PyString_AsString( ((PyClassObject*)(exc))->cl_name );
|
||||
}
|
||||
else {
|
||||
#endif
|
||||
class_name = (char *) ((PyTypeObject*)exc)->tp_name;
|
||||
#if !defined(PYTHREE) && !defined(UWSGI_PYPY)
|
||||
#if !defined(PYTHREE)
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -301,8 +301,9 @@ void init_pyargv() {
|
||||
#endif
|
||||
if (*ap != '\0') {
|
||||
#ifdef PYTHREE
|
||||
mbstowcs( wcargv + strlen(ap), ap, strlen(ap));
|
||||
up.py_argv[up.argc] = wcargv + strlen(ap);
|
||||
mbstowcs( wcargv, ap, strlen(ap));
|
||||
up.py_argv[up.argc] = wcargv;
|
||||
wcargv += strlen(ap) + 1;
|
||||
#else
|
||||
up.py_argv[up.argc] = ap;
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#include "uwsgi_python.h"
|
||||
|
||||
#ifndef UWSGI_PYPY
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
extern struct uwsgi_python up;
|
||||
|
||||
@@ -806,5 +804,3 @@ int uwsgi_init_symbol_import() {
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -22,6 +22,10 @@
|
||||
#define HAS_NOT_PyFrame_GetLineNumber
|
||||
#endif
|
||||
|
||||
#if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION == 0
|
||||
#define HAS_NO_ERRORS_IN_PyFile_FromFd
|
||||
#endif
|
||||
|
||||
#if PY_MAJOR_VERSION > 2
|
||||
#define PYTHREE
|
||||
#endif
|
||||
|
||||
@@ -14,10 +14,6 @@ NAME='python'
|
||||
GCC_LIST = ['python_plugin', 'pyutils', 'pyloader', 'wsgi_handlers', 'wsgi_headers', 'wsgi_subhandler', 'web3_subhandler', 'pump_subhandler', 'gil', 'uwsgi_pymodule', 'profiler', 'symimporter', 'tracebacker']
|
||||
|
||||
CFLAGS = ['-I' + sysconfig.get_python_inc(), '-I' + sysconfig.get_python_inc(plat_specific=True) ]
|
||||
|
||||
if 'pypy_version_info' in sys.__dict__:
|
||||
CFLAGS.append('-DUWSGI_PYPY')
|
||||
|
||||
LDFLAGS = []
|
||||
|
||||
if not 'UWSGI_PYTHON_NOLIB' in os.environ:
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
extern struct uwsgi_python up;
|
||||
extern struct uwsgi_plugin python_plugin;
|
||||
|
||||
|
||||
PyObject *uwsgi_Input_iter(PyObject *self) {
|
||||
@@ -339,7 +340,7 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
|
||||
}
|
||||
}
|
||||
|
||||
if ( (wsgi_req->app_id = uwsgi_get_app_id(wsgi_req, wsgi_req->appid, wsgi_req->appid_len, 0)) == -1) {
|
||||
if ( (wsgi_req->app_id = uwsgi_get_app_id(wsgi_req, wsgi_req->appid, wsgi_req->appid_len, python_plugin.modifier1)) == -1) {
|
||||
if (wsgi_req->dynamic) {
|
||||
UWSGI_GET_GIL
|
||||
if (uwsgi.single_interpreter) {
|
||||
@@ -350,6 +351,12 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
|
||||
}
|
||||
UWSGI_RELEASE_GIL
|
||||
}
|
||||
|
||||
if (wsgi_req->app_id == -1 && !uwsgi.no_default_app && uwsgi.default_app > -1) {
|
||||
if (uwsgi_apps[uwsgi.default_app].modifier1 == python_plugin.modifier1) {
|
||||
wsgi_req->app_id = uwsgi.default_app;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (wsgi_req->dynamic) {
|
||||
@@ -358,6 +365,7 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (wsgi_req->app_id == -1) {
|
||||
uwsgi_500(wsgi_req);
|
||||
uwsgi_log("--- no python application found, check your startup logs for errors ---\n");
|
||||
|
||||
@@ -80,7 +80,7 @@ PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) {
|
||||
#ifdef PYTHREE
|
||||
Py_DECREF(zero);
|
||||
#endif
|
||||
return PyErr_Format(PyExc_TypeError, "unable to set HTTP status line");
|
||||
goto end;
|
||||
}
|
||||
|
||||
#ifdef PYTHREE
|
||||
@@ -193,6 +193,7 @@ PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) {
|
||||
UWSGI_GET_GIL
|
||||
}
|
||||
|
||||
end:
|
||||
Py_INCREF(up.wsgi_writeout);
|
||||
return up.wsgi_writeout;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,44 @@ extern struct uwsgi_server uwsgi;
|
||||
extern struct uwsgi_python up;
|
||||
extern PyTypeObject uwsgi_InputType;
|
||||
|
||||
/*
|
||||
this is a hack for supporting non-file object passed to wsgi.file_wrapper
|
||||
*/
|
||||
static void uwsgi_python_consume_file_wrapper_read(struct wsgi_request *wsgi_req, PyObject *pychunk) {
|
||||
PyObject *read_method_args = NULL;
|
||||
PyObject *read_method = PyObject_GetAttrString(pychunk, "read");
|
||||
if (wsgi_req->sendfile_fd_chunk > 0) {
|
||||
read_method_args = PyTuple_New(1);
|
||||
PyTuple_SetItem(read_method_args, 0, PyInt_FromLong(wsgi_req->sendfile_fd_chunk));
|
||||
}
|
||||
else {
|
||||
read_method_args = PyTuple_New(0);
|
||||
}
|
||||
for(;;) {
|
||||
PyObject *read_method_output = PyEval_CallObject(read_method, read_method_args);
|
||||
if (PyErr_Occurred()) {
|
||||
uwsgi_manage_exception(wsgi_req, 0);
|
||||
break;
|
||||
}
|
||||
if (!read_method_output) break;
|
||||
if (PyString_Check(read_method_output)) {
|
||||
char *content = PyString_AsString(read_method_output);
|
||||
size_t content_len = PyString_Size(read_method_output);
|
||||
if (content_len == 0) {
|
||||
Py_DECREF(read_method_output);
|
||||
break;
|
||||
}
|
||||
UWSGI_RELEASE_GIL
|
||||
uwsgi_response_write_body_do(wsgi_req, content, content_len);
|
||||
UWSGI_GET_GIL
|
||||
}
|
||||
Py_DECREF(read_method_output);
|
||||
if (wsgi_req->sendfile_fd_chunk == 0) break;
|
||||
}
|
||||
Py_DECREF(read_method_args);
|
||||
Py_DECREF(read_method);
|
||||
}
|
||||
|
||||
void *uwsgi_request_subhandler_wsgi(struct wsgi_request *wsgi_req, struct uwsgi_app *wi) {
|
||||
|
||||
|
||||
@@ -143,10 +181,16 @@ int uwsgi_response_subhandler_wsgi(struct wsgi_request *wsgi_req) {
|
||||
}
|
||||
|
||||
|
||||
if (wsgi_req->sendfile_obj == wsgi_req->async_result && wsgi_req->sendfile_fd != -1) {
|
||||
UWSGI_RELEASE_GIL
|
||||
uwsgi_response_sendfile_do(wsgi_req, wsgi_req->sendfile_fd, 0, 0);
|
||||
UWSGI_GET_GIL
|
||||
if (wsgi_req->sendfile_obj == wsgi_req->async_result) {
|
||||
if (wsgi_req->sendfile_fd >= 0) {
|
||||
UWSGI_RELEASE_GIL
|
||||
uwsgi_response_sendfile_do(wsgi_req, wsgi_req->sendfile_fd, 0, 0);
|
||||
UWSGI_GET_GIL
|
||||
}
|
||||
// we do not have an iterable, check for read() method
|
||||
else if (PyObject_HasAttrString((PyObject *)wsgi_req->async_result, "read")) {
|
||||
uwsgi_python_consume_file_wrapper_read(wsgi_req, (PyObject *)wsgi_req->async_result);
|
||||
}
|
||||
uwsgi_py_check_write_errors {
|
||||
uwsgi_py_write_exception(wsgi_req);
|
||||
}
|
||||
@@ -190,10 +234,17 @@ exception:
|
||||
}
|
||||
}
|
||||
|
||||
else if (wsgi_req->sendfile_obj == pychunk && wsgi_req->sendfile_fd != -1) {
|
||||
UWSGI_RELEASE_GIL
|
||||
uwsgi_response_sendfile_do(wsgi_req, wsgi_req->sendfile_fd, 0, 0);
|
||||
UWSGI_GET_GIL
|
||||
else if (wsgi_req->sendfile_obj == pychunk) {
|
||||
if (wsgi_req->sendfile_fd >= 0) {
|
||||
UWSGI_RELEASE_GIL
|
||||
uwsgi_response_sendfile_do(wsgi_req, wsgi_req->sendfile_fd, 0, 0);
|
||||
UWSGI_GET_GIL
|
||||
}
|
||||
// we do not have an iterable, check for read() method
|
||||
else if (PyObject_HasAttrString(pychunk, "read")) {
|
||||
uwsgi_python_consume_file_wrapper_read(wsgi_req, pychunk);
|
||||
}
|
||||
|
||||
uwsgi_py_check_write_errors {
|
||||
uwsgi_py_write_exception(wsgi_req);
|
||||
Py_DECREF(pychunk);
|
||||
|
||||
@@ -888,7 +888,9 @@ int uwsgi_rack_request(struct wsgi_request *wsgi_req) {
|
||||
status = rb_obj_as_string(RARRAY_PTR(ret)[0]);
|
||||
// get the status code
|
||||
|
||||
uwsgi_response_prepare_headers(wsgi_req, RSTRING_PTR(status), RSTRING_LEN(status));
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, RSTRING_PTR(status), RSTRING_LEN(status))) {
|
||||
goto clear;
|
||||
}
|
||||
|
||||
headers = RARRAY_PTR(ret)[1] ;
|
||||
if (rb_respond_to( headers, rb_intern("each") )) {
|
||||
|
||||
@@ -163,6 +163,8 @@ static ssize_t rr_instance_connected(struct corerouter_peer *peer) {
|
||||
struct rawrouter_session *rr = (struct rawrouter_session *) cs;
|
||||
cr_peer_connected(peer, "rr_instance_connected()");
|
||||
|
||||
peer->can_retry = 0;
|
||||
|
||||
if (rr->xclient) {
|
||||
cr_reset_hooks_and_read(peer, rr_xclient_read);
|
||||
return 1;
|
||||
@@ -251,6 +253,7 @@ static int rawrouter_alloc_session(struct uwsgi_corerouter *ucr, struct uwsgi_ga
|
||||
return -1;
|
||||
}
|
||||
|
||||
peer->can_retry = 1;
|
||||
cr_connect(peer, rr_instance_connected);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -56,6 +56,7 @@ struct uwsgi_router_cache_conf {
|
||||
|
||||
char *status_str;
|
||||
int status;
|
||||
char *no_offload;
|
||||
};
|
||||
|
||||
// this is allocated for each transformation
|
||||
@@ -189,6 +190,13 @@ static int uwsgi_routing_func_cache(struct wsgi_request *wsgi_req, struct uwsgi_
|
||||
if (uwsgi_response_add_expires(wsgi_req, expires)) goto error;
|
||||
}
|
||||
if (uwsgi_response_add_content_length(wsgi_req, valsize)) goto error;
|
||||
if (wsgi_req->socket->can_offload && !ur->custom && !urcc->no_offload) {
|
||||
if (!uwsgi_offload_request_memory_do(wsgi_req, value, valsize)) {
|
||||
wsgi_req->via = UWSGI_VIA_OFFLOAD;
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_response_write_body_do(wsgi_req, value, valsize);
|
||||
free(value);
|
||||
if (ur->custom)
|
||||
@@ -369,6 +377,7 @@ static int uwsgi_router_cache(struct uwsgi_route *ur, char *args) {
|
||||
"content_encoding", &urcc->content_encoding,
|
||||
"mime", &urcc->mime,
|
||||
"name", &urcc->name,
|
||||
"no_offload", &urcc->no_offload,
|
||||
NULL)) {
|
||||
uwsgi_log("invalid route syntax: %s\n", args);
|
||||
exit(1);
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
#ifdef UWSGI_ROUTING
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
/*
|
||||
|
||||
by Unbit
|
||||
|
||||
syntax:
|
||||
|
||||
route = /^foobar1(.*)/ hash:key=foo$1poo,algo=murmur2,var=MYHASH,items=node1;node2;node3
|
||||
|
||||
*/
|
||||
|
||||
struct uwsgi_router_hash_conf {
|
||||
|
||||
char *key;
|
||||
size_t key_len;
|
||||
|
||||
char *var;
|
||||
size_t var_len;
|
||||
|
||||
char *algo;
|
||||
char *items;
|
||||
size_t items_len;
|
||||
};
|
||||
|
||||
static int uwsgi_routing_func_hash(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){
|
||||
|
||||
struct uwsgi_router_hash_conf *urhc = (struct uwsgi_router_hash_conf *) ur->data2;
|
||||
|
||||
struct uwsgi_hash_algo *uha = uwsgi_hash_algo_get(urhc->algo);
|
||||
if (!uha) {
|
||||
uwsgi_log("[uwsgi-hash-router] unable to find hash algo \"%s\"\n", urhc->algo);
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
}
|
||||
|
||||
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, urhc->key, urhc->key_len);
|
||||
if (!ub) return UWSGI_ROUTE_BREAK;
|
||||
|
||||
uint32_t h = uha->func(ub->buf, ub->pos);
|
||||
uwsgi_buffer_destroy(ub);
|
||||
|
||||
// now count the number of items
|
||||
uint32_t items = 1;
|
||||
size_t i, ilen = urhc->items_len;
|
||||
for(i=0;i<ilen;i++) {
|
||||
if (urhc->items[i] == ';') items++;
|
||||
}
|
||||
|
||||
// skip last semicolon
|
||||
if (urhc->items[ilen-1] == ';') items--;
|
||||
|
||||
uint32_t hashed_result = h % items;
|
||||
uint32_t found = 0;
|
||||
char *value = urhc->items;
|
||||
uint16_t vallen = 0;
|
||||
for(i=0;i<ilen;i++) {
|
||||
if (!value) {
|
||||
value = urhc->items + i;
|
||||
}
|
||||
if (urhc->items[i] == ';') {
|
||||
if (found == hashed_result) {
|
||||
vallen = (urhc->items+i) - value;
|
||||
break;
|
||||
}
|
||||
value = NULL;
|
||||
found++;
|
||||
}
|
||||
}
|
||||
|
||||
if (vallen == 0) {
|
||||
// first item
|
||||
if (hashed_result == 0) {
|
||||
value = urhc->items;
|
||||
vallen = urhc->items_len;
|
||||
}
|
||||
// last item
|
||||
else {
|
||||
vallen = (urhc->items + urhc->items_len) - value;
|
||||
}
|
||||
}
|
||||
|
||||
if (!vallen) {
|
||||
uwsgi_log("[uwsgi-hash-router] BUG !!! unable to hash items\n");
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
}
|
||||
|
||||
if (!uwsgi_req_append(wsgi_req, urhc->var, urhc->var_len, value, vallen)) {
|
||||
uwsgi_log("[uwsgi-hash-router] unable to append hash var to the request\n");
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
}
|
||||
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
|
||||
static int uwsgi_router_hash(struct uwsgi_route *ur, char *args) {
|
||||
ur->func = uwsgi_routing_func_hash;
|
||||
ur->data = args;
|
||||
ur->data_len = strlen(args);
|
||||
struct uwsgi_router_hash_conf *urhc = uwsgi_calloc(sizeof(struct uwsgi_router_hash_conf));
|
||||
if (uwsgi_kvlist_parse(ur->data, ur->data_len, ',', '=',
|
||||
"key", &urhc->key,
|
||||
"var", &urhc->var,
|
||||
"algo", &urhc->algo,
|
||||
"items", &urhc->items,
|
||||
NULL)) {
|
||||
uwsgi_log("invalid route syntax: %s\n", args);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!urhc->key || !urhc->var || !urhc->items) {
|
||||
uwsgi_log("invalid route syntax: you need to specify a hash key, a var and a set of items\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
urhc->key_len = strlen(urhc->key);
|
||||
urhc->var_len = strlen(urhc->var);
|
||||
urhc->items_len = strlen(urhc->items);
|
||||
|
||||
|
||||
if (!urhc->algo) urhc->algo = "djb33x";
|
||||
|
||||
ur->data2 = urhc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void router_hash_register() {
|
||||
uwsgi_register_router("hash", uwsgi_router_hash);
|
||||
}
|
||||
|
||||
struct uwsgi_plugin router_hash_plugin = {
|
||||
.name = "router_hash",
|
||||
.on_load = router_hash_register,
|
||||
};
|
||||
|
||||
#else
|
||||
struct uwsgi_plugin router_hash_plugin = {
|
||||
.name = "router_hash",
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,6 @@
|
||||
NAME='router_hash'
|
||||
|
||||
CFLAGS = []
|
||||
LDFLAGS = []
|
||||
LIBS = []
|
||||
GCC_LIST = ['router_hash']
|
||||
@@ -1,20 +1,24 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
#ifdef UWSGI_ROUTING
|
||||
|
||||
#define MEMCACHED_BUFSIZE 8192
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
/*
|
||||
|
||||
memcached internal router
|
||||
memcached internal router and transformation
|
||||
|
||||
route = /^foobar1(.*)/ memcached:addr=127.0.0.1:11211,key=foo$1poo,type=body
|
||||
route = /^foobar1(.*)/ memcached:addr=127.0.0.1:11211,key=foo$1poo
|
||||
route = /^foobar1(.*)/ memcachedstore:addr=127.0.0.1:11211,key=foo$1poo
|
||||
|
||||
*/
|
||||
|
||||
struct uwsgi_router_memcached_conf {
|
||||
|
||||
char *addr;
|
||||
size_t addr_len;
|
||||
|
||||
char *key;
|
||||
size_t key_len;
|
||||
@@ -22,12 +26,19 @@ struct uwsgi_router_memcached_conf {
|
||||
char *content_type;
|
||||
size_t content_type_len;
|
||||
|
||||
// 0 -> full, 1 -> body
|
||||
char *type;
|
||||
int type_num;
|
||||
char *no_offload;
|
||||
char *expires;
|
||||
|
||||
};
|
||||
|
||||
// this is allocated for each transformation
|
||||
struct uwsgi_transformation_memcached_conf {
|
||||
struct uwsgi_buffer *addr;
|
||||
struct uwsgi_buffer *key;
|
||||
char *expires;
|
||||
};
|
||||
|
||||
|
||||
static size_t memcached_firstline_parse(char *buf, size_t len) {
|
||||
// check for "VALUE x 0 0"
|
||||
if (len < 11) return 0;
|
||||
@@ -48,6 +59,86 @@ static size_t memcached_firstline_parse(char *buf, size_t len) {
|
||||
}
|
||||
}
|
||||
|
||||
// store an item in memcached
|
||||
static void memcached_store(char *addr, struct uwsgi_buffer *key, struct uwsgi_buffer *value, char *expires) {
|
||||
|
||||
int timeout = uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT];
|
||||
|
||||
int fd = uwsgi_connect(addr, 0, 1);
|
||||
if (fd < 0) return;
|
||||
|
||||
// wait for connection
|
||||
int ret = uwsgi.wait_write_hook(fd, timeout);
|
||||
if (ret <= 0) goto end;
|
||||
|
||||
// build the request
|
||||
struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size);
|
||||
if (uwsgi_buffer_append(ub, "set ", 4)) goto end2;
|
||||
if (uwsgi_buffer_append(ub, key->buf, key->pos)) goto end2;
|
||||
if (uwsgi_buffer_append(ub, " 0 " , 3)) goto end2;
|
||||
if (uwsgi_buffer_append(ub, expires, strlen(expires))) goto end2;
|
||||
if (uwsgi_buffer_append(ub, " " , 1)) goto end2;
|
||||
if (uwsgi_buffer_num64(ub, value->pos)) goto end2;
|
||||
if (uwsgi_buffer_append(ub, "\r\n" , 2)) goto end2;
|
||||
|
||||
if (uwsgi_write_true_nb(fd, ub->buf, ub->pos, timeout)) goto end2;
|
||||
if (uwsgi_write_true_nb(fd, value->buf, value->pos, timeout)) goto end2;
|
||||
if (uwsgi_write_true_nb(fd, "\r\n", 2, timeout)) goto end2;
|
||||
|
||||
// we are not interested in command result... (ugly but it works)
|
||||
end2:
|
||||
uwsgi_buffer_destroy(ub);
|
||||
end:
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static int transform_memcached(struct wsgi_request *wsgi_req, struct uwsgi_transformation *ut) {
|
||||
struct uwsgi_transformation_memcached_conf *utmc = (struct uwsgi_transformation_memcached_conf *) ut->data;
|
||||
struct uwsgi_buffer *ub = ut->chunk;
|
||||
|
||||
// store only successfull response
|
||||
if (wsgi_req->write_errors == 0 && wsgi_req->status == 200 && ub->pos > 0) {
|
||||
memcached_store(utmc->addr->buf, utmc->key, ub, utmc->expires);
|
||||
}
|
||||
|
||||
// free resources
|
||||
uwsgi_buffer_destroy(utmc->key);
|
||||
uwsgi_buffer_destroy(utmc->addr);
|
||||
free(utmc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// be tolerant on errors
|
||||
static int uwsgi_routing_func_memcached_store(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){
|
||||
struct uwsgi_router_memcached_conf *urmc = (struct uwsgi_router_memcached_conf *) ur->data2;
|
||||
|
||||
struct uwsgi_transformation_memcached_conf *utmc = uwsgi_calloc(sizeof(struct uwsgi_transformation_memcached_conf));
|
||||
|
||||
// build key and name
|
||||
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
|
||||
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
|
||||
|
||||
utmc->key = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urmc->key, urmc->key_len);
|
||||
if (!utmc->key) goto error;
|
||||
|
||||
utmc->addr = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urmc->addr, urmc->addr_len);
|
||||
if (!utmc->addr) goto error;
|
||||
|
||||
utmc->expires = urmc->expires;
|
||||
|
||||
uwsgi_add_transformation(wsgi_req, transform_memcached, utmc);
|
||||
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
|
||||
error:
|
||||
if (utmc->key) uwsgi_buffer_destroy(utmc->key);
|
||||
if (utmc->addr) uwsgi_buffer_destroy(utmc->addr);
|
||||
free(utmc);
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
|
||||
|
||||
static int uwsgi_routing_func_memcached(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){
|
||||
// this is the buffer for the memcached response
|
||||
char buf[MEMCACHED_BUFSIZE];
|
||||
@@ -62,13 +153,24 @@ static int uwsgi_routing_func_memcached(struct wsgi_request *wsgi_req, struct uw
|
||||
struct uwsgi_buffer *ub_key = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urmc->key, urmc->key_len);
|
||||
if (!ub_key) return UWSGI_ROUTE_BREAK;
|
||||
|
||||
int fd = uwsgi_connect(urmc->addr, 0, 1);
|
||||
if (fd < 0) { uwsgi_buffer_destroy(ub_key) ; goto end; }
|
||||
struct uwsgi_buffer *ub_addr = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urmc->addr, urmc->addr_len);
|
||||
if (!ub_addr) {
|
||||
uwsgi_buffer_destroy(ub_key);
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
}
|
||||
|
||||
int fd = uwsgi_connect(ub_addr->buf, 0, 1);
|
||||
if (fd < 0) {
|
||||
uwsgi_buffer_destroy(ub_key);
|
||||
uwsgi_buffer_destroy(ub_addr);
|
||||
goto end;
|
||||
}
|
||||
|
||||
// wait for connection;
|
||||
int ret = uwsgi.wait_write_hook(fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
|
||||
if (ret <= 0) {
|
||||
uwsgi_buffer_destroy(ub_key) ;
|
||||
uwsgi_buffer_destroy(ub_addr);
|
||||
close(fd);
|
||||
goto end;
|
||||
}
|
||||
@@ -77,11 +179,13 @@ static int uwsgi_routing_func_memcached(struct wsgi_request *wsgi_req, struct uw
|
||||
char *cmd = uwsgi_concat3n("get ", 4, ub_key->buf, ub_key->pos, "\r\n", 2);
|
||||
if (uwsgi_write_true_nb(fd, cmd, 6+ub_key->pos, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT])) {
|
||||
uwsgi_buffer_destroy(ub_key);
|
||||
uwsgi_buffer_destroy(ub_addr);
|
||||
free(cmd);
|
||||
close(fd);
|
||||
goto end;
|
||||
}
|
||||
uwsgi_buffer_destroy(ub_key);
|
||||
uwsgi_buffer_destroy(ub_addr);
|
||||
free(cmd);
|
||||
|
||||
// ok, start reading the response...
|
||||
@@ -130,26 +234,34 @@ read:
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (urmc->type_num == 1) {
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) { close(fd); goto end; }
|
||||
if (uwsgi_response_add_content_type(wsgi_req, urmc->content_type, urmc->content_type_len)) { close(fd); goto end; }
|
||||
if (uwsgi_response_add_content_length(wsgi_req, response_size)) { close(fd); goto end; }
|
||||
}
|
||||
// from now on, every error will trigger a BREAK...
|
||||
|
||||
// send headers
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) goto error;
|
||||
if (uwsgi_response_add_content_type(wsgi_req, urmc->content_type, urmc->content_type_len)) goto error;
|
||||
if (uwsgi_response_add_content_length(wsgi_req, response_size)) goto error;
|
||||
|
||||
// the first chunk could already contains part of the body
|
||||
size_t remains = pos-(found+2);
|
||||
if (remains >= response_size) {
|
||||
uwsgi_response_write_body_do(wsgi_req, buf+found+2, response_size);
|
||||
close(fd);
|
||||
goto end;
|
||||
goto done;
|
||||
}
|
||||
|
||||
// send what we have
|
||||
if (uwsgi_response_write_body_do(wsgi_req, buf+found+2, remains)) {
|
||||
close(fd);
|
||||
goto end;
|
||||
}
|
||||
if (uwsgi_response_write_body_do(wsgi_req, buf+found+2, remains)) goto error;
|
||||
|
||||
// and now start reading til the output is consumed
|
||||
response_size -= remains;
|
||||
|
||||
// try to offload via the pipe engine
|
||||
if (wsgi_req->socket->can_offload && !ur->custom && !urmc->no_offload) {
|
||||
if (!uwsgi_offload_request_pipe_do(wsgi_req, fd, response_size)) {
|
||||
wsgi_req->via = UWSGI_VIA_OFFLOAD;
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
}
|
||||
}
|
||||
|
||||
while(response_size > 0) {
|
||||
ssize_t len = read(fd, buf, UMIN(MEMCACHED_BUFSIZE, response_size));
|
||||
if (len > 0) goto write;
|
||||
@@ -165,23 +277,22 @@ wait2:
|
||||
}
|
||||
goto error;
|
||||
write:
|
||||
if (uwsgi_response_write_body_do(wsgi_req, buf, len)) {
|
||||
goto error;
|
||||
}
|
||||
if (uwsgi_response_write_body_do(wsgi_req, buf, len)) goto error;
|
||||
response_size -= len;
|
||||
}
|
||||
|
||||
done:
|
||||
close(fd);
|
||||
if (ur->custom)
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
|
||||
error:
|
||||
close(fd);
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
|
||||
end:
|
||||
if (ur->custom)
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
|
||||
static int uwsgi_router_memcached(struct uwsgi_route *ur, char *args) {
|
||||
@@ -193,27 +304,23 @@ static int uwsgi_router_memcached(struct uwsgi_route *ur, char *args) {
|
||||
"addr", &urmc->addr,
|
||||
"key", &urmc->key,
|
||||
"content_type", &urmc->content_type,
|
||||
"type", &urmc->type, NULL)) {
|
||||
"no_offload", &urmc->no_offload,
|
||||
NULL)) {
|
||||
uwsgi_log("invalid route syntax: %s\n", args);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!urmc->key || !urmc->addr) {
|
||||
uwsgi_log("invalid route syntax: you need to specify a memcached address and key pattern\n");
|
||||
exit(1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
urmc->key_len = strlen(urmc->key);
|
||||
urmc->addr_len = strlen(urmc->addr);
|
||||
|
||||
if (!urmc->type) urmc->type = "full";
|
||||
if (!urmc->content_type) urmc->content_type = "text/html";
|
||||
|
||||
urmc->content_type_len = strlen(urmc->content_type);
|
||||
|
||||
if (!strcmp(urmc->type, "body")) {
|
||||
urmc->type_num = 1;
|
||||
}
|
||||
|
||||
ur->data2 = urmc;
|
||||
return 0;
|
||||
}
|
||||
@@ -224,12 +331,46 @@ static int uwsgi_router_memcached_continue(struct uwsgi_route *ur, char *args) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_router_memcached_store(struct uwsgi_route *ur, char *args) {
|
||||
ur->func = uwsgi_routing_func_memcached_store;
|
||||
ur->data = args;
|
||||
ur->data_len = strlen(args);
|
||||
struct uwsgi_router_memcached_conf *urmc = uwsgi_calloc(sizeof(struct uwsgi_router_memcached_conf));
|
||||
if (uwsgi_kvlist_parse(ur->data, ur->data_len, ',', '=',
|
||||
"addr", &urmc->addr,
|
||||
"key", &urmc->key,
|
||||
"expires", &urmc->expires, NULL)) {
|
||||
uwsgi_log("invalid memcachedstore route syntax: %s\n", args);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!urmc->key || !urmc->addr) {
|
||||
uwsgi_log("invalid memcachedstore route syntax: you need to specify an address and a key\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
urmc->key_len = strlen(urmc->key);
|
||||
urmc->addr_len = strlen(urmc->addr);
|
||||
|
||||
if (!urmc->expires) urmc->expires = "0";
|
||||
|
||||
ur->data2 = urmc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void router_memcached_register() {
|
||||
uwsgi_register_router("memcached", uwsgi_router_memcached);
|
||||
uwsgi_register_router("memcached-continue", uwsgi_router_memcached_continue);
|
||||
uwsgi_register_router("memcachedstore", uwsgi_router_memcached_store);
|
||||
uwsgi_register_router("memcached-store", uwsgi_router_memcached_store);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
struct uwsgi_plugin router_memcached_plugin = {
|
||||
.name = "router_memcached",
|
||||
#ifdef UWSGI_ROUTING
|
||||
.on_load = router_memcached_register,
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -0,0 +1,374 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
#ifdef UWSGI_ROUTING
|
||||
|
||||
#define REDIS_BUFSIZE 8192
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
/*
|
||||
|
||||
redis internal router and transformation
|
||||
|
||||
route = /^foobar1(.*)/ redis:addr=127.0.0.1:11211,key=foo$1poo
|
||||
route = /^foobar1(.*)/ redisstore:addr=127.0.0.1:11211,key=foo$1poo
|
||||
|
||||
*/
|
||||
|
||||
struct uwsgi_router_redis_conf {
|
||||
|
||||
char *addr;
|
||||
size_t addr_len;
|
||||
|
||||
char *key;
|
||||
size_t key_len;
|
||||
|
||||
char *content_type;
|
||||
size_t content_type_len;
|
||||
|
||||
char *no_offload;
|
||||
char *expires;
|
||||
|
||||
};
|
||||
|
||||
// this is allocated for each transformation
|
||||
struct uwsgi_transformation_redis_conf {
|
||||
struct uwsgi_buffer *addr;
|
||||
struct uwsgi_buffer *key;
|
||||
char *expires;
|
||||
};
|
||||
|
||||
|
||||
static size_t redis_firstline_parse(char *buf, size_t len) {
|
||||
// check for "$0"
|
||||
if (len < 2) return 0;
|
||||
if (buf[0] != '$') return 0;
|
||||
if (buf[1] == '-') return 0;
|
||||
return uwsgi_str_num(buf + 1, len - 1);
|
||||
}
|
||||
|
||||
// store an item in redis
|
||||
static void redis_store(char *addr, struct uwsgi_buffer *key, struct uwsgi_buffer *value, char *expires) {
|
||||
|
||||
int timeout = uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT];
|
||||
|
||||
int fd = uwsgi_connect(addr, 0, 1);
|
||||
if (fd < 0) return;
|
||||
|
||||
// wait for connection
|
||||
int ret = uwsgi.wait_write_hook(fd, timeout);
|
||||
if (ret <= 0) goto end;
|
||||
|
||||
// build the request
|
||||
struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size);
|
||||
if (uwsgi_buffer_append(ub, "*3\r\n$3\r\nSET\r\n$", 14)) goto end2;
|
||||
if (uwsgi_buffer_num64(ub, key->pos)) goto end2;
|
||||
if (uwsgi_buffer_append(ub, "\r\n" , 2)) goto end2;
|
||||
if (uwsgi_buffer_append(ub, key->buf, key->pos)) goto end2;
|
||||
if (uwsgi_buffer_append(ub, "\r\n$" , 3)) goto end2;
|
||||
if (uwsgi_buffer_num64(ub, value->pos)) goto end2;
|
||||
if (uwsgi_buffer_append(ub, "\r\n" , 2)) goto end2;
|
||||
if (uwsgi_write_true_nb(fd, ub->buf, ub->pos, timeout)) goto end2;
|
||||
if (uwsgi_write_true_nb(fd, value->buf, value->pos, timeout)) goto end2;
|
||||
ub->pos = 0;
|
||||
if (strcmp(expires, "0")) {
|
||||
if (uwsgi_buffer_append(ub, "\r\n*3\r\n$6\r\nEXPIRE\r\n$" , 19)) goto end2;
|
||||
if (uwsgi_buffer_num64(ub, key->pos)) goto end2;
|
||||
if (uwsgi_buffer_append(ub, "\r\n" , 2)) goto end2;
|
||||
if (uwsgi_buffer_append(ub, key->buf, key->pos)) goto end2;
|
||||
if (uwsgi_buffer_append(ub, "\r\n$" , 3)) goto end2;
|
||||
if (uwsgi_buffer_num64(ub, strlen(expires))) goto end2;
|
||||
if (uwsgi_buffer_append(ub, "\r\n" , 2)) goto end2;
|
||||
if (uwsgi_buffer_append(ub, expires, strlen(expires))) goto end2;
|
||||
}
|
||||
if (uwsgi_buffer_append(ub, "\r\n" , 2)) goto end2;
|
||||
if (uwsgi_write_true_nb(fd, ub->buf, ub->pos, timeout)) goto end2;
|
||||
|
||||
// we are not interested in command result... (ugly but it works)
|
||||
end2:
|
||||
uwsgi_buffer_destroy(ub);
|
||||
end:
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static int transform_redis(struct wsgi_request *wsgi_req, struct uwsgi_transformation *ut) {
|
||||
struct uwsgi_transformation_redis_conf *utrc = (struct uwsgi_transformation_redis_conf *) ut->data;
|
||||
struct uwsgi_buffer *ub = ut->chunk;
|
||||
|
||||
// store only successfull response
|
||||
if (wsgi_req->write_errors == 0 && wsgi_req->status == 200 && ub->pos > 0) {
|
||||
redis_store(utrc->addr->buf, utrc->key, ub, utrc->expires);
|
||||
}
|
||||
|
||||
// free resources
|
||||
uwsgi_buffer_destroy(utrc->key);
|
||||
uwsgi_buffer_destroy(utrc->addr);
|
||||
free(utrc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// be tolerant on errors
|
||||
static int uwsgi_routing_func_redis_store(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){
|
||||
struct uwsgi_router_redis_conf *urrc = (struct uwsgi_router_redis_conf *) ur->data2;
|
||||
|
||||
struct uwsgi_transformation_redis_conf *utrc = uwsgi_calloc(sizeof(struct uwsgi_transformation_redis_conf));
|
||||
|
||||
// build key and name
|
||||
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
|
||||
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
|
||||
|
||||
utrc->key = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urrc->key, urrc->key_len);
|
||||
if (!utrc->key) goto error;
|
||||
|
||||
utrc->addr = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urrc->addr, urrc->addr_len);
|
||||
if (!utrc->addr) goto error;
|
||||
|
||||
utrc->expires = urrc->expires;
|
||||
|
||||
uwsgi_add_transformation(wsgi_req, transform_redis, utrc);
|
||||
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
|
||||
error:
|
||||
if (utrc->key) uwsgi_buffer_destroy(utrc->key);
|
||||
if (utrc->addr) uwsgi_buffer_destroy(utrc->addr);
|
||||
free(utrc);
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
|
||||
|
||||
static int uwsgi_routing_func_redis(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){
|
||||
// this is the buffer for the redis response
|
||||
char buf[REDIS_BUFSIZE];
|
||||
size_t i;
|
||||
char last_char = 0;
|
||||
|
||||
struct uwsgi_router_redis_conf *urrc = (struct uwsgi_router_redis_conf *) ur->data2;
|
||||
|
||||
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
|
||||
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
|
||||
|
||||
struct uwsgi_buffer *ub_key = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urrc->key, urrc->key_len);
|
||||
if (!ub_key) return UWSGI_ROUTE_BREAK;
|
||||
|
||||
struct uwsgi_buffer *ub_addr = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urrc->addr, urrc->addr_len);
|
||||
if (!ub_addr) {
|
||||
uwsgi_buffer_destroy(ub_key);
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
}
|
||||
|
||||
int fd = uwsgi_connect(ub_addr->buf, 0, 1);
|
||||
if (fd < 0) {
|
||||
uwsgi_buffer_destroy(ub_key);
|
||||
uwsgi_buffer_destroy(ub_addr);
|
||||
goto end;
|
||||
}
|
||||
|
||||
// wait for connection;
|
||||
int ret = uwsgi.wait_write_hook(fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
|
||||
if (ret <= 0) {
|
||||
uwsgi_buffer_destroy(ub_key) ;
|
||||
uwsgi_buffer_destroy(ub_addr);
|
||||
close(fd);
|
||||
goto end;
|
||||
}
|
||||
|
||||
// build the request and send it
|
||||
char *cmd = uwsgi_concat3n("get ", 4, ub_key->buf, ub_key->pos, "\r\n", 2);
|
||||
if (uwsgi_write_true_nb(fd, cmd, 6+ub_key->pos, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT])) {
|
||||
uwsgi_buffer_destroy(ub_key);
|
||||
uwsgi_buffer_destroy(ub_addr);
|
||||
free(cmd);
|
||||
close(fd);
|
||||
goto end;
|
||||
}
|
||||
uwsgi_buffer_destroy(ub_key);
|
||||
uwsgi_buffer_destroy(ub_addr);
|
||||
free(cmd);
|
||||
|
||||
// ok, start reading the response...
|
||||
// first we need to get a full line;
|
||||
size_t found = 0;
|
||||
size_t pos = 0;
|
||||
for(;;) {
|
||||
ssize_t len = read(fd, buf + pos, REDIS_BUFSIZE - pos);
|
||||
if (len > 0) {
|
||||
pos += len;
|
||||
goto read;
|
||||
}
|
||||
if (len < 0) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) goto wait;
|
||||
}
|
||||
close(fd);
|
||||
goto end;
|
||||
wait:
|
||||
ret = uwsgi.wait_read_hook(fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
|
||||
// when we have a chunk try to read the first line
|
||||
if (ret > 0) {
|
||||
len = read(fd, buf + pos, REDIS_BUFSIZE - pos);
|
||||
if (len > 0) {
|
||||
pos += len;
|
||||
goto read;
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
goto end;
|
||||
read:
|
||||
for(i=0;i<pos;i++) {
|
||||
if (last_char == '\r' && buf[i] == '\n') {
|
||||
found = i-1;
|
||||
break;
|
||||
}
|
||||
last_char = buf[i];
|
||||
}
|
||||
if (found) break;
|
||||
}
|
||||
|
||||
// ok parse the first line
|
||||
size_t response_size = redis_firstline_parse(buf, found);
|
||||
if (response_size == 0) {
|
||||
close(fd);
|
||||
goto end;
|
||||
}
|
||||
|
||||
// from now on, every error will trigger a BREAK...
|
||||
|
||||
// send headers
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) goto error;
|
||||
if (uwsgi_response_add_content_type(wsgi_req, urrc->content_type, urrc->content_type_len)) goto error;
|
||||
if (uwsgi_response_add_content_length(wsgi_req, response_size)) goto error;
|
||||
|
||||
// the first chunk could already contains part of the body
|
||||
size_t remains = pos-(found+2);
|
||||
if (remains >= response_size) {
|
||||
uwsgi_response_write_body_do(wsgi_req, buf+found+2, response_size);
|
||||
goto done;
|
||||
}
|
||||
|
||||
// send what we have
|
||||
if (uwsgi_response_write_body_do(wsgi_req, buf+found+2, remains)) goto error;
|
||||
|
||||
// and now start reading til the output is consumed
|
||||
response_size -= remains;
|
||||
|
||||
// try to offload via the pipe engine
|
||||
if (wsgi_req->socket->can_offload && !ur->custom && !urrc->no_offload) {
|
||||
if (!uwsgi_offload_request_pipe_do(wsgi_req, fd, response_size)) {
|
||||
wsgi_req->via = UWSGI_VIA_OFFLOAD;
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
}
|
||||
}
|
||||
|
||||
while(response_size > 0) {
|
||||
ssize_t len = read(fd, buf, UMIN(REDIS_BUFSIZE, response_size));
|
||||
if (len > 0) goto write;
|
||||
if (len < 0) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) goto wait2;
|
||||
}
|
||||
goto error;
|
||||
wait2:
|
||||
ret = uwsgi.wait_read_hook(fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
|
||||
if (ret > 0) {
|
||||
len = read(fd, buf, UMIN(REDIS_BUFSIZE, response_size));
|
||||
if (len > 0) goto write;
|
||||
}
|
||||
goto error;
|
||||
write:
|
||||
if (uwsgi_response_write_body_do(wsgi_req, buf, len)) goto error;
|
||||
response_size -= len;
|
||||
}
|
||||
|
||||
done:
|
||||
close(fd);
|
||||
if (ur->custom)
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
|
||||
error:
|
||||
close(fd);
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
|
||||
end:
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
|
||||
static int uwsgi_router_redis(struct uwsgi_route *ur, char *args) {
|
||||
ur->func = uwsgi_routing_func_redis;
|
||||
ur->data = args;
|
||||
ur->data_len = strlen(args);
|
||||
struct uwsgi_router_redis_conf *urrc = uwsgi_calloc(sizeof(struct uwsgi_router_redis_conf));
|
||||
if (uwsgi_kvlist_parse(ur->data, ur->data_len, ',', '=',
|
||||
"addr", &urrc->addr,
|
||||
"key", &urrc->key,
|
||||
"content_type", &urrc->content_type,
|
||||
"no_offload", &urrc->no_offload,
|
||||
NULL)) {
|
||||
uwsgi_log("invalid route syntax: %s\n", args);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!urrc->key || !urrc->addr) {
|
||||
uwsgi_log("invalid route syntax: you need to specify a redis address and key pattern\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
urrc->key_len = strlen(urrc->key);
|
||||
urrc->addr_len = strlen(urrc->addr);
|
||||
|
||||
if (!urrc->content_type) urrc->content_type = "text/html";
|
||||
urrc->content_type_len = strlen(urrc->content_type);
|
||||
|
||||
ur->data2 = urrc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_router_redis_continue(struct uwsgi_route *ur, char *args) {
|
||||
uwsgi_router_redis(ur, args);
|
||||
ur->custom = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_router_redis_store(struct uwsgi_route *ur, char *args) {
|
||||
ur->func = uwsgi_routing_func_redis_store;
|
||||
ur->data = args;
|
||||
ur->data_len = strlen(args);
|
||||
struct uwsgi_router_redis_conf *urrc = uwsgi_calloc(sizeof(struct uwsgi_router_redis_conf));
|
||||
if (uwsgi_kvlist_parse(ur->data, ur->data_len, ',', '=',
|
||||
"addr", &urrc->addr,
|
||||
"key", &urrc->key,
|
||||
"expires", &urrc->expires, NULL)) {
|
||||
uwsgi_log("invalid redisstore route syntax: %s\n", args);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!urrc->key || !urrc->addr) {
|
||||
uwsgi_log("invalid redisstore route syntax: you need to specify an address and a key\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
urrc->key_len = strlen(urrc->key);
|
||||
urrc->addr_len = strlen(urrc->addr);
|
||||
|
||||
if (!urrc->expires) urrc->expires = "0";
|
||||
|
||||
ur->data2 = urrc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void router_redis_register() {
|
||||
uwsgi_register_router("redis", uwsgi_router_redis);
|
||||
uwsgi_register_router("redis-continue", uwsgi_router_redis_continue);
|
||||
uwsgi_register_router("redisstore", uwsgi_router_redis_store);
|
||||
uwsgi_register_router("redis-store", uwsgi_router_redis_store);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
struct uwsgi_plugin router_redis_plugin = {
|
||||
.name = "router_redis",
|
||||
#ifdef UWSGI_ROUTING
|
||||
.on_load = router_redis_register,
|
||||
#endif
|
||||
};
|
||||
@@ -0,0 +1,6 @@
|
||||
NAME='router_redis'
|
||||
|
||||
CFLAGS = []
|
||||
LDFLAGS = []
|
||||
LIBS = []
|
||||
GCC_LIST = ['router_redis']
|
||||
@@ -1,9 +1,23 @@
|
||||
#include "../../uwsgi.h"
|
||||
#include <uwsgi.h>
|
||||
|
||||
#ifdef UWSGI_ROUTING
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
struct uwsgi_router_file_conf {
|
||||
|
||||
char *filename;
|
||||
size_t filename_len;
|
||||
|
||||
char *status;
|
||||
size_t status_len;
|
||||
|
||||
char *content_type;
|
||||
size_t content_type_len;
|
||||
|
||||
char *mime;
|
||||
};
|
||||
|
||||
int uwsgi_routing_func_static(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
|
||||
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
|
||||
@@ -17,8 +31,71 @@ int uwsgi_routing_func_static(struct wsgi_request *wsgi_req, struct uwsgi_route
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
}
|
||||
|
||||
int uwsgi_routing_func_file(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
|
||||
int uwsgi_router_static(struct uwsgi_route *ur, char *args) {
|
||||
char buf[32768];
|
||||
struct stat st;
|
||||
int ret = UWSGI_ROUTE_BREAK;
|
||||
|
||||
struct uwsgi_router_file_conf *urfc = (struct uwsgi_router_file_conf *) ur->data2;
|
||||
|
||||
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, urfc->filename, urfc->filename_len);
|
||||
if (!ub) return UWSGI_ROUTE_BREAK;
|
||||
|
||||
int fd = open(ub->buf, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
if (ur->custom)
|
||||
ret = UWSGI_ROUTE_NEXT;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (fstat(fd, &st)) {
|
||||
goto end2;
|
||||
}
|
||||
|
||||
struct uwsgi_buffer *ub_s = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urfc->status, urfc->status_len);
|
||||
if (!ub_s) goto end2;
|
||||
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, ub_s->buf, ub_s->pos)) {
|
||||
uwsgi_buffer_destroy(ub_s);
|
||||
goto end2;
|
||||
}
|
||||
uwsgi_buffer_destroy(ub_s);
|
||||
if (uwsgi_response_add_content_length(wsgi_req, st.st_size)) goto end2;
|
||||
if (urfc->mime) {
|
||||
size_t mime_type_len = 0;
|
||||
char *mime_type = uwsgi_get_mime_type(ub->buf, ub->pos, &mime_type_len);
|
||||
if (mime_type) {
|
||||
if (uwsgi_response_add_content_type(wsgi_req, mime_type, mime_type_len)) goto end2;
|
||||
}
|
||||
else {
|
||||
if (uwsgi_response_add_content_type(wsgi_req, urfc->content_type, urfc->content_type_len)) goto end2;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (uwsgi_response_add_content_type(wsgi_req, urfc->content_type, urfc->content_type_len)) goto end2;
|
||||
}
|
||||
|
||||
size_t remains = st.st_size;
|
||||
while(remains) {
|
||||
ssize_t rlen = read(fd, buf, UMIN(32768, remains));
|
||||
if (rlen <= 0) goto end2;
|
||||
if (uwsgi_response_write_body_do(wsgi_req, buf, rlen)) goto end2;
|
||||
remains -= rlen;
|
||||
}
|
||||
|
||||
end2:
|
||||
close(fd);
|
||||
end:
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int uwsgi_router_static(struct uwsgi_route *ur, char *args) {
|
||||
|
||||
ur->func = uwsgi_routing_func_static;
|
||||
ur->data = args;
|
||||
@@ -26,10 +103,52 @@ int uwsgi_router_static(struct uwsgi_route *ur, char *args) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_router_file(struct uwsgi_route *ur, char *args) {
|
||||
ur->func = uwsgi_routing_func_file;
|
||||
ur->data = args;
|
||||
ur->data_len = strlen(args);
|
||||
struct uwsgi_router_file_conf *urfc = uwsgi_calloc(sizeof(struct uwsgi_router_file_conf));
|
||||
if (uwsgi_kvlist_parse(ur->data, ur->data_len, ',', '=',
|
||||
"filename", &urfc->filename,
|
||||
"status", &urfc->status,
|
||||
"content_type", &urfc->content_type,
|
||||
"mime", &urfc->mime,
|
||||
NULL)) {
|
||||
uwsgi_log("invalid file route syntax: %s\n", args);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!urfc->filename) {
|
||||
uwsgi_log("you have to specifify a filename for the \"file\" router\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
urfc->filename_len = strlen(urfc->filename);
|
||||
if (!urfc->content_type) {
|
||||
urfc->content_type = "text/html";
|
||||
}
|
||||
urfc->content_type_len = strlen(urfc->content_type);
|
||||
|
||||
if (!urfc->status) {
|
||||
urfc->status = "200 OK";
|
||||
}
|
||||
urfc->status_len = strlen(urfc->status);
|
||||
|
||||
ur->data2 = urfc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_router_file_next(struct uwsgi_route *ur, char *args) {
|
||||
ur->custom = 1;
|
||||
return uwsgi_router_file(ur, args);
|
||||
}
|
||||
|
||||
|
||||
static void router_static_register(void) {
|
||||
|
||||
uwsgi_register_router("static", uwsgi_router_static);
|
||||
uwsgi_register_router("file", uwsgi_router_file);
|
||||
uwsgi_register_router("file-next", uwsgi_router_file_next);
|
||||
}
|
||||
|
||||
struct uwsgi_plugin router_static_plugin = {
|
||||
|
||||
@@ -1,7 +1,125 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
#ifdef UWSGI_XML_LIBXML2
|
||||
#include <libxml/parser.h>
|
||||
#include <libxml/tree.h>
|
||||
#endif
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
/*
|
||||
|
||||
rpc-HTTP interface.
|
||||
|
||||
modifier2 changes the parsser behaviours:
|
||||
|
||||
0 -> return uwsgi header + rpc response
|
||||
1 -> return raw rpc response
|
||||
2 -> split PATH_INFO to get func name and args and return as HTTP response with content_type as application/binary or Accept request header (if different from *)
|
||||
3 -> set xmlrpc wrapper (requires libxml2)
|
||||
4 -> set jsonrpc wrapper (requires libjansson)
|
||||
|
||||
*/
|
||||
|
||||
#ifdef UWSGI_XML_LIBXML2
|
||||
// raise error on non-string args
|
||||
static int uwsgi_rpc_xmlrpc_string(xmlNode *element, char **argv, uint16_t *argvs, uint8_t *argc) {
|
||||
|
||||
xmlNode *node;
|
||||
for (node = element->children; node; node = node->next) {
|
||||
if (node->type == XML_ELEMENT_NODE) {
|
||||
if (strcmp((char *) node->name, "string")) {
|
||||
return -1;
|
||||
}
|
||||
if (!node->children) return -1;
|
||||
if (!node->children->content) return -1;
|
||||
*argc+=1;
|
||||
argv[*argc] = (char *) node->children->content;
|
||||
argvs[*argc] = strlen(argv[*argc]);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
static int uwsgi_rpc_xmlrpc_value(xmlNode *element, char **argv, uint16_t *argvs, uint8_t *argc) {
|
||||
xmlNode *node;
|
||||
for (node = element->children; node; node = node->next) {
|
||||
if (node->type == XML_ELEMENT_NODE) {
|
||||
if (!strcmp((char *) node->name, "value")) {
|
||||
if (uwsgi_rpc_xmlrpc_string(node, argv, argvs, argc)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_rpc_xmlrpc_args(xmlNode *element, char **argv, uint16_t *argvs, uint8_t *argc) {
|
||||
xmlNode *node;
|
||||
for (node = element->children; node; node = node->next) {
|
||||
if (node->type == XML_ELEMENT_NODE) {
|
||||
if (!strcmp((char *) node->name, "param")) {
|
||||
if (uwsgi_rpc_xmlrpc_value(node, argv, argvs, argc)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_rpc_xmlrpc(struct wsgi_request *wsgi_req, xmlDoc *doc, char **argv, uint16_t *argvs, uint8_t *argc, char *response_buf) {
|
||||
char *method = NULL;
|
||||
xmlNode *element = xmlDocGetRootElement(doc);
|
||||
if (!element) return -1;
|
||||
|
||||
if (strcmp((char *) element->name, "methodCall")) return -1;
|
||||
|
||||
*argc = 0;
|
||||
xmlNode *node;
|
||||
for (node = element->children; node; node = node->next) {
|
||||
if (node->type == XML_ELEMENT_NODE) {
|
||||
if (!strcmp((char *) node->name, "methodName") && node->children) {
|
||||
method = (char *) node->children->content;
|
||||
}
|
||||
else if (!strcmp((char *) node->name, "params")) {
|
||||
if (uwsgi_rpc_xmlrpc_args(node, argv, argvs, argc)) return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!method) return -1;
|
||||
wsgi_req->uh->pktsize = uwsgi_rpc(method, *argc, argv+1, argvs+1, response_buf);
|
||||
|
||||
if (!wsgi_req->uh->pktsize) return -1;
|
||||
if (wsgi_req->uh->pktsize == UMAX16-1) return -1;
|
||||
// add final NULL byte
|
||||
response_buf[wsgi_req->uh->pktsize] = 0;
|
||||
|
||||
xmlDoc *rdoc = xmlNewDoc(BAD_CAST "1.0");
|
||||
xmlNode *m_response = xmlNewNode(NULL, BAD_CAST "methodResponse");
|
||||
xmlDocSetRootElement(rdoc, m_response);
|
||||
xmlNode *x_params = xmlNewChild(m_response, NULL, BAD_CAST "params", NULL);
|
||||
xmlNode *x_param = xmlNewChild(x_params, NULL, BAD_CAST "param", NULL);
|
||||
xmlNode *x_value = xmlNewChild(x_param, NULL, BAD_CAST "value", NULL);
|
||||
xmlNewTextChild(x_value, NULL, BAD_CAST "string", BAD_CAST response_buf);
|
||||
|
||||
xmlChar *xmlbuf;
|
||||
int xlen = 0;
|
||||
xmlDocDumpFormatMemory(rdoc, &xmlbuf, &xlen, 1);
|
||||
uwsgi_response_prepare_headers(wsgi_req,"200 OK", 6);
|
||||
uwsgi_response_add_content_length(wsgi_req, xlen);
|
||||
uwsgi_response_add_content_type(wsgi_req, "application/xml", 15);
|
||||
uwsgi_response_write_body_do(wsgi_req, (char *) xmlbuf, xlen);
|
||||
|
||||
xmlFreeDoc(rdoc);
|
||||
xmlFree(xmlbuf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int uwsgi_rpc_request(struct wsgi_request *wsgi_req) {
|
||||
|
||||
@@ -20,6 +138,82 @@ static int uwsgi_rpc_request(struct wsgi_request *wsgi_req) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (wsgi_req->uh->modifier2 == 2) {
|
||||
if (uwsgi_parse_vars(wsgi_req)) {
|
||||
uwsgi_log("Invalid RPC request. skip.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (wsgi_req->path_info_len == 0) {
|
||||
uwsgi_500(wsgi_req);
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
char *args = NULL;
|
||||
if (wsgi_req->path_info[0] == '/') {
|
||||
args = uwsgi_concat2n(wsgi_req->path_info+1, wsgi_req->path_info_len-1, "", 0);
|
||||
}
|
||||
else {
|
||||
args = uwsgi_concat2n(wsgi_req->path_info, wsgi_req->path_info_len, "", 0);
|
||||
}
|
||||
|
||||
argc = 0;
|
||||
argv[0] = strtok(args, "/");
|
||||
if (!argv[0]) {
|
||||
free(args);
|
||||
uwsgi_500(wsgi_req);
|
||||
return UWSGI_OK;
|
||||
}
|
||||
char *p = strtok(NULL, "/");
|
||||
while(p) {
|
||||
argc++;
|
||||
argv[argc] = p;
|
||||
argvs[argc] = strlen(p);
|
||||
p = strtok(NULL, "/");
|
||||
}
|
||||
|
||||
wsgi_req->uh->pktsize = uwsgi_rpc(argv[0], argc, argv+1, argvs+1, response_buf);
|
||||
free(args);
|
||||
|
||||
if (!wsgi_req->uh->pktsize) {
|
||||
uwsgi_404(wsgi_req);
|
||||
return UWSGI_OK;
|
||||
}
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) return 1;
|
||||
if (uwsgi_response_add_content_length(wsgi_req, wsgi_req->uh->pktsize)) return -1;
|
||||
uint16_t ctype_len = 0;
|
||||
char *ctype = uwsgi_get_var(wsgi_req, "HTTP_ACCEPT", 11, &ctype_len);
|
||||
if (ctype && strcmp(ctype, "*/*") && strcmp(ctype, "*")) {
|
||||
if (uwsgi_response_add_content_type(wsgi_req, ctype, ctype_len)) return -1;
|
||||
}
|
||||
else {
|
||||
if (uwsgi_response_add_content_type(wsgi_req, "application/binary", 18)) return -1;
|
||||
}
|
||||
goto sendbody;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_XML_LIBXML2
|
||||
if (wsgi_req->uh->modifier2 == 3) {
|
||||
if (wsgi_req->post_cl == 0) {
|
||||
uwsgi_500(wsgi_req);
|
||||
return UWSGI_OK;
|
||||
}
|
||||
ssize_t body_len = 0;
|
||||
char *body = uwsgi_request_body_read(wsgi_req, wsgi_req->post_cl, &body_len);
|
||||
xmlDoc *doc = xmlReadMemory(body, body_len, NULL, NULL, 0);
|
||||
if (!doc) {
|
||||
uwsgi_500(wsgi_req);
|
||||
return UWSGI_OK;
|
||||
}
|
||||
int ret = uwsgi_rpc_xmlrpc(wsgi_req, doc, argv, argvs, &argc, response_buf);
|
||||
xmlFreeDoc(doc);
|
||||
if (ret) {
|
||||
uwsgi_500(wsgi_req);
|
||||
}
|
||||
return UWSGI_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (uwsgi_parse_array(wsgi_req->buffer, wsgi_req->uh->pktsize, argv, argvs, &argc)) {
|
||||
uwsgi_log("Invalid RPC request. skip.\n");
|
||||
return -1;
|
||||
@@ -34,6 +228,9 @@ static int uwsgi_rpc_request(struct wsgi_request *wsgi_req) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sendbody:
|
||||
// write the response
|
||||
uwsgi_response_write_body_do(wsgi_req, response_buf, wsgi_req->uh->pktsize);
|
||||
|
||||
|
||||
@@ -193,6 +193,7 @@ static ssize_t sr_instance_read(struct corerouter_peer *peer) {
|
||||
// the instance is connected now we cannot retry connections
|
||||
static ssize_t sr_instance_connected(struct corerouter_peer *peer) {
|
||||
cr_peer_connected(peer, "sr_instance_connected()");
|
||||
peer->can_retry = 0;
|
||||
// set the output buffer as the main_peer output one
|
||||
peer->out = peer->session->main_peer->in;
|
||||
peer->out_pos = 0;
|
||||
@@ -307,6 +308,7 @@ static ssize_t sr_read(struct corerouter_peer *main_peer) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
peer->can_retry = 1;
|
||||
cr_connect(peer, sr_instance_connected);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
#if defined(UWSGI_ROUTING)
|
||||
|
||||
/*
|
||||
|
||||
offload transformation
|
||||
|
||||
each chunk is buffered to the transformation custom buffer
|
||||
|
||||
if the buffer grows higher than the specified limit, the response will be buffered to disk
|
||||
|
||||
on final the memory (or the tmpfile) will be offloaded
|
||||
|
||||
even if we are talking about buffering, this is a streaming transformation
|
||||
as we need to hold control on memory usage
|
||||
|
||||
"offload" MUST BE the last transformation in the chain. Hellish things will happen otherwise...
|
||||
|
||||
*/
|
||||
|
||||
static int transform_offload(struct wsgi_request *wsgi_req, struct uwsgi_transformation *ut) {
|
||||
|
||||
if (ut->is_final) {
|
||||
struct uwsgi_transformation *orig_ut = (struct uwsgi_transformation *) ut->data;
|
||||
// sendfile offload
|
||||
if (orig_ut->fd > -1) {
|
||||
if (!uwsgi_offload_request_sendfile_do(wsgi_req, orig_ut->fd, orig_ut->len)) {
|
||||
// the fd will be closed by the offload engine
|
||||
orig_ut->fd = -1;
|
||||
wsgi_req->via = UWSGI_VIA_OFFLOAD;
|
||||
wsgi_req->response_size += orig_ut->len;
|
||||
return 0;
|
||||
}
|
||||
// fallback to non-offloaded write
|
||||
if (uwsgi_simple_sendfile(wsgi_req, orig_ut->fd, 0, orig_ut->len)) {
|
||||
return -1;
|
||||
}
|
||||
wsgi_req->response_size += orig_ut->len;
|
||||
return 0;
|
||||
}
|
||||
// memory offload
|
||||
if (orig_ut->ub) {
|
||||
if (!uwsgi_offload_request_memory_do(wsgi_req, orig_ut->ub->buf, orig_ut->ub->pos)) {
|
||||
// memory will be freed by the offload engine
|
||||
orig_ut->ub->buf = NULL;
|
||||
wsgi_req->via = UWSGI_VIA_OFFLOAD;
|
||||
wsgi_req->response_size += orig_ut->ub->pos;
|
||||
return 0;
|
||||
}
|
||||
// fallback to non-offloaded write
|
||||
if (uwsgi_simple_write(wsgi_req, orig_ut->ub->buf, orig_ut->ub->pos)) {
|
||||
return -1;
|
||||
}
|
||||
wsgi_req->response_size += orig_ut->ub->pos;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// check if we need to start buffering to disk
|
||||
if (ut->fd == -1 && ut->len + ut->chunk->pos > ut->custom64) {
|
||||
ut->fd = uwsgi_tmpfd();
|
||||
if (ut->fd < 0) return -1;
|
||||
// save already buffered data
|
||||
if (ut->ub) {
|
||||
ssize_t wlen = write(ut->fd, ut->ub->buf, ut->ub->pos);
|
||||
if (wlen != (ssize_t) ut->ub->pos) {
|
||||
uwsgi_error("transform_offload/write()");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if fd > -1, append to file
|
||||
if (ut->fd > -1) {
|
||||
ssize_t wlen = write(ut->fd, ut->chunk->buf, ut->chunk->pos);
|
||||
if (wlen != (ssize_t) ut->chunk->pos) {
|
||||
uwsgi_error("transform_offload/write()");
|
||||
return -1;
|
||||
}
|
||||
ut->len += wlen;
|
||||
goto done;
|
||||
}
|
||||
|
||||
// buffer to memory
|
||||
if (!ut->ub) {
|
||||
ut->ub = uwsgi_buffer_new(ut->chunk->pos);
|
||||
}
|
||||
|
||||
// append the chunk to the custom buffer
|
||||
if (uwsgi_buffer_append(ut->ub, ut->chunk->buf, ut->chunk->pos)) return -1;
|
||||
ut->len += ut->chunk->pos;
|
||||
done:
|
||||
// reset the chunk !!!
|
||||
ut->chunk->pos = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_routing_func_offload(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
if (!wsgi_req->socket->can_offload) {
|
||||
uwsgi_log("unable to use the offload transformation without offload threads !!!\n");
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
}
|
||||
struct uwsgi_transformation *ut = uwsgi_add_transformation(wsgi_req, transform_offload, NULL);
|
||||
ut->can_stream = 1;
|
||||
ut->custom64 = ur->custom;
|
||||
// add a "final" transformation to add the trailing chunk
|
||||
ut = uwsgi_add_transformation(wsgi_req, transform_offload, ut);
|
||||
ut->is_final = 1;
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
|
||||
static int uwsgi_router_offload(struct uwsgi_route *ur, char *args) {
|
||||
ur->func = uwsgi_routing_func_offload;
|
||||
if (args[0] == 0) {
|
||||
// 1 MB limit
|
||||
ur->custom = 1024 * 1024;
|
||||
}
|
||||
else {
|
||||
ur->custom = strtoul(args, NULL, 10);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void router_offload_register(void) {
|
||||
uwsgi_register_router("offload", uwsgi_router_offload);
|
||||
}
|
||||
|
||||
struct uwsgi_plugin transformation_offload_plugin = {
|
||||
.name = "transformation_offload",
|
||||
.on_load = router_offload_register,
|
||||
};
|
||||
#else
|
||||
struct uwsgi_plugin transformation_offload_plugin = {
|
||||
.name = "transformation_offload",
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,6 @@
|
||||
NAME='transformation_offload'
|
||||
|
||||
CFLAGS = []
|
||||
LDFLAGS = []
|
||||
LIBS = []
|
||||
GCC_LIST = ['offload']
|
||||
+13
-1
@@ -155,6 +155,11 @@ ssize_t uwsgi_proto_fastcgi_read_body(struct wsgi_request *wsgi_req, char *buf,
|
||||
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);
|
||||
wsgi_req->proto_parser_move = 0;
|
||||
}
|
||||
return remains;
|
||||
}
|
||||
|
||||
@@ -176,7 +181,14 @@ ssize_t uwsgi_proto_fastcgi_read_body(struct wsgi_request *wsgi_req, char *buf,
|
||||
// copy remaining
|
||||
wsgi_req->proto_parser_remains = fcgi_len - remains;
|
||||
wsgi_req->proto_parser_remains_buf = wsgi_req->proto_parser_buf + sizeof(struct fcgi_record) + remains;
|
||||
memmove(wsgi_req->proto_parser_buf, wsgi_req->proto_parser_buf + fcgi_all_len, wsgi_req->proto_parser_pos - fcgi_all_len);
|
||||
// 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);
|
||||
}
|
||||
else {
|
||||
// postpone memory move
|
||||
wsgi_req->proto_parser_move = fcgi_all_len;
|
||||
}
|
||||
wsgi_req->proto_parser_pos -= fcgi_all_len;
|
||||
return remains;
|
||||
}
|
||||
|
||||
@@ -12,13 +12,23 @@ from setuptools.command.build_ext import build_ext
|
||||
"""
|
||||
This is a hack allowing you installing
|
||||
uWSGI and uwsgidecorators via pip and easy_install
|
||||
since 1.9.11 it automatically detects pypy
|
||||
"""
|
||||
|
||||
uwsgi_compiled = False
|
||||
|
||||
|
||||
def get_profile():
|
||||
profile = os.environ.get('UWSGI_PROFILE', 'buildconf/default.ini')
|
||||
is_pypy = False
|
||||
try:
|
||||
import __pypy__
|
||||
is_pypy = True
|
||||
except ImportError:
|
||||
pass
|
||||
if is_pypy:
|
||||
profile = os.environ.get('UWSGI_PROFILE', 'buildconf/pypy.ini')
|
||||
else:
|
||||
profile = os.environ.get('UWSGI_PROFILE', 'buildconf/default.ini')
|
||||
if not profile.endswith('.ini'):
|
||||
profile = "%s.ini" % profile
|
||||
if not '/' in profile:
|
||||
|
||||
@@ -4,6 +4,7 @@ import "uwsgi"
|
||||
import "net/http"
|
||||
import "fmt"
|
||||
import "io/ioutil"
|
||||
import "os"
|
||||
|
||||
|
||||
func viewHandler(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -24,6 +25,7 @@ func postHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println(os.Args)
|
||||
http.HandleFunc("/view/", viewHandler)
|
||||
http.HandleFunc("/post/", postHandler)
|
||||
uwsgi.Run()
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
[uwsgi]
|
||||
plugins = geoip, router_cache
|
||||
http-socket = :9090
|
||||
|
||||
; 8 bytes blocksize is the right thing to do
|
||||
cache2 = name=limiter,items=1000,blocksize=8
|
||||
; allows expiring items
|
||||
master = true
|
||||
|
||||
; get the cache value for the current ip (if any)
|
||||
route-run = cachevar:key=${REMOTE_ADDR},as_num=1,var=LIMIT
|
||||
; block the peer if it did more than 10 404 requests in the last 30 seconds
|
||||
route-if = >:${LIMIT};10 goto:blockit
|
||||
; end of routing
|
||||
route-run = last:
|
||||
|
||||
|
||||
module = werkzeug.testapp:test_app
|
||||
threads = 10
|
||||
|
||||
; track the user if a 404 is returned
|
||||
final-route-if = equal:${uwsgi[status]};404 goto:trackit
|
||||
; end of final routing
|
||||
final-route-run = last:
|
||||
|
||||
final-route-label = trackit
|
||||
; increase the value in the 'limiter' cache
|
||||
final-route-run = cacheinc:key=${REMOTE_ADDR},expires=30
|
||||
; increase the value if the connection is from italy !!!
|
||||
final-route-if = equal:${geoip[country_name]};Italy cacheinc:key=${REMOTE_ADDR},expires=30
|
||||
|
||||
; block the client
|
||||
route-label = blockit
|
||||
route-run = log:STOP YOU BASTARD !!!
|
||||
route-run = break:503
|
||||
@@ -0,0 +1,80 @@
|
||||
#!./uwsgi --http-socket :9090 --gevent 100 --module tests.websocket_chat --gevent-monkey-patch
|
||||
import uwsgi
|
||||
import time
|
||||
import gevent.select
|
||||
import redis
|
||||
|
||||
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'])
|
||||
elif env['PATH_INFO'] == '/favicon.ico':
|
||||
return ""
|
||||
elif env['PATH_INFO'] == '/foobar/':
|
||||
uwsgi.websocket_handshake(env['HTTP_SEC_WEBSOCKET_KEY'], env.get('HTTP_ORIGIN', ''))
|
||||
print "websockets..."
|
||||
r = redis.StrictRedis(host='localhost', port=6379, db=0)
|
||||
channel = r.pubsub()
|
||||
channel.subscribe('foobar')
|
||||
|
||||
websocket_fd = uwsgi.connection_fd()
|
||||
redis_fd = channel.connection._sock.fileno()
|
||||
|
||||
while True:
|
||||
# wait max 4 seconds to allow ping to be sent
|
||||
ready = gevent.select.select([websocket_fd, redis_fd], [], [], 4.0)
|
||||
# send ping on timeout
|
||||
if not ready[0]:
|
||||
uwsgi.websocket_recv_nb()
|
||||
for fd in ready[0]:
|
||||
if fd == websocket_fd:
|
||||
msg = uwsgi.websocket_recv_nb()
|
||||
if msg:
|
||||
r.publish('foobar', msg)
|
||||
elif fd == redis_fd:
|
||||
msg = channel.parse_response()
|
||||
# only interested in user messages
|
||||
if msg[0] == 'message':
|
||||
uwsgi.websocket_send("[%s] %s" % (time.time(), msg))
|
||||
+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 = '2013-05-08'
|
||||
s.date = '2013-06-05'
|
||||
s.summary = "uWSGI"
|
||||
s.description = "The uWSGI server for Ruby/Rack"
|
||||
s.authors = ["Unbit"]
|
||||
|
||||
@@ -278,7 +278,9 @@ extern int pivot_root(const char *new_root, const char *put_old);
|
||||
#endif
|
||||
|
||||
#if defined(__HAIKU__) || defined(__CYGWIN__)
|
||||
#ifndef WAIT_ANY
|
||||
#define WAIT_ANY (-1)
|
||||
#endif
|
||||
#define PRIO_MAX 20
|
||||
#endif
|
||||
|
||||
@@ -292,6 +294,7 @@ extern int pivot_root(const char *new_root, const char *put_old);
|
||||
#include <sys/devpoll.h>
|
||||
#elif defined(__HAIKU__)
|
||||
#elif defined(__CYGWIN__)
|
||||
#elif defined(__HURD__)
|
||||
#else
|
||||
#include <sys/event.h>
|
||||
#endif
|
||||
@@ -783,6 +786,9 @@ struct uwsgi_opt {
|
||||
#elif defined(__APPLE__)
|
||||
#include <libkern/OSByteOrder.h>
|
||||
#elif defined(__HAIKU__)
|
||||
#elif defined(__HURD__)
|
||||
#define PATH_MAX 8192
|
||||
#define RTLD_DEFAULT ((void *) 0)
|
||||
#else
|
||||
#include <machine/endian.h>
|
||||
#endif
|
||||
@@ -1082,6 +1088,7 @@ struct uwsgi_route {
|
||||
|
||||
int (*if_func)(struct wsgi_request *, struct uwsgi_route *);
|
||||
int if_negate;
|
||||
int if_status;
|
||||
|
||||
int (*func) (struct wsgi_request *, struct uwsgi_route *);
|
||||
|
||||
@@ -1215,6 +1222,10 @@ struct uwsgi_transformation {
|
||||
uint8_t flushed;
|
||||
void *data;
|
||||
uint64_t round;
|
||||
int fd;
|
||||
struct uwsgi_buffer *ub;
|
||||
uint64_t len;
|
||||
uint64_t custom64;
|
||||
struct uwsgi_transformation *next;
|
||||
};
|
||||
|
||||
@@ -1393,6 +1404,7 @@ struct wsgi_request {
|
||||
int headers_hvec;
|
||||
|
||||
uint64_t proto_parser_pos;
|
||||
uint64_t proto_parser_move;
|
||||
int64_t proto_parser_status;
|
||||
void *proto_parser_buf;
|
||||
uint64_t proto_parser_buf_size;
|
||||
@@ -1425,11 +1437,19 @@ struct wsgi_request {
|
||||
|
||||
// avoid routing loops
|
||||
int is_routing;
|
||||
int is_final_routing;
|
||||
int is_error_routing;
|
||||
int routes_applied;
|
||||
// internal routing vm program counter
|
||||
uint32_t route_pc;
|
||||
uint32_t error_route_pc;
|
||||
uint32_t final_route_pc;
|
||||
// internal routing goto instruction
|
||||
uint32_t route_goto;
|
||||
uint32_t error_route_goto;
|
||||
uint32_t final_route_goto;
|
||||
|
||||
int ignore_body;
|
||||
|
||||
struct uwsgi_transformation *transformations;
|
||||
char *transformed_chunk;
|
||||
@@ -1931,6 +1951,8 @@ struct uwsgi_server {
|
||||
struct uwsgi_offload_engine *offload_engines;
|
||||
struct uwsgi_offload_engine *offload_engine_sendfile;
|
||||
struct uwsgi_offload_engine *offload_engine_transfer;
|
||||
struct uwsgi_offload_engine *offload_engine_memory;
|
||||
struct uwsgi_offload_engine *offload_engine_pipe;
|
||||
int offload_threads;
|
||||
int offload_threads_events;
|
||||
struct uwsgi_thread **offload_thread;
|
||||
@@ -1981,6 +2003,7 @@ struct uwsgi_server {
|
||||
struct uwsgi_string_list *touch_logrotate;
|
||||
struct uwsgi_string_list *touch_logreopen;
|
||||
struct uwsgi_string_list *touch_exec;
|
||||
struct uwsgi_string_list *touch_signal;
|
||||
|
||||
int propagate_touch;
|
||||
|
||||
@@ -2084,6 +2107,7 @@ struct uwsgi_server {
|
||||
struct uwsgi_mule *mules;
|
||||
struct uwsgi_string_list *farms_list;
|
||||
struct uwsgi_farm *farms;
|
||||
int mule_msg_size;
|
||||
|
||||
pid_t mypid;
|
||||
int mywid;
|
||||
@@ -2113,6 +2137,8 @@ struct uwsgi_server {
|
||||
#ifdef UWSGI_ROUTING
|
||||
struct uwsgi_router *routers;
|
||||
struct uwsgi_route *routes;
|
||||
struct uwsgi_route *final_routes;
|
||||
struct uwsgi_route *error_routes;
|
||||
struct uwsgi_route_condition *route_conditions;
|
||||
struct uwsgi_route_var *route_vars;
|
||||
#endif
|
||||
@@ -2146,6 +2172,7 @@ struct uwsgi_server {
|
||||
#ifdef __linux__
|
||||
struct uwsgi_string_list *cgroup;
|
||||
struct uwsgi_string_list *cgroup_opt;
|
||||
char *cgroup_dir_mode;
|
||||
char *ns;
|
||||
char *ns_net;
|
||||
struct uwsgi_string_list *ns_keep_mount;
|
||||
@@ -2168,6 +2195,7 @@ struct uwsgi_server {
|
||||
struct uwsgi_string_list *map_socket;
|
||||
|
||||
struct uwsgi_cron *crons;
|
||||
time_t cron_harakiri;
|
||||
|
||||
time_t respawn_delta;
|
||||
|
||||
@@ -2369,6 +2397,16 @@ struct uwsgi_cron {
|
||||
#endif
|
||||
void (*func)(struct uwsgi_cron *, time_t);
|
||||
|
||||
time_t started_at;
|
||||
|
||||
// next harakiri timestamp
|
||||
time_t harakiri;
|
||||
// number of seconds to wait before calling harakiri on cron
|
||||
int mercy;
|
||||
|
||||
uint8_t unique;
|
||||
pid_t pid;
|
||||
|
||||
struct uwsgi_cron *next;
|
||||
};
|
||||
|
||||
@@ -2903,7 +2941,8 @@ struct uwsgi_async_request {
|
||||
int event_queue_read(void);
|
||||
int event_queue_write(void);
|
||||
|
||||
void uwsgi_help(char *opt, char *val, void *);
|
||||
void uwsgi_help(char *, char *, void *);
|
||||
void uwsgi_print_sym(char *, char *, void *);
|
||||
|
||||
int uwsgi_str2_num(char *);
|
||||
int uwsgi_str3_num(char *);
|
||||
@@ -2927,7 +2966,7 @@ char *uwsgi_amqp_consume(int, uint64_t *, char **);
|
||||
|
||||
int uwsgi_file_serve(struct wsgi_request *, char *, uint16_t, char *, uint16_t, int);
|
||||
int uwsgi_starts_with(char *, int, char *, int);
|
||||
int uwsgi_static_want_gzip(struct wsgi_request *, char *, size_t, struct stat *);
|
||||
int uwsgi_static_want_gzip(struct wsgi_request *, char *, size_t *, struct stat *);
|
||||
|
||||
#ifdef __sun__
|
||||
time_t timegm(struct tm *);
|
||||
@@ -3146,6 +3185,7 @@ void mule_send_msg(int, char *, size_t);
|
||||
|
||||
uint32_t djb33x_hash(char *, uint64_t);
|
||||
void create_signal_pipe(int *);
|
||||
void create_msg_pipe(int *, int);
|
||||
struct uwsgi_subscribe_slot *uwsgi_get_subscribe_slot(struct uwsgi_subscribe_slot **, char *, uint16_t);
|
||||
struct uwsgi_subscribe_node *uwsgi_get_subscribe_node_by_name(struct uwsgi_subscribe_slot **, char *, uint16_t, char *, uint16_t);
|
||||
struct uwsgi_subscribe_node *uwsgi_get_subscribe_node(struct uwsgi_subscribe_slot **, char *, uint16_t);
|
||||
@@ -3196,6 +3236,7 @@ struct uwsgi_gateway_socket *uwsgi_new_gateway_socket(char *, char *);
|
||||
struct uwsgi_gateway_socket *uwsgi_new_gateway_socket_from_fd(int, char *);
|
||||
|
||||
void escape_shell_arg(char *, size_t, char *);
|
||||
void escape_json(char *, size_t, char *);
|
||||
|
||||
void *uwsgi_malloc_shared(size_t);
|
||||
void *uwsgi_calloc_shared(size_t);
|
||||
@@ -3238,12 +3279,15 @@ void uwsgi_opt_add_shared_socket(char *, char *, void *);
|
||||
void uwsgi_opt_add_socket(char *, char *, void *);
|
||||
void uwsgi_opt_add_lazy_socket(char *, char *, void *);
|
||||
void uwsgi_opt_add_cron(char *, char *, void *);
|
||||
void uwsgi_opt_add_cron2(char *, char *, void *);
|
||||
void uwsgi_opt_add_unique_cron(char *, char *, void *);
|
||||
void uwsgi_opt_load_plugin(char *, char *, void *);
|
||||
void uwsgi_opt_load_dl(char *, char *, void *);
|
||||
void uwsgi_opt_load(char *, char *, void *);
|
||||
void uwsgi_opt_safe_fd(char *, char *, void *);
|
||||
#ifdef UWSGI_SSL
|
||||
void uwsgi_opt_add_legion_cron(char *, char *, void *);
|
||||
void uwsgi_opt_add_unique_legion_cron(char *, char *, void *);
|
||||
void uwsgi_opt_sni(char *, char *, void *);
|
||||
struct uwsgi_string_list *uwsgi_ssl_add_sni_item(char *, char *, char *, char *, char *);
|
||||
#endif
|
||||
@@ -3321,19 +3365,22 @@ void uwsgi_opt_set_cap(char *, char *, void *);
|
||||
void uwsgi_opt_set_unshare(char *, char *, void *);
|
||||
#endif
|
||||
|
||||
char *uwsgi_tmpname(char *, char *);
|
||||
int uwsgi_tmpfd();
|
||||
FILE *uwsgi_tmpfile();
|
||||
|
||||
#ifdef UWSGI_ROUTING
|
||||
struct uwsgi_router *uwsgi_register_router(char *, int (*)(struct uwsgi_route *, char *));
|
||||
void uwsgi_opt_add_route(char *, char *, void *);
|
||||
int uwsgi_apply_routes(struct wsgi_request *);
|
||||
int uwsgi_apply_routes_do(struct wsgi_request *, char *, uint16_t);
|
||||
void uwsgi_apply_final_routes(struct wsgi_request *);
|
||||
int uwsgi_apply_error_routes(struct wsgi_request *);
|
||||
int uwsgi_apply_routes_do(struct uwsgi_route *, struct wsgi_request *, char *, uint16_t);
|
||||
void uwsgi_register_embedded_routers(void);
|
||||
void uwsgi_routing_dump();
|
||||
struct uwsgi_buffer *uwsgi_routing_translate(struct wsgi_request *, struct uwsgi_route *, char *, uint16_t, char *, size_t);
|
||||
int uwsgi_route_api_func(struct wsgi_request *, char *, char *);
|
||||
struct uwsgi_route_condition *uwsgi_register_route_condition(char *, int (*) (struct wsgi_request *, struct uwsgi_route *));
|
||||
void uwsgi_fixup_routes(void);
|
||||
void uwsgi_fixup_routes(struct uwsgi_route *);
|
||||
#endif
|
||||
|
||||
void uwsgi_reload(char **);
|
||||
@@ -3733,6 +3780,11 @@ void uwsgi_offload_engines_register_all(void);
|
||||
struct uwsgi_thread *uwsgi_offload_thread_start(void);
|
||||
int uwsgi_offload_request_sendfile_do(struct wsgi_request *, int, size_t);
|
||||
int uwsgi_offload_request_net_do(struct wsgi_request *, char *, struct uwsgi_buffer *);
|
||||
int uwsgi_offload_request_memory_do(struct wsgi_request *, char *, size_t);
|
||||
int uwsgi_offload_request_pipe_do(struct wsgi_request *, int, size_t);
|
||||
|
||||
int uwsgi_simple_sendfile(struct wsgi_request *, int, size_t, size_t);
|
||||
int uwsgi_simple_write(struct wsgi_request *, char *, size_t);
|
||||
|
||||
|
||||
void uwsgi_subscription_set_algo(char *);
|
||||
@@ -3761,8 +3813,8 @@ int uwsgi_plugin_modifier1(char *);
|
||||
|
||||
void *cache_udp_server_loop(void *);
|
||||
|
||||
void uwsgi_user_lock(int);
|
||||
void uwsgi_user_unlock(int);
|
||||
int uwsgi_user_lock(int);
|
||||
int uwsgi_user_unlock(int);
|
||||
|
||||
void simple_loop_run_int(int);
|
||||
|
||||
@@ -3827,6 +3879,7 @@ int uwsgi_response_add_header(struct wsgi_request *, char *, uint16_t, char *, u
|
||||
int uwsgi_response_add_header_force(struct wsgi_request *, char *, uint16_t, char *, uint16_t);
|
||||
int uwsgi_response_commit_headers(struct wsgi_request *);
|
||||
int uwsgi_response_sendfile_do(struct wsgi_request *, int, size_t, size_t);
|
||||
int uwsgi_response_sendfile_do_can_close(struct wsgi_request *, int, size_t, size_t, int);
|
||||
|
||||
struct uwsgi_buffer *uwsgi_proto_base_add_header(struct wsgi_request *, char *, uint16_t, char *, uint16_t);
|
||||
|
||||
@@ -3871,6 +3924,7 @@ void uwsgi_master_check_workers_deadline(void);
|
||||
void uwsgi_master_check_gateways_deadline(void);
|
||||
void uwsgi_master_check_mules_deadline(void);
|
||||
void uwsgi_master_check_spoolers_deadline(void);
|
||||
void uwsgi_master_check_crons_deadline(void);
|
||||
int uwsgi_master_check_spoolers_death(int);
|
||||
int uwsgi_master_check_emperor_death(int);
|
||||
int uwsgi_master_check_mules_death(int);
|
||||
@@ -3993,11 +4047,21 @@ void uwsgi_add_safe_fd(int);
|
||||
void uwsgi_ipcsem_clear(void);
|
||||
char *uwsgi_str_to_hex(char *, size_t);
|
||||
|
||||
// this 3 functions have been added 1.9.10 to allow plugins take the control over processes
|
||||
void uwsgi_worker_run(void);
|
||||
void uwsgi_mule_run(void);
|
||||
void uwsgi_spooler_run(void);
|
||||
void uwsgi_takeover(void);
|
||||
|
||||
char *uwsgi_binary_path(void);
|
||||
|
||||
void uwsgi_check_emperor(void);
|
||||
#ifdef UWSGI_AS_SHARED_LIBRARY
|
||||
int uwsgi_init(int, char **, char **);
|
||||
#endif
|
||||
|
||||
int uwsgi_master_check_cron_death(int);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
+42
-7
@@ -1,6 +1,6 @@
|
||||
# uWSGI build system
|
||||
|
||||
uwsgi_version = '1.9.9'
|
||||
uwsgi_version = '1.9.12'
|
||||
|
||||
import os
|
||||
import re
|
||||
@@ -153,7 +153,7 @@ def spcall3(cmd):
|
||||
def add_o(x):
|
||||
if x == 'uwsgi':
|
||||
x = 'main'
|
||||
elif x.endswith('.a'):
|
||||
elif x.endswith('.a') or x.endswith('.o'):
|
||||
return x
|
||||
x = x + '.o'
|
||||
return x
|
||||
@@ -277,7 +277,7 @@ def build_uwsgi(uc, print_only=False):
|
||||
objfile = file
|
||||
if objfile == 'uwsgi':
|
||||
objfile = 'main'
|
||||
if not objfile.endswith('.a'):
|
||||
if not objfile.endswith('.a') and not objfile.endswith('.o'):
|
||||
compile(' '.join(cflags), last_cflags_ts, objfile + '.o', file + '.c')
|
||||
|
||||
if uc.get('embedded_plugins'):
|
||||
@@ -346,6 +346,8 @@ def build_uwsgi(uc, print_only=False):
|
||||
for cfile in up['GCC_LIST']:
|
||||
if cfile.endswith('.a'):
|
||||
gcc_list.append(cfile)
|
||||
elif cfile.endswith('.o'):
|
||||
gcc_list.append('%s/%s' % (path, cfile))
|
||||
elif not cfile.endswith('.c') and not cfile.endswith('.cc') and not cfile.endswith('.m'):
|
||||
compile(' '.join(uniq_warnings(p_cflags)), last_cflags_ts,
|
||||
path + '/' + cfile + '.o', path + '/' + cfile + '.c')
|
||||
@@ -354,6 +356,20 @@ def build_uwsgi(uc, print_only=False):
|
||||
compile(' '.join(uniq_warnings(p_cflags)), last_cflags_ts,
|
||||
path + '/' + cfile + '.o', path + '/' + cfile)
|
||||
gcc_list.append('%s/%s' % (path, cfile))
|
||||
for bfile in up.get('BINARY_LIST', []):
|
||||
try:
|
||||
binary_link_cmd = "ld -r -b binary -o %s/%s.o %s/%s" % (path, bfile[1], path, bfile[1])
|
||||
print(binary_link_cmd)
|
||||
if os.system(binary_link_cmd) != 0:
|
||||
raise Exception('unable to link binary file')
|
||||
for kind in ('start','end'):
|
||||
objcopy_cmd = "objcopy --redefine-sym _binary_%s_%s=%s_%s %s/%s.o" % (binarize('%s/%s' % (path, bfile[1])), kind, bfile[0], kind, path, bfile[1])
|
||||
print(objcopy_cmd)
|
||||
if os.system(objcopy_cmd) != 0:
|
||||
raise Exception('unable to link binary file')
|
||||
gcc_list.append('%s/%s.o' % (path, bfile[1]))
|
||||
except:
|
||||
pass
|
||||
|
||||
libs += up['LIBS']
|
||||
|
||||
@@ -471,7 +487,7 @@ class uConf(object):
|
||||
self.gcc_list.append('proto/scgi')
|
||||
self.include_path = []
|
||||
|
||||
self.cflags = ['-O2', '-I.', '-Wall', '-Werror', '-D_LARGEFILE_SOURCE', '-D_FILE_OFFSET_BITS=64'] + os.environ.get("CFLAGS", "").split()
|
||||
self.cflags = ['-O2', '-I.', '-Wall', '-Werror', '-D_LARGEFILE_SOURCE', '-D_FILE_OFFSET_BITS=64'] + os.environ.get("CFLAGS", "").split() + self.get('cflags','').split()
|
||||
|
||||
report['kernel'] = uwsgi_os
|
||||
|
||||
@@ -485,6 +501,9 @@ class uConf(object):
|
||||
except:
|
||||
pass
|
||||
|
||||
if uwsgi_os == 'GNU':
|
||||
self.cflags.append('-D__HURD__')
|
||||
|
||||
try:
|
||||
gcc_version = str(spcall("%s -dumpversion" % GCC))
|
||||
except:
|
||||
@@ -568,7 +587,7 @@ class uConf(object):
|
||||
return None
|
||||
return value
|
||||
except:
|
||||
if default:
|
||||
if default is not None:
|
||||
return default
|
||||
return None
|
||||
|
||||
@@ -658,6 +677,8 @@ class uConf(object):
|
||||
locking_mode = 'posix_sem'
|
||||
except:
|
||||
pass
|
||||
elif uwsgi_os == 'GNU':
|
||||
locking_mode = 'posix_sem'
|
||||
elif uwsgi_os == 'Darwin':
|
||||
locking_mode = 'osx_spinlock'
|
||||
elif uwsgi_os.startswith('CYGWIN'):
|
||||
@@ -694,7 +715,7 @@ class uConf(object):
|
||||
event_mode = 'port'
|
||||
elif uwsgi_os in ('Darwin', 'FreeBSD', 'OpenBSD', 'NetBSD', 'DragonFly'):
|
||||
event_mode = 'kqueue'
|
||||
elif uwsgi_os.startswith('CYGWIN'):
|
||||
elif uwsgi_os.startswith('CYGWIN') or uwsgi_os == 'GNU':
|
||||
event_mode = 'poll'
|
||||
|
||||
if event_mode == 'epoll':
|
||||
@@ -1122,10 +1143,24 @@ def build_plugin(path, uc, cflags, ldflags, libs, name = None):
|
||||
for cfile in up['GCC_LIST']:
|
||||
if cfile.endswith('.a'):
|
||||
gcc_list.append(cfile)
|
||||
elif not cfile.endswith('.c') and not cfile.endswith('.cc') and not cfile.endswith('.m'):
|
||||
elif not cfile.endswith('.c') and not cfile.endswith('.cc') and not cfile.endswith('.m') and not cfile.endswith('.o'):
|
||||
gcc_list.append(path + '/' + cfile + '.c')
|
||||
else:
|
||||
gcc_list.append(path + '/' + cfile)
|
||||
for bfile in up.get('BINARY_LIST', []):
|
||||
try:
|
||||
binary_link_cmd = "ld -r -b binary -o %s/%s.o %s/%s" % (path, bfile[1], path, bfile[1])
|
||||
print(binary_link_cmd)
|
||||
if os.system(binary_link_cmd) != 0:
|
||||
raise Exception('unable to link binary file')
|
||||
for kind in ('start','end'):
|
||||
objcopy_cmd = "objcopy --redefine-sym _binary_%s_%s=%s_%s %s/%s.o" % (binarize('%s/%s' % (path, bfile[1])), kind, bfile[0], kind, path, bfile[1])
|
||||
print(objcopy_cmd)
|
||||
if os.system(objcopy_cmd) != 0:
|
||||
raise Exception('unable to link binary file')
|
||||
gcc_list.append('%s/%s.o' % (path, bfile[1]))
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
p_ldflags.remove('-Wl,--no-undefined')
|
||||
|
||||
Reference in New Issue
Block a user