diff options
Diffstat (limited to 'src/server')
| -rw-r--r-- | src/server/__init__.py | 64 | ||||
| -rw-r--r-- | src/server/management/commands/runmodwsgi.py | 57 | ||||
| -rw-r--r-- | src/server/mod_wsgi.c | 80 | ||||
| -rw-r--r-- | src/server/wsgi_daemon.h | 1 | ||||
| -rw-r--r-- | src/server/wsgi_interp.c | 12 | ||||
| -rw-r--r-- | src/server/wsgi_logger.c | 182 | ||||
| -rw-r--r-- | src/server/wsgi_logger.h | 8 | ||||
| -rw-r--r-- | src/server/wsgi_metrics.c | 6 | ||||
| -rw-r--r-- | src/server/wsgi_thread.c | 2 | ||||
| -rw-r--r-- | src/server/wsgi_thread.h | 2 | ||||
| -rw-r--r-- | src/server/wsgi_version.h | 4 |
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" /* ------------------------------------------------------------------------- */ |
