Repository URL to install this package:
|
Version:
2.0.17 ▾
|
/*
*** uWSGI/mod_Ruwsgi ***
Copyright 2009-2010 Roger Florkowski <rflorkowski@mypublisher.com>
Copyright 2009-2010 Unbit S.a.s. <info@unbit.it>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#define MOD_UWSGI_VERSION "1.0"
#include "ap_config.h"
#include "apr_version.h"
#include "apr_lib.h"
#include "apr_strings.h"
#include "httpd.h"
#include "http_core.h"
#include "http_request.h"
#include "http_config.h"
#include "http_log.h"
#include "http_protocol.h"
#include "util_script.h"
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/uio.h>
#include <time.h>
#include <poll.h>
#define DEFAULT_TIMEOUT 60 /* default socket timeout */
#define DEFAULT_CGIMODE 0 /* not enabled */
#define UNSET 0
#define ENABLED 1
#define DISABLED 2
#if APR_MAJOR_VERSION == 0
#define apr_socket_send apr_send
#define GET_PORT(port, addr) apr_sockaddr_port_get(&(port), addr)
#define CREATE_SOCKET(sock, family, pool) \
apr_socket_create(sock, family, SOCK_STREAM, pool)
#else
#define GET_PORT(port, addr) ((port) = (addr)->port)
#define CREATE_SOCKET(sock, family, pool) \
apr_socket_create(sock, family, SOCK_STREAM, APR_PROTO_TCP, pool)
#endif
typedef struct {
char *path;
char *addr;
apr_port_t port;
} mount_entry;
/*
* Configuration record. Used per-directory configuration data.
*/
typedef struct {
mount_entry mount;
int enabled; /* mod_uwsgi is enabled from this directory */
int timeout;
int cgi_mode;
uint8_t modifier1;
uint8_t modifier2;
} uwsgi_cfg;
/* Server level configuration */
typedef struct {
apr_array_header_t *mounts;
int timeout;
int cgi_mode;
} uwsgi_server_cfg;
module AP_MODULE_DECLARE_DATA uwsgi_module;
/*
* Locate our directory configuration record for the current request.
*/
static uwsgi_cfg *
our_dconfig(request_rec *r)
{
return (uwsgi_cfg *) ap_get_module_config(r->per_dir_config, &uwsgi_module);
}
static uwsgi_server_cfg *our_sconfig(server_rec *s)
{
return (uwsgi_server_cfg *) ap_get_module_config(s->module_config,
&uwsgi_module);
}
static int
mount_entry_matches(const char *url, const char *prefix,
const char **path_info)
{
int i;
for (i=0; prefix[i] != '\0'; i++) {
if (url[i] == '\0' || url[i] != prefix[i])
return 0;
}
if (url[i] == '\0' || url[i] == '/') {
*path_info = url + i;
return 1;
}
return 0;
}
static int uwsgi_translate(request_rec *r)
{
uwsgi_cfg *cfg = our_dconfig(r);
if (cfg->enabled == DISABLED) {
return DECLINED;
}
if (cfg->mount.addr != UNSET) {
ap_assert(cfg->mount.port != UNSET);
r->handler = "uwsgi-handler";
r->filename = r->uri;
return OK;
}
else {
int i;
uwsgi_server_cfg *scfg = our_sconfig(r->server);
mount_entry *entries = (mount_entry *) scfg->mounts->elts;
for (i = 0; i < scfg->mounts->nelts; ++i) {
const char *path_info;
mount_entry *mount = &entries[i];
if (mount_entry_matches(r->uri, mount->path, &path_info)) {
r->handler = "uwsgi-handler";
r->path_info = apr_pstrdup(r->pool, path_info);
r->filename = r->uri;
ap_set_module_config(r->request_config, &uwsgi_module, mount);
return OK;
}
}
}
return DECLINED;
}
static int uwsgi_map_location(request_rec *r)
{
if (r->handler && strcmp(r->handler, "uwsgi-handler") == 0) {
return OK; /* We don't want directory walk. */
}
return DECLINED;
}
#if AP_MODULE_MAGIC_AT_LEAST(20111130,0)
static void log_err(const char *file, int line, int ami, request_rec *r,
apr_status_t status, const char *msg)
{
ap_log_rerror(file, line, APLOG_MODULE_INDEX, APLOG_ERR, status, r, "uwsgi: %s", msg);
#else
static void log_err(const char *file, int line, request_rec *r,
apr_status_t status, const char *msg)
{
ap_log_rerror(file, line, APLOG_ERR, status, r, "uwsgi: %s", msg);
#endif
}
#if AP_MODULE_MAGIC_AT_LEAST(20111130,0)
static void log_debug(const char *file, int line, int ami, request_rec *r, const
char *msg)
{
/*
ap_log_rerror(file, line, APLOG_DEBUG, APR_SUCCESS, r, msg);
ap_log_rerror(file, line, APLOG_WARNING, APR_SUCCESS, r, "uwsgi: %s", msg);
*/
ap_log_rerror(file, line, APLOG_MODULE_INDEX, APLOG_DEBUG, APR_SUCCESS, r, "uwsgi: %s", msg);
#else
static void log_debug(const char *file, int line, request_rec *r, const
char *msg) {
ap_log_rerror(file, line, APLOG_DEBUG, APR_SUCCESS, r, "uwsgi: %s", msg);
#endif
}
/* buffered socket implementation (buckets are overkill) */
#define BUFFER_SIZE 8000
struct sockbuff {
apr_socket_t *sock;
char buf[BUFFER_SIZE];
int used;
};
static void binit(struct sockbuff *s, apr_socket_t *sock)
{
s->sock = sock;
s->used = 0;
}
static apr_status_t sendall(apr_socket_t *sock, char *buf, apr_size_t len)
{
apr_status_t rv;
apr_size_t n;
while (len > 0) {
n = len;
if ((rv = apr_socket_send(sock, buf, &n))) return rv;
buf += n;
len -= n;
}
return APR_SUCCESS;
}
static apr_status_t bflush(struct sockbuff *s)
{
apr_status_t rv;
ap_assert(s->used >= 0 && s->used <= BUFFER_SIZE);
if (s->used) {
if ((rv = sendall(s->sock, s->buf, s->used))) return rv;
s->used = 0;
}
return APR_SUCCESS;
}
static apr_status_t bwrite(struct sockbuff *s, char *buf, apr_size_t len)
{
apr_status_t rv;
if (len >= BUFFER_SIZE - s->used) {
if ((rv = bflush(s))) return rv;
while (len >= BUFFER_SIZE) {
if ((rv = sendall(s->sock, buf, BUFFER_SIZE))) return rv;
buf += BUFFER_SIZE;
len -= BUFFER_SIZE;
}
}
if (len > 0) {
ap_assert(len < BUFFER_SIZE - s->used);
memcpy(s->buf + s->used, buf, len);
s->used += len;
}
return APR_SUCCESS;
}
static apr_status_t bputs(struct sockbuff *s, char *buf)
{
return bwrite(s, buf, strlen(buf));
}
static apr_status_t bputc(struct sockbuff *s, char c)
{
char buf[1];
buf[0] = c;
return bwrite(s, buf, 1);
}
static apr_status_t bputh(struct sockbuff *s, unsigned short h)
{
return bwrite(s, (char *)&h, 2);
}
#define CONFIG_VALUE(value, fallback) ((value) != UNSET ? (value) : (fallback))
static apr_status_t
open_socket(apr_socket_t **sock, request_rec *r)
{
int timeout;
int retries = 4;
int sleeptime = 1;
apr_status_t rv;
apr_sockaddr_t *sockaddr;
uwsgi_server_cfg *scfg = our_sconfig(r->server);
uwsgi_cfg *cfg = our_dconfig(r);
mount_entry *m = (mount_entry *) ap_get_module_config(r->request_config,
&uwsgi_module);
if (!m) {
m = &cfg->mount;
}
timeout = CONFIG_VALUE(cfg->timeout, CONFIG_VALUE(scfg->timeout,
DEFAULT_TIMEOUT));
rv = apr_sockaddr_info_get(&sockaddr,
CONFIG_VALUE(m->addr, "localhost"),
APR_UNSPEC,
CONFIG_VALUE(m->port, 5000),
0,
r->pool);
if (rv) {
log_err(APLOG_MARK, r, rv, "apr_sockaddr_info_get() error");
return rv;
}
restart:
*sock = NULL;
rv = CREATE_SOCKET(sock, sockaddr->family, r->pool);
if (rv) {
log_err(APLOG_MARK, r, rv, "apr_socket_create() error");
return rv;
}
rv = apr_socket_timeout_set(*sock, apr_time_from_sec(timeout));
if (rv) {
log_err(APLOG_MARK, r, rv, "apr_socket_timeout_set() error");
return rv;
}
rv = apr_socket_connect(*sock, sockaddr);
if (rv) {
apr_socket_close(*sock);
if ((APR_STATUS_IS_ECONNREFUSED(rv) |
APR_STATUS_IS_EINPROGRESS(rv)) && retries > 0) {
/* server may be temporarily down, retry */
ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_DEBUG, rv, r,
"uwsgi: connection failed, retrying");
apr_sleep(apr_time_from_sec(sleeptime));
--retries;
sleeptime *= 2;
goto restart;
}
log_err(APLOG_MARK, r, rv, "uwsgi: can't connect to server");
return rv;
}
#ifdef APR_TCP_NODELAY
/* disable Nagle, we don't send small packets */
apr_socket_opt_set(*sock, APR_TCP_NODELAY, 1);
#endif
return APR_SUCCESS;
}
/* This code is a duplicate of what's in util_script.c. We can't use
* r->unparsed_uri because it gets changed if there was a redirect. */
static char *original_uri(request_rec *r)
{
char *first, *last;
if (r->the_request == NULL) {
return (char *) apr_pcalloc(r->pool, 1);
}
first = r->the_request; /* use the request-line */
while (*first && !apr_isspace(*first)) {
++first; /* skip over the method */
}
while (apr_isspace(*first)) {
++first; /* and the space(s) */
}
last = first;
while (*last && !apr_isspace(*last)) {
++last; /* end at next whitespace */
}
return apr_pstrmemdup(r->pool, first, last - first);
}
static char *lookup_name(apr_table_t *t, const char *name)
{
const apr_array_header_t *hdrs_arr = apr_table_elts(t);
apr_table_entry_t *hdrs = (apr_table_entry_t *) hdrs_arr->elts;
int i;
for (i = 0; i < hdrs_arr->nelts; ++i) {
if (hdrs[i].key == NULL)
continue;
if (strcasecmp(hdrs[i].key, name) == 0)
return hdrs[i].val;
}
return NULL;
}
static char *lookup_header(request_rec *r, const char *name)
{
return lookup_name(r->headers_in, name);
}
static void add_header(apr_table_t *t, const char *name, const char *value)
{
if (name != NULL && value != NULL)
apr_table_addn(t, name, value);
}
static int find_path_info(const char *uri, const char *path_info)
{
int n;
n = strlen(uri) - strlen(path_info);
ap_assert(n >= 0);
return n;
}
static char *http2env(apr_pool_t *p, const char *name)
{
char *env_name = apr_pstrcat(p, "HTTP_", name, NULL);
char *cp;
for (cp = env_name + 5; *cp != 0; cp++) {
if (*cp == '-') {
*cp = '_';
}
else {
*cp = apr_toupper(*cp);
}
}
return env_name;
}
static apr_status_t
send_headers(request_rec *r, struct sockbuff *s)
{
int i;
const apr_array_header_t *hdrs_arr, *env_arr;
apr_table_entry_t *hdrs, *env;
char *buf;
unsigned short int n = 0;
apr_table_t *t;
apr_status_t rv = 0;
apr_port_t port = 0;
#if AP_MODULE_MAGIC_AT_LEAST(20111130,0)
GET_PORT(port, r->useragent_addr);
#else
GET_PORT(port, r->connection->remote_addr);
#endif
uwsgi_cfg *cfg = our_dconfig(r);
log_debug(APLOG_MARK,r, "sending headers");
t = apr_table_make(r->pool, 40);
if (!t)
return APR_ENOMEM;
/* headers to send */
/* CONTENT_LENGTH must come first and always be present */
buf = lookup_header(r, "Content-Length");
if (buf == NULL)
buf = "0";
add_header(t, "CONTENT_LENGTH", buf);
add_header(t, "REQUEST_METHOD", (char *) r->method);
add_header(t, "QUERY_STRING", r->args ? r->args : "");
#if AP_MODULE_MAGIC_AT_LEAST(20111130,0)
add_header(t, "SERVER_SOFTWARE", ap_get_server_description());
#else
add_header(t, "SERVER_SOFTWARE", ap_get_server_version());
#endif
add_header(t, "SERVER_ADMIN", r->server->server_admin);
add_header(t, "SERVER_NAME", (char *) ap_get_server_name(r));
add_header(t, "SERVER_PORT", apr_psprintf(r->pool, "%u",ap_get_server_port(r)));
add_header(t, "SERVER_ADDR", r->connection->local_ip);
add_header(t, "SERVER_PROTOCOL", r->protocol);
add_header(t, "REQUEST_URI", original_uri(r));
#if AP_MODULE_MAGIC_AT_LEAST(20111130,0)
add_header(t, "REMOTE_ADDR", r->useragent_ip);
#else
add_header(t, "REMOTE_ADDR", r->connection->remote_ip);
#endif
add_header(t, "REMOTE_PORT", apr_psprintf(r->pool, "%d", port));
add_header(t, "REMOTE_USER", r->user);
add_header(t, "DOCUMENT_ROOT", (char *) ap_document_root(r));
if (r->path_info) {
int path_info_start = find_path_info(r->uri, r->path_info);
add_header(t, "SCRIPT_NAME", apr_pstrndup(r->pool, r->uri,
path_info_start));
add_header(t, "PATH_INFO", r->path_info);
}
else {
/* skip PATH_INFO, don't know it */
add_header(t, "SCRIPT_NAME", r->uri);
}
add_header(t, "CONTENT_TYPE", lookup_header(r, "Content-type"));
/* HTTP headers */
hdrs_arr = apr_table_elts(r->headers_in);
hdrs = (apr_table_entry_t *) hdrs_arr->elts;
for (i = 0; i < hdrs_arr->nelts; ++i) {
if (hdrs[i].key) {
add_header(t, http2env(r->pool, hdrs[i].key), hdrs[i].val);
}
}
/* environment variables */
env_arr = apr_table_elts(r->subprocess_env);
env = (apr_table_entry_t*) env_arr->elts;
for (i = 0; i < env_arr->nelts; ++i) {
add_header(t, env[i].key, env[i].val);
}
hdrs_arr = apr_table_elts(t);
hdrs = (apr_table_entry_t*) hdrs_arr->elts;
/* calculate length of header data */
for (i = 0; i < hdrs_arr->nelts; ++i) {
n += strlen(hdrs[i].key);
n += strlen(hdrs[i].val);
n += 4; /* XXX */
}
log_debug(APLOG_MARK,r, apr_psprintf(r->pool, "pktheader size is %u", n));
log_debug(APLOG_MARK,r, apr_psprintf(r->pool, "num headers %u", hdrs_arr->nelts));
/* write pkt header */
rv = bputc(s, cfg->modifier1); /* marker */
if (rv) return rv;
rv = bputh(s, n); /* length of header data */
if (rv) return rv;
rv = bputc(s, cfg->modifier2); /* marker */
if (rv) return rv;
/* write out headers */
for (i = 0; i < hdrs_arr->nelts; ++i) {
rv = bputh(s, strlen(hdrs[i].key)); /* length */
if (rv) return rv;
rv = bputs(s, hdrs[i].key); /* key */
if (rv) return rv;
rv = bputh(s, strlen(hdrs[i].val)); /* length */
if (rv) return rv;
rv = bputs(s, hdrs[i].val); /* data */
if (rv) return rv;
}
return APR_SUCCESS;
}
static apr_status_t send_request_body(request_rec *r, struct sockbuff *s)
{
if (ap_should_client_block(r)) {
char buf[BUFFER_SIZE];
apr_status_t rv;
apr_off_t len;
while ((len = ap_get_client_block(r, buf, sizeof buf)) > 0) {
if ((rv = bwrite(s, buf, len))) return rv;
}
if (len == -1)
return HTTP_INTERNAL_SERVER_ERROR; /* what to return? */
}
return APR_SUCCESS;
}
static int uwsgi_handler(request_rec *r)
{
apr_status_t rv = 0;
int cgi_mode, http_status = 0;
struct sockbuff s;
apr_socket_t *sock;
apr_bucket_brigade *bb = NULL;
apr_bucket *b = NULL;
const char *location;
uwsgi_cfg *cfg = our_dconfig(r);
uwsgi_server_cfg *scfg = our_sconfig(r->server);
if (strcmp(r->handler, "uwsgi-handler"))
return DECLINED;
http_status = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR);
if (http_status != OK)
return http_status;
log_debug(APLOG_MARK, r, "connecting to server");
rv = open_socket(&sock, r);
if (rv) {
return HTTP_INTERNAL_SERVER_ERROR;
}
binit(&s, sock);
rv = send_headers(r, &s);
if (rv) {
log_err(APLOG_MARK, r, rv, "error sending request headers");
return HTTP_INTERNAL_SERVER_ERROR;
}
rv = send_request_body(r, &s);
if (rv) {
log_err(APLOG_MARK, r, rv, "error sending request body");
return HTTP_INTERNAL_SERVER_ERROR;
}
rv = bflush(&s);
if (rv) {
log_err(APLOG_MARK, r, rv, "error sending request");
return HTTP_INTERNAL_SERVER_ERROR;
}
log_debug(APLOG_MARK, r, "reading response headers");
bb = apr_brigade_create(r->connection->pool, r->connection->bucket_alloc);
cgi_mode = CONFIG_VALUE(cfg->cgi_mode, CONFIG_VALUE(scfg->cgi_mode, DEFAULT_CGIMODE));
if (!cgi_mode) {
/* receive implemented with http-0.9 based protocol */
apr_interval_time_t timeout;
char buf[4096];
apr_pollfd_t pollfd = {r->pool, APR_POLL_SOCKET, APR_POLLIN, 0, { NULL }, NULL };
pollfd.desc.s = sock;
timeout = CONFIG_VALUE(cfg->timeout, CONFIG_VALUE(scfg->timeout,
DEFAULT_TIMEOUT)) * 1000 * 1000;
r->assbackwards = 1; /* XXX */
for(;;) {
apr_int32_t nsds;
apr_size_t len;
if ((rv = apr_poll(&pollfd, 1, &nsds, timeout)) == APR_TIMEUP) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: recv() timeout");
break;
}
if (rv != APR_SUCCESS) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: poll() %s", strerror(errno));
break;
}
len = 4096;
rv = apr_socket_recv(sock, buf, &len);
if (rv == APR_SUCCESS) {
apr_brigade_write(bb, NULL, NULL, buf, len);
}
else if (rv == APR_EOF) {
break;
}
else {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: recv() %s", strerror(errno));
}
}
log_debug(APLOG_MARK,r, "recv finished");
b = apr_bucket_flush_create(r->connection->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(bb, b);
b = apr_bucket_eos_create(r->connection->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(bb, b);
} else {
/* receive implemented with http-1.x based protocol */
b = apr_bucket_socket_create(sock, r->connection->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(bb, b);
b = apr_bucket_eos_create(r->connection->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(bb, b);
rv = ap_scan_script_header_err_brigade(r, bb, NULL);
if (rv) {
if (rv == HTTP_INTERNAL_SERVER_ERROR) {
log_err(APLOG_MARK, r, rv, "error reading response headers");
}
else {
/* Work around an Apache bug whereby the returned status is
* ignored and status_line is used instead. This bug is
* present at least in 2.0.54.
*/
r->status_line = NULL;
}
apr_brigade_destroy(bb);
return rv;
}
location = apr_table_get(r->headers_out, "Location");
if (location && location[0] == '/' &&
((r->status == HTTP_OK) || ap_is_HTTP_REDIRECT(r->status))) {
apr_brigade_destroy(bb);
/* Internal redirect -- fake-up a pseudo-request */
r->status = HTTP_OK;
/* This redirect needs to be a GET no matter what the original
* method was.
*/
r->method = apr_pstrdup(r->pool, "GET");
r->method_number = M_GET;
ap_internal_redirect_handler(location, r);
return OK;
}
}
rv = ap_pass_brigade(r->output_filters, bb);
if (rv) {
log_err(APLOG_MARK, r, rv, "ap_pass_brigade()");
return HTTP_INTERNAL_SERVER_ERROR;
}
return OK;
}
static int uwsgi_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp,
server_rec *base_server)
{
ap_add_version_component(p, "mod_uwsgi/" MOD_UWSGI_VERSION);
return OK;
}
static void *
uwsgi_create_dir_config(apr_pool_t *p, char *dirspec)
{
uwsgi_cfg *cfg = apr_pcalloc(p, sizeof(uwsgi_cfg));
cfg->enabled = UNSET;
cfg->mount.addr = UNSET;
cfg->mount.port = UNSET;
cfg->timeout = UNSET;
cfg->cgi_mode = UNSET;
cfg->modifier1 = UNSET;
cfg->modifier2 = UNSET;
return cfg;
}
#define MERGE(b, n, a) (n->a == UNSET ? b->a : n->a)
static void *
uwsgi_merge_dir_config(apr_pool_t *p, void *basev, void *newv)
{
uwsgi_cfg* cfg = apr_pcalloc(p, sizeof(uwsgi_cfg));
uwsgi_cfg* base = basev;
uwsgi_cfg* new = newv;
cfg->enabled = MERGE(base, new, enabled);
cfg->mount.addr = MERGE(base, new, mount.addr);
cfg->mount.port = MERGE(base, new, mount.port);
cfg->timeout = MERGE(base, new, timeout);
cfg->cgi_mode = MERGE(base, new, cgi_mode);
cfg->modifier1 = MERGE(base, new, modifier1);
cfg->modifier2 = MERGE(base, new, modifier2);
return cfg;
}
static void *
uwsgi_create_server_config(apr_pool_t *p, server_rec *s)
{
uwsgi_server_cfg *c =
(uwsgi_server_cfg *) apr_pcalloc(p, sizeof(uwsgi_server_cfg));
c->mounts = apr_array_make(p, 20, sizeof(mount_entry));
c->timeout = UNSET;
c->cgi_mode = UNSET;
return c;
}
static void *
uwsgi_merge_server_config(apr_pool_t *p, void *basev, void *overridesv)
{
uwsgi_server_cfg *c = (uwsgi_server_cfg *)
apr_pcalloc(p, sizeof(uwsgi_server_cfg));
uwsgi_server_cfg *base = (uwsgi_server_cfg *) basev;
uwsgi_server_cfg *overrides = (uwsgi_server_cfg *) overridesv;
c->mounts = apr_array_append(p, overrides->mounts, base->mounts);
c->timeout = MERGE(base, overrides, timeout);
c->cgi_mode = MERGE(base, overrides, cgi_mode);
return c;
}
static const char *
cmd_uwsgi_mount(cmd_parms *cmd, void *dummy, const char *path, const char *addr)
{
int n;
apr_status_t rv;
char *scope_id = NULL; /* A ip6 parameter - not used here. */
uwsgi_server_cfg *scfg = our_sconfig(cmd->server);
mount_entry *new = apr_array_push(scfg->mounts);
n = strlen(path);
while (n > 0 && path[n-1] == '/') {
n--; /* strip trailing slashes */
}
new->path = apr_pstrndup(cmd->pool, path, n);
rv = apr_parse_addr_port(&new->addr, &scope_id, &new->port, addr,
cmd->pool);
if (rv)
return "error parsing address:port string";
return NULL;
}
static const char *
cmd_uwsgi_server(cmd_parms *cmd, void *pcfg, const char *addr_and_port)
{
apr_status_t rv;
uwsgi_cfg *cfg = pcfg;
char *scope_id = NULL; /* A ip6 parameter - not used here. */
if (cmd->path == NULL)
return "not a server command";
rv = apr_parse_addr_port(&cfg->mount.addr, &scope_id, &cfg->mount.port,
addr_and_port, cmd->pool);
if (rv)
return "error parsing address:port string";
return NULL;
}
static const char *
cmd_uwsgi_handler(cmd_parms* cmd, void* pcfg, int flag)
{
uwsgi_cfg *cfg = pcfg;
if (cmd->path == NULL) /* server command */
return "not a server command";
if (flag)
cfg->enabled = ENABLED;
else
cfg->enabled = DISABLED;
return NULL;
}
static const char *
cmd_uwsgi_timeout(cmd_parms *cmd, void* pcfg, const char *strtimeout)
{
uwsgi_cfg *dcfg = pcfg;
int timeout = atoi(strtimeout);
if (cmd->path == NULL) {
uwsgi_server_cfg *scfg = our_sconfig(cmd->server);
scfg->timeout = timeout;
}
else {
dcfg->timeout = timeout;
}
return NULL;
}
static const char *
cmd_uwsgi_force_cgi_mode(cmd_parms *cmd, void *pcfg, const char *value)
{
int cgi_mode;
if (!strcmp("yes", value) || !strcmp("on", value) || !strcmp("enable", value) || !strcmp("1", value)) {
cgi_mode = 1;
}
else {
cgi_mode = 0;
}
if (cmd->path == NULL) {
uwsgi_server_cfg *scfg = our_sconfig(cmd->server);
scfg->cgi_mode = cgi_mode;
}
else {
uwsgi_cfg *dcfg = pcfg;
dcfg->cgi_mode = cgi_mode;
}
return NULL;
}
static const char *
cmd_uwsgi_modifier1(cmd_parms *cmd, void *pcfg, const char *value)
{
uwsgi_cfg *cfg = pcfg;
int val;
if (cmd->path == NULL) /* server command */
return "not a server command";
val = atoi(value);
if (val < 0 || val > 255) {
return "ignored uWSGImodifier1. Value must be between 0 and 255";
}
else {
cfg->modifier1 = (uint8_t) val;
}
return NULL;
}
static const char *
cmd_uwsgi_modifier2(cmd_parms *cmd, void *pcfg, const char *value)
{
uwsgi_cfg *cfg = pcfg;
int val;
if (cmd->path == NULL) /* server command */
return "not a server command";
val = atoi(value);
if (val < 0 || val > 255) {
return "ignored uWSGImodifier2. Value must be between 0 and 255";
}
else {
cfg->modifier2 = (uint8_t) val;
}
return NULL;
}
static const command_rec uwsgi_cmds[] = {
AP_INIT_TAKE2("uWSGImount", cmd_uwsgi_mount, NULL, RSRC_CONF,
"path prefix and address of UWSGI server"),
AP_INIT_TAKE1("uWSGIserver", cmd_uwsgi_server, NULL, ACCESS_CONF,
"Address and port of an UWSGI server (e.g. localhost:4000)"),
AP_INIT_FLAG( "uWSGIhandler", cmd_uwsgi_handler, NULL, ACCESS_CONF,
"On or Off to enable or disable the UWSGI handler"),
AP_INIT_TAKE1("uWSGIserverTimeout", cmd_uwsgi_timeout, NULL, ACCESS_CONF|RSRC_CONF,
"Timeout (in seconds) for communication with the UWSGI server."),
AP_INIT_TAKE1("uWSGIforceCGImode", cmd_uwsgi_force_cgi_mode, NULL, ACCESS_CONF|RSRC_CONF,
"Force uWSGI CGI mode for perfect integration with apache filter"),
AP_INIT_TAKE1("uWSGImodifier1", cmd_uwsgi_modifier1, NULL, ACCESS_CONF,
"Set uWSGI modifier1"),
AP_INIT_TAKE1("uWSGImodifier2", cmd_uwsgi_modifier2, NULL, ACCESS_CONF,
"Set uWSGI modifier2"),
/*
AP_INIT_TAKE12("uWSGIsocket", cmd_uwsgi_socket, NULL, RSRC_CONF|ACCESS_CONF,
"Absolute path and optional timeout in seconds of uwsgi server socket"),
AP_INIT_TAKE1("uWSGIsocket2", cmd_uwsgi_socket2, NULL, RSRC_CONF|ACCESS_CONF,
"Absolute path of failover uwsgi server socket"),
AP_INIT_TAKE1("uWSGIforceScriptName", cmd_uwsgi_force_script_name, NULL, ACCESS_CONF,
"Fix for PATH_INFO/SCRIPT_NAME when the location has filesystem correspondence"),
*/
{NULL}
};
static void uwsgi_register_hooks(apr_pool_t *p)
{
ap_hook_post_config(uwsgi_init, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_handler(uwsgi_handler, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_translate_name(uwsgi_translate, NULL, NULL, APR_HOOK_LAST);
ap_hook_map_to_storage(uwsgi_map_location, NULL, NULL, APR_HOOK_FIRST);
}
/* Dispatch list for API hooks */
module AP_MODULE_DECLARE_DATA uwsgi_module = {
STANDARD20_MODULE_STUFF,
uwsgi_create_dir_config, /* create per-dir config structs */
uwsgi_merge_dir_config, /* merge per-dir config structs */
uwsgi_create_server_config, /* create per-server config structs */
uwsgi_merge_server_config, /* merge per-server config structs */
uwsgi_cmds, /* table of config file commands */
uwsgi_register_hooks, /* register hooks */
};