Compare commits

...
68 Commits
Author SHA1 Message Date
Unbit d82ee16e0c completed first step of teajs integration, improved environ copy 2013-04-09 18:54:08 +02:00
unbit e4d65c07ce added support for gcc 4.8 2013-04-09 15:48:58 +02:00
Unbit 86fcb78cc3 fix for broken linkers 2013-04-09 14:51:47 +02:00
unbit 5beb422d75 Merge pull request #219 from prymitive/legion_cache_plugin
cache refactoring for better plugin friendliness
2013-04-09 05:48:49 -07:00
Łukasz Mierzwa 53679879ca cache refactoring for better plugin friendliness 2013-04-09 14:15:33 +02:00
Unbit a8ad766182 fixed matheval route var, added time route var 2013-04-09 11:09:15 +02:00
Unbit cbb2d30f79 more analysis for the metric subsystem 2013-04-09 06:38:34 +02:00
Unbit c5e00bcec6 preparing for uWSGI 1.9.6 2013-04-09 06:13:51 +02:00
Unbit 51535d374d reindented uwsgi.h 2013-04-09 06:13:28 +02:00
Unbit 1e057e6c35 the ldap support is now a plugin 2013-04-09 05:55:18 +02:00
Unbit b23e8ab862 added --socket-sndbuf and --socket-rcvbuf 2013-04-08 20:41:54 +02:00
Unbit 0f7f13dfb2 prepare for TeaJS integration 2013-04-08 19:50:01 +02:00
Unbit aa19ccda1d removed the probe subsystem 2013-04-08 17:05:12 +02:00
unbit cd0129e780 Merge pull request #218 from prymitive/legion_hooks
more legion hooks
2013-04-08 06:53:55 -07:00
Łukasz Mierzwa 506c9023e6 more legion hooks 2013-04-08 15:48:16 +02:00
Unbit d47c25ea4c added --lua-shell 2013-04-08 14:16:36 +02:00
Unbit 010651073c added rbshell 2013-04-08 13:49:23 +02:00
Unbit 76364e3799 added 'alarm' routing action 2013-04-08 11:10:18 +02:00
Unbit f9fd0a0203 added uwsgi route var 2013-04-08 10:34:45 +02:00
Unbit 8dfbde5d16 added --for-times 2013-04-08 10:20:22 +02:00
Unbit 888991f8c1 core/metrics.c 2013-04-08 09:39:57 +02:00
Unbit ece03922d6 added gridfs authentication 2013-04-06 15:09:01 +02:00
Unbit 47bb827e6e added 'lord' routing condition 2013-04-06 13:46:21 +02:00
Unbit a56003d847 added support for range header 2013-04-06 12:45:03 +02:00
Unbit 61022c398c added rpcraw 2013-04-06 08:42:55 +02:00
Unbit 00bd8cc525 improved pyshell 2013-04-06 07:44:12 +02:00
Unbit cf6a232aef added check for seek and tell in wsgi 2013-04-06 07:33:25 +02:00
Unbit 59d1a45ef0 added math route var 2013-04-05 19:26:33 +02:00
Unbit 0b5f9fcb48 added math[] route var 2013-04-05 18:39:01 +02:00
Unbit f713ffd6a1 improved mongodb dumb plugin 2013-04-05 18:17:28 +02:00
Unbit 22ba9d81d4 more generic mongodb plugin 2013-04-05 17:51:41 +02:00
Unbit 309bc98d7f added simple numeric checks for routing conditions 2013-04-05 17:48:20 +02:00
unbit 9b8646a583 Merge pull request #213 from prymitive/carbon_avg_policy
adds ability to control what values (if any) for avg_rt will be sent if ...
2013-04-05 02:18:19 -07:00
Unbit 48d1b87ab8 completed sqlite3 plugin 2013-04-05 10:37:18 +02:00
Unbit c5f849d846 added sqlite3 plugin 2013-04-05 10:35:30 +02:00
Unbit 31fbb6e4f5 prepare for moving sqlite to a dedicated plugin 2013-04-05 10:29:49 +02:00
Unbit 4d9a88e999 added setfile routing instruction and improved uwsgi_get_var 2013-04-05 07:47:32 +02:00
Unbit 252e8484a8 added chdir,setapp and sethome routing actions 2013-04-04 11:19:31 +02:00
Unbit 1b89203932 prepare for language independent home concept 2013-04-04 11:03:26 +02:00
Unbit 2263c6a618 prepare for uWSGI 1.9.5 release 2013-04-04 09:08:10 +02:00
Łukasz Mierzwa 673cb3ee21 adds ability to control what values (if any) for avg_rt will be sent if no requests were done, fixes #212 2013-04-04 00:55:02 +02:00
Unbit b4ecd504e3 prepare for 1.9.5 2013-04-03 19:19:23 +02:00
Unbit f226f29428 fix psgi post buffering 2013-04-03 18:20:54 +02:00
Unbit b87a284390 added 404/403 management for cgi routing 2013-04-03 18:09:05 +02:00
Unbit f63dcd0d9c fixed escaping in kvlist parse 2013-04-03 17:57:49 +02:00
Unbit 7f5563d581 added cgi router 2013-04-03 15:18:46 +02:00
Unbit d8a61a920e allows building a monolithic gridfs binary 2013-04-03 12:41:07 +02:00
Unbit 5a4900da8e added gridfs build profile 2013-04-03 12:39:00 +02:00
Unbit 677c30057a added routing support for gridfs 2013-04-03 12:24:21 +02:00
Unbit 26113e091b added the gridfs plugin 2013-04-03 11:54:54 +02:00
Unbit 1b5e98f593 more JSGI request vars 2013-04-02 18:22:39 +02:00
Unbit 0aa5201947 first implementation of a JSGI request 2013-04-02 17:30:58 +02:00
Unbit e3951baa3f completed JSGI response 2013-04-02 16:55:01 +02:00
Unbit 9f9dbbab9e preliminary support for JSGI 3.0 2013-04-02 12:26:55 +02:00
Unbit d546bbadbd added commonjs 'require' implementation to v8 2013-04-02 10:57:52 +02:00
Unbit 2b7f25054f added mule support for v8 2013-04-02 10:00:10 +02:00
Unbit bb3f6bcf7e more solid multithreading support for v8 2013-04-01 21:36:07 +02:00
Unbit 41da7175d1 working on v8 multithreading 2013-04-01 20:19:59 +02:00
Unbit 446763b58a added --honour-stdin 2013-04-01 10:07:33 +02:00
Unbit 3e9337a0fc added --daemons-honour-stdin 2013-04-01 09:30:19 +02:00
Unbit 028806165b force the emperor to honour --max-fd 2013-04-01 09:14:11 +02:00
unbit e4be42edbb Merge pull request #208 from xrmx/coverity11
More issues reported by Coverity
2013-04-01 00:07:29 -07:00
Unbit 230fa1f3bb fixed multiple interpreters support 2013-04-01 09:00:24 +02:00
unbit d74653bbad Merge pull request #209 from xrmx/coverity12
plugins/cgi: fix memory leak in uwsgi_cgi_request
2013-03-31 23:30:15 -07:00
Riccardo Magliocchetti 38049b0897 plugins/cgi: fix memory leak in uwsgi_cgi_request
Reported by Coverity as CID #990186.
2013-03-31 20:12:12 +02:00
Riccardo Magliocchetti b4af646929 core/emperor: fix memory leak in uwsgi_emperor_vassal_start
Reported by Coverity as CID #995786.
2013-03-31 19:51:25 +02:00
Riccardo Magliocchetti b21ec73a52 plugins/carbon: fix memory leak in carbon_post_init
Reported by Coverity as CID #995791
2013-03-31 19:45:24 +02:00
Riccardo Magliocchetti c595844f0e plugins/router_cache: fix memory leak in uwsgi_router_cache_store
Reported by Coverity as CID #995792.
2013-03-31 19:38:58 +02:00
59 changed files with 2570 additions and 1160 deletions
-2
View File
@@ -2,10 +2,8 @@
xml = auto
yaml = true
json = auto
sqlite3 = auto
zeromq = auto
ssl = auto
ldap = auto
pcre = auto
routing = auto
debug = false
+3
View File
@@ -0,0 +1,3 @@
[uwsgi]
main_plugin = gridfs
inherit = base
-2
View File
@@ -2,10 +2,8 @@
xml = true
yaml = true
json = true
sqlite3 = true
zeromq = true
ssl = true
ldap = true
pcre = true
routing = true
debug = false
-2
View File
@@ -2,10 +2,8 @@
xml = true
yaml = true
json = false
sqlite3 = false
zeromq = false
ssl = true
ldap = false
pcre = true
routing = true
debug = false
+88 -77
View File
@@ -288,21 +288,7 @@ void uwsgi_cache_init(struct uwsgi_cache *uc) {
(unsigned long long) ((sizeof(struct uwsgi_cache_item)+uc->keysize) * uc->max_items), (unsigned long long) (uc->blocksize * uc->max_items),
(unsigned long long) uc->blocks_bitmap_size);
struct uwsgi_string_list *usl = uc->nodes;
while(usl) {
char *port = strchr(usl->value, ':');
if (!port) {
uwsgi_log("[cache-udp-node] invalid udp address: %s\n", usl->value);
exit(1);
}
// no need to zero the memory, socket_to_in_addr will do that
struct sockaddr_in *sin = uwsgi_malloc(sizeof(struct sockaddr_in));
usl->custom = socket_to_in_addr(usl->value, port, 0, sin);
usl->custom_ptr = sin;
uwsgi_log("added udp node %s for cache \"%s\"\n", usl->value, uc->name);
usl = usl->next;
}
uwsgi_cache_setup_nodes(uc);
uc->udp_node_socket = socket(AF_INET, SOCK_DGRAM, 0);
if (uc->udp_node_socket < 0) {
@@ -311,70 +297,10 @@ void uwsgi_cache_init(struct uwsgi_cache *uc) {
}
uwsgi_socket_nb(uc->udp_node_socket);
usl = uc->sync_nodes;
while(usl) {
uwsgi_log("[cache-sync] getting cache dump from %s ...\n", usl->value);
int fd = uwsgi_connect(usl->value, 0, 0);
if (fd < 0) {
uwsgi_log("[cache-sync] unable to connect to the cache server\n");
goto next;
}
struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size + uc->filesize);
ub->pos = 4;
if (uwsgi_buffer_append(ub, uc->name, uc->name_len)) {
uwsgi_buffer_destroy(ub);
close(fd);
goto next;
}
if (uwsgi_buffer_set_uh(ub, 111, 6)) {
uwsgi_buffer_destroy(ub);
close(fd);
goto next;
}
if (uwsgi_write_nb(fd, ub->buf, ub->pos, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT])) {
uwsgi_buffer_destroy(ub);
uwsgi_log("[cache-sync] unable to write to the cache server\n");
close(fd);
goto next;
}
size_t rlen = ub->pos;
if (uwsgi_read_with_realloc(fd, &ub->buf, &rlen, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT])) {
uwsgi_buffer_destroy(ub);
uwsgi_log("[cache-sync] unable to read from the cache server\n");
close(fd);
goto next;
}
uwsgi_hooked_parse(ub->buf, ub->pos, cache_sync_hook, uc);
if (uwsgi_read_nb(fd, (char *) uc->items, uc->filesize, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT])) {
uwsgi_buffer_destroy(ub);
close(fd);
uwsgi_log("[cache-sync] unable to read from the cache server\n");
goto next;
}
// reset the hashtable
memset(uc->hashtable, 0, sizeof(uint64_t) * UMAX16);
// re-fill the hashtable
uwsgi_cache_fix(uc);
uwsgi_buffer_destroy(ub);
close(fd);
break;
next:
if (!usl->next) {
exit(1);
}
uwsgi_log("[cache-sync] trying with the next sync node...\n");
usl = usl->next;
}
uwsgi_cache_sync_from_nodes(uc);
uwsgi_cache_load_files(uc);
}
static uint64_t uwsgi_cache_get_index(struct uwsgi_cache *uc, char *key, uint16_t keylen) {
@@ -1696,3 +1622,88 @@ int uwsgi_cache_magic_clear(char *cache) {
}
void uwsgi_cache_sync_from_nodes(struct uwsgi_cache *uc) {
struct uwsgi_string_list *usl = uc->sync_nodes;
usl = uc->sync_nodes;
while(usl) {
uwsgi_log("[cache-sync] getting cache dump from %s ...\n", usl->value);
int fd = uwsgi_connect(usl->value, 0, 0);
if (fd < 0) {
uwsgi_log("[cache-sync] unable to connect to the cache server\n");
goto next;
}
struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size + uc->filesize);
ub->pos = 4;
if (uwsgi_buffer_append(ub, uc->name, uc->name_len)) {
uwsgi_buffer_destroy(ub);
close(fd);
goto next;
}
if (uwsgi_buffer_set_uh(ub, 111, 6)) {
uwsgi_buffer_destroy(ub);
close(fd);
goto next;
}
if (uwsgi_write_nb(fd, ub->buf, ub->pos, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT])) {
uwsgi_buffer_destroy(ub);
uwsgi_log("[cache-sync] unable to write to the cache server\n");
close(fd);
goto next;
}
size_t rlen = ub->pos;
if (uwsgi_read_with_realloc(fd, &ub->buf, &rlen, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT])) {
uwsgi_buffer_destroy(ub);
uwsgi_log("[cache-sync] unable to read from the cache server\n");
close(fd);
goto next;
}
uwsgi_hooked_parse(ub->buf, ub->pos, cache_sync_hook, uc);
if (uwsgi_read_nb(fd, (char *) uc->items, uc->filesize, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT])) {
uwsgi_buffer_destroy(ub);
close(fd);
uwsgi_log("[cache-sync] unable to read from the cache server\n");
goto next;
}
// reset the hashtable
memset(uc->hashtable, 0, sizeof(uint64_t) * UMAX16);
// re-fill the hashtable
uwsgi_cache_fix(uc);
uwsgi_buffer_destroy(ub);
close(fd);
break;
next:
if (!usl->next) {
exit(1);
}
uwsgi_log("[cache-sync] trying with the next sync node...\n");
usl = usl->next;
}
}
void uwsgi_cache_setup_nodes(struct uwsgi_cache *uc) {
struct uwsgi_string_list *usl = uc->nodes;
while(usl) {
char *port = strchr(usl->value, ':');
if (!port) {
uwsgi_log("[cache-udp-node] invalid udp address: %s\n", usl->value);
exit(1);
}
// no need to zero the memory, socket_to_in_addr will do that
struct sockaddr_in *sin = uwsgi_malloc(sizeof(struct sockaddr_in));
usl->custom = socket_to_in_addr(usl->value, port, 0, sin);
usl->custom_ptr = sin;
uwsgi_log("added udp node %s for cache \"%s\"\n", usl->value, uc->name);
usl = usl->next;
}
}
+12 -10
View File
@@ -208,18 +208,20 @@ void uwsgi_spawn_daemon(struct uwsgi_daemon *ud) {
uwsgi_write_pidfile(ud->pidfile);
}
// /dev/null will became stdin
devnull = open("/dev/null", O_RDONLY);
if (devnull < 0) {
uwsgi_error("/dev/null open()");
exit(1);
}
if (devnull != 0) {
if (dup2(devnull, 0) < 0) {
uwsgi_error("dup2()");
if (!uwsgi.daemons_honour_stdin) {
// /dev/null will became stdin
devnull = open("/dev/null", O_RDONLY);
if (devnull < 0) {
uwsgi_error("/dev/null open()");
exit(1);
}
close(devnull);
if (devnull != 0) {
if (dup2(devnull, 0) < 0) {
uwsgi_error("dup2()");
exit(1);
}
close(devnull);
}
}
if (setsid() < 0) {
+4 -3
View File
@@ -865,15 +865,16 @@ int uwsgi_emperor_vassal_start(struct uwsgi_instance *n_ui) {
uenvs = environ;
while (*uenvs) {
if (!strncmp(*uenvs, "UWSGI_VASSAL_", 13)) {
char *ne = uwsgi_concat2("UWSGI_", *uenvs + 13);
char *oe = uwsgi_concat2n(*uenvs, strchr(*uenvs, '=') - *uenvs, "", 0);
if (!strncmp(*uenvs, "UWSGI_VASSAL_", 13) && strchr(*uenvs, '=')) {
char *oe = uwsgi_concat2n(*uenvs, strchr(*uenvs, '=') - *uenvs, "", 0), *ne;
if (unsetenv(oe)) {
uwsgi_error("unsetenv()");
free(oe);
break;
}
free(oe);
ne = uwsgi_concat2("UWSGI_", *uenvs + 13);
#ifdef UWSGI_DEBUG
uwsgi_log("putenv %s\n", ne);
#endif
+25
View File
@@ -210,6 +210,15 @@ static void legions_check_nodes() {
uwsgi_wlock(legion->lock);
uwsgi_legion_remove_node(legion, tmp_node);
uwsgi_rwunlock(legion->lock);
// trigger node_left hooks
struct uwsgi_string_list *usl = legion->node_left_hooks;
while (usl) {
int ret = uwsgi_legion_action_call("node_left", legion, usl);
if (ret) {
uwsgi_log("[uwsgi-legion] ERROR, node_left hook returned: %d\n", ret);
}
usl = usl->next;
}
continue;
}
node = node->next;
@@ -570,6 +579,15 @@ static void *legion_loop(void *foobar) {
legion_rebuild_scrolls(ul);
uwsgi_rwunlock(ul->lock);
uwsgi_log("[uwsgi-legion] node: %.*s valor: %llu uuid: %.*s joined Legion %s\n", node->name_len, node->name, node->valor, 36, node->uuid, ul->legion);
// trigger node_joined hooks
struct uwsgi_string_list *usl = ul->node_joined_hooks;
while (usl) {
int ret = uwsgi_legion_action_call("node_joined", ul, usl);
if (ret) {
uwsgi_log("[uwsgi-legion] ERROR, node_joined hook returned: %d\n", ret);
}
usl = usl->next;
}
}
node->last_seen = uwsgi_now();
@@ -882,6 +900,13 @@ void uwsgi_legion_register_hook(struct uwsgi_legion *ul, char *event, char *acti
else if (!strcmp(event, "join")) {
usl = uwsgi_string_new_list(&ul->join_hooks, action);
}
else if (!strcmp(event, "node-joined")) {
usl = uwsgi_string_new_list(&ul->node_joined_hooks, action);
}
else if (!strcmp(event, "node-left")) {
usl = uwsgi_string_new_list(&ul->node_left_hooks, action);
}
else {
uwsgi_log("[uwsgi-legion] invalid event: %s\n", event);
exit(1);
-3
View File
@@ -679,9 +679,6 @@ ready:
// timer table lock
uwsgi.timer_table_lock = uwsgi_lock_init("timer");
// probe table lock
uwsgi.probe_table_lock = uwsgi_lock_init("probe");
// rb_timer table lock
uwsgi.rb_timer_table_lock = uwsgi_lock_init("rbtimer");
-16
View File
@@ -638,22 +638,6 @@ int master_loop(char **argv, char **environ) {
uwsgi_manage_command_cron(uwsgi_now());
}
// check for probes
if (ushared->probes_cnt > 0) {
uwsgi_lock(uwsgi.probe_table_lock);
for (i = 0; i < ushared->probes_cnt; i++) {
if (interesting_fd == -1) {
// increment cycles
ushared->probes[i].cycles++;
}
if (ushared->probes[i].func(interesting_fd, &ushared->probes[i])) {
uwsgi_route_signal(ushared->probes[i].sig);
}
}
uwsgi_unlock(uwsgi.probe_table_lock);
}
// some event returned
if (rlen > 0) {
// if the following function returns -1, a new worker has just spawned
+112
View File
@@ -0,0 +1,112 @@
/*
uWSGI metrics subsystem
a metric is a node in a tree reachable via a numeric id (OID, in SNMP way) or a simple string:
uwsgi.worker.1.requests
uwsgi.custom.foo.bar
the oid representation:
1.3.6.1.4.1.35156.17 = iso.org.dod.internet.private.enterprise.unbit.uwsgi
1.3.6.1.4.1.35156.17.3.1.1 = iso.org.dod.internet.private.enterprise.unbit.uwsgi.worker.1.requests
1.3.6.1.4.1.35156.17.3.1.1 = iso.org.dod.internet.private.enterprise.unbit.uwsgi.worker.1.requests
1.3.6.1.4.1.35156.17.3.1.2.1.1 = iso.org.dod.internet.private.enterprise.unbit.uwsgi.worker.1.core.1.requests
1.3.6.1.4.1.35156.17.4.1 = iso.org.dod.internet.private.enterprise.unbit.uwsgi.system.load_avg
...
each metric is a collected value with a specific frequency (a frequency of zero means the value is re-computed every time)
metrics are meant for numeric values signed 64 bit, but they can be exposed as:
gauge
counter
absolute
both 32 and 64bit, both signed and unsigned
metrics are managed by a dedicated thread (in the master) holding a linked list of all the items. For few metrics it is a good (read: simple) approach,
but you can cache lookups in a uWSGI cache for really big list.
struct uwsgi_metric *um = uwsgi_register_metric("worker.1.requests", "3.1.1", UWSGI_METRIC_COUNTER, UWSGI_METRIC_PTR, &uwsgi.workers[1].requests, 0, NULL);
prototype: struct uwsgi_metric *uwsgi_register_metric(char *name, char *oid, uint8_t value_type, uint8_t collect_way, void *ptr, uint32_t freq, void *custom);
value_type = UWSGI_METRIC_COUNTER/UWSGI_METRIC_GAUGE/UWSGI_METRIC_ABSOLUTE
collect_way = UWSGI_METRIC_PTR -> get from a pointer / UWSGI_METRIC_FUNC -> get from a func with the prototype int64_t func(struct uwsgi_metric *); / UWSGI_METRIC_FILE -> get the value from a file, ptr is the filename
when freq is zero the value is recomputed whenever requested, otherwise the metrics thread compute it every time the frequency is elapsed and caches it
For some metric (or all ?) you may want to hold a value even after a server reload. For such a reason you can specify a directory on wich the server (on startup/restart) will look for
a file named like the metric and will read the initial value from it. It may look an old-fashioned and quite inefficient way, but it is the most versatile for a sysadmin (allowing him/her
to even modify the values manually)
When registering a metric with the same name of an already registered one, the new one will overwrite the previous one. This allows plugins writer to override default behaviours
Applications are allowed to update metrics (but they cannot register new ones), with simple api funcs:
uwsgi.metric_set("worker.1.requests", N)
uwsgi.metric_inc("worker.1.requests", N=1)
uwsgi.metric_dec("worker.1.requests", N=1)
uwsgi.metric_mul("worker.1.requests", N=1)
uwsgi.metric_div("worker.1.requests", N=1)
and obviously they can get values:
uwsgi.metric_get("worker.1.requests", no_cache|force=False)
if the second parameter is True, the value is recomputed (but if it is a metric with a cache, the cache value will not be updated accordingly, this is the job of the metric thread)
Updating metrics from your app MUST BE ATOMIC, for such a reason a uWSGI rwlock is initialized on startup and used for each operation (simple reading from a metric does not require locking)
Metrics can be updated from the internal routing subsystem too:
route-if = equal:${REQUEST_URI};/foobar metricinc:foobar.test 2
and can be accessed as ${metric[foobar.test]}
The stats server exports the metrics list in the "metrics" attribute (obviously some info could be redundant)
*/
struct uwsgi_metric {
char *name;
char *oid;
// pre-computed snmp representation
char *asn;
size_t asn_size;
// ABSOLUTE/COUNTER/GAUGE
uint8_t type;
// the value of the metric
int64_t value;
// a custom blob you can attach to a metric
void *custom;
// the collection frequency
uint32_t freq;
time_t last_update;
// run this function to collect the value
int64_t (*collector)(struct uwsgi_metric *);
// take the value from this pointer to a 64bit value
int64_t *ptr;
// get the initial value from this file, and store each update in it
char *filename;
struct uwsgi_metric *next;
};
struct uwsgi_metric *uwsgi_register_metric(char *name, char *oid, uint8_t value_type, uint8_t collect_way, void *ptr, uint32_t freq, void *custom) {
struct uwsgi_metric *old_metric=NULL,*metric=uwsgi.metric;
while(metric) {
metric = metric->next;
}
}
void uwsgi_metric_loop() {
// every second scan the whole metrics tree
time_t now = uwsgi_now();
}
+97 -4
View File
@@ -2,7 +2,7 @@
extern struct uwsgi_server uwsgi;
// this is line uwsgi_str_num but with security checks
// this is like uwsgi_str_num but with security checks
static size_t get_content_length(char *buf, uint16_t size) {
int i;
size_t val = 0;
@@ -80,7 +80,7 @@ ssize_t send_udp_message(uint8_t modifier1, uint8_t modifier2, char *host, char
ret = sendto(fd, (char *) uh, message_size + 4, 0, (struct sockaddr *) &un_addr, sizeof(un_addr));
}
if (ret < 0) {
uwsgi_error("sendto()");
uwsgi_error("send_udp_message()/sendto()");
}
close(fd);
@@ -303,8 +303,41 @@ static int uwsgi_proto_check_9(struct wsgi_request *wsgi_req, char *key, char *b
return 0;
}
static void uwsgi_parse_http_range(char *buf, uint16_t len, size_t *from, size_t *to) {
*from = 0;
*to = 0;
uint16_t rlen = 0;
uint16_t i;
for(i=0;i<len;i++) {
if (buf[i] == ',') break;
rlen++;
}
// bytes=X-
if (rlen < 8) return;
char *equal = memchr(buf, '=', rlen);
if (!equal) return;
if (equal-buf != 5) return;
if (memcmp(buf, "bytes", 5)) return;
char *range = equal+1;
rlen -= 6;
char *dash = memchr(range, '-', rlen);
if (!dash) return;
*from = uwsgi_str_num(range, dash-range);
*to = uwsgi_str_num(dash+1, rlen - ((dash+1)-range));
if (*to > 0 && *from > *to) {
*from = 0;
*to = 0;
}
}
static int uwsgi_proto_check_10(struct wsgi_request *wsgi_req, char *key, char *buf, uint16_t len) {
if (uwsgi.honour_range && !uwsgi_proto_key("HTTP_RANGE", 10)) {
uwsgi_parse_http_range(buf, len, &wsgi_req->range_from, &wsgi_req->range_to);
return 0;
}
if (!uwsgi_proto_key("UWSGI_FILE", 10)) {
wsgi_req->file = buf;
wsgi_req->file_len = len;
@@ -312,6 +345,12 @@ static int uwsgi_proto_check_10(struct wsgi_request *wsgi_req, char *key, char *
return 0;
}
if (!uwsgi_proto_key("UWSGI_HOME", 10)) {
wsgi_req->home = buf;
wsgi_req->home_len = len;
return 0;
}
return 0;
}
@@ -416,8 +455,8 @@ static int uwsgi_proto_check_12(struct wsgi_request *wsgi_req, char *key, char *
}
if (!uwsgi_proto_key("UWSGI_PYHOME", 12)) {
wsgi_req->pyhome = buf;
wsgi_req->pyhome_len = len;
wsgi_req->home = buf;
wsgi_req->home_len = len;
return 0;
}
@@ -968,6 +1007,60 @@ int uwsgi_hooked_parse_array(char *buffer, size_t len, void (*hook) (uint16_t, c
}
// this functions transform a raw HTTP response to a uWSGI-managed response
int uwsgi_blob_to_response(struct wsgi_request *wsgi_req, char *body, size_t len) {
char *line = body;
size_t line_len = 0;
size_t i;
int status_managed = 0;
for(i=0;i<len;i++) {
if (body[i] == '\n') {
// invalid line
if (line_len < 1) {
return -1;
}
if (line[line_len-1] != '\r') {
return -1;
}
// end of the headers
if (line_len == 1) {
break;
}
if (status_managed) {
char *colon = memchr(line, ':', line_len-1);
if (!colon) return -1;
if (colon[1] != ' ') return -1;
if (uwsgi_response_add_header(wsgi_req, line, colon-line, colon+2, (line_len-1) - ((colon+2)-line))) return -1;
}
else {
char *space = memchr(line, ' ', line_len-1);
if (!space) return -1;
if ((line_len-1) - ((space+1)-line) < 3) return -1;
if (uwsgi_response_prepare_headers(wsgi_req, space+1, (line_len-1) - ((space+1)-line))) return -1;
status_managed = 1;
}
line = NULL;
line_len = 0;
}
else {
if (!line) {
line = body + i;
}
line_len++;
}
}
if ((i+1) < len) {
if (uwsgi_response_write_body_do(wsgi_req, body + (i + 1), len-(i+1))) {
return -1;
}
}
return 0;
}
/*
the following functions need to take in account that POST data could be already available in wsgi_req->buffer (generally when uwsgi protocol is in use)
+1 -1
View File
@@ -47,7 +47,7 @@ void uwsgi_request_body_seek(struct wsgi_request *wsgi_req, off_t pos) {
if (uwsgi.post_buffering) {
if (pos < 0) {
if (pos > (off_t) wsgi_req->post_pos) {
if ((off_t) wsgi_req->post_pos - pos < 0) {
wsgi_req->post_pos = 0;
return;
}
+353
View File
@@ -220,6 +220,10 @@ run:
if (ret == UWSGI_ROUTE_GOON) {
goon_func = routes->func;
}
if (ret == -1) {
return UWSGI_ROUTE_BREAK;
}
}
next:
subject = orig_subject;
@@ -661,6 +665,153 @@ static int uwsgi_router_signal(struct uwsgi_route *ur, char *arg) {
return 0;
}
// chdir route
static int uwsgi_router_chdir_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len);
if (!ub) return UWSGI_ROUTE_BREAK;
if (chdir(ub->buf)) {
uwsgi_error("uwsgi_router_chdir_func()/chdir()");
uwsgi_buffer_destroy(ub);
return UWSGI_ROUTE_BREAK;
}
uwsgi_buffer_destroy(ub);
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_chdir(struct uwsgi_route *ur, char *arg) {
ur->func = uwsgi_router_chdir_func;
ur->data = arg;
ur->data_len = strlen(arg);
return 0;
}
// setapp route
static int uwsgi_router_setapp_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len);
if (!ub) return UWSGI_ROUTE_BREAK;
char *ptr = uwsgi_req_append(wsgi_req, "UWSGI_APPID", 11, ub->buf, ub->pos);
if (!ptr) {
uwsgi_buffer_destroy(ub);
return UWSGI_ROUTE_BREAK;
}
wsgi_req->appid = ptr;
wsgi_req->appid_len = ub->pos;
uwsgi_buffer_destroy(ub);
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_setapp(struct uwsgi_route *ur, char *arg) {
ur->func = uwsgi_router_setapp_func;
ur->data = arg;
ur->data_len = strlen(arg);
return 0;
}
// sethome route
static int uwsgi_router_sethome_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len);
if (!ub) return UWSGI_ROUTE_BREAK;
char *ptr = uwsgi_req_append(wsgi_req, "UWSGI_HOME", 10, ub->buf, ub->pos);
if (!ptr) {
uwsgi_buffer_destroy(ub);
return UWSGI_ROUTE_BREAK;
}
wsgi_req->home = ptr;
wsgi_req->home_len = ub->pos;
uwsgi_buffer_destroy(ub);
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_sethome(struct uwsgi_route *ur, char *arg) {
ur->func = uwsgi_router_sethome_func;
ur->data = arg;
ur->data_len = strlen(arg);
return 0;
}
// setfile route
static int uwsgi_router_setfile_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len);
if (!ub) return UWSGI_ROUTE_BREAK;
char *ptr = uwsgi_req_append(wsgi_req, "UWSGI_HOME", 10, ub->buf, ub->pos);
if (!ptr) {
uwsgi_buffer_destroy(ub);
return UWSGI_ROUTE_BREAK;
}
wsgi_req->file = ptr;
wsgi_req->file_len = ub->pos;
wsgi_req->dynamic = 1;
uwsgi_buffer_destroy(ub);
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_setfile(struct uwsgi_route *ur, char *arg) {
ur->func = uwsgi_router_setfile_func;
ur->data = arg;
ur->data_len = strlen(arg);
return 0;
}
// setprocname route
static int uwsgi_router_setprocname_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len);
if (!ub) return UWSGI_ROUTE_BREAK;
uwsgi_set_processname(ub->buf);
uwsgi_buffer_destroy(ub);
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_setprocname(struct uwsgi_route *ur, char *arg) {
ur->func = uwsgi_router_setprocname_func;
ur->data = arg;
ur->data_len = strlen(arg);
return 0;
}
// alarm route
static int uwsgi_router_alarm_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
struct uwsgi_buffer *ub_alarm = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len);
if (!ub_alarm) return UWSGI_ROUTE_BREAK;
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data2, ur->data2_len);
if (!ub) {
uwsgi_buffer_destroy(ub_alarm);
return UWSGI_ROUTE_BREAK;
}
uwsgi_alarm_trigger(ub_alarm->buf, ub->buf, ub->pos);
uwsgi_buffer_destroy(ub_alarm);
uwsgi_buffer_destroy(ub);
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_alarm(struct uwsgi_route *ur, char *arg) {
ur->func = uwsgi_router_alarm_func;
char *space = strchr(arg, ' ');
if (!space) {
return -1;
}
*space = 0;
ur->data = arg;
ur->data_len = strlen(arg);
ur->data2 = space+1;
ur->data2_len = strlen(ur->data2);
return 0;
}
// send route
static int uwsgi_router_send_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route) {
@@ -780,6 +931,119 @@ static int uwsgi_route_condition_equal(struct wsgi_request *wsgi_req, struct uws
return 0;
}
static int uwsgi_route_condition_higher(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
char *semicolon = memchr(ur->subject_str, ';', ur->subject_str_len);
if (!semicolon) return 0;
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, semicolon - ur->subject_str);
if (!ub) return -1;
struct uwsgi_buffer *ub2 = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, semicolon+1, ur->subject_str_len - ((semicolon+1) - ur->subject_str));
if (!ub2) {
uwsgi_buffer_destroy(ub);
return -1;
}
long num1 = strtol(ub->buf, NULL, 10);
long num2 = strtol(ub2->buf, NULL, 10);
if(num1 > num2) {
uwsgi_buffer_destroy(ub);
uwsgi_buffer_destroy(ub2);
return 1;
}
uwsgi_buffer_destroy(ub);
uwsgi_buffer_destroy(ub2);
return 0;
}
static int uwsgi_route_condition_higherequal(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
char *semicolon = memchr(ur->subject_str, ';', ur->subject_str_len);
if (!semicolon) return 0;
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, semicolon - ur->subject_str);
if (!ub) return -1;
struct uwsgi_buffer *ub2 = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, semicolon+1, ur->subject_str_len - ((semicolon+1) - ur->subject_str));
if (!ub2) {
uwsgi_buffer_destroy(ub);
return -1;
}
long num1 = strtol(ub->buf, NULL, 10);
long num2 = strtol(ub2->buf, NULL, 10);
if(num1 >= num2) {
uwsgi_buffer_destroy(ub);
uwsgi_buffer_destroy(ub2);
return 1;
}
uwsgi_buffer_destroy(ub);
uwsgi_buffer_destroy(ub2);
return 0;
}
static int uwsgi_route_condition_lower(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
char *semicolon = memchr(ur->subject_str, ';', ur->subject_str_len);
if (!semicolon) return 0;
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, semicolon - ur->subject_str);
if (!ub) return -1;
struct uwsgi_buffer *ub2 = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, semicolon+1, ur->subject_str_len - ((semicolon+1) - ur->subject_str));
if (!ub2) {
uwsgi_buffer_destroy(ub);
return -1;
}
long num1 = strtol(ub->buf, NULL, 10);
long num2 = strtol(ub2->buf, NULL, 10);
if(num1 < num2) {
uwsgi_buffer_destroy(ub);
uwsgi_buffer_destroy(ub2);
return 1;
}
uwsgi_buffer_destroy(ub);
uwsgi_buffer_destroy(ub2);
return 0;
}
static int uwsgi_route_condition_lowerequal(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
char *semicolon = memchr(ur->subject_str, ';', ur->subject_str_len);
if (!semicolon) return 0;
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, semicolon - ur->subject_str);
if (!ub) return -1;
struct uwsgi_buffer *ub2 = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, semicolon+1, ur->subject_str_len - ((semicolon+1) - ur->subject_str));
if (!ub2) {
uwsgi_buffer_destroy(ub);
return -1;
}
long num1 = strtol(ub->buf, NULL, 10);
long num2 = strtol(ub2->buf, NULL, 10);
if(num1 <= num2) {
uwsgi_buffer_destroy(ub);
uwsgi_buffer_destroy(ub2);
return 1;
}
uwsgi_buffer_destroy(ub);
uwsgi_buffer_destroy(ub2);
return 0;
}
#ifdef UWSGI_SSL
static int uwsgi_route_condition_lord(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, ur->subject_str_len);
if (!ub) return -1;
int ret = uwsgi_legion_i_am_the_lord(ub->buf);
uwsgi_buffer_destroy(ub);
return ret;
}
#endif
static int uwsgi_route_condition_startswith(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
char *semicolon = memchr(ur->subject_str, ';', ur->subject_str_len);
if (!semicolon) return 0;
@@ -865,6 +1129,70 @@ static int uwsgi_route_condition_isexec(struct wsgi_request *wsgi_req, struct uw
return 0;
}
static char *uwsgi_route_var_uwsgi(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, uint16_t *vallen) {
char *ret = NULL;
if (!uwsgi_strncmp(key, keylen, "wid", 3)) {
ret = uwsgi_num2str(uwsgi.mywid);
*vallen = strlen(ret);
}
else if (!uwsgi_strncmp(key, keylen, "pid", 3)) {
ret = uwsgi_num2str(uwsgi.mypid);
*vallen = strlen(ret);
}
return ret;
}
static char *uwsgi_route_var_time(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, uint16_t *vallen) {
char *ret = NULL;
if (!uwsgi_strncmp(key, keylen, "unix", 4)) {
ret = uwsgi_num2str(uwsgi_now());
*vallen = strlen(ret);
}
return ret;
}
#ifdef UWSGI_MATHEVAL
static char *uwsgi_route_var_math(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, uint16_t *vallen) {
char *ret = NULL;
// avoid crash
if (!wsgi_req->var_cnt) return NULL;
// we make a bit of fun here, we do a copy of the vars buffer (+1 byte for final zero) and zeor-pad all of the strings
char *vars_buf = uwsgi_malloc(wsgi_req->uh->pktsize + keylen + 1);
char **names = uwsgi_malloc(sizeof(char *) * (wsgi_req->var_cnt/2));
double *values = uwsgi_calloc(sizeof(double) * (wsgi_req->var_cnt/2));
int i,j = 0;
char *ptr = vars_buf;
for (i = wsgi_req->var_cnt-1; i > 0; i -= 2) {
memcpy(ptr, wsgi_req->hvec[i-1].iov_base, wsgi_req->hvec[i-1].iov_len);
names[j] = ptr;
ptr += wsgi_req->hvec[i-1].iov_len;
*ptr++=0;
char *num = ptr;
memcpy(ptr, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len);
ptr += wsgi_req->hvec[i].iov_len;
*ptr++=0;
values[j] = strtod(num, NULL);
j++;
}
char *expr = ptr;
memcpy(ptr, key, keylen); ptr += keylen;
*ptr++=0;
void *e = evaluator_create(expr);
if (!e) goto end;
double n = evaluator_evaluate(e, j, names, values);
evaluator_destroy(e);
ret = uwsgi_num2str((int)n);
*vallen = strlen(ret);
end:
free(vars_buf);
free(names);
free(values);
return ret;
}
#endif
// register embedded routers
void uwsgi_register_embedded_routers() {
@@ -882,6 +1210,12 @@ void uwsgi_register_embedded_routers() {
uwsgi_register_router("signal", uwsgi_router_signal);
uwsgi_register_router("send", uwsgi_router_send);
uwsgi_register_router("send-crnl", uwsgi_router_send_crnl);
uwsgi_register_router("chdir", uwsgi_router_chdir);
uwsgi_register_router("setapp", uwsgi_router_setapp);
uwsgi_register_router("sethome", uwsgi_router_sethome);
uwsgi_register_router("setfile", uwsgi_router_setfile);
uwsgi_register_router("setprocname", uwsgi_router_setprocname);
uwsgi_register_router("alarm", uwsgi_router_alarm);
uwsgi_register_route_condition("exists", uwsgi_route_condition_exists);
uwsgi_register_route_condition("isfile", uwsgi_route_condition_isfile);
@@ -896,11 +1230,30 @@ void uwsgi_register_embedded_routers() {
uwsgi_register_route_condition("endswith", uwsgi_route_condition_endswith);
uwsgi_register_route_condition("regexp", uwsgi_route_condition_regexp);
uwsgi_register_route_condition("re", uwsgi_route_condition_regexp);
uwsgi_register_route_condition("ishigher", uwsgi_route_condition_higher);
uwsgi_register_route_condition(">", uwsgi_route_condition_higher);
uwsgi_register_route_condition("islower", uwsgi_route_condition_lower);
uwsgi_register_route_condition("<", uwsgi_route_condition_lower);
uwsgi_register_route_condition("ishigherequal", uwsgi_route_condition_higherequal);
uwsgi_register_route_condition(">=", uwsgi_route_condition_higherequal);
uwsgi_register_route_condition("islowerequal", uwsgi_route_condition_lowerequal);
uwsgi_register_route_condition("<=", uwsgi_route_condition_lowerequal);
#ifdef UWSGI_SSL
uwsgi_register_route_condition("lord", uwsgi_route_condition_lord);
#endif
uwsgi_register_route_condition("empty", uwsgi_route_condition_empty);
uwsgi_register_route_var("cookie", uwsgi_get_cookie);
uwsgi_register_route_var("qs", uwsgi_get_qs);
struct uwsgi_route_var *urv = uwsgi_register_route_var("uwsgi", uwsgi_route_var_uwsgi);
urv->need_free = 1;
urv = uwsgi_register_route_var("time", uwsgi_route_var_time);
urv->need_free = 1;
#ifdef UWSGI_MATHEVAL
urv = uwsgi_register_route_var("math", uwsgi_route_var_math);
urv->need_free = 1;
#endif
}
struct uwsgi_router *uwsgi_register_router(char *name, int (*func) (struct uwsgi_route *, char *)) {
-81
View File
@@ -177,87 +177,6 @@ int uwsgi_add_file_monitor(uint8_t sig, char *filename) {
}
struct uwsgi_probe *uwsgi_probe_register(struct uwsgi_probe **up, char *name, int (*func) (int, struct uwsgi_signal_probe *)) {
struct uwsgi_probe *uwsgi_up = *up, *old_up;
if (!uwsgi_up) {
*up = uwsgi_malloc(sizeof(struct uwsgi_probe));
uwsgi_up = *up;
}
else {
while (uwsgi_up) {
old_up = uwsgi_up;
uwsgi_up = uwsgi_up->next;
}
uwsgi_up = uwsgi_malloc(sizeof(struct uwsgi_probe));
old_up->next = uwsgi_up;
}
uwsgi_up->name = name;
uwsgi_up->func = func;
uwsgi_up->next = NULL;
uwsgi_log("registered new probe \"%s\" at %p\n", name, uwsgi_up);
return uwsgi_up;
}
int uwsgi_add_probe(uint8_t sig, char *kind, char *args, int timeout, int freq) {
uwsgi_lock(uwsgi.probe_table_lock);
if (ushared->probes_cnt < MAX_PROBES) {
struct uwsgi_probe *up = uwsgi.probes;
while (up) {
if (!strcmp(up->name, kind)) {
break;
}
up = up->next;
}
if (!up) {
uwsgi_log("unable to find probe \"%s\" !!!\n", kind);
uwsgi_unlock(uwsgi.probe_table_lock);
return -1;
}
// fill the probe table
ushared->probes[ushared->probes_cnt].func = up->func;
strncpy(ushared->probes[ushared->probes_cnt].args, args, 1024 - 1);
ushared->probes[ushared->probes_cnt].registered = 0;
ushared->probes[ushared->probes_cnt].sig = sig;
ushared->probes[ushared->probes_cnt].fd = -1;
ushared->probes[ushared->probes_cnt].state = 0;
ushared->probes[ushared->probes_cnt].last_event = 0;
ushared->probes[ushared->probes_cnt].data = NULL;
ushared->probes[ushared->probes_cnt].cycles = 0;
ushared->probes[ushared->probes_cnt].bad = 0;
if (!timeout) {
timeout = uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT];
}
ushared->probes[ushared->probes_cnt].timeout = timeout;
if (!freq) {
freq = 1;
}
ushared->probes[ushared->probes_cnt].freq = freq;
ushared->probes_cnt++;
}
else {
uwsgi_log("you can register max %d probes !!!\n", MAX_PROBES);
uwsgi_unlock(uwsgi.probe_table_lock);
return -1;
}
uwsgi_unlock(uwsgi.probe_table_lock);
return 0;
}
int uwsgi_add_timer(uint8_t sig, int secs) {
if (!uwsgi.master_process) return -1;
+36
View File
@@ -136,6 +136,24 @@ int bind_to_unix(char *socket_name, int listen_queue, int chmod_socket, int abst
uwsgi_log("setting abstract socket mode (warning: only Linux supports this)\n");
}
if (uwsgi.so_sndbuf) {
socklen_t sndbuf = (socklen_t) uwsgi.so_sndbuf;
if (setsockopt(serverfd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(socklen_t)) < 0) {
uwsgi_error("SO_SNDBUF setsockopt()");
uwsgi_nuclear_blast();
return -1;
}
}
if (uwsgi.so_rcvbuf) {
socklen_t rcvbuf = (socklen_t) uwsgi.so_rcvbuf;
if (setsockopt(serverfd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(socklen_t)) < 0) {
uwsgi_error("SO_RCVBUF setsockopt()");
uwsgi_nuclear_blast();
return -1;
}
}
uws_addr->sun_family = AF_UNIX;
if (socket_name[0] == '@') {
memcpy(uws_addr->sun_path + abstract_socket, socket_name + 1, UMIN(strlen(socket_name + 1), 101));
@@ -587,6 +605,24 @@ int bind_to_tcp(char *socket_name, int listen_queue, char *tcp_port) {
uwsgi_nuclear_blast();
return -1;
}
if (uwsgi.so_sndbuf) {
socklen_t sndbuf = (socklen_t) uwsgi.so_sndbuf;
if (setsockopt(serverfd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(socklen_t)) < 0) {
uwsgi_error("SO_SNDBUF setsockopt()");
uwsgi_nuclear_blast();
return -1;
}
}
if (uwsgi.so_rcvbuf) {
socklen_t rcvbuf = (socklen_t) uwsgi.so_rcvbuf;
if (setsockopt(serverfd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(socklen_t)) < 0) {
uwsgi_error("SO_RCVBUF setsockopt()");
uwsgi_nuclear_blast();
return -1;
}
}
if (setsockopt(serverfd, SOL_SOCKET, SO_REUSEADDR, (const void *) &reuse, sizeof(int)) < 0) {
uwsgi_error("SO_REUSEADDR setsockopt()");
-57
View File
@@ -1,57 +0,0 @@
#ifdef UWSGI_SQLITE3
#include "uwsgi.h"
#include <sqlite3.h>
extern struct uwsgi_server uwsgi;
static int uwsgi_sqlite3_config_callback(void *magic_table, int field_count, char **fields, char **col) {
// make a copy of the string
if (field_count >= 2) {
size_t value_len = strlen(fields[1]) + 1;
char *value = magic_sub(fields[1], value_len, &value_len, (char **) magic_table);
add_exported_option(uwsgi_strncopy(fields[0], strlen(fields[0])), value, 0);
}
return 0;
}
void uwsgi_sqlite3_config(char *file, char *magic_table[]) {
sqlite3 *db;
char *err = NULL;
char *query = "SELECT * FROM uwsgi";
char *colon = uwsgi_get_last_char(file, ':');
if (colon) {
colon[0] = 0;
if (colon[1] != 0) {
query = colon + 1;
}
}
uwsgi_log("[uWSGI] getting sqlite3 configuration from %s\n", file);
#ifdef sqlite3_open_v2
if (sqlite3_open_v2(file, &db, SQLITE_OPEN_READONLY, NULL)) {
#else
if (sqlite3_open(file, &db)) {
#endif
uwsgi_log("unable to open sqlite3 db: %s\n", sqlite3_errmsg(db));
sqlite3_close(db);
exit(1);
}
if (sqlite3_exec(db, query, uwsgi_sqlite3_config_callback, (void *) magic_table, &err)) {
uwsgi_log("sqlite3 error: %s\n", err);
sqlite3_close(db);
exit(1);
}
sqlite3_close(db);
}
#endif
+33 -6
View File
@@ -315,7 +315,7 @@ int uwsgi_add_expires_uri(struct wsgi_request *wsgi_req, struct stat *st) {
#endif
char *uwsgi_get_mime_type(char *name, int namelen, int *size) {
char *uwsgi_get_mime_type(char *name, int namelen, size_t *size) {
int i;
int count = 0;
@@ -429,7 +429,7 @@ static int uwsgi_static_stat(struct wsgi_request *wsgi_req, char *filename, size
int uwsgi_real_file_serve(struct wsgi_request *wsgi_req, char *real_filename, size_t real_filename_len, struct stat *st) {
int mime_type_size = 0;
size_t mime_type_size = 0;
char http_last_modified[49];
if (uwsgi.threads > 1)
@@ -451,8 +451,31 @@ int uwsgi_real_file_serve(struct wsgi_request *wsgi_req, char *real_filename, si
uwsgi_log("[uwsgi-fileserve] file %s found\n", real_filename);
#endif
size_t fsize = st->st_size;
if (wsgi_req->range_to) {
fsize = wsgi_req->range_to - wsgi_req->range_from;
if (fsize > (size_t)st->st_size) {
fsize = st->st_size;
}
}
else {
// reset in case of inconsistent size
if (wsgi_req->range_from > fsize) {
wsgi_req->range_from = 0;
fsize = 0 ;
}
else {
fsize -= wsgi_req->range_from;
}
}
// HTTP status
if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) return -1;
if (fsize > 0 && (wsgi_req->range_from || wsgi_req->range_to)) {
if (uwsgi_response_prepare_headers(wsgi_req, "206 Partial Content", 19)) return -1;
}
else {
if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) return -1;
}
#ifdef UWSGI_PCRE
uwsgi_add_expires(wsgi_req, real_filename, real_filename_len, st);
@@ -490,8 +513,12 @@ int uwsgi_real_file_serve(struct wsgi_request *wsgi_req, char *real_filename, si
if (uwsgi_static_want_gzip(wsgi_req, real_filename, real_filename_len, st)) {
if (uwsgi_response_add_header(wsgi_req, "Content-Encoding", 16, "gzip", 4)) return -1;
}
// set Content-Length
if (uwsgi_response_add_content_length(wsgi_req, st->st_size)) return -1;
// set Content-Length (to fsize NOT st->st_size)
if (uwsgi_response_add_content_length(wsgi_req, fsize)) return -1;
if (fsize > 0 && (wsgi_req->range_from || wsgi_req->range_to)) {
// here use teh original size !!!
if (uwsgi_response_add_content_range(wsgi_req, wsgi_req->range_from, wsgi_req->range_to, st->st_size)) return -1;
}
int size = set_http_date(st->st_mtime, http_last_modified);
if (uwsgi_response_add_header(wsgi_req, "Last-Modified", 13, http_last_modified, size)) return -1;
@@ -506,7 +533,7 @@ int uwsgi_real_file_serve(struct wsgi_request *wsgi_req, char *real_filename, si
int fd = open(real_filename, O_RDONLY);
if (fd < 0) return -1;
// fd will be closed in the following function
uwsgi_response_sendfile_do(wsgi_req, fd, 0, st->st_size);
uwsgi_response_sendfile_do(wsgi_req, fd, wsgi_req->range_from, fsize);
}
wsgi_req->status = 200;
+27 -4
View File
@@ -1525,6 +1525,25 @@ int uwsgi_logic_opt_for_glob(char *key, char *value) {
return 1;
}
int uwsgi_logic_opt_for_times(char *key, char *value) {
int num = atoi(uwsgi.logic_opt_data);
int i;
char str_num[11];
for (i = 1; i <= num; i++) {
int ret = uwsgi_num2str2(i, str_num);
// security check
if (ret < 0 || ret > 11) {
exit(1);
}
add_exported_option(key, uwsgi_substitute(value, "%(_)", str_num), 0);
}
return 1;
}
void add_exported_option(char *key, char *value, int configured) {
@@ -3054,14 +3073,17 @@ void http_url_decode(char *buf, uint16_t * len, char *dst) {
}
/*
we scan the table in reverse, as updated values are at the end
*/
char *uwsgi_get_var(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, uint16_t * len) {
int i;
for (i = 0; i < wsgi_req->var_cnt; i += 2) {
if (!uwsgi_strncmp(key, keylen, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len)) {
*len = wsgi_req->hvec[i + 1].iov_len;
return wsgi_req->hvec[i + 1].iov_base;
for (i = wsgi_req->var_cnt-1; i > 0; i -= 2) {
if (!uwsgi_strncmp(key, keylen, wsgi_req->hvec[i-1].iov_base, wsgi_req->hvec[i-1].iov_len)) {
*len = wsgi_req->hvec[i].iov_len;
return wsgi_req->hvec[i].iov_base;
}
}
@@ -3480,6 +3502,7 @@ int uwsgi_kvlist_parse(char *src, size_t len, char list_separator, char kv_separ
escaped = 1;
}
else if (escaped) {
*ptr++ = src[i];
escaped = 0;
}
else {
+25 -38
View File
@@ -80,6 +80,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"for", required_argument, 0, "(opt logic) for cycle", uwsgi_opt_logic, (void *) uwsgi_logic_opt_for, UWSGI_OPT_IMMEDIATE},
{"for-glob", required_argument, 0, "(opt logic) for cycle (expand glob)", uwsgi_opt_logic, (void *) uwsgi_logic_opt_for_glob, UWSGI_OPT_IMMEDIATE},
{"for-times", required_argument, 0, "(opt logic) for cycle (expand the specified num to a list starting from 1)", uwsgi_opt_logic, (void *) uwsgi_logic_opt_for_times, UWSGI_OPT_IMMEDIATE},
{"endfor", optional_argument, 0, "(opt logic) end for cycle", uwsgi_opt_noop, NULL, UWSGI_OPT_IMMEDIATE},
{"end-for", optional_argument, 0, "(opt logic) end for cycle", uwsgi_opt_noop, NULL, UWSGI_OPT_IMMEDIATE},
@@ -166,6 +167,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"single-interpreter", no_argument, 'i', "do not use multiple interpreters (where available)", uwsgi_opt_true, &uwsgi.single_interpreter, 0},
{"need-app", no_argument, 0, "exit if no app can be loaded", uwsgi_opt_true, &uwsgi.need_app, 0},
{"master", no_argument, 'M', "enable master process", uwsgi_opt_true, &uwsgi.master_process, 0},
{"honour-stdin", no_argument, 0, "do not remap stdin to /dev/null", uwsgi_opt_true, &uwsgi.honour_stdin, 0},
{"emperor", required_argument, 0, "run the Emperor", uwsgi_opt_add_string_list, &uwsgi.emperor, 0},
{"emperor-procname", required_argument, 0, "set the Emperor process name", uwsgi_opt_set_str, &uwsgi.emperor_procname, 0},
{"emperor-freq", required_argument, 0, "set the Emperor scan frequency (default 3 seconds)", uwsgi_opt_set_int, &uwsgi.emperor_freq, 0},
@@ -293,20 +295,11 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"json", required_argument, 'j', "load config from json file", uwsgi_opt_load_json, NULL, UWSGI_OPT_IMMEDIATE},
{"js", required_argument, 'j', "load config from json file", uwsgi_opt_load_json, NULL, UWSGI_OPT_IMMEDIATE},
#endif
#ifdef UWSGI_SQLITE3
{"sqlite3", required_argument, 0, "load config from sqlite3 db", uwsgi_opt_load_sqlite3, NULL, UWSGI_OPT_IMMEDIATE},
{"sqlite", required_argument, 0, "load config from sqlite3 db", uwsgi_opt_load_sqlite3, NULL, UWSGI_OPT_IMMEDIATE},
#endif
#ifdef UWSGI_ZEROMQ
{"zeromq", required_argument, 0, "create a zeromq pub/sub pair", uwsgi_opt_add_lazy_socket, "zmq", 0},
{"zmq", required_argument, 0, "create a zeromq pub/sub pair", uwsgi_opt_add_lazy_socket, "zmq", 0},
{"zeromq-socket", required_argument, 0, "create a zeromq pub/sub pair", uwsgi_opt_add_lazy_socket, "zmq", 0},
{"zmq-socket", required_argument, 0, "create a zeromq pub/sub pair", uwsgi_opt_add_lazy_socket, "zmq", 0},
#endif
#ifdef UWSGI_LDAP
{"ldap", required_argument, 0, "load configuration from ldap server", uwsgi_opt_load_ldap, NULL, UWSGI_OPT_IMMEDIATE},
{"ldap-schema", no_argument, 0, "dump uWSGI ldap schema", uwsgi_opt_ldap_dump, NULL, UWSGI_OPT_IMMEDIATE},
{"ldap-schema-ldif", no_argument, 0, "dump uWSGI ldap schema in ldif format", uwsgi_opt_ldap_dump_ldif, NULL, UWSGI_OPT_IMMEDIATE},
#endif
{"weight", required_argument, 0, "weight of the instance (used by clustering/lb/subscriptions)", uwsgi_opt_set_64bit, &uwsgi.weight, 0},
{"auto-weight", required_argument, 0, "set weight of the instance (used by clustering/lb/subscriptions) automatically", uwsgi_opt_true, &uwsgi.auto_weight, 0},
@@ -319,6 +312,8 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"socket-send-timeout", no_argument, 0, "set SO_SNDTIMEO", uwsgi_opt_set_int, &uwsgi.so_send_timeout, 0},
{"so-write-timeout", no_argument, 0, "set SO_SNDTIMEO", uwsgi_opt_set_int, &uwsgi.so_send_timeout, 0},
{"socket-write-timeout", no_argument, 0, "set SO_SNDTIMEO", uwsgi_opt_set_int, &uwsgi.so_send_timeout, 0},
{"socket-sndbuf", required_argument, 0, "set SO_SNDBUF", uwsgi_opt_set_64bit, &uwsgi.so_sndbuf, 0},
{"socket-rcvbuf", required_argument, 0, "set SO_RCVBUF", uwsgi_opt_set_64bit, &uwsgi.so_rcvbuf, 0},
{"limit-as", required_argument, 0, "limit processes address space/vsz", uwsgi_opt_set_megabytes, &uwsgi.rl.rlim_max, 0},
{"limit-nproc", required_argument, 0, "limit the number of spawnable processes", uwsgi_opt_set_int, &uwsgi.rl_nproc.rlim_max, 0},
{"reload-on-as", required_argument, 0, "reload if address space is higher than specified megabytes", uwsgi_opt_set_megabytes, &uwsgi.reload_on_as, UWSGI_OPT_MEMORY},
@@ -384,6 +379,8 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"legion-setup", required_argument, 0, "action to call on legion setup", uwsgi_opt_legion_hook, NULL, UWSGI_OPT_MASTER},
{"legion-death", required_argument, 0, "action to call on legion death (shutdown of the instance)", uwsgi_opt_legion_hook, NULL, UWSGI_OPT_MASTER},
{"legion-join", required_argument, 0, "action to call on legion join (first time quorum is reached)", uwsgi_opt_legion_hook, NULL, UWSGI_OPT_MASTER},
{"legion-node-joined", required_argument, 0, "action to call on new node joining legion", uwsgi_opt_legion_hook, NULL, UWSGI_OPT_MASTER},
{"legion-node-left", required_argument, 0, "action to call node leaving legion", uwsgi_opt_legion_hook, NULL, UWSGI_OPT_MASTER},
{"legion-quorum", required_argument, 0, "set the quorum of a legion", uwsgi_opt_legion_quorum, NULL, UWSGI_OPT_MASTER},
{"legion-scroll", required_argument, 0, "set the scroll of a legion", uwsgi_opt_legion_scroll, NULL, UWSGI_OPT_MASTER},
{"legion-scroll-max-size", required_argument, 0, "set max size of legion scroll buffer", uwsgi_opt_set_16bit, &uwsgi.legion_scroll_max_size, 0},
@@ -575,6 +572,8 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"static-gzip-ext", required_argument, 0, "check for a gzip version of all requested static files with the specified ext/suffix", uwsgi_opt_add_string_list, &uwsgi.static_gzip_ext, UWSGI_OPT_MIME},
{"static-gzip-suffix", required_argument, 0, "check for a gzip version of all requested static files with the specified ext/suffix", uwsgi_opt_add_string_list, &uwsgi.static_gzip_ext, UWSGI_OPT_MIME},
{"honour-range", no_argument, 0, "enable support for the HTTP Range header", uwsgi_opt_true, &uwsgi.honour_range, 0},
{"offload-threads", required_argument, 0, "set the number of offload threads to spawn (per-worker, default 0)", uwsgi_opt_set_int, &uwsgi.offload_threads, 0},
{"offload-thread", required_argument, 0, "set the number of offload threads to spawn (per-worker, default 0)", uwsgi_opt_set_int, &uwsgi.offload_threads, 0},
@@ -613,6 +612,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"attach-daemon", required_argument, 0, "attach a command/daemon to the master process (the command has to not go in background)", uwsgi_opt_add_daemon, NULL, UWSGI_OPT_MASTER},
{"smart-attach-daemon", required_argument, 0, "attach a command/daemon to the master process managed by a pidfile (the command has to daemonize)", uwsgi_opt_add_daemon, NULL, UWSGI_OPT_MASTER},
{"smart-attach-daemon2", required_argument, 0, "attach a command/daemon to the master process managed by a pidfile (the command has to NOT daemonize)", uwsgi_opt_add_daemon, NULL, UWSGI_OPT_MASTER},
{"daemons-honour-stdin", no_argument, 0, "do not change the stdin of external daemons to /dev/null", uwsgi_opt_true, &uwsgi.daemons_honour_stdin, UWSGI_OPT_MASTER},
{"plugins", required_argument, 0, "load uWSGI plugins", uwsgi_opt_load_plugin, NULL, UWSGI_OPT_IMMEDIATE},
{"plugin", required_argument, 0, "load uWSGI plugins", uwsgi_opt_load_plugin, NULL, UWSGI_OPT_IMMEDIATE},
{"plugins-dir", required_argument, 0, "add a directory to uWSGI plugin search path", uwsgi_opt_add_string_list, &uwsgi.plugins_dir, UWSGI_OPT_IMMEDIATE},
@@ -1370,7 +1370,7 @@ void fixup_argv_and_environ(int argc, char **argv, char **environ) {
env_count++;
}
uwsgi.environ = uwsgi_malloc(sizeof(char *) * env_count);
uwsgi.environ = uwsgi_malloc(sizeof(char *) * (env_count+1));
for (i = 0; i < env_count; i++) {
uwsgi.environ[i] = strdup(environ[i]);
#ifdef UWSGI_DEBUG
@@ -1378,6 +1378,7 @@ void fixup_argv_and_environ(int argc, char **argv, char **environ) {
#endif
environ[i] = uwsgi.environ[i];
}
uwsgi.environ[env_count] = NULL;
#ifdef UWSGI_DEBUG
uwsgi_log("max space for custom process name = %d\n", uwsgi.max_procname);
@@ -2127,6 +2128,20 @@ int uwsgi_start(void *v_argv) {
// automatically fix options
sanitize_args();
if (uwsgi.requested_max_fd) {
uwsgi.rl.rlim_cur = uwsgi.requested_max_fd;
uwsgi.rl.rlim_max = uwsgi.requested_max_fd;
if (setrlimit(RLIMIT_NOFILE, &uwsgi.rl)) {
uwsgi_error("setrlimit()");
}
}
if (!getrlimit(RLIMIT_NOFILE, &uwsgi.rl)) {
uwsgi.max_fd = uwsgi.rl.rlim_cur;
uwsgi_log_initial("detected max file descriptor number: %lu\n", (unsigned long) uwsgi.max_fd);
}
// start the Emperor if needed
if (!uwsgi.early_emperor && uwsgi.emperor) {
uwsgi_emperor_start();
@@ -2151,19 +2166,6 @@ int uwsgi_start(void *v_argv) {
}
}
if (uwsgi.requested_max_fd) {
uwsgi.rl.rlim_cur = uwsgi.requested_max_fd;
uwsgi.rl.rlim_max = uwsgi.requested_max_fd;
if (setrlimit(RLIMIT_NOFILE, &uwsgi.rl)) {
uwsgi_error("setrlimit()");
}
}
if (!getrlimit(RLIMIT_NOFILE, &uwsgi.rl)) {
uwsgi.max_fd = uwsgi.rl.rlim_cur;
uwsgi_log_initial("detected max file descriptor number: %lu\n", (unsigned long) uwsgi.max_fd);
}
if (uwsgi.async > 1) {
if ((unsigned long) uwsgi.max_fd < (unsigned long) uwsgi.async) {
uwsgi_log("- your current max open files limit is %lu, this is lower than requested async cores !!! -\n", (unsigned long) uwsgi.max_fd);
@@ -2549,11 +2551,9 @@ next:
exit(0);
}
#ifdef UWSGI_MINTERPRETERS
if (!uwsgi.single_interpreter && uwsgi.numproc > 0) {
uwsgi_log("*** uWSGI is running in multiple interpreter mode ***\n");
}
#endif
// check for request plugins, and eventually print a warning
int rp_available = 0;
@@ -3882,13 +3882,6 @@ void uwsgi_opt_load_yml(char *opt, char *filename, void *none) {
}
#endif
#ifdef UWSGI_SQLITE3
void uwsgi_opt_load_sqlite3(char *opt, char *filename, void *none) {
config_magic_table_fill(filename, uwsgi.magic_table);
uwsgi_sqlite3_config(filename, uwsgi.magic_table);
}
#endif
#ifdef UWSGI_JSON
void uwsgi_opt_load_json(char *opt, char *filename, void *none) {
config_magic_table_fill(filename, uwsgi.magic_table);
@@ -3896,12 +3889,6 @@ void uwsgi_opt_load_json(char *opt, char *filename, void *none) {
}
#endif
#ifdef UWSGI_LDAP
void uwsgi_opt_load_ldap(char *opt, char *url, void *none) {
uwsgi_ldap_config(url);
}
#endif
void uwsgi_opt_add_custom_option(char *opt, char *value, void *none) {
struct uwsgi_custom_option *uco = uwsgi.custom_options, *old_uco;
+14
View File
@@ -12,6 +12,19 @@ int uwsgi_response_add_content_length(struct wsgi_request *wsgi_req, uint64_t cl
return uwsgi_response_add_header(wsgi_req, "Content-Length", 14, buf, ret);
}
int uwsgi_response_add_content_range(struct wsgi_request *wsgi_req, uint64_t start, uint64_t end, uint64_t cl) {
char buf[6+(sizeof(UMAX64_STR)*3)+4];
if (end == 0) {
end = cl-1;
}
int ret = snprintf(buf, 6+(sizeof(UMAX64_STR)*3)+4, "bytes %llu-%llu/%llu", (unsigned long long) start, (unsigned long long) end, (unsigned long long) cl);
if (ret <= 0 || ret > (int) (6+(sizeof(UMAX64_STR)*3)+4)) {
wsgi_req->write_errors++;
return -1;
}
return uwsgi_response_add_header(wsgi_req, "Content-Range", 13, buf, ret);
}
// status could be NNN or NNN message
int uwsgi_response_prepare_headers(struct wsgi_request *wsgi_req, char *status, uint16_t status_len) {
@@ -225,6 +238,7 @@ sendfile:
if (can_close) close(fd);
return -1;
}
if (pos >= (size_t)st.st_size) return UWSGI_OK;
len = st.st_size;
}
+58 -5
View File
@@ -35,6 +35,10 @@ struct uwsgi_carbon {
char *hostname_dot_replacement;
char *hostname;
int resolve_hostname;
char *idle_avg;
int push_avg;
int zero_avg;
uint64_t last_requests;
struct uwsgi_stats_pusher *pusher;
} u_carbon;
@@ -50,6 +54,7 @@ static struct uwsgi_option carbon_options[] = {
{"carbon-hostname-dots", required_argument, 0, "set char to use as a replacement for dots in hostname (dots are not replaced by default)", uwsgi_opt_set_str, &u_carbon.hostname_dot_replacement, 0},
{"carbon-name-resolve", no_argument, 0, "allow using hostname as carbon server address (default disabled)", uwsgi_opt_true, &u_carbon.resolve_hostname, 0},
{"carbon-resolve-names", no_argument, 0, "allow using hostname as carbon server address (default disabled)", uwsgi_opt_true, &u_carbon.resolve_hostname, 0},
{"carbon-idle-avg", required_argument, 0, "average values source during idle period (no requests), can be \"last\", \"zero\", \"none\" (default is last)", uwsgi_opt_set_str, &u_carbon.idle_avg, 0},
{0, 0, 0, 0, 0, 0, 0},
};
@@ -74,12 +79,17 @@ static void carbon_post_init() {
else if (!u_server->port) {
u_server->port = uwsgi_str(p);
}
else break;
else
break;
p = strtok(NULL, ":");
}
if (!u_server->hostname || !u_server->port) {
uwsgi_log("[carbon] invalid carbon server address (%s)\n", usl->value);
usl = usl->next;
if (u_server->hostname) free(u_server->hostname);
if (u_server->port) free(u_server->port);
free(u_server);
continue;
}
@@ -116,6 +126,22 @@ static void carbon_post_init() {
}
}
u_carbon.push_avg = 1;
u_carbon.zero_avg = 0;
if (!u_carbon.idle_avg) {
u_carbon.idle_avg = "last";
}
else if (!strcmp(u_carbon.idle_avg, "zero")) {
u_carbon.zero_avg = 1;
}
else if (!strcmp(u_carbon.idle_avg, "none")) {
u_carbon.push_avg = 0;
}
else if (strcmp(u_carbon.idle_avg, "last")) {
uwsgi_log("[carbon] invalid value for carbon-idle-avg: \"%s\"\n", u_carbon.idle_avg);
exit(1);
}
if (!u_carbon.last_busyness_values) {
u_carbon.last_busyness_values = uwsgi_calloc(sizeof(unsigned long long) * uwsgi.numproc);
}
@@ -232,6 +258,8 @@ static void carbon_push_stats(int retry_cycle, time_t now) {
unsigned long long worker_busyness = 0;
unsigned long long total_harakiri = 0;
int do_avg_push;
wok = carbon_write(fd, "%s%s.%s.requests %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, (unsigned long long) uwsgi.workers[0].requests, (unsigned long long) now);
if (!wok) goto clear;
@@ -282,8 +310,19 @@ static void carbon_push_stats(int retry_cycle, time_t now) {
if (!wok) goto clear;
}
wok = carbon_write(fd, "%s%s.%s.worker%d.avg_rt %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, i, (unsigned long long) avg_rt, (unsigned long long) now);
if (!wok) goto clear;
do_avg_push = 1;
if (!u_carbon.last_requests || u_carbon.last_requests == uwsgi.workers[0].requests) {
if (!u_carbon.push_avg) {
do_avg_push = 0;
}
else if (u_carbon.zero_avg) {
avg_rt = 0;
}
}
if (do_avg_push) {
wok = carbon_write(fd, "%s%s.%s.worker%d.avg_rt %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, i, (unsigned long long) avg_rt, (unsigned long long) now);
if (!wok) goto clear;
}
wok = carbon_write(fd, "%s%s.%s.worker%d.tx %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, i, (unsigned long long) uwsgi.workers[i].tx, (unsigned long long) now);
if (!wok) goto clear;
@@ -304,8 +343,20 @@ static void carbon_push_stats(int retry_cycle, time_t now) {
if (!wok) goto clear;
}
wok = carbon_write(fd, "%s%s.%s.avg_rt %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, (unsigned long long) (active_workers ? total_avg_rt / active_workers : 0), (unsigned long long) now);
if (!wok) goto clear;
do_avg_push = 1;
uint64_t c_total_avg_rt = (active_workers ? total_avg_rt / active_workers : 0);
if (!u_carbon.last_requests || u_carbon.last_requests == uwsgi.workers[0].requests) {
if (!u_carbon.push_avg) {
do_avg_push = 0;
}
else if (u_carbon.zero_avg) {
c_total_avg_rt = 0;
}
}
if (do_avg_push) {
wok = carbon_write(fd, "%s%s.%s.avg_rt %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, (unsigned long long) c_total_avg_rt, (unsigned long long) now);
if (!wok) goto clear;
}
wok = carbon_write(fd, "%s%s.%s.tx %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, (unsigned long long) total_tx, (unsigned long long) now);
if (!wok) goto clear;
@@ -333,6 +384,8 @@ static void carbon_push_stats(int retry_cycle, time_t now) {
usl->healthy = 1;
usl->errors = 0;
u_carbon.last_requests = uwsgi.workers[0].requests;
clear:
close(fd);
nxt:
+109 -43
View File
@@ -18,7 +18,7 @@ struct uwsgi_cgi {
int path_info;
} uc ;
void uwsgi_opt_add_cgi(char *opt, char *value, void *foobar) {
static void uwsgi_opt_add_cgi(char *opt, char *value, void *foobar) {
char *val = strchr(value, '=');
if (!val) {
@@ -30,7 +30,7 @@ void uwsgi_opt_add_cgi(char *opt, char *value, void *foobar) {
}
void uwsgi_opt_add_cgi_maphelper(char *opt, char *value, void *foobar) {
static void uwsgi_opt_add_cgi_maphelper(char *opt, char *value, void *foobar) {
char *val = strchr(value, '=');
if (!val) {
uwsgi_log("invalid CGI helper syntax, must be ext=command\n");
@@ -66,7 +66,7 @@ struct uwsgi_option uwsgi_cgi_options[] = {
};
void uwsgi_cgi_apps() {
static void uwsgi_cgi_apps() {
struct uwsgi_dyn_dict *udd = uc.mountpoint;
struct stat st;
@@ -123,7 +123,7 @@ void uwsgi_cgi_apps() {
}
int uwsgi_cgi_init(){
static int uwsgi_cgi_init(){
void (*cgi_sym)(void);
@@ -161,7 +161,7 @@ int uwsgi_cgi_init(){
}
char *uwsgi_cgi_get_helper(char *filename) {
static char *uwsgi_cgi_get_helper(char *filename) {
struct uwsgi_dyn_dict *helpers = uc.helpers;
size_t len = strlen(filename);
@@ -179,7 +179,7 @@ char *uwsgi_cgi_get_helper(char *filename) {
}
int uwsgi_cgi_parse(struct wsgi_request *wsgi_req, char *buf, size_t len) {
static int uwsgi_cgi_parse(struct wsgi_request *wsgi_req, char *buf, size_t len) {
size_t i;
char *key = buf, *value = NULL;
@@ -266,7 +266,7 @@ send_body:
return 0;
}
char *uwsgi_cgi_get_docroot(char *path_info, uint16_t path_info_len, int *need_free, int *is_a_file, int *discard_base, char **script_name) {
static char *uwsgi_cgi_get_docroot(char *path_info, uint16_t path_info_len, int *need_free, int *is_a_file, int *discard_base, char **script_name) {
struct uwsgi_dyn_dict *udd = uc.mountpoint, *choosen_udd = NULL;
int best_found = 0;
@@ -323,7 +323,7 @@ char *uwsgi_cgi_get_docroot(char *path_info, uint16_t path_info_len, int *need_f
return path;
}
int uwsgi_cgi_walk(struct wsgi_request *wsgi_req, char *full_path, char *docroot, size_t docroot_len, int discard_base, char **path_info) {
static int uwsgi_cgi_walk(struct wsgi_request *wsgi_req, char *full_path, char *docroot, size_t docroot_len, int discard_base, char **path_info) {
// and now start walking...
uint16_t i;
@@ -380,18 +380,12 @@ int uwsgi_cgi_walk(struct wsgi_request *wsgi_req, char *full_path, char *docroot
}
int uwsgi_cgi_request(struct wsgi_request *wsgi_req) {
static int uwsgi_cgi_run(struct wsgi_request *, char *, size_t, char *, char *, char *, char *, int, int);
static int uwsgi_cgi_request(struct wsgi_request *wsgi_req) {
int i;
pid_t cgi_pid;
int waitpid_status;
char **argv;
int nargs = 0;
char full_path[PATH_MAX];
char tmp_path[PATH_MAX];
int cgi_pipe[2];
int post_pipe[2];
ssize_t len;
struct stat cgi_stat;
int need_free = 0;
int is_a_file = 0;
@@ -399,7 +393,6 @@ int uwsgi_cgi_request(struct wsgi_request *wsgi_req) {
size_t docroot_len = 0;
size_t full_path_len = 0;
char *helper = NULL;
char *command = NULL;
char *path_info = NULL;
char *script_name = NULL;
@@ -533,11 +526,8 @@ int uwsgi_cgi_request(struct wsgi_request *wsgi_req) {
return UWSGI_OK;
}
if (is_a_file) {
command = docroot;
}
else {
command = full_path;
// get the helper
if (!is_a_file) {
helper = uwsgi_cgi_get_helper(full_path);
if (helper == NULL) {
@@ -551,28 +541,43 @@ int uwsgi_cgi_request(struct wsgi_request *wsgi_req) {
}
}
int ret = uwsgi_cgi_run(wsgi_req, docroot, docroot_len, full_path, helper, path_info, script_name, is_a_file, discard_base);
if (need_free) free(docroot);
return ret;
}
static int uwsgi_cgi_run(struct wsgi_request *wsgi_req, char *docroot, size_t docroot_len, char *full_path, char *helper, char *path_info, char *script_name, int is_a_file, int discard_base) {
int cgi_pipe[2];
int post_pipe[2];
int nargs = 0;
int waitpid_status;
ssize_t len;
int i;
char **argv;
char *command = full_path;
if (is_a_file) {
command = docroot;
}
if (pipe(cgi_pipe)) {
if (need_free)
free(docroot);
uwsgi_error("pipe()");
uwsgi_error("uwsgi_cgi_run()/pipe()");
return UWSGI_OK;
}
if (pipe(post_pipe)) {
if (need_free)
free(docroot);
close(cgi_pipe[0]);
close(cgi_pipe[1]);
uwsgi_error("pipe()");
uwsgi_error("uwsgi_cgi_run()/pipe()");
return UWSGI_OK;
}
cgi_pid = fork();
pid_t cgi_pid = fork();
if (cgi_pid < 0) {
uwsgi_error("fork()");
if (need_free)
free(docroot);
uwsgi_error("uwsgi_cgi_run()/fork()");
close(cgi_pipe[0]);
close(cgi_pipe[1]);
close(post_pipe[0]);
@@ -582,9 +587,6 @@ int uwsgi_cgi_request(struct wsgi_request *wsgi_req) {
if (cgi_pid > 0) {
if (need_free)
free(docroot);
close(cgi_pipe[1]);
close(post_pipe[0]);
@@ -795,7 +797,7 @@ clear2:
}
*base = '/';
}
else {
else if (docroot_len > 0) {
if (chdir(docroot)) {
uwsgi_error("chdir()");
}
@@ -837,9 +839,8 @@ clear2:
escape_shell_arg(arg_copy, arg_copy_len, argv[i]);
i++;
p = strtok(NULL, "+");
}
}
else {
}
free(qs);
}
}
@@ -864,7 +865,7 @@ clear2:
}
if (execvp(argv[0], argv)) {
uwsgi_error("execvp()");
uwsgi_error("uwsgi_cgi_run()/execvp()");
}
// never here
@@ -872,11 +873,73 @@ clear2:
}
void uwsgi_cgi_after_request(struct wsgi_request *wsgi_req) {
static void uwsgi_cgi_after_request(struct wsgi_request *wsgi_req) {
log_request(wsgi_req);
}
#ifdef UWSGI_ROUTING
static int uwsgi_routing_func_cgi(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
struct uwsgi_buffer *ub_command = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len);
if (!ub_command) return UWSGI_ROUTE_BREAK;
struct uwsgi_buffer *ub_helper = NULL;
if (ur->data2_len) {
ub_helper = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data2, ur->data2_len);
if (!ub_helper) {
uwsgi_buffer_destroy(ub_command);
return UWSGI_ROUTE_BREAK;
}
}
else {
if (!uwsgi_is_file(ub_command->buf)) {
uwsgi_404(wsgi_req);
uwsgi_buffer_destroy(ub_command);
return UWSGI_ROUTE_BREAK;
}
if (access(ub_command->buf, X_OK)) {
uwsgi_403(wsgi_req);
uwsgi_buffer_destroy(ub_command);
return UWSGI_ROUTE_BREAK;
}
}
// we need a NULL suffix-ed copy of the docroot
char *docroot = uwsgi_concat2n(wsgi_req->document_root, wsgi_req->document_root_len, "", 0);
uwsgi_cgi_run(wsgi_req, wsgi_req->document_root, wsgi_req->document_root_len, ub_command->buf, ub_helper ? ub_helper->buf : NULL, NULL, NULL, 0, 0 );
free(docroot);
uwsgi_buffer_destroy(ub_command);
if (ub_helper) uwsgi_buffer_destroy(ub_helper);
return UWSGI_ROUTE_BREAK;
}
static int uwsgi_router_cgi_helper(struct uwsgi_route *ur, char *args) {
ur->func = uwsgi_routing_func_cgi;
char *space = strchr(args, ' ');
if (!space) {
uwsgi_log("invalid cgihelper syntax, must be \"cgihelper:helper command\"\n");
return -1;
}
*space = 0;
ur->data = space+1;
ur->data_len = strlen(space+1);
ur->data2 = args;
ur->data2_len = strlen(args);
return 0;
}
static int uwsgi_router_cgi(struct uwsgi_route *ur, char *args) {
ur->func = uwsgi_routing_func_cgi;
ur->data = args;
ur->data_len = strlen(args);
return 0;
}
static void uwsgi_cgi_register_router() {
uwsgi_register_router("cgi", uwsgi_router_cgi);
uwsgi_register_router("cgihelper", uwsgi_router_cgi_helper);
}
#endif
struct uwsgi_plugin cgi_plugin = {
@@ -887,5 +950,8 @@ struct uwsgi_plugin cgi_plugin = {
.options = uwsgi_cgi_options,
.request = uwsgi_cgi_request,
.after_request = uwsgi_cgi_after_request,
#ifdef UWSGI_ROUTING
.on_load = uwsgi_cgi_register_router,
#endif
};
+285
View File
@@ -0,0 +1,285 @@
#include <uwsgi.h>
#include <client/dbclient.h>
#include <client/gridfs.h>
struct uwsgi_gridfs_mountpoint {
char *mountpoint;
uint16_t mountpoint_len;
char *server;
char *db;
char *timeout_str;
int timeout;
char *no_mime;
char *orig_filename;
char *md5;
char *etag;
char *prefix;
char *itemname;
uint16_t itemname_len;
char *skip_slash;
uint16_t prefix_len;
char *username;
char *password;
};
struct uwsgi_gridfs {
int debug;
struct uwsgi_string_list *mountpoints;
} ugridfs;
struct uwsgi_option uwsgi_gridfs_options[] = {
{(char *)"gridfs-mount", required_argument, 0, (char *)"mount a gridfs db on the specified mountpoint", uwsgi_opt_add_string_list, &ugridfs.mountpoints, UWSGI_OPT_MIME},
{(char *)"gridfs-debug", no_argument, 0, (char *)"report gridfs mountpoint and itemname for each request (debug)", uwsgi_opt_true, &ugridfs.debug, UWSGI_OPT_MIME},
{0, 0, 0, 0, 0, 0, 0},
};
extern struct uwsgi_server uwsgi;
extern struct uwsgi_plugin gridfs_plugin;
static void uwsgi_gridfs_do(struct wsgi_request *wsgi_req, struct uwsgi_gridfs_mountpoint *ugm, char *itemname, int need_free) {
try {
mongo::scoped_ptr<mongo::ScopedDbConnection> conn( mongo::ScopedDbConnection::getScopedDbConnection(ugm->server, ugm->timeout) );
try {
if (ugm->username && ugm->password) {
std::string errmsg;
if ((*conn).conn().auth(ugm->db, ugm->username, ugm->password, errmsg)) {
uwsgi_log("[uwsgi-gridfs]: %s\n", errmsg.c_str());
(*conn).done();
uwsgi_403(wsgi_req);
return;
}
}
mongo::GridFS gridfs((*conn).conn(), ugm->db);
mongo::GridFile gfile = gridfs.findFile(itemname);
if (need_free) {
free(itemname);
itemname = NULL;
}
if (!gfile.exists()) {
(*conn).done();
uwsgi_404(wsgi_req);
return;
}
uwsgi_response_prepare_headers(wsgi_req, (char *)"200 OK", 6);
// first get the content_type (if possibile)
std::string filename = gfile.getFilename();
if (!ugm->no_mime) {
size_t mime_type_len = 0;
char *mime_type = uwsgi_get_mime_type((char *)filename.c_str(), filename.length(), &mime_type_len);
if (mime_type) {
uwsgi_response_add_content_type(wsgi_req, mime_type, mime_type_len);
}
}
if (ugm->orig_filename) {
char *filename_header = uwsgi_concat3((char *)"inline; filename=\"", (char *)filename.c_str(), (char *)"\"");
uwsgi_response_add_header(wsgi_req, (char *)"Content-Disposition", 19, filename_header, 19 + filename.length());
free(filename_header);
}
uwsgi_response_add_content_length(wsgi_req, gfile.getContentLength());
if (ugm->etag) {
std::string g_md5 = gfile.getMD5();
if (!g_md5.empty()) {
char *etag = uwsgi_concat3((char *)"\"", (char *)g_md5.c_str(), (char *)"\"");
uwsgi_response_add_header(wsgi_req, (char *)"ETag", 4, etag, 2+g_md5.length());
free(etag);
}
}
if (ugm->md5) {
std::string g_md5 = gfile.getMD5();
size_t base64_len = 0;
char *base64 = uwsgi_base64_encode((char *)g_md5.c_str(), g_md5.length(), &base64_len);
uwsgi_response_add_header(wsgi_req, (char *) "Content-MD5", 11, base64, base64_len);
free(base64);
}
if (uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, (char *)"HEAD", 4)) {
int nc = gfile.getNumChunks();
int i;
for(i=0;i<nc;i++) {
mongo::GridFSChunk gchunk = gfile.getChunk(i);
int chunk_len = 0;
const char *chunk = gchunk.data(chunk_len);
uwsgi_response_write_body_do(wsgi_req, (char *) chunk, chunk_len);
}
}
(*conn).done();
}
catch ( mongo::DBException &e ) {
uwsgi_log("[uwsgi-gridfs]: %s\n", e.what());
(*conn).done();
if (need_free && itemname) {
free(itemname);
itemname = NULL;
}
}
}
catch ( mongo::DBException &e ) {
uwsgi_log("[uwsgi-gridfs]: %s\n", e.what());
if (need_free && itemname) {
free(itemname);
itemname = NULL;
}
}
}
static struct uwsgi_gridfs_mountpoint *uwsgi_gridfs_add_mountpoint(char *arg, size_t arg_len) {
struct uwsgi_gridfs_mountpoint *ugm = (struct uwsgi_gridfs_mountpoint *) uwsgi_calloc(sizeof(struct uwsgi_gridfs_mountpoint));
if (uwsgi_kvlist_parse(arg, arg_len, ',', '=',
"mountpoint", &ugm->mountpoint,
"server", &ugm->server,
"db", &ugm->db,
"prefix", &ugm->prefix,
"no_mime", &ugm->no_mime,
"timeout", &ugm->timeout_str,
"orig_filename", &ugm->orig_filename,
"skip_slash", &ugm->skip_slash,
"md5", &ugm->md5,
"etag", &ugm->etag,
"itemname", &ugm->itemname,
"item", &ugm->itemname,
"username", &ugm->username,
"password", &ugm->password,
NULL)) {
uwsgi_log("invalid gridfs mountpoint syntax\n");
free(ugm);
return NULL;
}
if (!ugm->db) {
uwsgi_log("you need to specify a \"db\" name for gridfs\n");
free(ugm);
return NULL;
}
if (!ugm->mountpoint) {
ugm->mountpoint = (char *)"";
}
ugm->mountpoint_len = strlen(ugm->mountpoint);
if (!ugm->server) {
ugm->server = (char *)"127.0.0.1:27017";
}
if (ugm->timeout_str) {
ugm->timeout = atoi(ugm->timeout_str);
}
else {
ugm->timeout = uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT];
}
if (ugm->prefix) {
ugm->prefix_len = strlen(ugm->prefix);
}
if (ugm->itemname) {
ugm->itemname_len = strlen(ugm->itemname);
}
return ugm;
}
extern "C" int uwsgi_gridfs_request(struct wsgi_request *wsgi_req) {
// this is the gridfs file
char *itemname = NULL;
/* Standard GridFS request */
if (!wsgi_req->uh->pktsize) {
uwsgi_log( "Empty GridFS request. skip.\n");
return -1;
}
if (uwsgi_parse_vars(wsgi_req)) {
return -1;
}
if (wsgi_req->appid_len == 0) {
if (!uwsgi.ignore_script_name) {
wsgi_req->appid = wsgi_req->script_name;
wsgi_req->appid_len = wsgi_req->script_name_len;
}
}
wsgi_req->app_id = uwsgi_get_app_id(wsgi_req->appid, wsgi_req->appid_len, gridfs_plugin.modifier1);
if (ugridfs.debug) {
uwsgi_log("[uwsgi-gridfs-debug] app_id = %d\n", wsgi_req->app_id);
}
if (wsgi_req->app_id == -1) {
uwsgi_404(wsgi_req);
return UWSGI_OK;
}
struct uwsgi_app *ua = &uwsgi_apps[wsgi_req->app_id];
struct uwsgi_gridfs_mountpoint *ugm = (struct uwsgi_gridfs_mountpoint *) ua->interpreter;
if (ugm->skip_slash && (wsgi_req->path_info_len > 0 && wsgi_req->path_info[0] == '/')) {
itemname = uwsgi_concat2n(ugm->prefix, ugm->prefix_len, wsgi_req->path_info+1, wsgi_req->path_info_len-1);
}
else {
itemname = uwsgi_concat2n(ugm->prefix, ugm->prefix_len, wsgi_req->path_info, wsgi_req->path_info_len);
}
if (ugridfs.debug) {
uwsgi_log("[uwsgi-gridfs-debug] itemname = %s\n", itemname);
}
// itemname will be freed here
uwsgi_gridfs_do(wsgi_req, ugm, itemname, 1);
return UWSGI_OK;
}
extern "C" void uwsgi_gridfs_mount() {
struct uwsgi_string_list *usl = ugridfs.mountpoints;
while(usl) {
if (uwsgi_apps_cnt >= uwsgi.max_apps) {
uwsgi_log("ERROR: you cannot load more than %d apps in a worker\n", uwsgi.max_apps);
exit(1);
}
int id = uwsgi_apps_cnt;
struct uwsgi_gridfs_mountpoint *ugm = uwsgi_gridfs_add_mountpoint(uwsgi_str(usl->value), usl->len);
if (!ugm) exit(1);
uwsgi_add_app(id, gridfs_plugin.modifier1, ugm->mountpoint, ugm->mountpoint_len, ugm, ugm);
uwsgi_emulate_cow_for_apps(id);
uwsgi_log("GridFS mountpoint \"%.*s\" (%d) added: server=%s db=%s\n", ugm->mountpoint_len, ugm->mountpoint, id, ugm->server, ugm->db);
usl = usl->next;
}
}
#ifdef UWSGI_ROUTING
static int uwsgi_routing_func_gridfs(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){
struct uwsgi_gridfs_mountpoint *ugm = (struct uwsgi_gridfs_mountpoint *) 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_itemname = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ugm->itemname, ugm->itemname_len);
if (!ub_itemname) return UWSGI_ROUTE_BREAK;
if (ugridfs.debug) {
uwsgi_log("[uwsgi-gridfs-debug] itemname = %s\n", ub_itemname->buf);
}
uwsgi_gridfs_do(wsgi_req, ugm, ub_itemname->buf, 0);
uwsgi_buffer_destroy(ub_itemname);
return UWSGI_ROUTE_BREAK;
}
extern "C" int uwsgi_router_gridfs(struct uwsgi_route *ur, char *args) {
ur->func = uwsgi_routing_func_gridfs;
ur->data = args;
ur->data_len = strlen(args);
ur->data2 = uwsgi_gridfs_add_mountpoint((char *)ur->data, ur->data_len);
if (!ur->data2) {
exit(1);
}
return 0;
}
#endif
+31
View File
@@ -0,0 +1,31 @@
#include <uwsgi.h>
int uwsgi_gridfs_request(struct wsgi_request *);
void uwsgi_gridfs_mount();
extern struct uwsgi_option uwsgi_gridfs_options[];
static void uwsgi_gridfs_log(struct wsgi_request *wsgi_req) {
log_request(wsgi_req);
}
#ifdef UWSGI_ROUTING
int uwsgi_router_gridfs(struct uwsgi_route *, char *);
static void uwsgi_gridfs_register_router() {
uwsgi_register_router("gridfs", uwsgi_router_gridfs);
}
#endif
struct uwsgi_plugin gridfs_plugin = {
.name = "gridfs",
.modifier1 = 25,
.init_apps = uwsgi_gridfs_mount,
.options = uwsgi_gridfs_options,
.request = uwsgi_gridfs_request,
.after_request = uwsgi_gridfs_log,
#ifdef UWSGI_ROUTING
.on_load = uwsgi_gridfs_register_router,
#endif
};
+16
View File
@@ -0,0 +1,16 @@
import os
NAME='gridfs'
CFLAGS = ['-I/usr/include/mongo','-I/usr/local/include/mongo']
LDFLAGS = []
LIBS = []
if not 'UWSGI_MONGODB_NOLIB' in os.environ:
LIBS.append('-lmongoclient')
LIBS.append('-lstdc++')
LIBS.append('-lboost_thread')
LIBS.append('-lboost_system')
LIBS.append('-lboost_filesystem')
GCC_LIST = ['plugin', 'gridfs.cc']
+29 -27
View File
@@ -1,6 +1,4 @@
#ifdef UWSGI_LDAP
#include "uwsgi.h"
#include <uwsgi.h>
extern struct uwsgi_server uwsgi;
@@ -14,7 +12,22 @@ extern struct uwsgi_server uwsgi;
#define ldap_unbind_ext_s ldap_unbind_ext
#endif
void ldap2uwsgi(char *ldapname, char *uwsginame) {
static void uwsgi_opt_ldap_dump(char *, char *, void *);
static void uwsgi_opt_ldap_dump_ldif(char *, char *, void *);
static void uwsgi_ldap_config(char *);
static void uwsgi_opt_load_ldap(char *opt, char *url, void *none) {
uwsgi_ldap_config(url);
}
static struct uwsgi_option uwsgi_ldap_options[] = {
{"ldap", required_argument, 0, "load configuration from ldap server", uwsgi_opt_load_ldap, NULL, UWSGI_OPT_IMMEDIATE},
{"ldap-schema", no_argument, 0, "dump uWSGI ldap schema", uwsgi_opt_ldap_dump, NULL, UWSGI_OPT_IMMEDIATE},
{"ldap-schema-ldif", no_argument, 0, "dump uWSGI ldap schema in ldif format", uwsgi_opt_ldap_dump_ldif, NULL, UWSGI_OPT_IMMEDIATE},
{0, 0, 0, 0, 0, 0, 0},
};
static void ldap2uwsgi(char *ldapname, char *uwsginame) {
char *ptr = uwsginame;
int i;
@@ -32,7 +45,7 @@ void ldap2uwsgi(char *ldapname, char *uwsginame) {
*ptr++ = 0;
}
int calc_ldap_name(char *name) {
static int calc_ldap_name(char *name) {
int i;
int counter = 0;
@@ -52,7 +65,7 @@ struct uwsgi_ldap_entry {
};
void uwsgi_name_to_ldap(char *src, char *dst) {
static void uwsgi_name_to_ldap(char *src, char *dst) {
int i;
char *ptr = dst;
@@ -77,22 +90,7 @@ void uwsgi_name_to_ldap(char *src, char *dst) {
}
struct uwsgi_ldap_entry *get_ldap_by_num(struct uwsgi_ldap_entry *root, int num, int count) {
int i;
struct uwsgi_ldap_entry *ule;
for (i = 0; i < count; i++) {
ule = &root[i];
if (ule->num == num) {
return ule;
}
}
return NULL;
}
struct uwsgi_ldap_entry *search_ldap_cache(struct uwsgi_ldap_entry *root, char *name, int count) {
static struct uwsgi_ldap_entry *search_ldap_cache(struct uwsgi_ldap_entry *root, char *name, int count) {
int i;
struct uwsgi_ldap_entry *ule;
@@ -106,7 +104,7 @@ struct uwsgi_ldap_entry *search_ldap_cache(struct uwsgi_ldap_entry *root, char *
return NULL;
}
struct uwsgi_ldap_entry *get_ldap_names(int *count) {
static struct uwsgi_ldap_entry *get_ldap_names(int *count) {
struct uwsgi_option *op = uwsgi.options;
struct uwsgi_ldap_entry *ule, *entry;
@@ -139,7 +137,7 @@ next:
return ule;
}
void uwsgi_opt_ldap_dump_ldif(char *opt, char *foo, void *bar) {
static void uwsgi_opt_ldap_dump_ldif(char *opt, char *foo, void *bar) {
int i;
int items;
@@ -192,7 +190,7 @@ void uwsgi_opt_ldap_dump_ldif(char *opt, char *foo, void *bar) {
exit(0);
}
void uwsgi_opt_ldap_dump(char *opt, char *foo, void *bar) {
static void uwsgi_opt_ldap_dump(char *opt, char *foo, void *bar) {
int i;
int items;
@@ -240,7 +238,7 @@ void uwsgi_opt_ldap_dump(char *opt, char *foo, void *bar) {
exit(0);
}
void uwsgi_ldap_config(char *url) {
static void uwsgi_ldap_config(char *url) {
LDAP *ldp;
LDAPMessage *results, *entry;
@@ -367,4 +365,8 @@ void uwsgi_ldap_config(char *url) {
ldap_unbind_ext_s(ldp, NULL, NULL);
}
#endif
struct uwsgi_plugin ldap_plugin = {
.name = "ldap",
.options = uwsgi_ldap_options,
};
+7
View File
@@ -0,0 +1,7 @@
NAME='ldap'
CFLAGS = []
LDFLAGS = []
LIBS = ['-lldap']
GCC_LIST = ['ldap']
+49 -2
View File
@@ -8,17 +8,31 @@ extern struct uwsgi_server uwsgi;
struct uwsgi_lua {
struct lua_State **L;
char *shell;
char *filename;
struct uwsgi_string_list *load;
} ulua;
#define lca(L, n) ulua_check_args(L, __FUNCTION__, n)
static void uwsgi_opt_luashell(char *opt, char *value, void *foobar) {
uwsgi.honour_stdin = 1;
if (value) {
ulua.shell = value;
}
else {
ulua.shell = "";
}
}
static struct uwsgi_option uwsgi_lua_options[] = {
{"lua", required_argument, 0, "load lua wsapi app", uwsgi_opt_set_str, &ulua.filename, 0},
{"lua-load", required_argument, 0, "load a lua file", uwsgi_opt_add_string_list, &ulua.load, 0},
{"lua-shell", no_argument, 0, "run the lua interactive shell (debug.debug())", uwsgi_opt_luashell, NULL, 0},
{"luashell", no_argument, 0, "run the lua interactive shell (debug.debug())", uwsgi_opt_luashell, NULL, 0},
{0, 0, 0, 0},
@@ -347,6 +361,7 @@ static const luaL_reg uwsgi_api[] = {
{"lock", uwsgi_api_lock},
{"unlock", uwsgi_api_unlock},
{NULL, NULL}
};
@@ -389,13 +404,16 @@ static int uwsgi_lua_init(){
static void uwsgi_lua_app() {
int i;
if (!ulua.filename && !ulua.load) return;
if (!ulua.filename && !ulua.load && !ulua.shell) return;
for(i=0;i<uwsgi.cores;i++) {
ulua.L[i] = luaL_newstate();
luaL_openlibs(ulua.L[i]);
luaL_register(ulua.L[i], "uwsgi", uwsgi_api);
lua_pushstring(ulua.L[i], UWSGI_VERSION);
lua_setfield(ulua.L[i], -2, "version");
struct uwsgi_string_list *usl = ulua.load;
while(usl) {
if (luaL_dofile(ulua.L[i], usl->value)) {
@@ -765,6 +783,33 @@ static void uwsgi_register_lua_features() {
uwsgi_register_configurator(".lua", uwsgi_lua_configurator);
}
static void uwsgi_lua_hijack(void) {
if (ulua.shell && uwsgi.mywid == 1) {
uwsgi.workers[uwsgi.mywid].hijacked = 1;
uwsgi.workers[uwsgi.mywid].hijacked_count++;
// re-map stdin to stdout and stderr if we are logging to a file
if (uwsgi.logfile) {
if (dup2(0, 1) < 0) {
uwsgi_error("dup2()");
}
if (dup2(0, 2) < 0) {
uwsgi_error("dup2()");
}
}
int ret = -1;
// run in the first state
lua_State *L = ulua.L[0];
lua_getglobal(L, "debug");
lua_getfield(L, -1, "debug");
ret = lua_pcall(L, 0, 0, 0);
if (ret == 0) {
exit(UWSGI_QUIET_CODE);
}
exit(0);
}
}
struct uwsgi_plugin lua_plugin = {
@@ -778,6 +823,8 @@ struct uwsgi_plugin lua_plugin = {
.magic = uwsgi_lua_magic,
.signal_handler = uwsgi_lua_signal_handler,
.hijack_worker = uwsgi_lua_hijack,
.code_string = uwsgi_lua_code_string,
.rpc = uwsgi_lua_rpc,
-9
View File
@@ -1,9 +0,0 @@
#include <uwsgi.h>
#include "client/dbclient.h"
extern "C" int uwsgi_mongodb_version() {
// this is only a hack to force the linked to embed libmongoclient.a
mongo::DBClientConnection c;
return 0;
}
-3
View File
@@ -6,9 +6,6 @@ a fake plugin used for preloading mongodb library when only available as static.
*/
int uwsgi_mongodb_version(void);
struct uwsgi_plugin mongodb_plugin = {
.name = "mongodb",
.init = uwsgi_mongodb_version,
};
+3 -3
View File
@@ -1,8 +1,8 @@
NAME='mongodb'
CFLAGS = ['-I/usr/include/mongo','-I/usr/local/include/mongo']
CFLAGS = []
LDFLAGS = []
LIBS = ['-lmongoclient', '-lboost_thread','-lboost_filesystem']
LIBS = ['-Wl,-whole-archive', '-lmongoclient', '-Wl,-no-whole-archive', '-lboost_thread', '-lboost_system', '-lboost_filesystem']
GCC_LIST = ['plugin', 'foobar.cc']
GCC_LIST = ['plugin']
+3 -3
View File
@@ -1,4 +1,4 @@
#include "../../uwsgi.h"
#include <uwsgi.h>
extern struct uwsgi_server uwsgi;
@@ -29,7 +29,7 @@ struct uwsgi_mongodb_state {
struct iovec iovec[13];
};
ssize_t uwsgi_mongodb_logger(struct uwsgi_logger *ul, char *message, size_t len) {
static ssize_t uwsgi_mongodb_logger(struct uwsgi_logger *ul, char *message, size_t len) {
struct uwsgi_mongodb_state *ums = NULL;
@@ -151,7 +151,7 @@ done:
return ret;
}
void uwsgi_mongodblog_register() {
static void uwsgi_mongodblog_register() {
uwsgi_register_logger("mongodblog", uwsgi_mongodb_logger);
}
-90
View File
@@ -1,90 +0,0 @@
#include "../../uwsgi.h"
extern struct uwsgi_server uwsgi;
int connect_prober_callback(int interesting_fd, struct uwsgi_signal_probe *up) {
// is this a timeout event ?
if (interesting_fd == -1) {
// am i wating for something ?
if (up->fd != -1) {
if (up->cycles > (uint64_t) up->timeout) {
// reset the cycle
up->cycles = 0;
close(up->fd);
up->fd = -1;
// state = NOOP
up->state = 0;
// avoid duplicated events
if (!up->bad) {
up->bad = 1;
return 1;
}
}
}
// ok register a new event
else {
if ((up->cycles % up->freq) == 0) {
up->fd = uwsgi_connect(up->args, -1, 1);
if (up->fd != -1) {
// status = CONNECTING
up->state = 1;
event_queue_add_fd_write(uwsgi.master_queue, up->fd);
return 0;
}
// signal the bad event (if not already bad)
if (!up->bad) {
up->bad = 1;
return 1;
}
}
}
}
else if (up->fd != -1) {
// is this event for me ?
if (interesting_fd == up->fd) {
// uselsess here (we have only one state), only to show a good practice
// check the state
if (up->state == 1) {
if (uwsgi_is_bad_connection(up->fd)) {
// signal the bad connection (if needed)
up->cycles = 0;
close(up->fd);
up->fd = -1;
// state = NOOP
up->state = 0;
if (!up->bad) {
up->bad = 1;
return 1;
}
return 0;
}
// this is a good connection
up->cycles = 0;
close(up->fd);
up->fd = -1;
// state = NOOP
up->state = 0;
if (up->bad) {
up->bad = 0;
return 1;
}
}
}
}
// default action
return 0;
}
int probeconnect_init() {
uwsgi_probe_register(&uwsgi.probes, "connect", connect_prober_callback);
return 0;
}
struct uwsgi_plugin probeconnect_plugin = {
.init = probeconnect_init,
};
-7
View File
@@ -1,7 +0,0 @@
NAME='probeconnect'
CFLAGS = []
LDFLAGS = []
LIBS = []
GCC_LIST = ['connectprobe']
-132
View File
@@ -1,132 +0,0 @@
#include "../../uwsgi.h"
#include <libpq-fe.h>
extern struct uwsgi_server uwsgi;
int pg_prober_callback(int, struct uwsgi_signal_probe *);
int probepg_init(void);
int pg_prober_callback(int interesting_fd, struct uwsgi_signal_probe *up) {
// is this a timeout event ?
if (interesting_fd == -1) {
// am i wating for something ?
if (up->fd != -1) {
if (up->cycles > (uint64_t) up->timeout) {
// reset the cycle
up->cycles = 0;
PQfinish((PGconn *) up->data);
up->fd = -1;
// state = NOOP
up->state = 0;
// avoid duplicated events
if (!up->bad) {
up->bad = 1;
return 1;
}
}
}
// ok register a new event
else {
if ((up->cycles % up->freq) == 0) {
up->last_event = event_queue_write();
up->data = (void *) PQconnectStart(up->args);
if (up->data) {
// status = CONNECTING
up->state = PQstatus((PGconn *) up->data);
if (up->state == CONNECTION_BAD)
goto bad;
up->fd = PQsocket((PGconn *) up->data);
event_queue_add_fd_write(uwsgi.master_queue, up->fd);
return 0;
}
bad:
// signal the bad event (if not already bad)
if (!up->bad) {
up->bad = 1;
return 1;
}
}
}
}
else if (up->fd != -1) {
// is this event for me ?
if (interesting_fd == up->fd) {
// check the state
up->state = PQstatus((PGconn *) up->data);
if (up->state == CONNECTION_BAD) {
// signal the bad connection (if needed)
up->cycles = 0;
PQfinish((PGconn *) up->data);
up->fd = -1;
up->state = 0;
if (!up->bad) {
up->bad = 1;
return 1;
}
return 0;
}
else if (up->state == CONNECTION_OK) {
up->cycles = 0;
PQfinish((PGconn *) up->data);
up->fd = -1;
// state = NOOP
up->state = 0;
if (up->bad) {
up->bad = 0;
return 1;
}
}
// still wait...
else {
PostgresPollingStatusType wait_type = PQconnectPoll((PGconn *) up->data);
// the connection is good
if (wait_type == PGRES_POLLING_ACTIVE || wait_type == PGRES_POLLING_FAILED || wait_type == PGRES_POLLING_OK) {
if (wait_type == PGRES_POLLING_ACTIVE)
wait_type = PQconnectPoll((PGconn *) up->data);
up->cycles = 0;
up->fd = -1;
// state = NOOP
up->state = 0;
PQfinish((PGconn *) up->data);
if (wait_type == PGRES_POLLING_FAILED) {
if (!up->bad) {
up->bad = 1;
return 1;
}
}
else {
if (up->bad) {
up->bad = 0;
return 1;
}
}
}
else if (wait_type == PGRES_POLLING_READING) {
event_queue_del_fd(uwsgi.master_queue, up->fd, up->last_event);
event_queue_add_fd_read(uwsgi.master_queue, up->fd);
up->last_event = event_queue_read();
}
else if (wait_type == PGRES_POLLING_WRITING) {
event_queue_del_fd(uwsgi.master_queue, up->fd, up->last_event);
event_queue_add_fd_write(uwsgi.master_queue, up->fd);
up->last_event = event_queue_write();
}
}
}
}
// default action
return 0;
}
int probepg_init() {
uwsgi_probe_register(&uwsgi.probes, "pg", pg_prober_callback);
return 0;
}
struct uwsgi_plugin probepg_plugin = {
.init = probepg_init,
};
-9
View File
@@ -1,9 +0,0 @@
import os
NAME='probepg'
CFLAGS = os.popen('pg_config --cflags').read().rstrip().split()
CFLAGS.append('-I' + os.popen('pg_config --includedir').read().rstrip())
LDFLAGS = os.popen('pg_config --ldflags').read().rstrip().split()
LIBS = ['-L' + os.popen('pg_config --libdir').read().rstrip(), '-lpq']
GCC_LIST = ['pgprobe']
+3
View File
@@ -9,8 +9,11 @@ extern struct uwsgi_plugin psgi_plugin;
XS(XS_input_seek) {
dXSARGS;
struct wsgi_request *wsgi_req = current_wsgi_req();
psgi_check_args(1);
uwsgi_request_body_seek(wsgi_req, SvIV(ST(0)));
XSRETURN(0);
}
+5 -7
View File
@@ -33,12 +33,12 @@ void set_dyn_pyhome(char *home, uint16_t pyhome_len) {
}
// simulate a pythonhome directive
if (uwsgi.wsgi_req->pyhome_len > 0) {
if (uwsgi.wsgi_req->home_len > 0) {
PyObject *venv_path = UWSGI_PYFROMSTRINGSIZE(uwsgi.wsgi_req->pyhome, uwsgi.wsgi_req->pyhome_len);
PyObject *venv_path = UWSGI_PYFROMSTRINGSIZE(uwsgi.wsgi_req->home, uwsgi.wsgi_req->home_len);
#ifdef UWSGI_DEBUG
uwsgi_debug("setting dynamic virtualenv to %.*s\n", uwsgi.wsgi_req->pyhome_len, uwsgi.wsgi_req->pyhome);
uwsgi_debug("setting dynamic virtualenv to %.*s\n", uwsgi.wsgi_req->home_len, uwsgi.wsgi_req->home);
#endif
PyDict_SetItemString(pysys_dict, "prefix", venv_path);
@@ -177,8 +177,8 @@ int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, PyThre
wi->interpreter = up.main_thread;
}
if (wsgi_req->pyhome_len) {
set_dyn_pyhome(wsgi_req->pyhome, wsgi_req->pyhome_len);
if (wsgi_req->home_len) {
set_dyn_pyhome(wsgi_req->home, wsgi_req->home_len);
}
if (wsgi_req->touch_reload_len > 0 && wsgi_req->touch_reload_len < 0xff) {
@@ -196,8 +196,6 @@ int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, PyThre
goto doh;
}
// the module contains multiple apps
if (PyDict_Check((PyObject *)wi->callable)) {
applications = wi->callable;
+17 -9
View File
@@ -25,7 +25,12 @@ void uwsgi_opt_pythonpath(char *opt, char *value, void *foobar) {
void uwsgi_opt_pyshell(char *opt, char *value, void *foobar) {
uwsgi.honour_stdin = 1;
up.pyshell = 1;
if (value) {
up.pyshell = value;
}
else {
up.pyshell = "";
}
if (!strcmp("pyshell-oneshot", opt)) {
up.pyshell_oneshot = 1;
@@ -127,8 +132,8 @@ struct uwsgi_option uwsgi_python_options[] = {
{"no-site", no_argument, 0, "do not import site module", uwsgi_opt_true, &Py_NoSiteFlag, 0},
#endif
#endif
{"pyshell", no_argument, 0, "run an interactive python shell in the uWSGI environment", uwsgi_opt_pyshell, NULL, 0},
{"pyshell-oneshot", no_argument, 0, "run an interactive python shell in the uWSGI environment (one-shot variant)", uwsgi_opt_pyshell, NULL, 0},
{"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},
{"python", required_argument, 0, "run a python script in the uWSGI environment", uwsgi_opt_pyrun, NULL, 0},
{"py", required_argument, 0, "run a python script in the uWSGI environment", uwsgi_opt_pyrun, NULL, 0},
@@ -1063,9 +1068,7 @@ void uwsgi_python_init_apps() {
#endif
// setup app loaders
#ifdef UWSGI_MINTERPRETERS
up.loaders[LOADER_DYN] = uwsgi_dyn_loader;
#endif
up.loaders[LOADER_UWSGI] = uwsgi_uwsgi_loader;
up.loaders[LOADER_FILE] = uwsgi_file_loader;
up.loaders[LOADER_PASTE] = uwsgi_paste_loader;
@@ -1690,11 +1693,17 @@ void uwsgi_python_hijack(void) {
}
}
UWSGI_GET_GIL;
PyImport_ImportModule("readline");
int ret = -1;
if (up.pyshell[0] != 0) {
ret = PyRun_SimpleString(up.pyshell);
}
else {
PyImport_ImportModule("readline");
#ifndef UWSGI_PYPY
int ret = PyRun_InteractiveLoop(stdin, "uwsgi");
ret = PyRun_InteractiveLoop(stdin, "uwsgi");
#endif
}
if (up.pyshell_oneshot) {
exit(UWSGI_DE_HIJACKED_CODE);
}
@@ -1702,7 +1711,6 @@ void uwsgi_python_hijack(void) {
if (ret == 0) {
exit(UWSGI_QUIET_CODE);
}
#endif
exit(0);
}
}
-21
View File
@@ -210,26 +210,6 @@ PyObject *py_uwsgi_add_cron(PyObject * self, PyObject * args) {
}
PyObject *py_uwsgi_add_probe(PyObject * self, PyObject * args) {
uint8_t uwsgi_signal;
int timeout = 0;
int freq = 0;
char *probe, *probe_args;
if (!PyArg_ParseTuple(args, "Bss|ii:add_probe", &uwsgi_signal, &probe, &probe_args, &timeout, &freq)) {
return NULL;
}
if (uwsgi_add_probe(uwsgi_signal, probe, probe_args, timeout, freq))
return PyErr_Format(PyExc_ValueError, "unable to add probe");
Py_INCREF(Py_None);
return Py_None;
}
PyObject *py_uwsgi_add_timer(PyObject * self, PyObject * args) {
uint8_t uwsgi_signal;
@@ -2444,7 +2424,6 @@ static PyMethodDef uwsgi_advanced_methods[] = {
{"signal_received", py_uwsgi_signal_received, METH_VARARGS, ""},
{"add_file_monitor", py_uwsgi_add_file_monitor, METH_VARARGS, ""},
{"add_timer", py_uwsgi_add_timer, METH_VARARGS, ""},
{"add_probe", py_uwsgi_add_probe, METH_VARARGS, ""},
{"add_rb_timer", py_uwsgi_add_rb_timer, METH_VARARGS, ""},
{"add_cron", py_uwsgi_add_cron, METH_VARARGS, ""},
+1 -5
View File
@@ -106,7 +106,7 @@ struct uwsgi_python {
char *test_module;
int pyshell;
char *pyshell;
int pyshell_oneshot;
@@ -268,10 +268,6 @@ struct uwsgi_buffer *uwsgi_python_exception_repr(struct wsgi_request *);
struct uwsgi_buffer *uwsgi_python_backtrace(struct wsgi_request *);
void uwsgi_python_exception_log(struct wsgi_request *);
#ifdef UWSGI_PYPY
#undef UWSGI_MINTERPRETERS
#endif
#define py_current_wsgi_req() current_wsgi_req();\
if (!wsgi_req) {\
return PyErr_Format(PyExc_SystemError, "you can call uwsgi api function only from the main callable");\
+3
View File
@@ -42,6 +42,9 @@ if not 'UWSGI_PYTHON_NOLIB' in os.environ:
if not os.path.exists(libpath):
libpath = '%s/libpython%s.a' % (libdir, version)
LIBS.append(libpath)
# hack for messy linkers/compilers
if '-lutil' in LIBS:
LIBS.append('-lutil')
else:
try:
LDFLAGS.append("-L%s" % sysconfig.get_config_var('LIBDIR'))
+31 -2
View File
@@ -135,11 +135,34 @@ static PyObject *uwsgi_Input_close(uwsgi_Input *self, PyObject *args) {
static PyObject *uwsgi_Input_seek(uwsgi_Input *self, PyObject *args) {
long pos = 0;
int whence = 0;
if (!PyArg_ParseTuple(args, "l:seek", &pos)) {
if (!uwsgi.post_buffering) {
return PyErr_Format(PyExc_IOError, "seeking wsgi.input without post_buffering is IMPOSSIBLE !!!");
}
if (!PyArg_ParseTuple(args, "l|i:seek", &pos, &whence)) {
return NULL;
}
/*
uwsgi_request_body_seek() uses SEEK_SET for positive value and SEEK_CUR for negative
yous hould always try to transform the "pos" value to an absolute position.
*/
// current
if (whence == 1) {
pos += self->wsgi_req->post_pos;
}
// end of stream
if (whence == 2) {
pos += self->wsgi_req->post_cl;
}
if (pos < 0 || pos > (off_t)self->wsgi_req->post_cl) {
return PyErr_Format(PyExc_IOError, "invalid seek position for wsgi.input");
}
uwsgi_request_body_seek(self->wsgi_req, pos);
Py_INCREF(Py_None);
@@ -151,6 +174,12 @@ static PyObject *uwsgi_Input_fileno(uwsgi_Input *self, PyObject *args) {
return PyInt_FromLong(self->wsgi_req->fd);
}
static PyObject *uwsgi_Input_tell(uwsgi_Input *self, PyObject *args) {
return PyLong_FromLong(self->wsgi_req->post_pos);
}
static PyMethodDef uwsgi_Input_methods[] = {
{ "read", (PyCFunction)uwsgi_Input_read, METH_VARARGS, 0 },
{ "readline", (PyCFunction)uwsgi_Input_readline, METH_VARARGS, 0 },
@@ -158,6 +187,7 @@ static PyMethodDef uwsgi_Input_methods[] = {
// add close to allow mod_wsgi compatibility
{ "close", (PyCFunction)uwsgi_Input_close, METH_VARARGS, 0 },
{ "seek", (PyCFunction)uwsgi_Input_seek, METH_VARARGS, 0 },
{ "tell", (PyCFunction)uwsgi_Input_tell, METH_VARARGS, 0 },
{ "fileno", (PyCFunction)uwsgi_Input_fileno, METH_VARARGS, 0 },
{ NULL, NULL}
};
@@ -317,7 +347,6 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
}
}
if ( (wsgi_req->app_id = uwsgi_get_app_id(wsgi_req->appid, wsgi_req->appid_len, 0)) == -1) {
wsgi_req->app_id = uwsgi.default_app;
if (uwsgi.no_default_app) {
+63 -2
View File
@@ -5,6 +5,22 @@ extern struct uwsgi_server uwsgi;
struct uwsgi_rack ur;
struct uwsgi_plugin rack_plugin;
static void uwsgi_opt_rbshell(char *opt, char *value, void *foobar) {
uwsgi.honour_stdin = 1;
if (value) {
ur.rbshell = value;
}
else {
ur.rbshell = "";
}
if (!strcmp("rbshell-oneshot", opt)) {
ur.rb_shell_oneshot = 1;
}
}
struct uwsgi_option uwsgi_rack_options[] = {
{"rails", required_argument, 0, "load a rails <= 2.x app", uwsgi_opt_set_str, &ur.rails, UWSGI_OPT_POST_BUFFERING},
@@ -29,7 +45,8 @@ struct uwsgi_option uwsgi_rack_options[] = {
{"rvm-path", required_argument, 0, "search for rvm in the specified directory", uwsgi_opt_add_string_list, &ur.rvm_path, 0},
{"rbshell", optional_argument, 0, "run a ruby/irb shell", uwsgi_opt_true, &ur.rb_shell, 0},
{"rbshell", optional_argument, 0, "run a ruby/irb shell", uwsgi_opt_rbshell, NULL, 0},
{"rbshell-oneshot", no_argument, 0, "set ruby/irb shell (one shot)", uwsgi_opt_rbshell, NULL, 0},
#ifdef RUBY19
{"rb-threads", required_argument, 0, "set the number of ruby threads to run", uwsgi_opt_set_int, &ur.rb_threads, 0},
@@ -1029,7 +1046,51 @@ int uwsgi_rack_mount_app(char *mountpoint, char *app) {
return -1;
}
void uwsgi_rack_hijack(void) {
VALUE run_irb(VALUE arg) {
rb_funcall(rb_cObject, rb_intern("require"), 1, rb_str_new2("irb"));
VALUE irb = rb_const_get(rb_cObject, rb_intern("IRB"));
return rb_funcall(irb, rb_intern("start"), 0);
}
static void uwsgi_rack_hijack(void) {
if (ur.rb_shell_oneshot && uwsgi.workers[uwsgi.mywid].hijacked_count > 0) {
uwsgi.workers[uwsgi.mywid].hijacked = 0;
return;
}
if (ur.rbshell && uwsgi.mywid == 1) {
uwsgi.workers[uwsgi.mywid].hijacked = 1;
uwsgi.workers[uwsgi.mywid].hijacked_count++;
// re-map stdin to stdout and stderr if we are logging to a file
if (uwsgi.logfile) {
if (dup2(0, 1) < 0) {
uwsgi_error("dup2()");
}
if (dup2(0, 2) < 0) {
uwsgi_error("dup2()");
}
}
int ret = -1;
int error = 0;
if (ur.rbshell[0] != 0) {
rb_eval_string(ur.rbshell);
}
else {
rb_protect( run_irb, 0, &error ) ;
if (error) {
uwsgi_ruby_exception_log(NULL);
exit(1);
}
}
if (ur.rb_shell_oneshot) {
exit(UWSGI_DE_HIJACKED_CODE);
}
if (ret == 0) {
exit(UWSGI_QUIET_CODE);
}
exit(0);
}
}
int uwsgi_rack_mule(char *opt) {
+2 -1
View File
@@ -45,7 +45,8 @@ struct uwsgi_rack {
pthread_mutex_t gvl;
int rb_shell;
char *rbshell;
int rb_shell_oneshot;
int app_id;
int unprotected;
+1
View File
@@ -134,6 +134,7 @@ error:
if (urcc->key) free(urcc->key);
if (urcc->name) free(urcc->name);
if (urcc->expires_str) free(urcc->expires_str);
free(urcc);
return -1;
}
+60
View File
@@ -148,6 +148,60 @@ end:
return ret;
}
static int uwsgi_routing_func_rpc_raw(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
int ret = -1;
// this is the list of args
char *argv[UMAX8];
// this is the size of each argument
uint16_t argvs[UMAX8];
// this is a placeholder for tmp uwsgi_buffers
struct uwsgi_buffer *ubs[UMAX8];
char **r_argv = (char **) ur->data2;
uint16_t *r_argvs = (uint16_t *) ur->data3;
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
uint64_t i;
for(i=0;i<ur->custom;i++) {
ubs[i] = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, r_argv[i], r_argvs[i]);
if (!ubs[i]) goto end;
argv[i] = ubs[i]->buf;
argvs[i] = ubs[i]->pos;
}
// ok we now need to check it it is a local call or a remote one
char *func = uwsgi_str(ur->data);
char *remote = NULL;
char *at = strchr(func, '@');
if (at) {
*at = 0;
remote = at+1;
}
uint16_t size;
char *response = uwsgi_do_rpc(remote, func, ur->custom, argv, argvs, &size);
free(func);
if (!response) goto end;
ret = UWSGI_ROUTE_NEXT;
if (size == 0) goto end;
ret = uwsgi_blob_to_response(wsgi_req, response, size);
free(response);
if (ret == 0) {
ret = UWSGI_ROUTE_BREAK;
}
end:
for(i=0;i<ur->custom;i++) {
if (ubs[i] != NULL) {
uwsgi_buffer_destroy(ubs[i]);
}
}
return ret;
}
// "next" || "continue" || "break(.*)" || "goon" || "goto .+"
static int uwsgi_routing_func_rpc_ret(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
@@ -299,6 +353,11 @@ static int uwsgi_router_rpc_blob(struct uwsgi_route *ur, char *args) {
return uwsgi_router_rpc_base(ur, args);
}
static int uwsgi_router_rpc_raw(struct uwsgi_route *ur, char *args) {
ur->func = uwsgi_routing_func_rpc_raw;
return uwsgi_router_rpc_base(ur, args);
}
static void router_rpc_register() {
uwsgi_register_router("call", uwsgi_router_rpc);
@@ -306,6 +365,7 @@ static void router_rpc_register() {
uwsgi_register_router("rpcret", uwsgi_router_rpc_ret);
uwsgi_register_router("rpcblob", uwsgi_router_rpc_blob);
uwsgi_register_router("rpcnext", uwsgi_router_rpc_blob);
uwsgi_register_router("rpcraw", uwsgi_router_rpc_raw);
}
#endif
+70
View File
@@ -0,0 +1,70 @@
#include <uwsgi.h>
#include <sqlite3.h>
extern struct uwsgi_server uwsgi;
static void uwsgi_sqlite3_config(char *, char *[]);
static void uwsgi_opt_load_sqlite3(char *opt, char *filename, void *none) {
config_magic_table_fill(filename, uwsgi.magic_table);
uwsgi_sqlite3_config(filename, uwsgi.magic_table);
}
static struct uwsgi_option uwsgi_sqlite3_options[] = {
{"sqlite3", required_argument, 0, "load config from sqlite3 db", uwsgi_opt_load_sqlite3, NULL, UWSGI_OPT_IMMEDIATE},
{"sqlite", required_argument, 0, "load config from sqlite3 db", uwsgi_opt_load_sqlite3, NULL, UWSGI_OPT_IMMEDIATE},
{0, 0, 0, 0, 0, 0, 0},
};
static int uwsgi_sqlite3_config_callback(void *magic_table, int field_count, char **fields, char **col) {
// make a copy of the string
if (field_count >= 2) {
size_t value_len = strlen(fields[1]) + 1;
char *value = magic_sub(fields[1], value_len, &value_len, (char **) magic_table);
add_exported_option(uwsgi_strncopy(fields[0], strlen(fields[0])), value, 0);
}
return 0;
}
static void uwsgi_sqlite3_config(char *file, char *magic_table[]) {
sqlite3 *db;
char *err = NULL;
char *query = "SELECT * FROM uwsgi";
char *colon = uwsgi_get_last_char(file, ':');
if (colon) {
colon[0] = 0;
if (colon[1] != 0) {
query = colon + 1;
}
}
uwsgi_log("[uWSGI] getting sqlite3 configuration from %s\n", file);
#ifdef sqlite3_open_v2
if (sqlite3_open_v2(file, &db, SQLITE_OPEN_READONLY, NULL)) {
#else
if (sqlite3_open(file, &db)) {
#endif
uwsgi_log("unable to open sqlite3 db: %s\n", sqlite3_errmsg(db));
sqlite3_close(db);
exit(1);
}
if (sqlite3_exec(db, query, uwsgi_sqlite3_config_callback, (void *) magic_table, &err)) {
uwsgi_log("sqlite3 error: %s\n", err);
sqlite3_close(db);
exit(1);
}
sqlite3_close(db);
}
struct uwsgi_plugin sqlite3_plugin = {
.name = "sqlite3",
.options = uwsgi_sqlite3_options,
};
+7
View File
@@ -0,0 +1,7 @@
NAME='sqlite3'
CFLAGS = []
LDFLAGS = []
LIBS = ['-lsqlite3']
GCC_LIST = ['plugin']
+11 -2
View File
@@ -5,6 +5,9 @@ void uwsgi_v8_apps(void);
void uwsgi_v8_configurator(char *, char **);
uint16_t uwsgi_v8_rpc(void *, uint8_t, char **, uint16_t *, char *);
int uwsgi_v8_signal_handler(uint8_t, void *);
void uwsgi_v8_init_thread(int);
void uwsgi_v8_enable_threads();
int uwsgi_v8_mule(char *);
static void uwsgi_v8_register(void) {
uwsgi_register_configurator(".js", uwsgi_v8_configurator);
@@ -12,8 +15,10 @@ static void uwsgi_v8_register(void) {
extern struct uwsgi_option uwsgi_v8_options[];
static int uwsgi_v8_request(struct wsgi_request *wsgi_req) {
return UWSGI_OK;
int uwsgi_v8_request(struct wsgi_request *);
static void uwsgi_v8_after_request(struct wsgi_request *wsgi_req) {
log_request(wsgi_req);
}
struct uwsgi_plugin v8_plugin = {
@@ -25,5 +30,9 @@ struct uwsgi_plugin v8_plugin = {
.on_load = uwsgi_v8_register,
.rpc = uwsgi_v8_rpc,
.request = uwsgi_v8_request,
.after_request = uwsgi_v8_after_request,
.signal_handler = uwsgi_v8_signal_handler,
.enable_threads = uwsgi_v8_enable_threads,
.init_thread = uwsgi_v8_init_thread,
.mule = uwsgi_v8_mule,
};
+7 -2
View File
@@ -1,6 +1,11 @@
import os
NAME='v8'
CFLAGS = []
CFLAGS = ['-Wno-deprecated-declarations']
LDFLAGS = []
LIBS = ['-lv8']
GCC_LIST = ['plugin', 'v8_uwsgi.cc']
engine = os.environ.get('UWSGICONFIG_V8_ENGINE', '')
if engine == 'teajs':
CFLAGS.append('-DUWSGI_V8_TEAJS -fexceptions')
LIBS.append('-lteajs')
GCC_LIST = ['plugin', 'v8_uwsgi.cc', 'v8_commonjs.cc', 'v8_jsgi.cc']
+162
View File
@@ -0,0 +1,162 @@
#include "v8_uwsgi.h"
extern struct uwsgi_server uwsgi;
#ifdef UWSGI_V8_TEAJS
#include "app.h"
#include "macros.h"
class TeaJS_uWSGI : public TeaJS_App {
public:
void init() {
TeaJS_App::init();
v8::HandleScope handle_scope;
this->mainfile = "";
this->create_context();
this->mainModule = v8::Object::New();
this->prepare(uwsgi.environ);
}
v8::Persistent<v8::Context> getContext() {
return this->context;
}
private:
const char *instanceType() {
return "uWSGI";
}
const char *executableName() {
return uwsgi.binary_path;
}
};
static v8::Handle < v8::Value > uwsgi_v8_commonjs_require(const v8::Arguments & args) {
if (args.Length() > 0) {
try {
v8::String::Utf8Value module_name(args[0]->ToString());
return APP_PTR->require(std::string(*module_name), "");
}
catch (std::string e) {
uwsgi_log("%s\n", e.c_str());
}
}
return v8::Undefined();
}
#else
static v8::Handle < v8::Value > uwsgi_v8_commonjs_require(const v8::Arguments &);
static v8::Handle < v8::Value > uwsgi_v8_commonjs_require_do(char *);
#endif
extern struct uwsgi_v8 uv8;
extern struct uwsgi_server uwsgi;
TeaJS_uWSGI app;
v8::Persistent<v8::Context> uwsgi_v8_setup_context() {
#ifdef UWSGI_V8_TEAJS
v8::HandleScope handle_scope;
try {
app.init();
app.getContext()->Global()->Set(v8::String::New("require"), v8::FunctionTemplate::New(uwsgi_v8_commonjs_require)->GetFunction());
return app.getContext();
}
catch (std::string e) {
uwsgi_log("%s\n", e.c_str());
exit(1);
}
}
#else
// create a new context
v8::Persistent<v8::Context> context = v8::Context::New();
context->Enter();
v8::Handle<v8::Object> global = context->Global();
v8::Handle < v8::Object > system = v8::Object::New();
v8::Handle < v8::Array > args = v8::Array::New();
int i;
for (i = 0; i < uwsgi.argc; i++) {
args->Set(v8::Integer::New(i), v8::String::New(uwsgi.argv[i]));
}
system->Set(v8::String::New("args"), args);
v8::Handle < v8::Object > env = v8::Object::New();
system->Set(v8::String::New("env"), env);
global->Set(v8::String::New("require"), v8::FunctionTemplate::New(uwsgi_v8_commonjs_require)->GetFunction());
global->Set(v8::String::New("system"), system);
return context;
}
/*
uWSGI native "require" support
*/
static v8::Handle < v8::Value > uwsgi_v8_commonjs_require_do(char *filename) {
size_t len = 0;
char *code = uwsgi_open_and_read(filename, &len, 1, NULL);
// we re-create every time an "exports" object to emulate a local object
v8::Local < v8::Object > exports = v8::Object::New();
v8::Context::GetCurrent()->Global()->Set(v8::String::New("exports"), exports);
// we do not use TryCatch as we directly use stderr and simply exit with error code 1
v8::Handle < v8::Script > script = v8::Script::Compile(v8::String::New(code), v8::String::New(filename));
free(code);
if (script.IsEmpty()) {
exit(1);
}
v8::Handle < v8::Value > result = script->Run();
if (result.IsEmpty()) {
return v8::Undefined();
}
return exports;
}
static v8::Handle < v8::Value > uwsgi_v8_commonjs_require(const v8::Arguments & args) {
if (args.Length() > 0) {
v8::String::Utf8Value module_name(args[0]->ToString());
// ok lets start searching the module
if (uwsgi_is_file(*module_name)) {
return uwsgi_v8_commonjs_require_do(*module_name);
}
// try appending .js extension
if (!uwsgi_endswith(*module_name, (char *) ".js")) {
char *tmp_filename = uwsgi_concat2(*module_name, (char *) ".js");
if (uwsgi_is_file(tmp_filename)) {
v8::Handle < v8::Value > ret = uwsgi_v8_commonjs_require_do(tmp_filename);
free(tmp_filename);
return ret;
}
free(tmp_filename);
}
// let's start searching in the modules search path
struct uwsgi_string_list *usl = uv8.module_paths;
while (usl) {
char *tmp_filename = uwsgi_concat3(usl->value, (char *) "/", *module_name);
if (uwsgi_is_file(tmp_filename)) {
v8::Handle < v8::Value > ret = uwsgi_v8_commonjs_require_do(tmp_filename);
free(tmp_filename);
return ret;
}
free(tmp_filename);
if (!uwsgi_endswith(*module_name, (char *) ".js")) {
tmp_filename = uwsgi_concat4(usl->value, (char *) "/", *module_name, (char *) ".js");
if (uwsgi_is_file(tmp_filename)) {
v8::Handle < v8::Value > ret = uwsgi_v8_commonjs_require_do(tmp_filename);
free(tmp_filename);
return ret;
}
}
free(tmp_filename);
usl = usl->next;
}
}
return v8::Undefined();
}
#endif
+186
View File
@@ -0,0 +1,186 @@
#include "v8_uwsgi.h"
extern struct uwsgi_v8 uv8;
extern struct uwsgi_server uwsgi;
static v8::Handle<v8::Value> uwsgi_v8_jsgi_body_chunk(const v8::Arguments& args) {
if (args.Length() > 1) {
v8::String::Utf8Value chunk(args[0]->ToString());
struct wsgi_request *wsgi_req = current_wsgi_req();
if (uwsgi_response_write_body_do(wsgi_req, *chunk, args[0]->ToString()->Length())) {
return v8::ThrowException(v8::Exception::Error(v8::String::New("unable to send JSGI body")));
}
}
return v8::Undefined();
}
static void uwsgi_v8_jsgi_fill_request(struct wsgi_request *wsgi_req, v8::Handle<v8::Object> o) {
o->Set(v8::String::New("method"), v8::String::New(wsgi_req->method, wsgi_req->method_len));
o->Set(v8::String::New("scriptName"), v8::String::New(wsgi_req->script_name, wsgi_req->script_name_len));
o->Set(v8::String::New("pathInfo"), v8::String::New(wsgi_req->path_info, wsgi_req->path_info_len));
o->Set(v8::String::New("queryString"), v8::String::New(wsgi_req->query_string, wsgi_req->query_string_len));
o->Set(v8::String::New("host"), v8::String::New(wsgi_req->host, wsgi_req->host_len));
if (wsgi_req->scheme_len) {
o->Set(v8::String::New("scheme"), v8::String::New(wsgi_req->scheme, wsgi_req->scheme_len));
}
else {
o->Set(v8::String::New("scheme"), v8::String::New("http"));
}
o->Set(v8::String::New("remoteAddr"), v8::String::New(wsgi_req->remote_addr, wsgi_req->remote_addr_len));
if (wsgi_req->remote_user_len) {
o->Set(v8::String::New("remoteUser"), v8::String::New(wsgi_req->remote_user, wsgi_req->remote_user_len));
}
o->Set(v8::String::New("serverSoftware"), v8::String::New("uWSGI " UWSGI_VERSION));
v8::Handle<v8::Value> jsgi = v8::Object::New();
if (uwsgi.threads > 1) {
jsgi->ToObject()->Set(v8::String::New("multithread"), v8::True());
}
else {
jsgi->ToObject()->Set(v8::String::New("multithread"), v8::False());
}
if (uwsgi.numproc > 1) {
jsgi->ToObject()->Set(v8::String::New("multiprocess"), v8::True());
}
else {
jsgi->ToObject()->Set(v8::String::New("multiprocess"), v8::False());
}
o->Set(v8::String::New("jsgi"), jsgi);
}
extern "C" int uwsgi_v8_request(struct wsgi_request *wsgi_req) {
char status_str[11];
uint32_t i,l;
v8::Handle<v8::Value> status, headers, body;
v8::Local<v8::Array> props;
v8::Local<v8::Value> key, value;
v8::Handle<v8::Function> forEach;
/* Standard JSGI 3.0 request */
if (!wsgi_req->uh->pktsize) {
uwsgi_log( "Empty JSGI request. skip.\n");
return -1;
}
if (uwsgi_parse_vars(wsgi_req)) {
return -1;
}
int core_id = wsgi_req->async_id;
uv8.isolates[core_id]->Enter();
uv8.contexts[core_id]->Enter();
v8::HandleScope handle_scope;
v8::Handle<v8::Value> argj[1];
argj[0] = v8::Object::New();
uwsgi_v8_jsgi_fill_request(wsgi_req, argj[0]->ToObject());
v8::Handle<v8::Value> result = uv8.jsgi_func[core_id]->Call(uv8.contexts[core_id]->Global(), 1, argj);
if (result.IsEmpty()) goto end;
if (!result->IsObject()) goto end;
status = result->ToObject()->Get(v8::String::New("status"));
if (status.IsEmpty() || !status->IsNumber()) {
uwsgi_log("invalid JSGI response status\n");
exit(1);
}
headers = result->ToObject()->Get(v8::String::New("headers"));
if (headers.IsEmpty() || !headers->IsObject()) {
uwsgi_log("invalid JSGI response headers\n");
exit(1);
}
body = result->ToObject()->Get(v8::String::New("body"));
if (body.IsEmpty() || !body->IsObject()) {
uwsgi_log("invalid JSGI response body\n");
exit(1);
}
if (uwsgi_num2str2(status->Uint32Value(), status_str) != 3) {
goto end;
}
if (uwsgi_response_prepare_headers(wsgi_req, status_str, 3)) goto end;
props = headers->ToObject()->GetPropertyNames();
l = props->Length();
for(i=0;i<l;i++) {
key = props->Get(i);
value = headers->ToObject()->Get(key);
v8::String::Utf8Value c_key(key->ToString());
if (value->IsArray()) {
uint32_t opt_l = value->ToObject()->Get(v8::String::New("length"))->ToObject()->Uint32Value();
uint32_t j;
for(j=0;j<opt_l;j++) {
v8::String::Utf8Value c_value(value->ToObject()->Get(j)->ToString());
if (uwsgi_response_add_header(wsgi_req, *c_key, strlen(*c_key), *c_value, strlen(*c_value))) goto end;
}
}
else {
v8::String::Utf8Value c_value(value->ToString());
if (uwsgi_response_add_header(wsgi_req, *c_key, strlen(*c_key), *c_value, strlen(*c_value))) goto end;
}
}
// call forEach
forEach = v8::Handle<v8::Function>::Cast(body->ToObject()->Get(v8::String::New("forEach")));
argj[0] = uv8.jsgi_writer_func[core_id];
forEach->Call(body->ToObject(), 1, argj);
end:
while(!v8::V8::IdleNotification()) {};
return UWSGI_OK;
}
v8::Persistent<v8::Function> uwsgi_v8_load_jsgi(int core_id, char *filename) {
uv8.isolates[core_id]->Enter();
uv8.contexts[core_id]->Enter();
v8::HandleScope handle_scope;
size_t len = 0;
char *code = uwsgi_open_and_read(filename, &len, 1, NULL);
// we re-create every time an "exports" object to emulate a local object
v8::Local<v8::Object> exports = v8::Object::New();
v8::Context::GetCurrent()->Global()->Set(v8::String::New("exports"), exports);
// we do not use TryCatch as we directly use stderr and simply exit with error code 1
v8::Handle<v8::Script> script = v8::Script::Compile( v8::String::New(code), v8::String::New(filename) );
free(code);
if (script.IsEmpty()) {
exit(1);
}
v8::Handle<v8::Value> result = script->Run();
if (result.IsEmpty()) {
exit(1);
}
uv8.jsgi_writer_func[core_id] = v8::Persistent<v8::Function>::New(v8::FunctionTemplate::New(uwsgi_v8_jsgi_body_chunk)->GetFunction());
v8::Handle<v8::Value> app = exports->Get(v8::String::New("app"));
if (!app.IsEmpty() && !app->IsNull() && !app->IsUndefined()) {
if (app->ToObject()->IsFunction()) {
if (!uv8.jsgi_announced) {
uwsgi_log("JSGI 3.0 application loaded from \"exports.app\" in %s\n", filename);
uv8.jsgi_announced = -1;
}
return v8::Persistent<v8::Function>::New(v8::Handle<v8::Function>::Cast(app));
}
}
if (!result->IsNull() && !result->IsUndefined() && result->ToObject()->IsFunction()) {
if (!uv8.jsgi_announced) {
uwsgi_log("JSGI 3.0 application loaded from return value of %s\n", filename);
uv8.jsgi_announced = -1;
}
return v8::Persistent<v8::Function>::New(v8::Handle<v8::Function>::Cast(result));
}
uwsgi_log("unable to find JSGI 3.0 entry point function\n");
exit(1);
}
+166 -73
View File
@@ -1,16 +1,16 @@
#include <uwsgi.h>
#include <v8.h>
#include "v8_uwsgi.h"
struct uwsgi_v8 {
v8::Persistent<v8::Context> *contexts;
struct uwsgi_string_list *load;
} uv8;
struct uwsgi_v8 uv8;
extern struct uwsgi_server uwsgi;
extern struct uwsgi_plugin v8_plugin;
struct uwsgi_option uwsgi_v8_options[] = {
{(char *)"v8-load", required_argument, 0, (char *)"load a javascript file", uwsgi_opt_add_string_list, &uv8.load, 0},
{(char *)"v8-preemptive", required_argument, 0, (char *)"put v8 in preemptive move (single isolate) with the specified frequency", uwsgi_opt_set_int, &uv8.preemptive, 0},
{(char *)"v8-gc-freq", required_argument, 0, (char *)"set the v8 garbage collection frequency", uwsgi_opt_set_64bit, &uv8.gc_freq, 0},
{(char *)"v8-module-path", required_argument, 0, (char *)"set the v8 modules search path", uwsgi_opt_add_string_list, &uv8.module_paths, 0},
{(char *)"v8-jsgi", required_argument, 0, (char *)"load the specified JSGI 3.0 application", uwsgi_opt_set_str, &uv8.jsgi, 0},
{0, 0, 0, 0},
};
@@ -22,10 +22,25 @@ static v8::Handle<v8::Value> uwsgi_v8_api_register_signal(const v8::Arguments& a
v8::Persistent<v8::Function> func = v8::Persistent<v8::Function>::New(v8::Handle<v8::Function>::Cast(args[2]));
if (uwsgi_register_signal(uwsgi_signal, *signal_kind, *func, v8_plugin.modifier1)) {
int core_id = (long) pthread_getspecific(uv8.current_core);
struct uwsgi_v8_signal_table *uvst = &uv8.sigtable[uwsgi_signal];
int need_register = 1;
if (uvst->registered == 1) {
need_register = 0;
}
uvst->func[core_id] = func;
if (!need_register) {
return v8::True();
}
if (uwsgi_register_signal(uwsgi_signal, *signal_kind, uvst, v8_plugin.modifier1)) {
uwsgi_log("[uwsgi-v8] unable to register signal %d\n", uwsgi_signal);
return v8::Undefined();
}
uvst->registered = 1 ;
return v8::True();
}
@@ -44,7 +59,33 @@ static v8::Handle<v8::Value> uwsgi_v8_api_register_rpc(const v8::Arguments& args
v8::Persistent<v8::Function> func = v8::Persistent<v8::Function>::New(v8::Handle<v8::Function>::Cast(args[1]));
if (uwsgi_register_rpc(*name, v8_plugin.modifier1, j_argc, *func)) {
int core_id = (long) pthread_getspecific(uv8.current_core);
// get the rpc slot
int i;
int found = 0;
struct uwsgi_v8_rpc_table *uvrt = NULL;
for(i=0;i<(int)uwsgi.rpc_max;i++) {
uvrt = &uv8.rpctable[i];
if (uvrt->name == NULL) {
found = 1;
break;
}
// skip already registered funcs
else if (!strcmp(uvrt->name, *name)) {
uvrt->func[core_id] = func;
return v8::True();
}
}
if (!found || !uvrt) {
uwsgi_log("[uwsgi-v8] unable to register RPC function \"%s\"\n", *name);
return v8::Undefined();
}
uvrt->name = uwsgi_str(*name);
uvrt->func[core_id] = func;
// we can safely call register_rpc here as it will check for already registered funcs
if (uwsgi_register_rpc(*name, v8_plugin.modifier1, j_argc, uvrt)) {
uwsgi_log("[uwsgi-v8] unable to register RPC function \"%s\"\n", *name);
return v8::Undefined();
}
@@ -55,11 +96,11 @@ static v8::Handle<v8::Value> uwsgi_v8_api_register_rpc(const v8::Arguments& args
return v8::Undefined();
}
static void uwsgi_v8_load_file(v8::Persistent<v8::Context> context, char *filename) {
static void uwsgi_v8_load_file(int core_id, char *filename) {
uv8.isolates[core_id]->Enter();
uv8.contexts[core_id]->Enter();
v8::HandleScope handle_scope;
v8::Context::Scope context_scope(context);
size_t len = 0;
char *code = uwsgi_open_and_read(filename, &len, 1, NULL);
@@ -78,60 +119,85 @@ static void uwsgi_v8_load_file(v8::Persistent<v8::Context> context, char *filena
}
static v8::Handle<v8::Value> uwsgi_v8_api_log(const v8::Arguments& args) {
if (args.Length() > 0) {
v8::String::Utf8Value str(args[0]->ToString());
size_t slen = strlen(*str);
if ((*str)[slen-1] == '\n') {
uwsgi_log("%s", *str);
}
else {
uwsgi_log("%s\n", *str);
}
}
return v8::Undefined();
}
v8::Persistent<v8::Context> uwsgi_v8_setup_context();
static v8::Persistent<v8::Context> uwsgi_v8_new_isolate(int core_id) {
// create a new isolate
v8::Isolate *isolate = v8::Isolate::New();
// set as the current isolate
isolate->Enter();
uv8.isolates[core_id] = v8::Isolate::GetCurrent();
v8::Persistent<v8::Context> context = uwsgi_v8_setup_context();
context->Enter();
v8::HandleScope handle_scope;
// uWSGI api
v8::Handle<v8::Object> uwsgi_api = v8::Object::New();
uwsgi_api->Set(v8::String::New("log"), v8::FunctionTemplate::New(uwsgi_v8_api_log)->GetFunction());
uwsgi_api->Set(v8::String::New("register_rpc"), v8::FunctionTemplate::New(uwsgi_v8_api_register_rpc)->GetFunction());
uwsgi_api->Set(v8::String::New("register_signal"), v8::FunctionTemplate::New(uwsgi_v8_api_register_signal)->GetFunction());
context->Global()->Set(v8::String::New("uwsgi"), uwsgi_api);
return context;
}
extern "C" int uwsgi_v8_init(){
int i;
uwsgi_log("Initializing V8 %s environment... (%d Isolates)\n", v8::V8::GetVersion(), uwsgi.cores);
uv8.contexts = (v8::Persistent<v8::Context> *) uwsgi_malloc( sizeof(v8::Persistent<v8::Context>*) * uwsgi.cores );
uv8.isolates = (v8::Isolate **) uwsgi_malloc( sizeof(v8::Isolate *) * uwsgi.cores );
uv8.contexts = (v8::Persistent<v8::Context> *) uwsgi_malloc( sizeof(v8::Persistent<v8::Context>) * uwsgi.cores );
// allocates rpc and signal tables
uv8.rpctable = (struct uwsgi_v8_rpc_table *) uwsgi_calloc(sizeof(struct uwsgi_v8_rpc_table) * uwsgi.rpc_max);
for(i=0;i<(int)uwsgi.rpc_max;i++) {
uv8.rpctable[i].func = (v8::Persistent<v8::Function>*) uwsgi_calloc(sizeof(v8::Persistent<v8::Function>) * uwsgi.cores);
}
uv8.sigtable = (struct uwsgi_v8_signal_table *) uwsgi_calloc(sizeof(struct uwsgi_v8_signal_table) * 256);
for(i=0;i<256;i++) {
uv8.sigtable[i].func = (v8::Persistent<v8::Function>*) uwsgi_calloc(sizeof(v8::Persistent<v8::Function>) * uwsgi.cores);
}
uv8.jsgi_func = (v8::Persistent<v8::Function> *) uwsgi_calloc( sizeof(v8::Persistent<v8::Function>) * uwsgi.cores );
uv8.jsgi_writer_func = (v8::Persistent<v8::Function> *) uwsgi_calloc( sizeof(v8::Persistent<v8::Function>) * uwsgi.cores );
pthread_key_create(&uv8.current_core, NULL);
pthread_setspecific(uv8.current_core, (void *) 0);
uv8.contexts[0] = uwsgi_v8_new_isolate(0);
return 0;
}
static v8::Handle<v8::Value> uwsgi_v8_api_log(const v8::Arguments& args) {
if (args.Length() > 0) {
v8::String::Utf8Value str(args[0]->ToString());
size_t slen = strlen(*str);
if ((*str)[slen-1] == '\n') {
uwsgi_log("%s", *str);
}
else {
uwsgi_log("%s\n", *str);
}
static void uwsgi_v8_apps_do(int core_id) {
struct uwsgi_string_list *usl = uv8.load;
while(usl) {
uwsgi_v8_load_file(core_id, usl->value);
usl = usl->next;
}
if (uv8.jsgi) {
uv8.jsgi_func[core_id] = uwsgi_v8_load_jsgi(core_id, uv8.jsgi);
}
return v8::Undefined();
}
static v8::Persistent<v8::Context> uwsgi_v8_new_isolate(int core) {
v8::HandleScope handle_scope;
if (core > 0) {
// create a new isolate
v8::Isolate *isolate = v8::Isolate::New();
// set as the current isolate
v8::Isolate::Scope iscope(isolate);
}
v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New();
// print alias is always handy
global->Set(v8::String::New("uwsgi_log"), v8::FunctionTemplate::New(uwsgi_v8_api_log));
global->Set(v8::String::New("uwsgi_register_rpc"), v8::FunctionTemplate::New(uwsgi_v8_api_register_rpc));
global->Set(v8::String::New("uwsgi_register_signal"), v8::FunctionTemplate::New(uwsgi_v8_api_register_signal));
// create a new context
v8::Persistent<v8::Context> context = v8::Context::New(NULL, global);
return context;
}
extern "C" void uwsgi_v8_apps() {
if (!uv8.load) return;
int i;
for(i=0;i<uwsgi.cores;i++) {
uv8.contexts[i] = uwsgi_v8_new_isolate(i);
struct uwsgi_string_list *usl = uv8.load;
while(usl) {
uwsgi_v8_load_file(uv8.contexts[i], usl->value);
usl = usl->next;
}
}
uwsgi_v8_apps_do(0);
}
extern "C" void uwsgi_v8_configurator(char *filename, char *magic_table[]) {
@@ -191,29 +257,33 @@ extern "C" void uwsgi_v8_configurator(char *filename, char *magic_table[]) {
extern "C" uint16_t uwsgi_v8_rpc(void * func, uint8_t argc, char **argv, uint16_t argvs[], char *buffer) {
int core_id = (long) pthread_getspecific(uv8.current_core);
uv8.isolates[core_id]->Enter();
uv8.contexts[core_id]->Enter();
v8::HandleScope handle_scope;
v8::Handle<v8::Value> argj[256];
struct wsgi_request *wsgi_req = current_wsgi_req();
v8::Context::Scope context_scope(uv8.contexts[wsgi_req->async_id]);
v8::Persistent<v8::Function> l_func = static_cast<v8::Function*> (func);
struct uwsgi_v8_rpc_table *uvrt = (struct uwsgi_v8_rpc_table *) func;
uint8_t i;
for(i=0;i<argc;i++) {
argj[i] = v8::String::New(argv[i], argvs[i]);
}
v8::Handle<v8::Value> result = l_func->Call(l_func, argc, argj);
if (result.IsEmpty()) return 0;
v8::Persistent<v8::Function> l_func = uvrt->func[core_id];
v8::Handle<v8::Value> result = l_func->Call(uv8.contexts[core_id]->Global(), argc, argj);
if (result.IsEmpty()) {
return 0;
}
v8::Handle<v8::String> robj = result->ToString();
v8::String::Utf8Value r_value(robj);
if (!*robj) return 0;
if (!*robj) {
return 0;
}
uint16_t rlen = robj->Length();
memcpy(buffer, *r_value, rlen);
// call GC every time, could be overkill, we should allow to tune that choice
@@ -222,16 +292,39 @@ extern "C" uint16_t uwsgi_v8_rpc(void * func, uint8_t argc, char **argv, uint16_
}
extern "C" void uwsgi_v8_init_thread(int core_id) {
pthread_setspecific(uv8.current_core, (void *) ((long)core_id));
uv8.contexts[core_id] = uwsgi_v8_new_isolate(core_id);
uwsgi_v8_apps_do(core_id);
}
extern "C" void uwsgi_v8_enable_threads() {
}
extern "C" int uwsgi_v8_signal_handler(uint8_t sig, void *handler) {
int ret = 0;
v8::HandleScope handle_scope;
struct wsgi_request *wsgi_req = current_wsgi_req();
v8::Context::Scope context_scope(uv8.contexts[wsgi_req->async_id]);
v8::Persistent<v8::Function> l_func = static_cast<v8::Function*> (handler);
v8::Handle<v8::Value> argj[1];
int core_id = (long) pthread_getspecific(uv8.current_core);
uv8.isolates[core_id]->Enter();
uv8.contexts[core_id]->Enter();
v8::HandleScope handle_scope;
v8::Handle<v8::Value> argj[1];
argj[0] = v8::Number::New(sig);
v8::Handle<v8::Value> result = l_func->Call(l_func, 1, argj);
struct uwsgi_v8_signal_table *uvst = (struct uwsgi_v8_signal_table *) handler;
v8::Persistent<v8::Function> l_func = uvst->func[core_id];
v8::Handle<v8::Value> result = l_func->Call(uv8.contexts[core_id]->Global(), 1, argj);
if (result.IsEmpty()) ret = -1;
while(!v8::V8::IdleNotification()) {};
return ret;
}
extern "C" int uwsgi_v8_mule(char *opt) {
if (uwsgi_endswith(opt, (char *)".js")) {
uwsgi_v8_load_file(0, opt);
return 1;
}
return 0;
}
+32
View File
@@ -0,0 +1,32 @@
#include <uwsgi.h>
#include <v8.h>
// as we have isolates in multithread modes, we need to maintain
// special tables for the handlers (mules and spooler just run on the core 0)
struct uwsgi_v8_signal_table {
v8::Persistent<v8::Function> *func;
uint8_t registered;
};
struct uwsgi_v8_rpc_table {
char *name;
v8::Persistent<v8::Function> *func;
};
struct uwsgi_v8 {
v8::Persistent<v8::Context> *contexts;
v8::Isolate **isolates;
char *jsgi;
v8::Persistent<v8::Function> *jsgi_func;
v8::Persistent<v8::Function> *jsgi_writer_func;
int jsgi_announced;
struct uwsgi_string_list *load;
struct uwsgi_v8_signal_table *sigtable;
struct uwsgi_v8_rpc_table *rpctable;
pthread_key_t current_core;
int preemptive;
uint64_t gc_freq;
struct uwsgi_string_list *module_paths;
};
v8::Persistent<v8::Function> uwsgi_v8_load_jsgi(int, char *);
+1 -1
View File
@@ -2,7 +2,7 @@ Gem::Specification.new do |s|
s.name = 'uwsgi'
s.license = 'GPL-2'
s.version = `python -c "import uwsgiconfig as uc; print uc.uwsgi_version"`.sub(/-dev-.*/,'')
s.date = '2013-03-30'
s.date = '2013-04-04'
s.summary = "uWSGI"
s.description = "The uWSGI server for Ruby/Rack"
s.authors = ["Unbit"]
+319 -366
View File
File diff suppressed because it is too large Load Diff
+3 -30
View File
@@ -1,6 +1,6 @@
# uWSGI build system
uwsgi_version = '1.9.4'
uwsgi_version = '1.9.6'
import os
import re
@@ -66,11 +66,9 @@ report['routing'] = False
report['capabilities'] = False
report['yaml'] = False
report['json'] = False
report['ldap'] = False
report['ssl'] = False
report['zeromq'] = False
report['xml'] = False
report['sqlite3'] = False
report['debug'] = False
report['plugin_dir'] = False
report['zlib'] = False
@@ -524,6 +522,8 @@ class uConf(object):
# add -fno-strict-aliasing only on python2 and gcc < 4.3
if gcc_major >= 4:
self.cflags = self.cflags + [ '-Wextra', '-Wno-unused-parameter', '-Wno-missing-field-initializers' ]
if (gcc_major == 4 and gcc_minor >= 8) or gcc_major > 4:
self.cflags.append('-Wno-format')
self.ldflags = os.environ.get("LDFLAGS", "").split()
self.libs = ['-lpthread', '-lm', '-rdynamic']
@@ -971,19 +971,6 @@ class uConf(object):
if has_json:
report['json'] = True
if self.get('ldap'):
if self.get('ldap') == 'auto':
if self.has_include('ldap.h'):
self.cflags.append("-DUWSGI_LDAP")
self.gcc_list.append('core/ldap')
self.libs.append('-lldap')
report['ldap'] = True
else:
self.cflags.append("-DUWSGI_LDAP")
self.gcc_list.append('core/ldap')
self.libs.append('-lldap')
report['ldap'] = True
if self.get('ssl'):
if self.get('ssl') == 'auto':
if self.has_include('openssl/ssl.h'):
@@ -1052,20 +1039,6 @@ class uConf(object):
self.gcc_list.append('core/xmlconf')
report['xml'] = 'expat'
if self.get('sqlite3'):
if self.get('sqlite3') == 'auto':
if self.has_include('sqlite3.h'):
self.cflags.append("-DUWSGI_SQLITE3")
self.libs.append('-lsqlite3')
self.gcc_list.append('core/sqlite3')
report['sqlite3'] = True
else:
self.cflags.append("-DUWSGI_SQLITE3")
self.libs.append('-lsqlite3')
self.gcc_list.append('core/sqlite3')
report['sqlite3'] = True
if self.get('plugin_dir'):
self.cflags.append('-DUWSGI_PLUGIN_DIR=\\"%s\\"' % self.get('plugin_dir'))
report['plugin_dir'] = self.get('plugin_dir')