127
#if !AP_MODULE_MAGIC_AT_LEAST(20081201,0)
128
#define ap_unixd_config unixd_config
113
135
#include "Python.h"
137
#if !defined(PY_VERSION_HEX)
138
#error Sorry, Python developer package does not appear to be installed.
141
#if PY_VERSION_HEX <= 0x02030000
142
#error Sorry, mod_wsgi requires at least Python 2.3.0 for Python 2.X.
145
#if PY_VERSION_HEX >= 0x03000000 && PY_VERSION_HEX < 0x03010000
146
#error Sorry, mod_wsgi requires at least Python 3.1.0 for Python 3.X.
149
#if !defined(WITH_THREAD)
150
#error Sorry, mod_wsgi requires that Python supporting thread.
114
153
#include "compile.h"
115
154
#include "node.h"
116
155
#include "osdefs.h"
118
#if !defined(PY_VERSION_HEX) || PY_VERSION_HEX <= 0x02030000
119
#error Sorry, mod_wsgi requires at least Python 2.3.0.
157
#ifndef PyVarObject_HEAD_INIT
158
#define PyVarObject_HEAD_INIT(type, size) \
159
PyObject_HEAD_INIT(type) size,
122
#if !defined(WITH_THREAD)
123
#error Sorry, mod_wsgi requires that Python supporting thread.
162
#if PY_MAJOR_VERSION >= 3
163
#define PyStringObject PyBytesObject
164
#define PyString_Check PyBytes_Check
165
#define PyString_Size PyBytes_Size
166
#define PyString_AsString PyBytes_AsString
167
#define PyString_FromString PyBytes_FromString
168
#define PyString_FromStringAndSize PyBytes_FromStringAndSize
169
#define PyString_AS_STRING PyBytes_AS_STRING
170
#define PyString_GET_SIZE PyBytes_GET_SIZE
171
#define _PyString_Resize _PyBytes_Resize
280
#if defined(WIN32) && defined(APR_HAS_UNICODE_FS)
281
typedef apr_uint16_t apr_wchar_t;
283
APR_DECLARE(apr_status_t) apr_conv_utf8_to_ucs2(const char *in,
286
apr_size_t *outwords);
288
static apr_status_t wsgi_utf8_to_unicode_path(apr_wchar_t* retstr,
292
/* TODO: The computations could preconvert the string to determine
293
* the true size of the retstr, but that's a memory over speed
294
* tradeoff that isn't appropriate this early in development.
296
* Allocate the maximum string length based on leading 4
297
* characters of \\?\ (allowing nearly unlimited path lengths)
298
* plus the trailing null, then transform /'s into \\'s since
299
* the \\?\ form doesn't allow '/' path seperators.
301
* Note that the \\?\ form only works for local drive paths, and
302
* \\?\UNC\ is needed UNC paths.
304
apr_size_t srcremains = strlen(srcstr) + 1;
305
apr_wchar_t *t = retstr;
308
/* This is correct, we don't twist the filename if it is will
309
* definately be shorter than 248 characters. It merits some
310
* performance testing to see if this has any effect, but there
311
* seem to be applications that get confused by the resulting
312
* Unicode \\?\ style file names, especially if they use argv[0]
313
* or call the Win32 API functions such as GetModuleName, etc.
314
* Not every application is prepared to handle such names.
316
* Note also this is shorter than MAX_PATH, as directory paths
317
* are actually limited to 248 characters.
319
* Note that a utf-8 name can never result in more wide chars
320
* than the original number of utf-8 narrow chars.
322
if (srcremains > 248) {
323
if (srcstr[1] == ':' && (srcstr[2] == '/' || srcstr[2] == '\\')) {
324
wcscpy (retstr, L"\\\\?\\");
328
else if ((srcstr[0] == '/' || srcstr[0] == '\\')
329
&& (srcstr[1] == '/' || srcstr[1] == '\\')
330
&& (srcstr[2] != '?')) {
331
/* Skip the slashes */
334
wcscpy (retstr, L"\\\\?\\UNC\\");
340
if (rv = apr_conv_utf8_to_ucs2(srcstr, &srcremains, t, &retlen)) {
341
return (rv == APR_INCOMPLETE) ? APR_EINVAL : rv;
344
return APR_ENAMETOOLONG;
226
353
/* Compatibility macros for log level and status. */
228
355
#if AP_SERVER_MAJORVERSION_NUMBER < 2
998
1199
if (config->group_authoritative == -1)
999
1200
config->group_authoritative = 1;
1202
#if AP_SERVER_MAJORVERSION_NUMBER >= 2
1203
if (!dconfig->handler_scripts)
1204
config->handler_scripts = sconfig->handler_scripts;
1205
else if (!sconfig->handler_scripts)
1206
config->handler_scripts = dconfig->handler_scripts;
1208
config->handler_scripts = apr_hash_overlay(p, dconfig->handler_scripts,
1209
sconfig->handler_scripts);
1213
config->handler_script = "";
1219
* Apache 2.X and UNIX specific definitions related to
1220
* distinct daemon processes.
1223
#if defined(MOD_WSGI_WITH_DAEMONS)
1226
#include "scoreboard.h"
1227
#include "mpm_common.h"
1228
#include "apr_proc_mutex.h"
1229
#include "apr_thread_cond.h"
1230
#include "apr_atomic.h"
1231
#include "http_connection.h"
1232
#include "apr_buckets.h"
1233
#include "apr_poll.h"
1234
#include "apr_signal.h"
1235
#include "http_vhost.h"
1237
#if APR_MAJOR_VERSION < 1
1238
#define apr_atomic_cas32 apr_atomic_cas
1241
#if APR_HAVE_SYS_SOCKET_H
1242
#include <sys/socket.h>
1244
#if APR_HAVE_UNISTD_H
1247
#if APR_HAVE_SYS_TYPES_H
1248
#include <sys/types.h>
1250
#ifdef HAVE_SYS_SEM_H
1251
#include <sys/sem.h>
1256
#ifndef WSGI_LISTEN_BACKLOG
1257
#define WSGI_LISTEN_BACKLOG 100
1260
#ifndef WSGI_CONNECT_ATTEMPTS
1261
#define WSGI_CONNECT_ATTEMPTS 15
1264
#define WSGI_STACK_HEAD 0xffff
1265
#define WSGI_STACK_LAST 0xffff
1266
#define WSGI_STACK_TERMINATED 0x10000
1267
#define WSGI_STACK_NO_LISTENER 0x20000
1284
const char *python_path;
1285
const char *python_eggs;
1287
int maximum_requests;
1288
int shutdown_timeout;
1289
apr_time_t deadlock_timeout;
1290
apr_time_t inactivity_timeout;
1291
const char *display_name;
1292
int send_buffer_size;
1293
int recv_buffer_size;
1294
const char *script_user;
1295
const char *script_group;
1300
const char* mutex_path;
1301
apr_proc_mutex_t* mutex;
1305
WSGIProcessGroup *group;
1308
apr_socket_t *listener;
1309
} WSGIDaemonProcess;
1313
WSGIDaemonProcess *process;
1314
apr_thread_t *thread;
1318
apr_thread_cond_t *condition;
1319
apr_thread_mutex_t *mutex;
1332
static int wsgi_daemon_count = 0;
1333
static apr_hash_t *wsgi_daemon_index = NULL;
1334
static apr_hash_t *wsgi_daemon_listeners = NULL;
1336
static WSGIDaemonProcess *wsgi_daemon_process = NULL;
1338
static int volatile wsgi_request_count = 0;
1340
static WSGIDaemonThread *wsgi_worker_threads = NULL;
1342
static WSGIThreadStack *wsgi_worker_stack = NULL;
1004
1346
/* Class objects used by response handler. */
1006
1348
static PyTypeObject Dispatch_Type;
1008
1350
typedef struct {
1010
1353
request_rec *r;
1014
1358
#if PY_MAJOR_VERSION < 3
1019
1363
static PyTypeObject Log_Type;
1021
static LogObject *newLogObject(request_rec *r, int level)
1365
static PyObject *newLogObject(request_rec *r, int level, const char *target)
1023
1367
LogObject *self;
1369
#if PY_MAJOR_VERSION >= 3
1370
PyObject *module = NULL;
1371
PyObject *dict = NULL;
1372
PyObject *object = NULL;
1373
PyObject *args = NULL;
1374
PyObject *result = NULL;
1376
module = PyImport_ImportModule("io");
1381
dict = PyModule_GetDict(module);
1382
object = PyDict_GetItemString(dict, "TextIOWrapper");
1385
PyErr_SetString(PyExc_NameError,
1386
"name 'TextIOWrapper' is not defined");
1025
1391
self = PyObject_New(LogObject, &Log_Type);
1026
1392
if (self == NULL)
1395
self->target = target;
1030
1397
self->level = APLOG_NOERRNO|level;
1031
1398
self->s = NULL;
1032
1400
self->expired = 0;
1033
1401
#if PY_MAJOR_VERSION < 3
1034
1402
self->softspace = 0;
1405
#if PY_MAJOR_VERSION >= 3
1407
args = Py_BuildValue("(OssOO)", self, "utf-8", "replace",
1410
result = PyEval_CallObject(object, args);
1416
return (PyObject *)self;
1421
static void Log_file(LogObject *self, const char *s, int l)
1424
* XXX This function is not currently being used.
1425
* The intention was that it be called instead of
1426
* Log_call() when 'target' is non zero. This would
1427
* be the case for 'stdout' and 'stderr'. Doing
1428
* this bypasses normally Apache logging mechanisms
1429
* though. May reawaken this code in mod_wsgi 4.0
1430
* by way of a mechanism to divert logging from a
1431
* daemon process to specfic log file or pipe using
1432
* an option to WSGIDaemonProcess.
1435
char errstr[MAX_STRING_LEN];
1440
#if AP_SERVER_MAJORVERSION_NUMBER < 2
1443
apr_file_t *logf = NULL;
1447
logf = self->r->server->error_log;
1449
logf = wsgi_server->error_log;
1451
#if AP_SERVER_MAJORVERSION_NUMBER < 2
1452
plen = ap_snprintf(errstr, sizeof(errstr), "[%s] ", ap_get_time());
1455
ap_recent_ctime(errstr + 1, apr_time_now());
1456
errstr[1 + APR_CTIME_LEN - 1] = ']';
1457
errstr[1 + APR_CTIME_LEN ] = ' ';
1458
plen = 1 + APR_CTIME_LEN + 1;
1464
errstr[plen++] = '[';
1466
len = strlen(self->target);
1467
memcpy(errstr+plen, self->target, len);
1471
errstr[plen++] = ']';
1472
errstr[plen++] = ' ';
1475
slen = MAX_STRING_LEN - plen - 1;
1477
Py_BEGIN_ALLOW_THREADS
1480
* We actually break long lines up into segments
1481
* of around 8192 characters, with the date/time
1482
* and target information prefixing each line.
1483
* This is just to avoid having to allocate more
1484
* memory just to format the line with prefix.
1485
* We want to avoid writing the prefix separately
1486
* so at least try and write line in one atomic
1492
memcpy(errstr+plen, s, slen);
1493
errstr[plen+slen] = '\n';
1494
#if AP_SERVER_MAJORVERSION_NUMBER < 2
1495
fwrite(errstr, plen+slen+1, 1, logf);
1498
apr_file_write_full(logf, errstr, plen+slen+1, NULL);
1499
apr_file_flush(logf);
1505
memcpy(errstr+plen, s, l);
1506
errstr[plen+l] = '\n';
1507
#if AP_SERVER_MAJORVERSION_NUMBER < 2
1508
fwrite(errstr, plen+l+1, 1, logf);
1511
apr_file_write_full(logf, errstr, plen+l+1, NULL);
1512
apr_file_flush(logf);
1518
Py_END_ALLOW_THREADS
1522
static void Log_call(LogObject *self, const char *s, int l)
1525
* The length of the string to be logged is ignored
1526
* for now. We just pass the whole string to the
1527
* Apache error log functions. It will actually
1528
* truncate it at some value less than 8192
1529
* characters depending on the length of the prefix
1530
* to go at the front. If there are embedded NULLs
1531
* then truncation will occur at that point. That
1532
* truncation occurs like this is also what happens
1533
* if using FASTCGI solutions for Apache, so not
1534
* doing anything different here.
1538
Py_BEGIN_ALLOW_THREADS
1539
ap_log_rerror(APLOG_MARK, WSGI_LOG_LEVEL(self->level),
1541
Py_END_ALLOW_THREADS
1544
Py_BEGIN_ALLOW_THREADS
1545
ap_log_error(APLOG_MARK, WSGI_LOG_LEVEL(self->level),
1546
wsgi_server, "%s", s);
1547
Py_END_ALLOW_THREADS
1040
1551
static void Log_dealloc(LogObject *self)
1043
if (!self->expired) {
1045
Py_BEGIN_ALLOW_THREADS
1046
ap_log_rerror(APLOG_MARK, WSGI_LOG_LEVEL(self->level),
1047
self->r, "%s", self->s);
1048
Py_END_ALLOW_THREADS
1051
Py_BEGIN_ALLOW_THREADS
1052
ap_log_error(APLOG_MARK, WSGI_LOG_LEVEL(self->level),
1053
wsgi_server, "%s", self->s);
1054
Py_END_ALLOW_THREADS
1555
Log_call(self, self->s, self->l);
2415
3032
if (self->headers) {
2417
* Force a zero length read before sending the
2418
* headers. This will ensure that if no request
2419
* content has been read that any '100 Continue'
2420
* response will be flushed and sent back to the
2421
* client if client was expecting one. Only
2422
* want to do this for 2xx and 3xx status values.
3034
* Apache prior to Apache 2.2.8 has a bug in it
3035
* whereby it doesn't force '100 Continue'
3036
* response before responding with headers if no
3037
* read. So, force a zero length read before
3038
* sending the headers if haven't yet attempted
3039
* to read anything. This will ensure that if no
3040
* request content has been read that any '100
3041
* Continue' response will be flushed and sent
3042
* back to the client if client was expecting
3043
* one. Only want to do this for 2xx and 3xx
3044
* status values. Note that even though Apple
3045
* supplied version of Apache on MacOS X Leopard
3046
* is newer than version 2.2.8, the header file
3047
* has never been patched when they make updates
3048
* and so anything compiled against it thinks it
2425
if (self->status >= 200 && self->status < 400) {
2426
PyObject *args = NULL;
2427
PyObject *result = NULL;
2428
args = Py_BuildValue("(i)", 0);
2429
result = Input_read(self->input, args);
2430
if (PyErr_Occurred())
3052
#if (AP_SERVER_MAJORVERSION_NUMBER == 1) || \
3053
(AP_SERVER_MAJORVERSION_NUMBER == 2 && \
3054
AP_SERVER_MINORVERSION_NUMBER < 2) || \
3055
(AP_SERVER_MAJORVERSION_NUMBER == 2 && \
3056
AP_SERVER_MINORVERSION_NUMBER == 2 && \
3057
AP_SERVER_PATCHLEVEL_NUMBER < 8)
3059
if (!self->input->init) {
3060
if (self->status >= 200 && self->status < 400) {
3061
PyObject *args = NULL;
3062
PyObject *result = NULL;
3063
args = Py_BuildValue("(i)", 0);
3064
result = Input_read(self->input, args);
3065
if (PyErr_Occurred())
2436
3074
/* Now setup response headers in request object. */
2438
3076
r->status = self->status;
2466
3104
object1 = PyTuple_GetItem(tuple, 0);
2467
3105
object2 = PyTuple_GetItem(tuple, 1);
2469
if (!PyString_Check(object1)) {
2470
PyErr_SetString(PyExc_TypeError, "expected string object "
2475
if (!PyString_Check(object2)) {
2476
PyErr_SetString(PyExc_TypeError, "expected string object "
2477
"for header value");
2481
if (!PyArg_ParseTuple(tuple, "ss", &name, &value)) {
2482
PyErr_SetString(PyExc_TypeError, "header name and value "
2483
"must be string objects without null bytes");
3107
if (PyString_Check(object1)) {
3108
name = PyString_AsString(object1);
3110
#if PY_MAJOR_VERSION >= 3
3111
else if (PyUnicode_Check(object1)) {
3112
PyObject *latin_object;
3113
latin_object = PyUnicode_AsLatin1String(object1);
3114
if (!latin_object) {
3115
PyErr_Format(PyExc_TypeError, "header name "
3116
"contained non 'latin-1' characters ");
3120
name = apr_pstrdup(r->pool, PyString_AsString(latin_object));
3121
Py_DECREF(latin_object);
3125
PyErr_Format(PyExc_TypeError, "expected byte string object "
3126
"for header name, value of type %.200s "
3127
"found", object1->ob_type->tp_name);
3131
if (PyString_Check(object2)) {
3132
value = PyString_AsString(object2);
3134
#if PY_MAJOR_VERSION >= 3
3135
else if (PyUnicode_Check(object2)) {
3136
PyObject *latin_object;
3137
latin_object = PyUnicode_AsLatin1String(object2);
3138
if (!latin_object) {
3139
PyErr_Format(PyExc_TypeError, "header value "
3140
"contained non 'latin-1' characters ");
3144
value = apr_pstrdup(r->pool, PyString_AsString(latin_object));
3145
Py_DECREF(latin_object);
3149
PyErr_Format(PyExc_TypeError, "expected byte string object "
3150
"for header value, value of type %.200s "
3151
"found", object2->ob_type->tp_name);
4233
5075
Py_DECREF(module);
4235
/* Restore previous thread state. */
4237
PyThreadState_Clear(tstate);
4238
PyThreadState_Swap(save_tstate);
4239
PyThreadState_Delete(tstate);
5078
* Restore previous thread state. Only need to do
5079
* this where had to create a new interpreter. This
5080
* is basically anything except the first Python
5081
* interpreter instance. We need to restore it in
5082
* these cases as came into the function holding the
5083
* simplified GIL state for this thread but creating
5084
* the interpreter has resulted in a new thread
5085
* state object being created bound to the newly
5086
* created interpreter. In doing this though we want
5087
* to cache the thread state object which has been
5088
* created when interpreter is created. This is so
5089
* it can be reused later ensuring that thread local
5090
* data persists between requests.
5096
int *thread_handle = NULL;
5098
self->tstate_table = apr_hash_make(wsgi_server->process->pool);
5100
apr_threadkey_private_get((void**)&thread_handle, wsgi_thread_key);
5102
if (!thread_handle) {
5103
thread_id = wsgi_thread_count++;
5104
thread_handle = (int*)apr_pmemdup(wsgi_server->process->pool,
5105
&thread_id, sizeof(thread_id));
5106
apr_threadkey_private_set(thread_handle, wsgi_thread_key);
5109
thread_id = *thread_handle;
5112
if (wsgi_server_config->verbose_debugging) {
5113
ap_log_error(APLOG_MARK, WSGI_LOG_DEBUG(0), wsgi_server,
5114
"mod_wsgi (pid=%d): Bind thread state for "
5115
"thread %d against interpreter '%s'.", getpid(),
5116
thread_id, self->name);
5119
apr_hash_set(self->tstate_table, thread_handle,
5120
sizeof(*thread_handle), tstate);
5122
PyThreadState_Swap(save_tstate);
5124
self->tstate = tstate;
5125
PyThreadState_Swap(save_tstate);
4707
5709
Py_OptimizeFlag = 0;
4709
if (wsgi_server_config->python_home)
5711
/* Check for control options for Python warnings. */
5713
if (wsgi_server_config->python_warnings) {
5714
apr_array_header_t *options = NULL;
5719
options = wsgi_server_config->python_warnings;
5720
entries = (char **)options->elts;
5722
for (i = 0; i < options->nelts; ++i) {
5723
#if PY_MAJOR_VERSION >= 3
5725
int len = strlen(entries[i])+1;
5727
s = (wchar_t *)apr_palloc(p, len*sizeof(wchar_t));
5729
#if defined(WIN32) && defined(APR_HAS_UNICODE_FS)
5730
wsgi_utf8_to_unicode_path(s, len, entries[i]);
5732
mbstowcs(s, entries[i], len);
5734
PySys_AddWarnOption(s);
5736
PySys_AddWarnOption(entries[i]);
5741
/* Check for Python HOME being overridden. */
5743
#if PY_MAJOR_VERSION >= 3
5744
if (wsgi_server_config->python_home) {
5746
int len = strlen(wsgi_server_config->python_home)+1;
5748
ap_log_error(APLOG_MARK, WSGI_LOG_INFO(0), wsgi_server,
5749
"mod_wsgi (pid=%d): Python home %s.", getpid(),
5750
wsgi_server_config->python_home);
5752
s = (wchar_t *)apr_palloc(p, len*sizeof(wchar_t));
5754
#if defined(WIN32) && defined(APR_HAS_UNICODE_FS)
5755
wsgi_utf8_to_unicode_path(s, len, wsgi_server_config->python_home);
5757
mbstowcs(s, wsgi_server_config->python_home, len);
5759
Py_SetPythonHome(s);
5762
if (wsgi_server_config->python_home) {
5763
ap_log_error(APLOG_MARK, WSGI_LOG_INFO(0), wsgi_server,
5764
"mod_wsgi (pid=%d): Python home %s.", getpid(),
5765
wsgi_server_config->python_home);
4710
5767
Py_SetPythonHome((char *)wsgi_server_config->python_home);
5772
* Work around bug in Python 3.1 where it will crash
5773
* when used in non console application on Windows if
5774
* stdin/stdout have been initialised and aren't null.
5777
#if defined(WIN32) && PY_MAJOR_VERSION >= 3
5778
_wputenv(L"PYTHONIOENCODING=cp1252:backslashreplace");
4712
5781
/* Initialise Python. */
4844
5895
* extension modules which use that will still work.
4847
PyEval_ReleaseLock();
5898
PyGILState_Release(state);
4849
5900
#if APR_HAS_THREADS
4850
5901
apr_thread_mutex_unlock(wsgi_interp_lock);
4854
tstate = PyThreadState_New(interp);
5907
int *thread_handle = NULL;
5909
apr_threadkey_private_get((void**)&thread_handle, wsgi_thread_key);
5911
if (!thread_handle) {
5912
thread_id = wsgi_thread_count++;
5913
thread_handle = (int*)apr_pmemdup(wsgi_server->process->pool,
5914
&thread_id, sizeof(thread_id));
5915
apr_threadkey_private_set(thread_handle, wsgi_thread_key);
5918
thread_id = *thread_handle;
5921
tstate = apr_hash_get(handle->tstate_table, &thread_id,
5925
tstate = PyThreadState_New(interp);
5927
if (wsgi_server_config->verbose_debugging) {
5928
ap_log_error(APLOG_MARK, WSGI_LOG_DEBUG(0), wsgi_server,
5929
"mod_wsgi (pid=%d): Create thread state for "
5930
"thread %d against interpreter '%s'.", getpid(),
5931
thread_id, handle->name);
5934
apr_hash_set(handle->tstate_table, thread_handle,
5935
sizeof(*thread_handle), tstate);
5938
tstate = handle->tstate;
4855
5941
PyEval_AcquireThread(tstate);
4858
5944
PyGILState_Ensure();
5947
* When simplified GIL state API is used, the thread
5948
* local data only persists for the extent of the top
5949
* level matching ensure/release calls. We want to
5950
* extend lifetime of the thread local data beyond
5951
* that, retaining it for all requests within the one
5952
* thread for the life of the process. To do that we
5953
* need to artificially increment the reference count
5954
* for the associated thread state object.
5957
tstate = PyThreadState_Get();
5958
if (tstate && tstate->gilstate_counter == 1)
5959
tstate->gilstate_counter++;
5678
6856
/* The processors for directives. */
6858
static int wsgi_parse_option(apr_pool_t *p, const char **line,
6859
const char **name, const char **value)
6861
const char *str = *line, *strend;
6863
while (*str && apr_isspace(*str))
6866
if (!*str || *str == '=') {
6868
return !APR_SUCCESS;
6871
/* Option must be of form name=value. Extract the name. */
6874
while (*strend && *strend != '=' && !apr_isspace(*strend))
6877
if (*strend != '=') {
6879
return !APR_SUCCESS;
6882
*name = apr_pstrndup(p, str, strend-str);
6886
/* Now extract the value. Note that value can be quoted. */
6888
*value = ap_getword_conf(p, line);
5680
6893
static const char *wsgi_add_script_alias(cmd_parms *cmd, void *mconfig,
5681
const char *l, const char *a)
5683
WSGIServerConfig *config = NULL;
6896
const char *l = NULL;
6897
const char *a = NULL;
6899
WSGIServerConfig *sconfig = NULL;
5684
6900
WSGIAliasEntry *entry = NULL;
5686
config = ap_get_module_config(cmd->server->module_config, &wsgi_module);
5688
if (!config->alias_list) {
5689
config->alias_list = apr_array_make(config->pool, 20,
6902
const char *option = NULL;
6903
const char *value = NULL;
6905
#if defined(MOD_WSGI_WITH_DAEMONS)
6906
const char *process_group = NULL;
6908
const char *process_group = "";
6911
const char *application_group = NULL;
6912
const char *callable_object = NULL;
6914
int pass_authorization = -1;
6916
sconfig = ap_get_module_config(cmd->server->module_config, &wsgi_module);
6918
if (!sconfig->alias_list) {
6919
sconfig->alias_list = apr_array_make(sconfig->pool, 20,
5690
6920
sizeof(WSGIAliasEntry));
5693
entry = (WSGIAliasEntry *)apr_array_push(config->alias_list);
6923
l = ap_getword_conf(cmd->pool, &args);
6925
if (*l == '\0' || *args == 0) {
6926
return apr_pstrcat(cmd->pool, cmd->cmd->name,
6927
" requires at least two arguments",
6928
cmd->cmd->errmsg ? ", " : NULL,
6929
cmd->cmd->errmsg, NULL);
6932
a = ap_getword_conf(cmd->pool, &args);
6935
return apr_pstrcat(cmd->pool, cmd->cmd->name,
6936
" requires at least two arguments",
6937
cmd->cmd->errmsg ? ", " : NULL,
6938
cmd->cmd->errmsg, NULL);
6942
if (wsgi_parse_option(cmd->pool, &args, &option,
6943
&value) != APR_SUCCESS) {
6944
return "Invalid option to WSGI script alias definition.";
6947
if (!cmd->info && !strcmp(option, "application-group")) {
6949
return "Invalid name for WSGI application group.";
6951
if (!strcmp(value, "%{GLOBAL}"))
6954
application_group = value;
6956
#if defined(MOD_WSGI_WITH_DAEMONS)
6957
else if (!cmd->info && !strcmp(option, "process-group")) {
6959
return "Invalid name for WSGI process group.";
6961
if (!strcmp(value, "%{GLOBAL}"))
6964
process_group = value;
6967
else if (!strcmp(option, "callable-object")) {
6969
return "Invalid name for WSGI callable object.";
6971
callable_object = value;
6973
else if (!strcmp(option, "pass-authorization")) {
6975
return "Invalid value for authorization flag.";
6977
if (strcasecmp(value, "Off") == 0)
6978
pass_authorization = 0;
6979
else if (strcasecmp(value, "On") == 0)
6980
pass_authorization = 1;
6982
return "Invalid value for authorization flag.";
6985
return "Invalid option to WSGI script alias definition.";
6988
entry = (WSGIAliasEntry *)apr_array_push(sconfig->alias_list);
5695
6990
if (cmd->info) {
5696
6991
entry->regexp = ap_pregcomp(cmd->pool, l, AP_REG_EXTENDED);
5701
6996
entry->location = l;
5702
6997
entry->application = a;
6999
entry->process_group = process_group;
7000
entry->application_group = application_group;
7001
entry->callable_object = callable_object;
7002
entry->pass_authorization = pass_authorization;
7004
if (process_group && application_group &&
7005
!strstr(process_group, "%{") &&
7006
!strstr(application_group, "%{")) {
7008
WSGIScriptFile *object = NULL;
7010
if (!wsgi_import_list) {
7011
wsgi_import_list = apr_array_make(sconfig->pool, 20,
7012
sizeof(WSGIScriptFile));
7015
object = (WSGIScriptFile *)apr_array_push(wsgi_import_list);
7017
object->handler_script = a;
7018
object->process_group = process_group;
7019
object->application_group = application_group;
7021
#if defined(MOD_WSGI_WITH_DAEMONS)
7022
if (*object->process_group) {
7023
WSGIProcessGroup *group = NULL;
7024
WSGIProcessGroup *entries = NULL;
7025
WSGIProcessGroup *entry = NULL;
7028
if (!wsgi_daemon_list)
7029
return "WSGI process group not yet configured.";
7031
entries = (WSGIProcessGroup *)wsgi_daemon_list->elts;
7033
for (i = 0; i < wsgi_daemon_list->nelts; ++i) {
7034
entry = &entries[i];
7036
if (!strcmp(entry->name, object->process_group)) {
7043
return "WSGI process group not yet configured.";
7045
if (group->server != cmd->server && group->server->is_virtual)
7046
return "WSGI process group not accessible.";
7054
static const char *wsgi_set_verbose_debugging(cmd_parms *cmd, void *mconfig,
7057
const char *error = NULL;
7058
WSGIServerConfig *sconfig = NULL;
7060
error = ap_check_cmd_context(cmd, GLOBAL_ONLY);
7064
sconfig = ap_get_module_config(cmd->server->module_config, &wsgi_module);
7066
if (strcasecmp(f, "Off") == 0)
7067
sconfig->verbose_debugging = 0;
7068
else if (strcasecmp(f, "On") == 0)
7069
sconfig->verbose_debugging = 1;
7071
return "WSGIVerboseDebugging must be one of: Off | On";
7076
static const char *wsgi_set_lazy_initialization(cmd_parms *cmd, void *mconfig,
7079
const char *error = NULL;
7081
error = ap_check_cmd_context(cmd, GLOBAL_ONLY);
7085
if (strcasecmp(f, "Off") == 0)
7086
wsgi_python_after_fork = 0;
7087
else if (strcasecmp(f, "On") == 0)
7088
wsgi_python_after_fork = 1;
7090
return "WSGILazyInitialization must be one of: Off | On";
7095
static const char *wsgi_add_python_warnings(cmd_parms *cmd, void *mconfig,
7098
const char *error = NULL;
7099
WSGIServerConfig *sconfig = NULL;
7101
char **entry = NULL;
7103
error = ap_check_cmd_context(cmd, GLOBAL_ONLY);
7107
sconfig = ap_get_module_config(cmd->server->module_config, &wsgi_module);
7109
if (!sconfig->python_warnings) {
7110
sconfig->python_warnings = apr_array_make(sconfig->pool, 5,
7114
entry = (char **)apr_array_push(sconfig->python_warnings);
7115
*entry = apr_pstrdup(sconfig->pool, f);
7120
static const char *wsgi_set_py3k_warning_flag(cmd_parms *cmd, void *mconfig,
7123
const char *error = NULL;
7124
WSGIServerConfig *sconfig = NULL;
7126
error = ap_check_cmd_context(cmd, GLOBAL_ONLY);
7130
sconfig = ap_get_module_config(cmd->server->module_config, &wsgi_module);
7132
if (strcasecmp(f, "Off") == 0)
7133
sconfig->py3k_warning_flag = 0;
7134
else if (strcasecmp(f, "On") == 0)
7135
sconfig->py3k_warning_flag = 1;
7137
return "WSGIPy3kWarningFlag must be one of: Off | On";
6175
static const char *wsgi_set_reload_mechanism(cmd_parms *cmd, void *mconfig,
6179
WSGIDirectoryConfig *dconfig = NULL;
6180
dconfig = (WSGIDirectoryConfig *)mconfig;
6182
if (strcasecmp(f, "Module") == 0)
6183
dconfig->reload_mechanism = WSGI_RELOAD_MODULE;
6184
else if (strcasecmp(f, "Process") == 0)
6185
dconfig->reload_mechanism = WSGI_RELOAD_PROCESS;
6187
return "WSGIReloadMechanism must be one of: "
6192
WSGIServerConfig *sconfig = NULL;
6193
sconfig = ap_get_module_config(cmd->server->module_config,
6196
if (strcasecmp(f, "Module") == 0)
6197
sconfig->reload_mechanism = WSGI_RELOAD_MODULE;
6198
else if (strcasecmp(f, "Process") == 0)
6199
sconfig->reload_mechanism = WSGI_RELOAD_PROCESS;
6201
return "WSGIReloadMechanism must be one of: "
7642
static const char *wsgi_set_error_override(cmd_parms *cmd, void *mconfig,
7646
WSGIDirectoryConfig *dconfig = NULL;
7647
dconfig = (WSGIDirectoryConfig *)mconfig;
7649
if (strcasecmp(f, "Off") == 0)
7650
dconfig->error_override = 0;
7651
else if (strcasecmp(f, "On") == 0)
7652
dconfig->error_override = 1;
7654
return "WSGIErrorOverride must be one of: Off | On";
7657
WSGIServerConfig *sconfig = NULL;
7658
sconfig = ap_get_module_config(cmd->server->module_config,
7661
if (strcasecmp(f, "Off") == 0)
7662
sconfig->error_override = 0;
7663
else if (strcasecmp(f, "On") == 0)
7664
sconfig->error_override = 1;
7666
return "WSGIErrorOverride must be one of: Off | On";
7672
static const char *wsgi_set_chunked_request(cmd_parms *cmd, void *mconfig,
7676
WSGIDirectoryConfig *dconfig = NULL;
7677
dconfig = (WSGIDirectoryConfig *)mconfig;
7679
if (strcasecmp(f, "Off") == 0)
7680
dconfig->chunked_request = 0;
7681
else if (strcasecmp(f, "On") == 0)
7682
dconfig->chunked_request = 1;
7684
return "WSGIChunkedRequest must be one of: Off | On";
7687
WSGIServerConfig *sconfig = NULL;
7688
sconfig = ap_get_module_config(cmd->server->module_config,
7691
if (strcasecmp(f, "Off") == 0)
7692
sconfig->chunked_request = 0;
7693
else if (strcasecmp(f, "On") == 0)
7694
sconfig->chunked_request = 1;
7696
return "WSGIChunkedRequest must be one of: Off | On";
7854
#if AP_SERVER_MAJORVERSION_NUMBER >= 2
7855
static const char *wsgi_add_handler_script(cmd_parms *cmd, void *mconfig,
7858
WSGIServerConfig *sconfig = NULL;
7859
WSGIDirectoryConfig *dconfig = NULL;
7860
WSGIScriptFile *object = NULL;
7862
const char *name = NULL;
7863
const char *option = NULL;
7864
const char *value = NULL;
7866
name = ap_getword_conf(cmd->pool, &args);
7868
if (!name || !*name)
7869
return "Name for handler script not supplied.";
7871
object = newWSGIScriptFile(cmd->pool);
7873
object->handler_script = ap_getword_conf(cmd->pool, &args);
7875
if (!object->handler_script || !*object->handler_script)
7876
return "Location of handler script not supplied.";
7879
if (wsgi_parse_option(cmd->pool, &args, &option,
7880
&value) != APR_SUCCESS) {
7881
return "Invalid option to WSGI handler script definition.";
7884
if (!strcmp(option, "process-group")) {
7886
return "Invalid name for WSGI process group.";
7888
object->process_group = value;
7890
else if (!strcmp(option, "application-group")) {
7892
return "Invalid name for WSGI application group.";
7894
object->application_group = value;
7896
else if (!strcmp(option, "pass-authorization")) {
7898
return "Invalid value for authorization flag.";
7900
if (strcasecmp(value, "Off") == 0)
7901
object->pass_authorization = "0";
7902
else if (strcasecmp(value, "On") == 0)
7903
object->pass_authorization = "1";
7905
return "Invalid value for authorization flag.";
7908
return "Invalid option to WSGI handler script definition.";
7912
WSGIDirectoryConfig *dconfig = NULL;
7913
dconfig = (WSGIDirectoryConfig *)mconfig;
7915
if (!dconfig->handler_scripts)
7916
dconfig->handler_scripts = apr_hash_make(cmd->pool);
7918
apr_hash_set(dconfig->handler_scripts, name, APR_HASH_KEY_STRING,
7922
WSGIServerConfig *sconfig = NULL;
7923
sconfig = ap_get_module_config(cmd->server->module_config,
7926
if (!sconfig->handler_scripts)
7927
sconfig->handler_scripts = apr_hash_make(cmd->pool);
7929
apr_hash_set(sconfig->handler_scripts, name, APR_HASH_KEY_STRING,
6349
7937
/* Handler for the translate name phase. */
6351
7939
static int wsgi_alias_matches(const char *uri, const char *alias_fakename)
7113
8824
WSGIRequestConfig *config = NULL;
7116
* Only process requests for this module. Honour a content
7117
* type here because mod_rewrite prior to Apache 2.2 only
7118
* provides a means of setting content type and doesn't
7119
* provide a means of setting the handler name explicitly.
7122
if (!r->handler || (strcmp(r->handler, "wsgi-script") &&
7123
strcmp(r->handler, "application/x-httpd-wsgi"))) {
7128
* Ensure that have adequate privileges to run the WSGI
7129
* script. Require ExecCGI to be specified in Options for
7130
* this. In doing this, using the wider interpretation that
7131
* ExecCGI refers to any executable like script even though
7132
* not a separate process execution.
7135
if (!(ap_allow_options(r) & OPT_EXECCGI) && !wsgi_is_script_aliased(r)) {
7136
wsgi_log_script_error(r, "Options ExecCGI is off in this directory",
7138
return HTTP_FORBIDDEN;
7141
/* Ensure target script exists and is a file. */
7143
#if AP_SERVER_MAJORVERSION_NUMBER < 2
7144
if (r->finfo.st_mode == 0) {
7145
wsgi_log_script_error(r, "Target WSGI script not found or unable "
7146
"to stat", r->filename);
7147
return HTTP_NOT_FOUND;
7150
if (r->finfo.filetype == 0) {
7151
wsgi_log_script_error(r, "Target WSGI script not found or unable "
7152
"to stat", r->filename);
7153
return HTTP_NOT_FOUND;
7157
#if AP_SERVER_MAJORVERSION_NUMBER < 2
7158
if (S_ISDIR(r->finfo.st_mode)) {
7159
wsgi_log_script_error(r, "Attempt to invoke directory as WSGI "
7160
"application", r->filename);
7161
return HTTP_FORBIDDEN;
7164
if (r->finfo.filetype == APR_DIR) {
7165
wsgi_log_script_error(r, "Attempt to invoke directory as WSGI "
7166
"application", r->filename);
7167
return HTTP_FORBIDDEN;
8826
const char *value = NULL;
8828
/* Filter out the obvious case of no handler defined. */
8834
* Construct request configuration and cache it in the
8835
* request object against this module so can access it later
8836
* from handler code.
8839
config = wsgi_create_req_config(r->pool, r);
8841
ap_set_module_config(r->request_config, &wsgi_module, config);
8844
* Only process requests for this module. First check for
8845
* where target is the actual WSGI script. Then need to
8846
* check for the case where handler name mapped to a handler
8847
* script definition.
8850
if (!strcmp(r->handler, "wsgi-script") ||
8851
!strcmp(r->handler, "application/x-httpd-wsgi")) {
8854
* Ensure that have adequate privileges to run the WSGI
8855
* script. Require ExecCGI to be specified in Options for
8856
* this. In doing this, using the wider interpretation that
8857
* ExecCGI refers to any executable like script even though
8858
* not a separate process execution.
8861
if (!(ap_allow_options(r) & OPT_EXECCGI) &&
8862
!wsgi_is_script_aliased(r)) {
8863
wsgi_log_script_error(r, "Options ExecCGI is off in this "
8864
"directory", r->filename);
8865
return HTTP_FORBIDDEN;
8868
/* Ensure target script exists and is a file. */
8870
#if AP_SERVER_MAJORVERSION_NUMBER < 2
8871
if (r->finfo.st_mode == 0) {
8872
wsgi_log_script_error(r, "Target WSGI script not found or unable "
8873
"to stat", r->filename);
8874
return HTTP_NOT_FOUND;
8877
if (r->finfo.filetype == 0) {
8878
wsgi_log_script_error(r, "Target WSGI script not found or unable "
8879
"to stat", r->filename);
8880
return HTTP_NOT_FOUND;
8884
#if AP_SERVER_MAJORVERSION_NUMBER < 2
8885
if (S_ISDIR(r->finfo.st_mode)) {
8886
wsgi_log_script_error(r, "Attempt to invoke directory as WSGI "
8887
"application", r->filename);
8888
return HTTP_FORBIDDEN;
8891
if (r->finfo.filetype == APR_DIR) {
8892
wsgi_log_script_error(r, "Attempt to invoke directory as WSGI "
8893
"application", r->filename);
8894
return HTTP_FORBIDDEN;
8898
if (wsgi_is_script_aliased(r)) {
8900
* Allow any configuration supplied through request notes to
8901
* override respective values. Request notes are used when
8902
* configuration supplied with WSGIScriptAlias directives.
8905
if (value = apr_table_get(r->notes, "mod_wsgi.process_group"))
8906
config->process_group = wsgi_process_group(r, value);
8907
if (value = apr_table_get(r->notes, "mod_wsgi.application_group"))
8908
config->application_group = wsgi_application_group(r, value);
8909
if (value = apr_table_get(r->notes, "mod_wsgi.callable_object"))
8910
config->callable_object = value;
8912
if (value = apr_table_get(r->notes,
8913
"mod_wsgi.pass_authorization")) {
8914
if (!strcmp(value, "1"))
8915
config->pass_authorization = 1;
8917
config->pass_authorization = 0;
8921
#if AP_SERVER_MAJORVERSION_NUMBER >= 2
8922
else if (config->handler_scripts) {
8923
WSGIScriptFile *entry;
8925
entry = (WSGIScriptFile *)apr_hash_get(config->handler_scripts,
8927
APR_HASH_KEY_STRING);
8930
config->handler_script = entry->handler_script;
8931
config->callable_object = "handle_request";
8933
if (value = entry->process_group)
8934
config->process_group = wsgi_process_group(r, value);
8935
if (value = entry->application_group)
8936
config->application_group = wsgi_application_group(r, value);
8938
if (value = entry->pass_authorization) {
8939
if (!strcmp(value, "1"))
8940
config->pass_authorization = 1;
8942
config->pass_authorization = 0;
7172
8953
* For Apache 2.0+ honour AcceptPathInfo directive. Default
7323
9150
static const command_rec wsgi_commands[] =
7325
9152
{ "WSGIScriptAlias", wsgi_add_script_alias, NULL,
7326
RSRC_CONF, TAKE2, "Map location to target WSGI script file." },
9153
RSRC_CONF, RAW_ARGS, "Map location to target WSGI script file." },
7327
9154
{ "WSGIScriptAliasMatch", wsgi_add_script_alias, "*",
7328
RSRC_CONF, TAKE2, "Map location to target WSGI script file." },
9155
RSRC_CONF, RAW_ARGS, "Map location to target WSGI script file." },
9157
{ "WSGIVerboseDebugging", wsgi_set_verbose_debugging, NULL,
9158
RSRC_CONF, TAKE1, "Enable/Disable verbose debugging messages." },
9160
#if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION >= 6
9161
{ "WSGIPy3kWarningFlag", wsgi_set_py3k_warning_flag, NULL,
9162
RSRC_CONF, TAKE1, "Enable/Disable Python 3.0 warnings." },
9165
{ "WSGIPythonWarnings", wsgi_add_python_warnings, NULL,
9166
RSRC_CONF, TAKE1, "Control Python warning messages." },
7330
9167
{ "WSGIPythonOptimize", wsgi_set_python_optimize, NULL,
7331
9168
RSRC_CONF, TAKE1, "Set level of Python compiler optimisations." },
7332
9169
{ "WSGIPythonHome", wsgi_set_python_home, NULL,
8258
10080
ap_lingering_close(c);
10083
static apr_status_t wsgi_worker_acquire(int id)
10085
WSGIThreadStack *stack = wsgi_worker_stack;
10086
WSGIDaemonThread *thread = &wsgi_worker_threads[id];
10089
apr_uint32_t state = stack->state;
10090
if (state & (WSGI_STACK_TERMINATED | WSGI_STACK_NO_LISTENER)) {
10091
if (state & WSGI_STACK_TERMINATED) {
10094
if (apr_atomic_cas32(&(stack->state), WSGI_STACK_LAST, state) !=
10099
return APR_SUCCESS;
10102
thread->next = state;
10103
if (apr_atomic_cas32(&(stack->state), (unsigned)id, state) != state) {
10109
if (thread->wakeup) {
10110
thread->wakeup = 0;
10112
return APR_SUCCESS;
10115
rv = apr_thread_cond_wait(thread->condition, thread->mutex);
10117
while (rv == APR_SUCCESS && !thread->wakeup)
10118
rv = apr_thread_cond_wait(thread->condition, thread->mutex);
10120
if (rv != APR_SUCCESS) {
10121
ap_log_error(APLOG_MARK, WSGI_LOG_CRIT(rv),
10122
wsgi_server, "mod_wsgi (pid=%d): "
10123
"Wait on thread %d wakeup condition variable "
10124
"failed.", getpid(), id);
10127
thread->wakeup = 0;
10134
static apr_status_t wsgi_worker_release()
10136
WSGIThreadStack *stack = wsgi_worker_stack;
10139
apr_uint32_t state = stack->state;
10140
unsigned int first = state & WSGI_STACK_HEAD;
10141
if (first == WSGI_STACK_LAST) {
10142
if (apr_atomic_cas32(&(stack->state),
10143
state | WSGI_STACK_NO_LISTENER,
10148
return APR_SUCCESS;
10152
WSGIDaemonThread *thread = &wsgi_worker_threads[first];
10153
if (apr_atomic_cas32(&(stack->state),
10154
(state ^ first) | thread->next,
10160
* Flag that thread should be woken up and then
10161
* signal it via the condition variable.
10165
if ((rv = apr_thread_mutex_lock(thread->mutex)) !=
10170
thread->wakeup = 1;
10172
if ((rv = apr_thread_mutex_unlock(thread->mutex)) !=
10177
return apr_thread_cond_signal(thread->condition);
10183
static apr_status_t wsgi_worker_shutdown()
10187
WSGIThreadStack *stack = wsgi_worker_stack;
10190
apr_uint32_t state = stack->state;
10191
if (apr_atomic_cas32(&(stack->state), state | WSGI_STACK_TERMINATED,
10196
for (i = 0; i < wsgi_daemon_process->group->threads; i++) {
10197
if ((rv = wsgi_worker_release()) != APR_SUCCESS) {
10201
return APR_SUCCESS;
8261
10204
static void wsgi_daemon_worker(apr_pool_t *p, WSGIDaemonThread *thread)
8263
10206
apr_status_t status;
8536
10488
WSGIDaemonProcess *daemon = data;
8538
ap_log_error(APLOG_MARK, WSGI_LOG_INFO(0), wsgi_server,
8539
"mod_wsgi (pid=%d): Enable monitor thread in "
8540
"process '%s'.", getpid(), daemon->group->name);
10490
if (wsgi_server_config->verbose_debugging) {
10491
ap_log_error(APLOG_MARK, WSGI_LOG_DEBUG(0), wsgi_server,
10492
"mod_wsgi (pid=%d): Enable monitor thread in "
10493
"process '%s'.", getpid(), daemon->group->name);
8542
ap_log_error(APLOG_MARK, WSGI_LOG_DEBUG(0), wsgi_server,
8543
"mod_wsgi (pid=%d): Deadlock timeout is %d.",
8544
getpid(), (int)(apr_time_sec(wsgi_deadlock_timeout)));
8545
ap_log_error(APLOG_MARK, WSGI_LOG_DEBUG(0), wsgi_server,
8546
"mod_wsgi (pid=%d): Inactivity timeout is %d.",
8547
getpid(), (int)(apr_time_sec(wsgi_inactivity_timeout)));
10495
ap_log_error(APLOG_MARK, WSGI_LOG_DEBUG(0), wsgi_server,
10496
"mod_wsgi (pid=%d): Deadlock timeout is %d.",
10497
getpid(), (int)(apr_time_sec(wsgi_deadlock_timeout)));
10498
ap_log_error(APLOG_MARK, WSGI_LOG_DEBUG(0), wsgi_server,
10499
"mod_wsgi (pid=%d): Inactivity timeout is %d.",
10500
getpid(), (int)(apr_time_sec(wsgi_inactivity_timeout)));
8550
10504
apr_time_t now;
10650
/* Initialise worker stack. */
10652
wsgi_worker_stack = (WSGIThreadStack *)apr_palloc(p,
10653
sizeof(WSGIThreadStack));
10654
wsgi_worker_stack->state = WSGI_STACK_NO_LISTENER | WSGI_STACK_LAST;
8697
10656
/* Start the required number of threads. */
8699
threads = (WSGIDaemonThread *)apr_pcalloc(p, daemon->group->threads
8700
* sizeof(WSGIDaemonThread));
10658
wsgi_worker_threads = (WSGIDaemonThread *)apr_pcalloc(p,
10659
daemon->group->threads * sizeof(WSGIDaemonThread));
8702
ap_log_error(APLOG_MARK, WSGI_LOG_DEBUG(0), wsgi_server,
8703
"mod_wsgi (pid=%d): Starting %d threads in daemon "
8704
"process '%s'.", getpid(), daemon->group->threads,
8705
daemon->group->name);
10661
if (wsgi_server_config->verbose_debugging) {
10662
ap_log_error(APLOG_MARK, WSGI_LOG_DEBUG(0), wsgi_server,
10663
"mod_wsgi (pid=%d): Starting %d threads in daemon "
10664
"process '%s'.", getpid(), daemon->group->threads,
10665
daemon->group->name);
8707
10668
for (i=0; i<daemon->group->threads; i++) {
8708
ap_log_error(APLOG_MARK, WSGI_LOG_DEBUG(0), wsgi_server,
8709
"mod_wsgi (pid=%d): Starting thread %d in daemon "
8710
"process '%s'.", getpid(), i+1, daemon->group->name);
8712
threads[i].process = daemon;
8713
threads[i].running = 0;
8715
rv = apr_thread_create(&threads[i].thread, thread_attr,
8716
wsgi_daemon_thread, &threads[i], p);
10669
WSGIDaemonThread *thread = &wsgi_worker_threads[i];
10671
if (wsgi_server_config->verbose_debugging) {
10672
ap_log_error(APLOG_MARK, WSGI_LOG_DEBUG(0), wsgi_server,
10673
"mod_wsgi (pid=%d): Starting thread %d in daemon "
10674
"process '%s'.", getpid(), i+1, daemon->group->name);
10677
/* Create the mutex and condition variable for this thread. */
10679
rv = apr_thread_cond_create(&thread->condition, p);
10681
if (rv != APR_SUCCESS) {
10682
ap_log_error(APLOG_MARK, WSGI_LOG_ALERT(rv), wsgi_server,
10683
"mod_wsgi (pid=%d): Couldn't create worker "
10684
"thread %d state condition variable in daemon "
10685
"process '%s'.", getpid(), i, daemon->group->name);
10688
* Try to force an exit of the process if fail
10689
* to create the worker threads.
10692
kill(getpid(), SIGTERM);
10696
rv = apr_thread_mutex_create(&thread->mutex,
10697
APR_THREAD_MUTEX_DEFAULT, p);
10699
if (rv != APR_SUCCESS) {
10700
ap_log_error(APLOG_MARK, WSGI_LOG_ALERT(rv), wsgi_server,
10701
"mod_wsgi (pid=%d): Couldn't create worker "
10702
"thread %d state mutex variable in daemon "
10703
"process '%s'.", getpid(), i, daemon->group->name);
10706
* Try to force an exit of the process if fail
10707
* to create the worker threads.
10710
kill(getpid(), SIGTERM);
10714
/* Now create the actual thread. */
10717
thread->process = daemon;
10718
thread->running = 0;
10720
rv = apr_thread_create(&thread->thread, thread_attr,
10721
wsgi_daemon_thread, thread, p);
8718
10723
if (rv != APR_SUCCESS) {
8719
10724
ap_log_error(APLOG_MARK, WSGI_LOG_ALERT(rv), wsgi_server,
11072
* If the daemon is associated with a virtual host then
11073
* we can close all other error logs so long as they
11074
* aren't the same one as being used for the virtual
11075
* host. If the virtual host error log is different to
11076
* the main server error log, then also tie stderr to
11077
* that log file instead. This way any debugging sent
11078
* direct to stderr from C code also goes to the virtual
11079
* host error log. We close the error logs that aren't
11080
* required as that eliminates possibility that user
11081
* code executing in daemon process could maliciously
11082
* dump messages into error log for a different virtual
11083
* host, as well as stop them being reopened with mode
11084
* that would allow seeking back to start of file and
11085
* read any information in them.
11088
if (daemon->group->server->is_virtual) {
11089
server_rec *server = NULL;
11090
apr_file_t *errfile = NULL;
11093
* Iterate over all servers and close any error
11094
* logs different to that for virtual host. Note that
11095
* if errors are being redirected to syslog, then
11096
* the server error log reference will actually be
11097
* a null pointer, so need to ensure that check for
11098
* that and don't attempt to close it in that case.
11101
server = wsgi_server;
11103
while (server != NULL) {
11104
if (server->error_log &&
11105
server->error_log != daemon->group->server->error_log) {
11106
apr_file_close(server->error_log);
11109
server = server->next;
11113
* Reassociate stderr output with error log from the
11114
* virtual host the daemon is associated with. Close
11115
* the virtual host error log and point it at stderr
11116
* log instead. Do the latter so don't get two
11117
* references to same open file. Just in case
11118
* anything still accesses error log of main server,
11119
* map main server error log to that of the virtual
11120
* host. Note that cant do this if errors are being
11121
* redirected to syslog, as indicated by virtual
11122
* host error log being a null pointer. In that case
11123
* just leave everything as it was. Also can't remap
11124
* the error log for main server if it was being
11125
* redirected to syslog but virtual host wasn't.
11128
if (daemon->group->server->error_log &&
11129
daemon->group->server->error_log != wsgi_server->error_log) {
11130
apr_file_open_stderr(&errfile, wsgi_server->process->pool);
11131
apr_file_dup2(errfile, daemon->group->server->error_log,
11132
wsgi_server->process->pool);
11134
apr_file_close(daemon->group->server->error_log);
11135
daemon->group->server->error_log = errfile;
11137
if (wsgi_server->error_log)
11138
wsgi_server->error_log = daemon->group->server->error_log;
9016
11143
* Update reference to server object in case daemon
9017
11144
* process is actually associated with a virtual host.
9018
11145
* This way all logging actually goes into the virtual
9019
11146
* hosts log file.
9022
wsgi_server = daemon->group->server;
11149
if (daemon->group->server) {
11150
if (wsgi_server_config->verbose_debugging) {
11151
ap_log_error(APLOG_MARK, WSGI_LOG_DEBUG(0), wsgi_server,
11152
"mod_wsgi (pid=%d): Process '%s' logging to "
11153
"'%s' with log level %d.", getpid(),
11154
daemon->group->name,
11155
daemon->group->server->server_hostname,
11156
daemon->group->server->loglevel);
11159
wsgi_server = daemon->group->server;
11162
if (wsgi_server_config->verbose_debugging) {
11163
ap_log_error(APLOG_MARK, WSGI_LOG_DEBUG(0), wsgi_server,
11164
"mod_wsgi (pid=%d): Process '%s' forced to log "
11165
"to '%s' with log level %d.", getpid(),
11166
daemon->group->name, wsgi_server->server_hostname,
11167
wsgi_server->loglevel);
9024
11171
/* Retain a reference to daemon process details. */
11700
* Check restrictions related to the group of the WSGI
11701
* script file and who has write access to the directory it
11702
* is contained in. If not satisfied forbid access.
11705
if (group->script_group) {
11707
struct group *grent = NULL;
11708
const char *grname = NULL;
11710
const char *path = NULL;
11712
if (!(r->finfo.valid & APR_FINFO_GROUP)) {
11713
wsgi_log_script_error(r, apr_psprintf(r->pool, "Group "
11714
"information not available for WSGI "
11715
"script file"), r->filename);
11716
return HTTP_FORBIDDEN;
11719
gid = r->finfo.group;
11721
if ((grent = getgrgid(gid)) == NULL) {
11722
wsgi_log_script_error(r, apr_psprintf(r->pool, "Couldn't "
11723
"determine group of WSGI script file, "
11724
"gid=%ld", (long)gid), r->filename);
11725
return HTTP_FORBIDDEN;
11728
grname = grent->gr_name;
11730
if (strcmp(group->script_group, grname)) {
11731
wsgi_log_script_error(r, apr_psprintf(r->pool, "Group of WSGI "
11732
"script file does not match required group "
11733
"for daemon process, group=%s", grname),
11735
return HTTP_FORBIDDEN;
11738
if (!(r->finfo.valid & APR_FINFO_WPROT)) {
11739
wsgi_log_script_error(r, apr_psprintf(r->pool, "World "
11740
"permissions not available for WSGI "
11741
"script file"), r->filename);
11742
return HTTP_FORBIDDEN;
11745
if (r->finfo.protection & APR_FPROT_WWRITE) {
11746
wsgi_log_script_error(r, apr_psprintf(r->pool, "WSGI script "
11747
"file is writable to world"), r->filename);
11748
return HTTP_FORBIDDEN;
11751
path = ap_make_dirstr_parent(r->pool, r->filename);
11753
if (apr_stat(&finfo, path, APR_FINFO_NORM, r->pool) != APR_SUCCESS) {
11754
wsgi_log_script_error(r, apr_psprintf(r->pool, "Unable to stat "
11755
"parent directory of WSGI script"), path);
11756
return HTTP_FORBIDDEN;
11761
if ((grent = getgrgid(gid)) == NULL) {
11762
wsgi_log_script_error(r, apr_psprintf(r->pool, "Couldn't "
11763
"determine group of parent directory of "
11764
"WSGI script file, gid=%ld", (long)gid),
11766
return HTTP_FORBIDDEN;
11769
grname = grent->gr_name;
11771
if (strcmp(group->script_group, grname)) {
11772
wsgi_log_script_error(r, apr_psprintf(r->pool, "Group of parent "
11773
"directory of WSGI script file does not "
11774
"match required group for daemon process, "
11775
"group=%s", grname), r->filename);
11776
return HTTP_FORBIDDEN;
11779
if (finfo.protection & APR_FPROT_WWRITE) {
11780
wsgi_log_script_error(r, apr_psprintf(r->pool, "Parent directory "
11781
"of WSGI script file is writable to world"),
11783
return HTTP_FORBIDDEN;
11788
* Check restrictions related to who can be the owner of
11789
* the WSGI script file and who has write access to the
11790
* directory it is contained in. If not satisfied forbid
11794
if (group->script_user) {
11796
struct passwd *pwent = NULL;
11797
const char *pwname = NULL;
11799
const char *path = NULL;
11801
if (!(r->finfo.valid & APR_FINFO_USER)) {
11802
wsgi_log_script_error(r, apr_psprintf(r->pool, "User "
11803
"information not available for WSGI "
11804
"script file"), r->filename);
11805
return HTTP_FORBIDDEN;
11808
uid = r->finfo.user;
11810
if ((pwent = getpwuid(uid)) == NULL) {
11811
wsgi_log_script_error(r, apr_psprintf(r->pool, "Couldn't "
11812
"determine owner of WSGI script file, "
11813
"uid=%ld", (long)uid), r->filename);
11814
return HTTP_FORBIDDEN;
11817
pwname = pwent->pw_name;
11819
if (strcmp(group->script_user, pwname)) {
11820
wsgi_log_script_error(r, apr_psprintf(r->pool, "Owner of WSGI "
11821
"script file does not match required user "
11822
"for daemon process, user=%s", pwname),
11824
return HTTP_FORBIDDEN;
11827
if (!(r->finfo.valid & APR_FINFO_GPROT)) {
11828
wsgi_log_script_error(r, apr_psprintf(r->pool, "Group "
11829
"permissions not available for WSGI "
11830
"script file"), r->filename);
11831
return HTTP_FORBIDDEN;
11834
if (r->finfo.protection & APR_FPROT_GWRITE) {
11835
wsgi_log_script_error(r, apr_psprintf(r->pool, "WSGI script "
11836
"file is writable to group"), r->filename);
11837
return HTTP_FORBIDDEN;
11840
if (!(r->finfo.valid & APR_FINFO_WPROT)) {
11841
wsgi_log_script_error(r, apr_psprintf(r->pool, "World "
11842
"permissions not available for WSGI "
11843
"script file"), r->filename);
11844
return HTTP_FORBIDDEN;
11847
if (r->finfo.protection & APR_FPROT_WWRITE) {
11848
wsgi_log_script_error(r, apr_psprintf(r->pool, "WSGI script "
11849
"file is writable to world"), r->filename);
11850
return HTTP_FORBIDDEN;
11853
path = ap_make_dirstr_parent(r->pool, r->filename);
11855
if (apr_stat(&finfo, path, APR_FINFO_NORM, r->pool) != APR_SUCCESS) {
11856
wsgi_log_script_error(r, apr_psprintf(r->pool, "Unable to stat "
11857
"parent directory of WSGI script"), path);
11858
return HTTP_FORBIDDEN;
11863
if ((pwent = getpwuid(uid)) == NULL) {
11864
wsgi_log_script_error(r, apr_psprintf(r->pool, "Couldn't "
11865
"determine owner of parent directory of "
11866
"WSGI script file, uid=%ld", (long)uid),
11868
return HTTP_FORBIDDEN;
11871
pwname = pwent->pw_name;
11873
if (strcmp(group->script_user, pwname)) {
11874
wsgi_log_script_error(r, apr_psprintf(r->pool, "Owner of parent "
11875
"directory of WSGI script file does not "
11876
"match required user for daemon process, "
11877
"user=%s", pwname), r->filename);
11878
return HTTP_FORBIDDEN;
11881
if (finfo.protection & APR_FPROT_WWRITE) {
11882
wsgi_log_script_error(r, apr_psprintf(r->pool, "Parent directory "
11883
"of WSGI script file is writable to world"),
11885
return HTTP_FORBIDDEN;
11888
if (finfo.protection & APR_FPROT_GWRITE) {
11889
wsgi_log_script_error(r, apr_psprintf(r->pool, "Parent directory "
11890
"of WSGI script file is writable to group"),
11892
return HTTP_FORBIDDEN;
9523
11897
* Add magic marker into request environment so that daemon
9524
11898
* process can verify that request is from a sender that can
9525
11899
* be trusted. Wipe out original key to make it a bit harder
9772
12152
if (r->status == 0)
9773
12153
return HTTP_INTERNAL_SERVER_ERROR;
12156
* Look for 'Location' header and if an internal
12157
* redirect, execute the redirect. This behaviour is
12158
* consistent with how mod_cgi and mod_cgid work and
12159
* what is permitted by the CGI specification.
12162
location = apr_table_get(r->headers_out, "Location");
12164
if (location && location[0] == '/' && r->status == 200) {
12166
* Discard all response content returned from
12167
* the daemon process.
12170
wsgi_discard_output(bbin);
12171
apr_brigade_destroy(bbin);
12174
* The internal redirect needs to be a GET no
12175
* matter what the original method was.
12178
r->method = apr_pstrdup(r->pool, "GET");
12179
r->method_number = M_GET;
12182
* We already read the message body (if any), so
12183
* don't allow the redirected request to think
12184
* it has one. Not sure if we need to worry
12185
* about removing 'Transfer-Encoding' header.
12188
apr_table_unset(r->headers_in, "Content-Length");
12190
ap_internal_redirect_handler(location, r);
12196
* Allow the web server to override any error
12197
* page produced by the WSGI application.
12200
if (config->error_override && ap_is_HTTP_ERROR(r->status)) {
12201
status = r->status;
12203
r->status = HTTP_OK;
12204
r->status_line = NULL;
12207
* Discard all response content returned from
12208
* the daemon process if any expected.
12211
if (!r->header_only && /* not HEAD request */
12212
(status != HTTP_NO_CONTENT) && /* not 204 */
12213
(status != HTTP_NOT_MODIFIED)) { /* not 304 */
12214
wsgi_discard_output(bbin);
12215
apr_brigade_destroy(bbin);
9775
12221
/* Transfer any response content. */
9777
12223
ap_pass_brigade(r->output_filters, bbin);
10104
12559
return HTTP_INTERNAL_SERVER_ERROR;
10107
/* Set target of request and recalculate modification time. */
10109
r->filename = (char *)apr_table_get(r->subprocess_env, "SCRIPT_FILENAME");
10111
if ((rv = apr_stat(&r->finfo, r->filename, APR_FINFO_NORM,
12562
/* Check magic marker used to validate origin of request. */
12564
filename = apr_table_get(r->subprocess_env, "SCRIPT_FILENAME");
12565
script = apr_table_get(r->subprocess_env, "mod_wsgi.handler_script");
12567
magic = apr_table_get(r->subprocess_env, "mod_wsgi.magic");
12570
ap_log_error(APLOG_MARK, WSGI_LOG_ALERT(rv), wsgi_server,
12571
"mod_wsgi (pid=%d): Request origin could not be "
12572
"validated.", getpid());
12574
apr_pool_destroy(p);
12576
return HTTP_INTERNAL_SERVER_ERROR;
12579
key = apr_psprintf(r->pool, "%ld|%s|%s|%s",
12580
wsgi_daemon_process->group->random,
12581
wsgi_daemon_process->group->socket, filename, script);
12582
hash = ap_md5(r->pool, (const unsigned char *)key);
12583
memset(key, '\0', strlen(key));
12585
if (strcmp(magic, hash) != 0) {
12586
ap_log_error(APLOG_MARK, WSGI_LOG_ALERT(rv), wsgi_server,
12587
"mod_wsgi (pid=%d): Request origin could not be "
12588
"validated.", getpid());
12590
apr_pool_destroy(p);
12592
return HTTP_INTERNAL_SERVER_ERROR;
12595
apr_table_unset(r->subprocess_env, "mod_wsgi.magic");
12598
* If we are executing in a chroot environment, we need to
12599
* adjust SCRIPT_FILENAME to remove leading portion of path
12600
* that corresponds to the location of the chroot directory.
12601
* Also need to adjust DOCUMENT_ROOT as well, although in
12602
* that case if it doesn't actually fall within the choot
12603
* directory, we just delete it outright as would be incorrect
12604
* if that directory lay outside of the chroot directory.
12607
if (wsgi_daemon_process->group->root) {
12611
root = wsgi_daemon_process->group->root;
12615
if (strstr(path, root) == path && path[strlen(root)] == '/') {
12616
path += strlen(root);
12618
apr_table_set(r->subprocess_env, "SCRIPT_FILENAME", path);
12623
ap_log_error(APLOG_MARK, WSGI_LOG_CRIT(rv), wsgi_server,
12624
"mod_wsgi (pid=%d): WSGI script '%s' not located "
12625
"within chroot directory '%s'.", getpid(), path, root);
12627
return HTTP_INTERNAL_SERVER_ERROR;
12630
path = (char *)apr_table_get(r->subprocess_env, "DOCUMENT_ROOT");
12632
if (strstr(path, root) == path) {
12633
path += strlen(root);
12635
apr_table_set(r->subprocess_env, "DOCUMENT_ROOT", path);
12638
apr_table_unset(r->subprocess_env, "DOCUMENT_ROOT");
12642
r->filename = (char *)filename;
12644
/* Recalculate WSGI script file modification time. */
12646
if ((rv = apr_stat(&r->finfo, filename, APR_FINFO_NORM,
10112
12647
r->pool)) != APR_SUCCESS) {
10114
12649
* Don't fail at this point. Allow the lack of file to
10118
12653
ap_log_error(APLOG_MARK, WSGI_LOG_WARNING(rv), wsgi_server,
10119
12654
"mod_wsgi (pid=%d): Unable to stat target WSGI script "
10120
"'%s'.", getpid(), r->filename);
12655
"'%s'.", getpid(), filename);
10122
12657
r->finfo.mtime = 0;
10125
/* Check magic marker used to validate origin of request. */
10127
magic = apr_table_get(r->subprocess_env, "mod_wsgi.magic");
10130
ap_log_error(APLOG_MARK, WSGI_LOG_ALERT(rv), wsgi_server,
10131
"mod_wsgi (pid=%d): Request origin could not be "
10132
"validated.", getpid());
10134
apr_pool_destroy(p);
10136
return HTTP_INTERNAL_SERVER_ERROR;
10139
key = apr_psprintf(r->pool, "%ld|%s|%s",
10140
wsgi_daemon_process->group->random,
10141
wsgi_daemon_process->group->socket, r->filename);
10142
hash = ap_md5(r->pool, (const unsigned char *)key);
10143
memset(key, '\0', strlen(key));
10145
if (strcmp(magic, hash) != 0) {
10146
ap_log_error(APLOG_MARK, WSGI_LOG_ALERT(rv), wsgi_server,
10147
"mod_wsgi (pid=%d): Request origin could not be "
10148
"validated.", getpid());
10150
apr_pool_destroy(p);
10152
return HTTP_INTERNAL_SERVER_ERROR;
10155
apr_table_unset(r->subprocess_env, "mod_wsgi.magic");
10158
12661
* Trigger mapping of host information to server configuration
10159
12662
* so that when logging errors they go to the correct error log
10432
13065
request_rec *r = self->r;
10433
13066
server_rec *s = r->server;
10434
13067
conn_rec *c = r->connection;
10436
13068
apr_port_t rport;
13070
const apr_array_header_t *hdrs_arr;
13071
const apr_table_entry_t *hdrs;
13073
const char *value = NULL;
10438
13077
vars = PyDict_New();
10440
object = PyString_FromString(ap_psignature("", r));
13079
hdrs_arr = apr_table_elts(r->headers_in);
13080
hdrs = (const apr_table_entry_t *) hdrs_arr->elts;
13082
for (i = 0; i < hdrs_arr->nelts; ++i) {
13083
if (!hdrs[i].key) {
13087
if (!strcasecmp(hdrs[i].key, "Content-type")) {
13088
#if PY_MAJOR_VERSION >= 3
13089
object = PyUnicode_DecodeLatin1(hdrs[i].val,
13090
strlen(hdrs[i].val), NULL);
13092
object = PyString_FromString(hdrs[i].val);
13094
PyDict_SetItemString(vars, "CONTENT_TYPE", object);
13097
else if (!strcasecmp(hdrs[i].key, "Content-length")) {
13098
#if PY_MAJOR_VERSION >= 3
13099
object = PyUnicode_DecodeLatin1(hdrs[i].val,
13100
strlen(hdrs[i].val), NULL);
13102
object = PyString_FromString(hdrs[i].val);
13104
PyDict_SetItemString(vars, "CONTENT_LENGTH", object);
13107
else if (!strcasecmp(hdrs[i].key, "Authorization")
13108
|| !strcasecmp(hdrs[i].key, "Proxy-Authorization")) {
13112
#if PY_MAJOR_VERSION >= 3
13113
object = PyUnicode_DecodeLatin1(hdrs[i].val,
13114
strlen(hdrs[i].val), NULL);
13116
object = PyString_FromString(hdrs[i].val);
13118
PyDict_SetItemString(vars, wsgi_http2env(r->pool, hdrs[i].key),
13124
value = ap_psignature("", r);
13125
#if PY_MAJOR_VERSION >= 3
13126
object = PyUnicode_DecodeLatin1(value, strlen(value), NULL);
13128
object = PyString_FromString(value);
10441
13130
PyDict_SetItemString(vars, "SERVER_SIGNATURE", object);
10442
13131
Py_DECREF(object);
10444
object = PyString_FromString(ap_get_server_version());
13133
#if AP_MODULE_MAGIC_AT_LEAST(20060905,0)
13134
value = ap_get_server_banner();
13136
value = ap_get_server_version();
13138
#if PY_MAJOR_VERSION >= 3
13139
object = PyUnicode_DecodeLatin1(value, strlen(value), NULL);
13141
object = PyString_FromString(value);
10445
13143
PyDict_SetItemString(vars, "SERVER_SOFTWARE", object);
10446
13144
Py_DECREF(object);
10448
object = PyString_FromString(ap_escape_html(r->pool,
10449
ap_get_server_name(r)));
13146
value = ap_escape_html(r->pool, ap_get_server_name(r));
13147
#if PY_MAJOR_VERSION >= 3
13148
object = PyUnicode_DecodeLatin1(value, strlen(value), NULL);
13150
object = PyString_FromString(value);
10450
13152
PyDict_SetItemString(vars, "SERVER_NAME", object);
10451
13153
Py_DECREF(object);
10453
13155
if (r->connection->local_ip) {
10454
object = PyString_FromString(r->connection->local_ip);
13156
value = r->connection->local_ip;
13157
#if PY_MAJOR_VERSION >= 3
13158
object = PyUnicode_DecodeLatin1(value, strlen(value), NULL);
13160
object = PyString_FromString(value);
10455
13162
PyDict_SetItemString(vars, "SERVER_ADDR", object);
10456
13163
Py_DECREF(object);
10459
object = PyString_FromString(apr_psprintf(r->pool, "%u",
10460
ap_get_server_port(r)));
13166
value = apr_psprintf(r->pool, "%u", ap_get_server_port(r));
13167
#if PY_MAJOR_VERSION >= 3
13168
object = PyUnicode_DecodeLatin1(value, strlen(value), NULL);
13170
object = PyString_FromString(value);
10461
13172
PyDict_SetItemString(vars, "SERVER_PORT", object);
10462
13173
Py_DECREF(object);
10464
host = ap_get_remote_host(c, r->per_dir_config, REMOTE_HOST, NULL);
10466
object = PyString_FromString(host);
13175
value = ap_get_remote_host(c, r->per_dir_config, REMOTE_HOST, NULL);
13177
#if PY_MAJOR_VERSION >= 3
13178
object = PyUnicode_DecodeLatin1(value, strlen(value), NULL);
13180
object = PyString_FromString(value);
10467
13182
PyDict_SetItemString(vars, "REMOTE_HOST", object);
10468
13183
Py_DECREF(object);
10471
13186
if (c->remote_ip) {
10472
object = PyString_FromString(c->remote_ip);
13187
value = c->remote_ip;
13188
#if PY_MAJOR_VERSION >= 3
13189
object = PyUnicode_DecodeLatin1(value, strlen(value), NULL);
13191
object = PyString_FromString(value);
10473
13193
PyDict_SetItemString(vars, "REMOTE_ADDR", object);
10474
13194
Py_DECREF(object);
13197
#if PY_MAJOR_VERSION >= 3
13198
value = ap_document_root(r);
13199
object = PyUnicode_Decode(value, strlen(value),
13200
Py_FileSystemDefaultEncoding,
13201
"surrogateescape");
10477
13203
object = PyString_FromString(ap_document_root(r));
10478
13205
PyDict_SetItemString(vars, "DOCUMENT_ROOT", object);
10479
13206
Py_DECREF(object);
10481
13208
if (s->server_admin) {
10482
object = PyString_FromString(s->server_admin);
13209
value = s->server_admin;
13210
#if PY_MAJOR_VERSION >= 3
13211
object = PyUnicode_DecodeLatin1(value, strlen(value), NULL);
13213
object = PyString_FromString(value);
10483
13215
PyDict_SetItemString(vars, "SERVER_ADMIN", object);
10484
13216
Py_DECREF(object);
10487
13219
rport = c->remote_addr->port;
10488
object = PyString_FromString(apr_itoa(r->pool, rport));
13220
value = apr_itoa(r->pool, rport);
13221
#if PY_MAJOR_VERSION >= 3
13222
object = PyUnicode_DecodeLatin1(value, strlen(value), NULL);
13224
object = PyString_FromString(value);
10489
13226
PyDict_SetItemString(vars, "REMOTE_PORT", object);
10490
13227
Py_DECREF(object);
10492
object = PyString_FromString(r->protocol);
13229
value = r->protocol;
13230
#if PY_MAJOR_VERSION >= 3
13231
object = PyUnicode_DecodeLatin1(value, strlen(value), NULL);
13233
object = PyString_FromString(value);
10493
13235
PyDict_SetItemString(vars, "SERVER_PROTOCOL", object);
10494
13236
Py_DECREF(object);
10496
object = PyString_FromString(r->method);
13239
#if PY_MAJOR_VERSION >= 3
13240
object = PyUnicode_DecodeLatin1(value, strlen(value), NULL);
13242
object = PyString_FromString(value);
10497
13244
PyDict_SetItemString(vars, "REQUEST_METHOD", object);
10498
13245
Py_DECREF(object);
10500
object = PyString_FromString(r->args ? r->args : "");
13247
value = r->args ? r->args : "";
13248
#if PY_MAJOR_VERSION >= 3
13249
object = PyUnicode_DecodeLatin1(value, strlen(value), NULL);
13251
object = PyString_FromString(value);
10501
13253
PyDict_SetItemString(vars, "QUERY_STRING", object);
10502
13254
Py_DECREF(object);
10504
object = PyString_FromString(wsgi_original_uri(r));
13256
value = wsgi_original_uri(r);
13257
#if PY_MAJOR_VERSION >= 3
13258
object = PyUnicode_DecodeLatin1(value, strlen(value), NULL);
13260
object = PyString_FromString(value);
10505
13262
PyDict_SetItemString(vars, "REQUEST_URI", object);
10506
13263
Py_DECREF(object);
13265
#if PY_MAJOR_VERSION >= 3
13266
object = PyUnicode_FromString("");
10508
13268
object = PyString_FromString("");
10509
13270
PyDict_SetItemString(vars, "mod_wsgi.process_group", object);
10510
13271
Py_DECREF(object);
13273
#if PY_MAJOR_VERSION >= 3
13274
object = PyUnicode_DecodeLatin1(group, strlen(group), NULL);
10512
13276
object = PyString_FromString(group);
10513
13278
PyDict_SetItemString(vars, "mod_wsgi.application_group", object);
10514
13279
Py_DECREF(object);
10516
object = PyInt_FromLong(self->config->script_reloading);
13281
object = PyLong_FromLong(self->config->script_reloading);
10517
13282
PyDict_SetItemString(vars, "mod_wsgi.script_reloading", object);
10518
13283
Py_DECREF(object);
10520
object = PyInt_FromLong(self->config->reload_mechanism);
10521
PyDict_SetItemString(vars, "mod_wsgi.reload_mechanism", object);
10525
13286
* Setup log object for WSGI errors. Don't decrement
10526
13287
* reference to log object as keep reference to it.
11751
14567
return status;
14570
#if defined(MOD_WSGI_WITH_AUTHZ_PROVIDER)
14572
static authz_status wsgi_check_authorization(request_rec *r,
14573
const char *require_args)
14575
WSGIRequestConfig *config;
14577
apr_table_t *grpstatus = NULL;
14581
config = wsgi_create_req_config(r->pool, r);
14583
if (!config->auth_group_script) {
14584
ap_log_error(APLOG_MARK, WSGI_LOG_ERR(0), wsgi_server,
14585
"mod_wsgi (pid=%d): Location of WSGI group "
14586
"authorization script not provided.", getpid());
14588
return AUTHZ_DENIED;
14591
status = wsgi_groups_for_user(r, config, &grpstatus);
14594
return AUTHZ_DENIED;
14596
if (apr_table_elts(grpstatus)->nelts == 0) {
14597
ap_log_rerror(APLOG_MARK, WSGI_LOG_ERR(0), r, "mod_wsgi (pid=%d): "
14598
"Authorization of user '%s' to access '%s' failed. ",
14599
"User is not a member of any groups.", getpid(),
14601
return AUTHZ_DENIED;
14605
while ((w = ap_getword_conf(r->pool, &t)) && w[0]) {
14606
if (apr_table_get(grpstatus, w)) {
14607
return AUTHZ_GRANTED;
14611
ap_log_rerror(APLOG_MARK, WSGI_LOG_ERR(0), r, "mod_wsgi (pid=%d): "
14612
"Authorization of user '%s' to access '%s' failed. "
14613
"User is not a member of designated groups.", getpid(),
14616
return AUTHZ_DENIED;
14619
static const authz_provider wsgi_authz_provider =
14621
&wsgi_check_authorization,
11754
14626
static int wsgi_hook_auth_checker(request_rec *r)
11756
14628
WSGIRequestConfig *config;
11887
14763
#if defined(MOD_WSGI_WITH_AAA_HANDLERS)
11888
#if !defined(MOD_WSGI_WITH_AUTH_PROVIDER)
14764
#if !defined(MOD_WSGI_WITH_AUTHN_PROVIDER)
11889
14765
ap_hook_check_user_id(wsgi_hook_check_user_id, p3, NULL, APR_HOOK_MIDDLE);
11891
ap_register_provider(p, AUTHN_PROVIDER_GROUP, "wsgi", "0",
11892
&wsgi_authn_provider);
14767
ap_register_provider(p, AUTHN_PROVIDER_GROUP, "wsgi",
14768
AUTHN_PROVIDER_VERSION, &wsgi_authn_provider);
14770
#if !defined(MOD_WSGI_WITH_AUTHZ_PROVIDER)
11894
14771
ap_hook_auth_checker(wsgi_hook_auth_checker, NULL, n4, APR_HOOK_MIDDLE);
14773
ap_register_provider(p, AUTHZ_PROVIDER_GROUP, "wsgi-group",
14774
AUTHZ_PROVIDER_VERSION, &wsgi_authz_provider);
11895
14776
ap_hook_access_checker(wsgi_hook_access_checker, NULL, n5, APR_HOOK_MIDDLE);
11899
14780
static const command_rec wsgi_commands[] =
11901
AP_INIT_TAKE2("WSGIScriptAlias", wsgi_add_script_alias,
14782
AP_INIT_RAW_ARGS("WSGIScriptAlias", wsgi_add_script_alias,
11902
14783
NULL, RSRC_CONF, "Map location to target WSGI script file."),
11903
AP_INIT_TAKE2("WSGIScriptAliasMatch", wsgi_add_script_alias,
14784
AP_INIT_RAW_ARGS("WSGIScriptAliasMatch", wsgi_add_script_alias,
11904
14785
"*", RSRC_CONF, "Map location pattern to target WSGI script file."),
11906
14787
#if defined(MOD_WSGI_WITH_DAEMONS)
11910
14791
NULL, RSRC_CONF, "Path prefix for the daemon process sockets."),
11911
14792
AP_INIT_TAKE1("WSGIAcceptMutex", wsgi_set_accept_mutex,
11912
14793
NULL, RSRC_CONF, "Set accept mutex type for daemon processes."),
14795
AP_INIT_TAKE1("WSGILazyInitialization", wsgi_set_lazy_initialization,
14796
NULL, RSRC_CONF, "Enable/Disable lazy Python initialization."),
14799
AP_INIT_TAKE1("WSGIVerboseDebugging", wsgi_set_verbose_debugging,
14800
NULL, RSRC_CONF, "Enable/Disable verbose debugging messages."),
14802
#if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION >= 6
14803
AP_INIT_TAKE1("WSGIPy3kWarningFlag", wsgi_set_py3k_warning_flag,
14804
NULL, RSRC_CONF, "Enable/Disable Python 3.0 warnings."),
14807
AP_INIT_TAKE1("WSGIPythonWarnings", wsgi_add_python_warnings,
14808
NULL, RSRC_CONF, "Control Python warning messages."),
11915
14809
AP_INIT_TAKE1("WSGIPythonOptimize", wsgi_set_python_optimize,
11916
14810
NULL, RSRC_CONF, "Set level of Python compiler optimisations."),
11918
14811
AP_INIT_TAKE1("WSGIPythonHome", wsgi_set_python_home,
11919
14812
NULL, RSRC_CONF, "Python prefix/exec_prefix absolute path names."),
11921
14813
AP_INIT_TAKE1("WSGIPythonPath", wsgi_set_python_path,
11922
14814
NULL, RSRC_CONF, "Python module search path."),
11923
14815
AP_INIT_TAKE1("WSGIPythonEggs", wsgi_set_python_eggs,
11924
14816
NULL, RSRC_CONF, "Python eggs cache directory."),
14818
#if defined(MOD_WSGI_WITH_DAEMONS)
11926
14819
AP_INIT_TAKE1("WSGIRestrictEmbedded", wsgi_set_restrict_embedded,
11927
14820
NULL, RSRC_CONF, "Enable/Disable use of embedded mode."),
11928
14822
AP_INIT_TAKE1("WSGIRestrictStdin", wsgi_set_restrict_stdin,
11929
14823
NULL, RSRC_CONF, "Enable/Disable restrictions on use of STDIN."),
11930
14824
AP_INIT_TAKE1("WSGIRestrictStdout", wsgi_set_restrict_stdout,
11952
14846
AP_INIT_RAW_ARGS("WSGIDispatchScript", wsgi_set_dispatch_script,
11953
14847
NULL, ACCESS_CONF|RSRC_CONF, "Location of WSGI dispatch script."),
11955
AP_INIT_TAKE1("WSGIApacheExtensions", wsgi_set_apache_extensions,
11956
NULL, ACCESS_CONF|RSRC_CONF, "Enable/Disable Apache extensions."),
14849
AP_INIT_TAKE1("WSGIPassApacheRequest", wsgi_set_pass_apache_request,
14850
NULL, ACCESS_CONF|RSRC_CONF, "Enable/Disable Apache request object."),
11957
14851
AP_INIT_TAKE1("WSGIPassAuthorization", wsgi_set_pass_authorization,
11958
14852
NULL, OR_FILEINFO, "Enable/Disable WSGI authorization."),
11959
14853
AP_INIT_TAKE1("WSGIScriptReloading", wsgi_set_script_reloading,
11960
14854
NULL, OR_FILEINFO, "Enable/Disable script reloading mechanism."),
11961
AP_INIT_TAKE1("WSGIReloadMechanism", wsgi_set_reload_mechanism,
11962
NULL, OR_FILEINFO, "Defines what is reloaded when a reload occurs."),
14855
AP_INIT_TAKE1("WSGIErrorOverride", wsgi_set_error_override,
14856
NULL, OR_FILEINFO, "Enable/Disable overriding of error pages."),
14857
AP_INIT_TAKE1("WSGIChunkedRequest", wsgi_set_chunked_request,
14858
NULL, OR_FILEINFO, "Enable/Disable support for chunked requests."),
11964
14860
#if defined(MOD_WSGI_WITH_AAA_HANDLERS)
11965
14861
AP_INIT_RAW_ARGS("WSGIAccessScript", wsgi_set_access_script,