summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/__init__.py64
-rw-r--r--src/server/management/commands/runmodwsgi.py57
-rw-r--r--src/server/mod_wsgi.c80
-rw-r--r--src/server/wsgi_daemon.h1
-rw-r--r--src/server/wsgi_interp.c12
-rw-r--r--src/server/wsgi_logger.c182
-rw-r--r--src/server/wsgi_logger.h8
-rw-r--r--src/server/wsgi_metrics.c6
-rw-r--r--src/server/wsgi_thread.c2
-rw-r--r--src/server/wsgi_thread.h2
-rw-r--r--src/server/wsgi_version.h4
11 files changed, 297 insertions, 121 deletions
diff --git a/src/server/__init__.py b/src/server/__init__.py
index a182bd0..d7f50c2 100644
--- a/src/server/__init__.py
+++ b/src/server/__init__.py
@@ -276,8 +276,13 @@ LimitRequestBody %(limit_request_body)s
<Directory />
AllowOverride None
+<IfVersion < 2.4>
Order deny,allow
Deny from all
+</IfVersion>
+<IfVersion >= 2.4>
+ Require all denied
+</IfVersion>
</Directory>
WSGIPythonHome '%(python_home)s'
@@ -304,6 +309,7 @@ WSGIDaemonProcess %(host)s:%(port)s \\
connect-timeout=%(connect_timeout)s \\
request-timeout=%(request_timeout)s \\
inactivity-timeout=%(inactivity_timeout)s \\
+ startup-timeout=%(startup_timeout)s \\
deadlock-timeout=%(deadlock_timeout)s \\
graceful-timeout=%(graceful_timeout)s \\
eviction-timeout=%(eviction_timeout)s \\
@@ -330,6 +336,7 @@ WSGIDaemonProcess %(host)s:%(port)s \\
connect-timeout=%(connect_timeout)s \\
request-timeout=%(request_timeout)s \\
inactivity-timeout=%(inactivity_timeout)s \\
+ startup-timeout=%(startup_timeout)s \\
deadlock-timeout=%(deadlock_timeout)s \\
graceful-timeout=%(graceful_timeout)s \\
eviction-timeout=%(eviction_timeout)s \\
@@ -361,9 +368,15 @@ WSGIServerMetrics %(server_metrics_flag)s
<IfDefine MOD_WSGI_SERVER_STATUS>
<Location /server-status>
SetHandler server-status
+<IfVersion < 2.4>
Order deny,allow
Deny from all
Allow from localhost
+</IfVersion>
+<IfVersion >= 2.4>
+ Require all denied
+ Require host localhost
+</IfVersion>
</Location>
</IfDefine>
@@ -510,8 +523,13 @@ NameVirtualHost *:%(port)s
</IfVersion>
<VirtualHost _default_:%(port)s>
<Location />
+<IfVersion < 2.4>
Order deny,allow
Deny from all
+</IfVersion>
+<IfVersion >= 2.4>
+Require all denied
+</IfVersion>
<IfDefine MOD_WSGI_ALLOW_LOCALHOST>
Allow from localhost
</IfDefine>
@@ -568,8 +586,13 @@ NameVirtualHost *:%(https_port)s
</IfVersion>
<VirtualHost _default_:%(https_port)s>
<Location />
+<IfVersion < 2.4>
Order deny,allow
Deny from all
+</IfVersion>
+<IfVersion >= 2.4>
+Require all denied
+</IfVersion>
<IfDefine MOD_WSGI_ALLOW_LOCALHOST>
Allow from localhost
</IfDefine>
@@ -633,8 +656,13 @@ DocumentRoot '%(document_root)s'
<Directory '%(server_root)s'>
<Files handler.wsgi>
+<IfVersion < 2.4>
Order allow,deny
Allow from all
+</IfVersion>
+<IfVersion >= 2.4>
+ Require all granted
+</IfVersion>
</Files>
</Directory>
@@ -663,8 +691,13 @@ DocumentRoot '%(document_root)s'
</IfDefine>
RewriteRule .* - [H=wsgi-handler]
</IfDefine>
+<IfVersion < 2.4>
Order allow,deny
Allow from all
+</IfVersion>
+<IfVersion >= 2.4>
+ Require all granted
+</IfVersion>
</Directory>
<IfDefine MOD_WSGI_ERROR_OVERRIDE>
@@ -765,8 +798,13 @@ APACHE_ALIAS_DIRECTORY_CONFIG = """
Alias '%(mount_point)s' '%(directory)s'
<Directory '%(directory)s'>
+<IfVersion < 2.4>
Order allow,deny
Allow from all
+</IfVersion>
+<IfVersion >= 2.4>
+ Require all granted
+</IfVersion>
</Directory>
"""
@@ -775,8 +813,13 @@ Alias '%(mount_point)s' '%(directory)s/%(filename)s'
<Directory '%(directory)s'>
<Files '%(filename)s'>
+<IfVersion < 2.4>
Order allow,deny
Allow from all
+</IfVersion>
+<IfVersion >= 2.4>
+ Require all granted
+</IfVersion>
</Files>
</Directory>
"""
@@ -787,13 +830,23 @@ Alias /__wsgi__/images '%(images_directory)s'
<Directory '%(documentation_directory)s'>
DirectoryIndex index.html
+<IfVersion < 2.4>
Order allow,deny
Allow from all
+</IfVersion>
+<IfVersion >= 2.4>
+ Require all granted
+</IfVersion>
</Directory>
<Directory '%(images_directory)s'>
+<IfVersion < 2.4>
Order allow,deny
Allow from all
+</IfVersion>
+<IfVersion >= 2.4>
+ Require all granted
+</IfVersion>
</Directory>
"""
@@ -1920,6 +1973,14 @@ option_list = (
'worker process should never be restarted based on the number '
'of requests received.'),
+ optparse.make_option('--startup-timeout', type='int', default=15,
+ metavar='SECONDS', help='Maximum number of seconds allowed '
+ 'to pass waiting for the application to be successfully '
+ 'loaded and started by a worker process. When this timeout '
+ 'has been reached without the application having been '
+ 'successfully loaded and started, the worker process will '
+ 'be forced to restart. Defaults to 15 seconds.'),
+
optparse.make_option('--shutdown-timeout', type='int', default=5,
metavar='SECONDS', help='Maximum number of seconds allowed '
'to pass when waiting for a worker process to shutdown as a '
@@ -3129,6 +3190,9 @@ def _cmd_setup_server(command, args, options):
print('Request Timeout : %s (seconds)' % options['request_timeout'])
+ if options['startup_timeout']:
+ print('Startup Timeout : %s (seconds)' % options['startup_timeout'])
+
print('Queue Backlog : %s (connections)' % options['daemon_backlog'])
print('Queue Timeout : %s (seconds)' % options['queue_timeout'])
diff --git a/src/server/management/commands/runmodwsgi.py b/src/server/management/commands/runmodwsgi.py
index 02ba17a..74eaf13 100644
--- a/src/server/management/commands/runmodwsgi.py
+++ b/src/server/management/commands/runmodwsgi.py
@@ -6,11 +6,60 @@ from django.core.management.base import BaseCommand
import mod_wsgi.server
+def check_percentage(string):
+ if value is not None and value < 0 or value > 1:
+ import argparse
+ msg = '%s option value needs to be within the range 0 to 1.' % string
+ raise argparse.ArgumentTypeError(msg)
+ return value
+
class Command(BaseCommand):
- option_list = BaseCommand.option_list + mod_wsgi.server.option_list
+
args = ''
help = 'Starts Apache/mod_wsgi web server.'
+ if hasattr('BaseCommand', 'option_list'):
+ # Used prior to Django 1.10.
+
+ option_list = BaseCommand.option_list + mod_wsgi.server.option_list
+
+ else:
+ # This horrible mess tries to convert optparse option list to
+ # argparse as required by Django 1.10+. We can't switch to
+ # using argparse as need to still support Python 2.6, which
+ # lacks the argparse module.
+
+ def add_arguments(self, parser):
+ ignore = set(['const', 'callback', 'callback_args',
+ 'callback_kwargs'])
+ types = { 'int': int, 'string': str }
+
+ for option in mod_wsgi.server.option_list:
+ opts = option._short_opts + option._long_opts
+ kwargs = {}
+
+ for attr in option.ATTRS:
+ if attr not in ignore and hasattr(option, attr):
+ if attr == 'type':
+ if getattr(option, attr) in types:
+ kwargs[attr] = types[getattr(option, attr)]
+ elif attr == 'default':
+ if getattr(option, attr) != ('NO', 'DEFAULT'):
+ kwargs[attr] = getattr(option, attr)
+ else:
+ if getattr(option, attr) is not None:
+ kwargs[attr] = getattr(option, attr)
+
+ if (kwargs.get('action') == 'callback' and
+ option.callback.__name__ == 'check_percentage'):
+ del kwargs['action']
+ kwargs['type'] = check_percentage
+
+ if kwargs.get('nargs') == 1:
+ del kwargs['nargs']
+
+ parser.add_argument(*opts, **kwargs)
+
def handle(self, *args, **options):
self.stdout.write('Successfully ran command.')
@@ -36,8 +85,10 @@ class Command(BaseCommand):
if hasattr(settings, 'BASE_DIR'):
options['working_directory'] = settings.BASE_DIR
else:
- settings_mod = sys.modules[os.environ['DJANGO_SETTINGS_MODULE']]
- parent = os.path.dirname(os.path.dirname(settings_mod.__file__))
+ settings_module_path = os.environ['DJANGO_SETTINGS_MODULE']
+ root_module_path = settings_module_path.split('.')[0]
+ root_module = sys.modules[root_module_path]
+ parent = os.path.dirname(os.path.dirname(root_module.__file__))
options['working_directory'] = parent
url_aliases = options.setdefault('url_aliases') or []
diff --git a/src/server/mod_wsgi.c b/src/server/mod_wsgi.c
index d684dd7..3c309ce 100644
--- a/src/server/mod_wsgi.c
+++ b/src/server/mod_wsgi.c
@@ -82,11 +82,13 @@ static int volatile wsgi_daemon_shutdown = 0;
static int volatile wsgi_daemon_graceful = 0;
#if defined(MOD_WSGI_WITH_DAEMONS)
+static apr_interval_time_t wsgi_startup_timeout = 0;
static apr_interval_time_t wsgi_deadlock_timeout = 0;
static apr_interval_time_t wsgi_idle_timeout = 0;
static apr_interval_time_t wsgi_request_timeout = 0;
static apr_interval_time_t wsgi_graceful_timeout = 0;
static apr_interval_time_t wsgi_eviction_timeout = 0;
+static apr_time_t volatile wsgi_startup_shutdown_time = 0;
static apr_time_t volatile wsgi_deadlock_shutdown_time = 0;
static apr_time_t volatile wsgi_idle_shutdown_time = 0;
static apr_time_t volatile wsgi_graceful_shutdown_time = 0;
@@ -1033,7 +1035,7 @@ static apr_status_t wsgi_strtoff(apr_off_t *offset, const char *nptr,
return APR_FROM_OS_ERROR(errno);
}
-static long Input_read_from_input(InputObject *self, char *buffer,
+static apr_int64_t Input_read_from_input(InputObject *self, char *buffer,
apr_size_t bufsiz)
{
request_rec *r = self->r;
@@ -1214,7 +1216,7 @@ static PyObject *Input_read(InputObject *self, PyObject *args)
apr_size_t length = 0;
int init = 0;
- apr_size_t n;
+ apr_int64_t n;
if (!self->r) {
PyErr_SetString(PyExc_RuntimeError, "request object has expired");
@@ -1490,7 +1492,7 @@ static PyObject *Input_readline(InputObject *self, PyObject *args)
char *buffer = NULL;
apr_size_t length = 0;
- apr_size_t n;
+ apr_int64_t n;
if (!self->r) {
PyErr_SetString(PyExc_RuntimeError, "request object has expired");
@@ -1938,6 +1940,7 @@ typedef struct {
apr_bucket_brigade *bb;
WSGIRequestConfig *config;
InputObject *input;
+ PyObject *log_buffer;
PyObject *log;
int status;
const char *status_line;
@@ -1983,7 +1986,9 @@ static AdapterObject *newAdapterObject(request_rec *r)
self->output_time = 0;
self->input = newInputObject(r);
- self->log = newLogObject(r, APLOG_ERR, NULL);
+
+ self->log_buffer = newLogBufferObject(r, APLOG_ERR, "wsgi.errors", 0);
+ self->log = newLogWrapperObject(self->log_buffer);
return self;
}
@@ -1994,6 +1999,8 @@ static void Adapter_dealloc(AdapterObject *self)
Py_XDECREF(self->sequence);
Py_DECREF(self->input);
+
+ Py_DECREF(self->log_buffer);
Py_DECREF(self->log);
PyObject_Del(self);
@@ -3771,6 +3778,19 @@ static int wsgi_execute_script(request_rec *r)
return HTTP_INTERNAL_SERVER_ERROR;
}
+ /* Setup startup timeout if first request and specified. */
+
+ if (wsgi_daemon_process) {
+ if (wsgi_startup_shutdown_time == 0) {
+ if (wsgi_startup_timeout > 0) {
+ apr_thread_mutex_lock(wsgi_monitor_lock);
+ wsgi_startup_shutdown_time = apr_time_now();
+ wsgi_startup_shutdown_time += wsgi_startup_timeout;
+ apr_thread_mutex_unlock(wsgi_monitor_lock);
+ }
+ }
+ }
+
/*
* Use a lock around the check to see if the module is
* already loaded and the import of the module to prevent
@@ -3997,8 +4017,8 @@ static int wsgi_execute_script(request_rec *r)
PyObject *method = NULL;
PyObject *args = NULL;
- Py_INCREF(adapter->log);
- thread_info->log = adapter->log;
+ Py_INCREF(adapter->log_buffer);
+ thread_info->log_buffer = adapter->log_buffer;
Py_INCREF(object);
status = Adapter_run(adapter, object);
@@ -4034,12 +4054,16 @@ static int wsgi_execute_script(request_rec *r)
Py_XDECREF(object);
Py_XDECREF(method);
- Py_CLEAR(thread_info->log);
+ Py_CLEAR(thread_info->log_buffer);
adapter->bb = NULL;
}
Py_XDECREF((PyObject *)adapter);
+
+ /* Clear startup timeout and prevent from running again. */
+
+ wsgi_startup_shutdown_time = -1;
}
else {
Py_BEGIN_ALLOW_THREADS
@@ -6103,7 +6127,7 @@ static DispatchObject *newDispatchObject(request_rec *r,
self->r = r;
- self->log = newLogObject(r, APLOG_ERR, NULL);
+ self->log = newLogObject(r, APLOG_ERR, NULL, 0);
return self;
}
@@ -7084,6 +7108,7 @@ static const char *wsgi_add_daemon_process(cmd_parms *cmd, void *mconfig,
int stack_size = 0;
int maximum_requests = 0;
+ int startup_timeout = 0;
int shutdown_timeout = 5;
int deadlock_timeout = 300;
int inactivity_timeout = 0;
@@ -7262,6 +7287,14 @@ static const char *wsgi_add_daemon_process(cmd_parms *cmd, void *mconfig,
if (maximum_requests < 0)
return "Invalid request count for WSGI daemon process.";
}
+ else if (!strcmp(option, "startup-timeout")) {
+ if (!*value)
+ return "Invalid startup timeout for WSGI daemon process.";
+
+ startup_timeout = atoi(value);
+ if (startup_timeout < 0)
+ return "Invalid startup timeout for WSGI daemon process.";
+ }
else if (!strcmp(option, "shutdown-timeout")) {
if (!*value)
return "Invalid shutdown timeout for WSGI daemon process.";
@@ -7575,6 +7608,7 @@ static const char *wsgi_add_daemon_process(cmd_parms *cmd, void *mconfig,
entry->stack_size = stack_size;
entry->maximum_requests = maximum_requests;
entry->shutdown_timeout = shutdown_timeout;
+ entry->startup_timeout = apr_time_from_sec(startup_timeout);
entry->deadlock_timeout = apr_time_from_sec(deadlock_timeout);
entry->inactivity_timeout = apr_time_from_sec(inactivity_timeout);
entry->request_timeout = apr_time_from_sec(request_timeout);
@@ -8780,6 +8814,9 @@ static void *wsgi_monitor_thread(apr_thread_t *thd, void *data)
"process '%s'.", getpid(), group->name);
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, wsgi_server,
+ "mod_wsgi (pid=%d): Startup timeout is %d.",
+ getpid(), (int)(apr_time_sec(wsgi_startup_timeout)));
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, wsgi_server,
"mod_wsgi (pid=%d): Deadlock timeout is %d.",
getpid(), (int)(apr_time_sec(wsgi_deadlock_timeout)));
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, wsgi_server,
@@ -8799,6 +8836,7 @@ static void *wsgi_monitor_thread(apr_thread_t *thd, void *data)
while (1) {
apr_time_t now;
+ apr_time_t startup_time;
apr_time_t deadlock_time;
apr_time_t idle_time;
apr_time_t graceful_time;
@@ -8813,6 +8851,7 @@ static void *wsgi_monitor_thread(apr_thread_t *thd, void *data)
apr_thread_mutex_lock(wsgi_monitor_lock);
+ startup_time = wsgi_startup_shutdown_time;
deadlock_time = wsgi_deadlock_shutdown_time;
idle_time = wsgi_idle_shutdown_time;
graceful_time = wsgi_graceful_shutdown_time;
@@ -8841,6 +8880,22 @@ static void *wsgi_monitor_thread(apr_thread_t *thd, void *data)
}
}
+ if (!restart && wsgi_startup_timeout) {
+ if (startup_time > 0) {
+ if (startup_time <= now) {
+ ap_log_error(APLOG_MARK, APLOG_INFO, 0, wsgi_server,
+ "mod_wsgi (pid=%d): Application startup "
+ "timer expired, stopping process '%s'.",
+ getpid(), group->name);
+
+ restart = 1;
+ }
+ else {
+ period = startup_time - now;
+ }
+ }
+ }
+
if (!restart && wsgi_deadlock_timeout) {
if (deadlock_time) {
if (deadlock_time <= now) {
@@ -8852,11 +8907,13 @@ static void *wsgi_monitor_thread(apr_thread_t *thd, void *data)
restart = 1;
}
else {
- period = deadlock_time - now;
+ if (!period || ((deadlock_time - now) < period))
+ period = deadlock_time - now;
}
}
else {
- period = wsgi_deadlock_timeout;
+ if (!period || (wsgi_deadlock_timeout < period))
+ period = wsgi_deadlock_timeout;
}
}
@@ -9094,6 +9151,7 @@ static void wsgi_daemon_main(apr_pool_t *p, WSGIDaemonProcess *daemon)
/* Start monitoring thread if required. */
+ wsgi_startup_timeout = daemon->group->startup_timeout;
wsgi_deadlock_timeout = daemon->group->deadlock_timeout;
wsgi_idle_timeout = daemon->group->inactivity_timeout;
wsgi_request_timeout = daemon->group->request_timeout;
@@ -13455,7 +13513,7 @@ static AuthObject *newAuthObject(request_rec *r, WSGIRequestConfig *config)
self->r = r;
- self->log = newLogObject(r, APLOG_ERR, NULL);
+ self->log = newLogObject(r, APLOG_ERR, NULL, 0);
return self;
}
diff --git a/src/server/wsgi_daemon.h b/src/server/wsgi_daemon.h
index ed6b56a..7ae4644 100644
--- a/src/server/wsgi_daemon.h
+++ b/src/server/wsgi_daemon.h
@@ -109,6 +109,7 @@ typedef struct {
int stack_size;
int maximum_requests;
int shutdown_timeout;
+ apr_time_t startup_timeout;
apr_time_t deadlock_timeout;
apr_time_t inactivity_timeout;
apr_time_t request_timeout;
diff --git a/src/server/wsgi_interp.c b/src/server/wsgi_interp.c
index d74cb10..5ffc82c 100644
--- a/src/server/wsgi_interp.c
+++ b/src/server/wsgi_interp.c
@@ -98,7 +98,7 @@ static PyObject *SignalIntercept_call(
PyObject *args = NULL;
PyObject *result = NULL;
Py_INCREF(o);
- log = newLogObject(NULL, APLOG_WARNING, NULL);
+ log = newLogObject(NULL, APLOG_WARNING, NULL, 0);
args = Py_BuildValue("(OOO)", Py_None, Py_None, log);
result = PyEval_CallObject(o, args);
Py_XDECREF(result);
@@ -269,7 +269,7 @@ static PyObject *ShutdownInterpreter_call(
PyObject *log = NULL;
PyObject *args = NULL;
Py_INCREF(o);
- log = newLogObject(NULL, APLOG_ERR, NULL);
+ log = newLogObject(NULL, APLOG_ERR, NULL, 0);
args = Py_BuildValue("(OOOOO)", type, value,
traceback, Py_None, log);
result = PyEval_CallObject(o, args);
@@ -516,7 +516,7 @@ InterpreterObject *newInterpreterObject(const char *name)
* the 'pdb' module.
*/
- object = newLogObject(NULL, APLOG_ERR, "stderr");
+ object = newLogObject(NULL, APLOG_ERR, "stderr", 1);
PySys_SetObject("stderr", object);
Py_DECREF(object);
@@ -529,7 +529,7 @@ InterpreterObject *newInterpreterObject(const char *name)
Py_DECREF(object);
}
else {
- object = newLogObject(NULL, APLOG_ERR, "stdout");
+ object = newLogObject(NULL, APLOG_ERR, "stdout", 1);
PySys_SetObject("stdout", object);
Py_DECREF(object);
}
@@ -1614,7 +1614,7 @@ static void Interpreter_dealloc(InterpreterObject *self)
PyObject *log = NULL;
PyObject *args = NULL;
Py_INCREF(o);
- log = newLogObject(NULL, APLOG_ERR, NULL);
+ log = newLogObject(NULL, APLOG_ERR, NULL, 0);
args = Py_BuildValue("(OOOOO)", type, value,
traceback, Py_None, log);
result = PyEval_CallObject(o, args);
@@ -1747,7 +1747,7 @@ static void Interpreter_dealloc(InterpreterObject *self)
PyObject *log = NULL;
PyObject *args = NULL;
Py_INCREF(o);
- log = newLogObject(NULL, APLOG_ERR, NULL);
+ log = newLogObject(NULL, APLOG_ERR, NULL, 0);
args = Py_BuildValue("(OOOOO)", type, value,
traceback, Py_None, log);
result = PyEval_CallObject(o, args);
diff --git a/src/server/wsgi_logger.c b/src/server/wsgi_logger.c
index 717083e..07ae4bb 100644
--- a/src/server/wsgi_logger.c
+++ b/src/server/wsgi_logger.c
@@ -28,7 +28,8 @@
typedef struct {
PyObject_HEAD
- const char *target;
+ const char *name;
+ int proxy;
request_rec *r;
int level;
char *s;
@@ -41,16 +42,37 @@ typedef struct {
PyTypeObject Log_Type;
-PyObject *newLogObject(request_rec *r, int level, const char *target)
+PyObject *newLogBufferObject(request_rec *r, int level, const char *name,
+ int proxy)
{
LogObject *self;
+ self = PyObject_New(LogObject, &Log_Type);
+ if (self == NULL)
+ return NULL;
+
+ self->name = name;
+ self->proxy = proxy;
+ self->r = r;
+ self->level = APLOG_NOERRNO|level;
+ self->s = NULL;
+ self->l = 0;
+ self->expired = 0;
+#if PY_MAJOR_VERSION < 3
+ self->softspace = 0;
+#endif
+
+ return (PyObject *)self;
+}
+
+PyObject *newLogWrapperObject(PyObject *buffer)
+{
#if PY_MAJOR_VERSION >= 3
PyObject *module = NULL;
PyObject *dict = NULL;
PyObject *object = NULL;
PyObject *args = NULL;
- PyObject *result = NULL;
+ PyObject *wrapper = NULL;
module = PyImport_ImportModule("io");
@@ -65,44 +87,50 @@ PyObject *newLogObject(request_rec *r, int level, const char *target)
"name 'TextIOWrapper' is not defined");
return NULL;
}
-#endif
- self = PyObject_New(LogObject, &Log_Type);
- if (self == NULL)
- return NULL;
+ Py_INCREF(object);
- self->target = target;
- self->r = r;
- self->level = APLOG_NOERRNO|level;
- self->s = NULL;
- self->l = 0;
- self->expired = 0;
-#if PY_MAJOR_VERSION < 3
- self->softspace = 0;
-#endif
+ args = Py_BuildValue("(OssOOO)", buffer, "utf-8", "replace",
+ Py_None, Py_True, Py_True);
+
+ wrapper = PyEval_CallObject(object, args);
-#if PY_MAJOR_VERSION >= 3
- Py_INCREF(object);
- args = Py_BuildValue("(OssOO)", self, "utf-8", "replace",
- Py_None, Py_True);
- Py_DECREF(self);
- result = PyEval_CallObject(object, args);
Py_DECREF(args);
Py_DECREF(object);
- return result;
+ return (PyObject *)wrapper;
#else
- return (PyObject *)self;
+ Py_INCREF(buffer);
+
+ return (PyObject *)buffer;
#endif
}
+PyObject *newLogObject(request_rec *r, int level, const char *name,
+ int proxy)
+{
+ PyObject *buffer = NULL;
+ PyObject *wrapper = NULL;
+
+ buffer = newLogBufferObject(r, level, name, proxy);
+
+ if (!buffer)
+ return NULL;
+
+ wrapper = newLogWrapperObject(buffer);
+
+ Py_DECREF(buffer);
+
+ return wrapper;
+}
+
#if 0
static void Log_file(LogObject *self, const char *s, int l)
{
/*
* XXX This function is not currently being used.
* The intention was that it be called instead of
- * Log_call() when 'target' is non zero. This would
+ * Log_call() when 'name' is non zero. This would
* be the case for 'stdout' and 'stderr'. Doing
* this bypasses normally Apache logging mechanisms
* though. May reawaken this code in mod_wsgi 4.0
@@ -129,13 +157,13 @@ static void Log_file(LogObject *self, const char *s, int l)
errstr[1 + APR_CTIME_LEN ] = ' ';
plen = 1 + APR_CTIME_LEN + 1;
- if (self->target) {
+ if (self->name) {
int len;
errstr[plen++] = '[';
- len = strlen(self->target);
- memcpy(errstr+plen, self->target, len);
+ len = strlen(self->name);
+ memcpy(errstr+plen, self->name, len);
plen += len;
@@ -221,6 +249,14 @@ static void Log_dealloc(LogObject *self)
static PyObject *Log_flush(LogObject *self, PyObject *args)
{
+ WSGIThreadInfo *thread_info = NULL;
+
+ if (self->proxy)
+ thread_info = wsgi_thread_info(0, 0);
+
+ if (thread_info && thread_info->log_buffer)
+ return Log_flush((LogObject *)thread_info->log_buffer, args);
+
if (self->expired) {
PyErr_SetString(PyExc_RuntimeError, "log object has expired");
return NULL;
@@ -242,6 +278,14 @@ static PyObject *Log_close(LogObject *self, PyObject *args)
{
PyObject *result = NULL;
+ WSGIThreadInfo *thread_info = NULL;
+
+ if (self->proxy)
+ thread_info = wsgi_thread_info(0, 0);
+
+ if (thread_info && thread_info->log_buffer)
+ return Log_close((LogObject *)thread_info->log_buffer, args);
+
if (!self->expired)
result = Log_flush(self, args);
@@ -369,21 +413,13 @@ static PyObject *Log_write(LogObject *self, PyObject *args)
const char *msg = NULL;
int len = -1;
-#if 0
WSGIThreadInfo *thread_info = NULL;
- thread_info = wsgi_thread_info(0, 0);
-
- if (thread_info && thread_info->log && thread_info->log != (PyObject *)self) {
- PyObject *result;
+ if (self->proxy)
+ thread_info = wsgi_thread_info(0, 0);
- Py_INCREF(thread_info->log);
- result = Log_write((LogObject *)thread_info->log, args);
- Py_DECREF(thread_info->log);
-
- return result;
- }
-#endif
+ if (thread_info && thread_info->log_buffer)
+ return Log_write((LogObject *)thread_info->log_buffer, args);
if (self->expired) {
PyErr_SetString(PyExc_RuntimeError, "log object has expired");
@@ -405,21 +441,13 @@ static PyObject *Log_writelines(LogObject *self, PyObject *args)
PyObject *iterator = NULL;
PyObject *item = NULL;
-#if 0
WSGIThreadInfo *thread_info = NULL;
- thread_info = wsgi_thread_info(0, 0);
-
- if (thread_info && thread_info->log && thread_info->log != (PyObject *)self) {
- PyObject *result;
+ if (self->proxy)
+ thread_info = wsgi_thread_info(0, 0);
- Py_INCREF(thread_info->log);
- result = Log_writelines((LogObject *)thread_info->log, args);
- Py_DECREF(thread_info->log);
-
- return result;
- }
-#endif
+ if (thread_info && thread_info->log_buffer)
+ return Log_writelines((LogObject *)thread_info->log_buffer, args);
if (self->expired) {
PyErr_SetString(PyExc_RuntimeError, "log object has expired");
@@ -502,21 +530,13 @@ static PyObject *Log_closed(LogObject *self, void *closure)
#if PY_MAJOR_VERSION < 3
static PyObject *Log_get_softspace(LogObject *self, void *closure)
{
-#if 0
WSGIThreadInfo *thread_info = NULL;
- thread_info = wsgi_thread_info(0, 0);
-
- if (thread_info && thread_info->log && thread_info->log != (PyObject *)self) {
- PyObject *result;
+ if (self->proxy)
+ thread_info = wsgi_thread_info(0, 0);
- Py_INCREF(thread_info->log);
- result = Log_get_softspace((LogObject *)thread_info->log, closure);
- Py_DECREF(thread_info->log);
-
- return result;
- }
-#endif
+ if (thread_info && thread_info->log_buffer)
+ return Log_get_softspace((LogObject *)thread_info->log_buffer, closure);
return PyInt_FromLong(self->softspace);
}
@@ -525,21 +545,13 @@ static int Log_set_softspace(LogObject *self, PyObject *value)
{
long new;
-#if 0
WSGIThreadInfo *thread_info = NULL;
- thread_info = wsgi_thread_info(0, 0);
-
- if (thread_info && thread_info->log && thread_info->log != (PyObject *)self) {
- PyObject *result;
+ if (self->proxy)
+ thread_info = wsgi_thread_info(0, 0);
- Py_INCREF(thread_info->log);
- result = Log_set_softspace((LogObject *)thread_info->log, value);
- Py_DECREF(thread_info->log);
-
- return result;
- }
-#endif
+ if (thread_info && thread_info->log_buffer)
+ return Log_set_softspace((LogObject *)thread_info->log_buffer, value);
if (value == NULL) {
PyErr_SetString(PyExc_TypeError, "can't delete softspace attribute");
@@ -559,22 +571,6 @@ static int Log_set_softspace(LogObject *self, PyObject *value)
static PyObject *Log_get_encoding(LogObject *self, void *closure)
{
-#if 0
- WSGIThreadInfo *thread_info = NULL;
-
- thread_info = wsgi_thread_info(0, 0);
-
- if (thread_info && thread_info->log && thread_info->log != (PyObject *)self) {
- PyObject *result;
-
- Py_INCREF(thread_info->log);
- result = Log_get_encoding((LogObject *)thread_info->log, closure);
- Py_DECREF(thread_info->log);
-
- return result;
- }
-#endif
-
return PyUnicode_FromString("utf-8");
}
@@ -672,7 +668,7 @@ void wsgi_log_python_error(request_rec *r, PyObject *log,
if (!log) {
PyErr_Fetch(&type, &value, &traceback);
- xlog = newLogObject(r, APLOG_ERR, NULL);
+ xlog = newLogObject(r, APLOG_ERR, NULL, 0);
log = xlog;
diff --git a/src/server/wsgi_logger.h b/src/server/wsgi_logger.h
index ff2cf43..d89a497 100644
--- a/src/server/wsgi_logger.h
+++ b/src/server/wsgi_logger.h
@@ -28,7 +28,13 @@
extern PyTypeObject Log_Type;
-extern PyObject *newLogObject(request_rec *r, int level, const char *target);
+extern PyObject *newLogBufferObject(request_rec *r, int level,
+ const char *name, int proxy);
+
+extern PyObject *newLogWrapperObject(PyObject *buffer);
+
+extern PyObject *newLogObject(request_rec *r, int level, const char *name,
+ int proxy);
extern void wsgi_log_python_error(request_rec *r, PyObject *log,
const char *filename, int publish);
diff --git a/src/server/wsgi_metrics.c b/src/server/wsgi_metrics.c
index 9f4558a..32fe40a 100644
--- a/src/server/wsgi_metrics.c
+++ b/src/server/wsgi_metrics.c
@@ -96,8 +96,8 @@ void wsgi_end_request(void)
thread_info = wsgi_thread_info(0, 1);
if (thread_info) {
- if (thread_info->log)
- Py_CLEAR(thread_info->log);
+ if (thread_info->log_buffer)
+ Py_CLEAR(thread_info->log_buffer);
if (thread_info->request_data)
Py_CLEAR(thread_info->request_data);
@@ -742,7 +742,7 @@ void wsgi_publish_event(const char *name, PyObject *event)
PyObject *log = NULL;
PyObject *args = NULL;
Py_INCREF(o);
- log = newLogObject(NULL, APLOG_ERR, NULL);
+ log = newLogObject(NULL, APLOG_ERR, NULL, 0);
args = Py_BuildValue("(OOOOO)", type, value,
traceback, Py_None, log);
result = PyEval_CallObject(o, args);
diff --git a/src/server/wsgi_thread.c b/src/server/wsgi_thread.c
index 8e7c640..4513eca 100644
--- a/src/server/wsgi_thread.c
+++ b/src/server/wsgi_thread.c
@@ -57,7 +57,7 @@ WSGIThreadInfo *wsgi_thread_info(int create, int request)
thread_handle = (WSGIThreadInfo *)apr_pcalloc(
wsgi_server->process->pool, sizeof(WSGIThreadInfo));
- thread_handle->log = NULL;
+ thread_handle->log_buffer = NULL;
thread_handle->thread_id = wsgi_total_threads++;
diff --git a/src/server/wsgi_thread.h b/src/server/wsgi_thread.h
index cddd127..0fa27e9 100644
--- a/src/server/wsgi_thread.h
+++ b/src/server/wsgi_thread.h
@@ -31,7 +31,7 @@ typedef struct {
int request_thread;
apr_int64_t request_count;
PyObject *request_data;
- PyObject *log;
+ PyObject *log_buffer;
} WSGIThreadInfo;
extern int wsgi_total_threads;
diff --git a/src/server/wsgi_version.h b/src/server/wsgi_version.h
index 0a1da73..faac66c 100644
--- a/src/server/wsgi_version.h
+++ b/src/server/wsgi_version.h
@@ -25,8 +25,8 @@
#define MOD_WSGI_MAJORVERSION_NUMBER 4
#define MOD_WSGI_MINORVERSION_NUMBER 5
-#define MOD_WSGI_MICROVERSION_NUMBER 5
-#define MOD_WSGI_VERSION_STRING "4.5.5"
+#define MOD_WSGI_MICROVERSION_NUMBER 6
+#define MOD_WSGI_VERSION_STRING "4.5.6"
/* ------------------------------------------------------------------------- */