summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/release-notes/index.rst1
-rw-r--r--docs/release-notes/version-4.3.2.rst63
-rw-r--r--src/server/__init__.py13
-rw-r--r--src/server/mod_wsgi.c331
-rw-r--r--src/server/wsgi_interp.c137
-rw-r--r--src/server/wsgi_version.h4
-rw-r--r--tests/environ.wsgi1
7 files changed, 262 insertions, 288 deletions
diff --git a/docs/release-notes/index.rst b/docs/release-notes/index.rst
index bb98bd2..ed8010a 100644
--- a/docs/release-notes/index.rst
+++ b/docs/release-notes/index.rst
@@ -5,6 +5,7 @@ Release Notes
.. toctree::
:maxdepth: 2
+ version-4.3.2.rst
version-4.3.1.rst
version-4.3.0.rst
diff --git a/docs/release-notes/version-4.3.2.rst b/docs/release-notes/version-4.3.2.rst
new file mode 100644
index 0000000..2ce46e7
--- /dev/null
+++ b/docs/release-notes/version-4.3.2.rst
@@ -0,0 +1,63 @@
+=============
+Version 4.3.2
+=============
+
+Version 4.3.2 of mod_wsgi can be obtained from:
+
+ https://github.com/GrahamDumpleton/mod_wsgi/archive/4.3.2.tar.gz
+
+Known Issues
+------------
+
+1. The makefiles for building mod_wsgi on Windows are currently broken and
+need updating. As most new changes relate to mod_wsgi daemon mode, which is
+not supported under Windows, you should keep using the last available
+binary for version 3.X on Windows instead.
+
+Bugs Fixed
+----------
+
+1. Linux behaviour when using ``connect()`` on a non blocking UNIX socket
+and the listener queue is full, is apparently not POSIX compliant and it
+returns ``EAGAIN`` instead of ``ECONNREFUSED``. The code handling errors
+from the ``connect()`` wasn't accomodating this non standard behaviour
+and so would fail immediately rather than retrying.
+
+2. Only change working directory for mod_wsgi daemon process after having
+dropped privileges to target user. This is required where the specified
+working directory is on an NFS file system configured so as not to have
+root access priviliges.
+
+3. The workaround for getting pyvenv style virtual environments to work
+with Python 3.3+ would break brew Python 2.7 on MacOS X as brew Python
+appears to not work in embedded systems which use Py_SetProgramName()
+instead of using Py_SetPythonHome(). Now only use Py_SetProgramName() if
+detect it is actually a pyvenv style virtual environment. This even appears
+to be okay for brew Python 3.4 at least as it does still work with the
+Py_SetProgramName() call even if brew Python 2.7 doesn't.
+
+New Features
+------------
+
+1. If the ``WSGIPythonHome`` directive or the ``python-home`` option is
+used with the ``WSGIDaemonProcess`` directive, the path provided, which is
+supposed to be the root directory of the Python installation or virtual
+environment, will be checked to see if it is actually accessible and refers
+to a directory. If it isn't, a warning message will be logged along with
+any details providing an indication of what may be wrong with the supplied
+path.
+
+This is being done to warn when an invalid path has been supplied that
+subsequently is likely to be rejected and ignored by the Python
+interpreter. In such a situation where an invalid path is supplied the
+Python interpreter doesn't actually log anything and will instead silently
+fallback to using any Python installation it finds by seaching for
+``python`` on the users ``PATH``. This may not be the Python installation
+or virtual environment you intended be used.
+
+2. The Apache configuration snippet generated as an example when running
+the ``install-module`` sub command of ``mod_wsgi-express`` to install the
+``mod_wsgi.so`` into the Apache installation itself, will now output a
+``WSGIPythonHome`` directive for the Python installation or virtual
+environment the mod_wsgi module was compiled against so that the correct
+Python runtime will be used.
diff --git a/src/server/__init__.py b/src/server/__init__.py
index fd0b54d..071ccae 100644
--- a/src/server/__init__.py
+++ b/src/server/__init__.py
@@ -1760,14 +1760,14 @@ def _cmd_setup_server(command, args, options):
if options['max_clients'] is not None:
max_clients = max(options['max_clients'], max_clients)
else:
- max_clients = int(1.5 * max_clients)
+ max_clients = 10 + max(10, int(1.5 * max_clients))
initial_workers = options['initial_workers']
min_spare_workers = options['minimum_spare_workers']
max_spare_workers = options['maximum_spare_workers']
if initial_workers is None:
- prefork_initial_workers = 0.02
+ prefork_initial_workers = 0.05
else:
prefork_initial_workers = initial_workers
@@ -1777,7 +1777,7 @@ def _cmd_setup_server(command, args, options):
prefork_min_spare_workers = min_spare_workers
if max_spare_workers is None:
- prefork_max_spare_workers = 0.05
+ prefork_max_spare_workers = 0.1
else:
prefork_max_spare_workers = max_spare_workers
@@ -1807,11 +1807,11 @@ def _cmd_setup_server(command, args, options):
options['worker_max_clients'] = max_clients
- if max_clients > 25:
+ if max_clients > 20:
options['worker_threads_per_child'] = int(max_clients /
- (int(max_clients / 25) + 1))
+ (int(max_clients / 20) + 1))
else:
- options['worker_threads_per_child'] = max_clients
+ options['worker_threads_per_child'] = 10
options['worker_thread_limit'] = options['worker_threads_per_child']
@@ -2003,6 +2003,7 @@ def cmd_install_module(params):
shutil.copyfile(where(), target)
print('LoadModule wsgi_module %s' % target)
+ print('WSGIPythonHome %s' % os.path.normpath(sys.prefix))
def cmd_module_location(params):
formatter = optparse.IndentedHelpFormatter()
diff --git a/src/server/mod_wsgi.c b/src/server/mod_wsgi.c
index 34bfd88..0e891dd 100644
--- a/src/server/mod_wsgi.c
+++ b/src/server/mod_wsgi.c
@@ -2509,7 +2509,7 @@ static int Adapter_run(AdapterObject *self, PyObject *object)
if (wsgi_newrelic_config_file) {
PyObject *module = NULL;
- module = PyImport_ImportModule("newrelic.api.web_transaction");
+ module = PyImport_ImportModule("newrelic.agent");
if (module) {
PyObject *dict;
@@ -2524,6 +2524,12 @@ static int Adapter_run(AdapterObject *self, PyObject *object)
wrapper = PyObject_CallFunctionObjArgs(
factory, object, Py_None, NULL);
+ if (!wrapper) {
+ wsgi_log_python_error(self->r, self->log,
+ self->r->filename);
+ PyErr_Clear();
+ }
+
Py_DECREF(factory);
}
@@ -2863,8 +2869,6 @@ static PyObject *wsgi_load_source(apr_pool_t *pool, request_rec *r,
PyObject *co = NULL;
struct _node *n = NULL;
- PyObject *transaction = NULL;
-
#if defined(WIN32) && defined(APR_HAS_UNICODE_FS)
apr_wchar_t wfilename[APR_PATH_MAX];
#endif
@@ -2970,85 +2974,6 @@ static PyObject *wsgi_load_source(apr_pool_t *pool, request_rec *r,
return NULL;
}
- if (wsgi_newrelic_config_file) {
- PyObject *module = NULL;
-
- PyObject *application = NULL;
-
-
- module = PyImport_ImportModule("newrelic.api.application");
-
- if (module) {
- PyObject *dict = NULL;
- PyObject *object = NULL;
-
- dict = PyModule_GetDict(module);
- object = PyDict_GetItemString(dict, "application");
-
- Py_INCREF(object);
- application = PyObject_CallFunctionObjArgs(object, NULL);
- Py_DECREF(object);
-
- Py_DECREF(module);
- module = NULL;
-
- if (!application)
- PyErr_Clear();
- }
- else
- PyErr_Clear();
-
- if (application)
- module = PyImport_ImportModule("newrelic.api.background_task");
-
- if (module) {
- PyObject *dict = NULL;
- PyObject *object = NULL;
-
- dict = PyModule_GetDict(module);
- object = PyDict_GetItemString(dict, "BackgroundTask");
-
- if (object) {
- PyObject *args = NULL;
-
- Py_INCREF(object);
-
- args = Py_BuildValue("(Oss)", application, filename,
- "Script/Import");
- transaction = PyObject_Call(object, args, NULL);
-
- if (!transaction)
- PyErr_WriteUnraisable(object);
-
- Py_DECREF(args);
- Py_DECREF(object);
-
- if (transaction) {
- PyObject *result = NULL;
-
- object = PyObject_GetAttrString(
- transaction, "__enter__");
- args = PyTuple_Pack(0);
- result = PyObject_Call(object, args, NULL);
-
- if (!result)
- PyErr_WriteUnraisable(object);
-
- Py_XDECREF(result);
- Py_DECREF(object);
- }
- }
-
- Py_DECREF(module);
- }
- else
- PyErr_Print();
-
- Py_XDECREF(application);
- }
- else
- PyErr_Clear();
-
co = (PyObject *)PyNode_Compile(n, filename);
PyNode_Free(n);
@@ -3057,67 +2982,6 @@ static PyObject *wsgi_load_source(apr_pool_t *pool, request_rec *r,
Py_XDECREF(co);
- if (wsgi_newrelic_config_file) {
- if (transaction) {
- PyObject *object;
-
- object = PyObject_GetAttrString(transaction, "__exit__");
-
- if (m) {
- PyObject *args = NULL;
- PyObject *result = NULL;
-
- args = PyTuple_Pack(3, Py_None, Py_None, Py_None);
- result = PyObject_Call(object, args, NULL);
-
- if (!result)
- PyErr_WriteUnraisable(object);
- else
- Py_DECREF(result);
-
- Py_DECREF(args);
- }
- else {
- PyObject *args = NULL;
- PyObject *result = NULL;
-
- PyObject *type = NULL;
- PyObject *value = NULL;
- PyObject *traceback = NULL;
-
- PyErr_Fetch(&type, &value, &traceback);
-
- if (!value) {
- value = Py_None;
- Py_INCREF(value);
- }
-
- if (!traceback) {
- traceback = Py_None;
- Py_INCREF(traceback);
- }
-
- PyErr_NormalizeException(&type, &value, &traceback);
-
- args = PyTuple_Pack(3, type, value, traceback);
- result = PyObject_Call(object, args, NULL);
-
- if (!result)
- PyErr_WriteUnraisable(object);
- else
- Py_DECREF(result);
-
- Py_DECREF(args);
-
- PyErr_Restore(type, value, traceback);
- }
-
- Py_DECREF(object);
-
- Py_DECREF(transaction);
- }
- }
-
if (m) {
PyObject *object = NULL;
@@ -7196,11 +7060,6 @@ static void wsgi_setup_daemon_name(WSGIDaemonProcess *daemon, apr_pool_t *p)
static int wsgi_setup_access(WSGIDaemonProcess *daemon)
{
- /* Setup the umask for the effective user. */
-
- if (daemon->group->umask != -1)
- umask(daemon->group->umask);
-
/* Change to chroot environment. */
if (daemon->group->root) {
@@ -7213,35 +7072,86 @@ static int wsgi_setup_access(WSGIDaemonProcess *daemon)
}
}
- /* Setup the working directory.*/
+ /* We don't need to switch user/group if not root. */
- if (daemon->group->home) {
- if (chdir(daemon->group->home) == -1) {
+ if (geteuid() == 0) {
+ /* Setup the daemon process real and effective group. */
+
+ if (setgid(daemon->group->gid) == -1) {
ap_log_error(APLOG_MARK, APLOG_ALERT, errno, wsgi_server,
- "mod_wsgi (pid=%d): Unable to change working "
- "directory to '%s'.", getpid(), daemon->group->home);
+ "mod_wsgi (pid=%d): Unable to set group id "
+ "to gid=%u.", getpid(),
+ (unsigned)daemon->group->gid);
return -1;
}
- }
- else if (geteuid()) {
- struct passwd *pwent;
+ else {
+ if (daemon->group->groups) {
+ if (setgroups(daemon->group->groups_count,
+ daemon->group->groups) == -1) {
+ ap_log_error(APLOG_MARK, APLOG_ALERT, errno,
+ wsgi_server, "mod_wsgi (pid=%d): Unable "
+ "to set supplementary groups for uname=%s "
+ "of '%s'.", getpid(), daemon->group->user,
+ daemon->group->groups_list);
+
+ return -1;
+ }
+ }
+ else if (initgroups(daemon->group->user,
+ daemon->group->gid) == -1) {
+ ap_log_error(APLOG_MARK, APLOG_ALERT, errno,
+ wsgi_server, "mod_wsgi (pid=%d): Unable "
+ "to set groups for uname=%s and gid=%u.",
+ getpid(), daemon->group->user,
+ (unsigned)daemon->group->gid);
- pwent = getpwuid(geteuid());
+ return -1;
+ }
+ }
- if (pwent) {
- if (chdir(pwent->pw_dir) == -1) {
- ap_log_error(APLOG_MARK, APLOG_ALERT, errno, wsgi_server,
- "mod_wsgi (pid=%d): Unable to change working "
- "directory to '%s'.", getpid(), pwent->pw_dir);
+ /* Setup the daemon process real and effective user. */
+
+ if (setuid(daemon->group->uid) == -1) {
+ ap_log_error(APLOG_MARK, APLOG_ALERT, errno, wsgi_server,
+ "mod_wsgi (pid=%d): Unable to change to uid=%ld.",
+ getpid(), (long)daemon->group->uid);
+
+ /*
+ * On true UNIX systems this should always succeed at
+ * this point. With certain Linux kernel versions though
+ * we can get back EAGAIN where the target user had
+ * reached their process limit. In that case will be left
+ * running as wrong user. Just exit on all failures to be
+ * safe. Don't die immediately to avoid a fork bomb.
+ *
+ * We could just return -1 here and let the caller do the
+ * sleep() and exit() but this failure is critical enough
+ * that we still do it here so it is obvious that the issue
+ * is being addressed.
+ */
+
+ ap_log_error(APLOG_MARK, APLOG_ALERT, 0, wsgi_server,
+ "mod_wsgi (pid=%d): Failure to configure the "
+ "daemon process correctly and process left in "
+ "unspecified state. Restarting daemon process "
+ "after delay.", getpid());
+
+ sleep(20);
+
+ wsgi_exit_daemon_process(-1);
return -1;
- }
}
- else {
+ }
+
+ /* Setup the working directory for the process. */
+
+ if (daemon->group->home) {
+ if (chdir(daemon->group->home) == -1) {
ap_log_error(APLOG_MARK, APLOG_ALERT, errno, wsgi_server,
- "mod_wsgi (pid=%d): Unable to determine home "
- "directory for uid=%ld.", getpid(), (long)geteuid());
+ "mod_wsgi (pid=%d): Unable to change working "
+ "directory to '%s'.", getpid(), daemon->group->home);
return -1;
}
@@ -7249,7 +7159,7 @@ static int wsgi_setup_access(WSGIDaemonProcess *daemon)
else {
struct passwd *pwent;
- pwent = getpwuid(daemon->group->uid);
+ pwent = getpwuid(geteuid());
if (pwent) {
if (chdir(pwent->pw_dir) == -1) {
@@ -7257,87 +7167,22 @@ static int wsgi_setup_access(WSGIDaemonProcess *daemon)
"mod_wsgi (pid=%d): Unable to change working "
"directory to '%s'.", getpid(), pwent->pw_dir);
- return -1;
+ return -1;
}
}
else {
ap_log_error(APLOG_MARK, APLOG_ALERT, errno, wsgi_server,
"mod_wsgi (pid=%d): Unable to determine home "
- "directory for uid=%ld.", getpid(),
- (long)daemon->group->uid);
-
- return -1;
- }
- }
-
- /* Don't bother switch user/group if not root. */
-
- if (geteuid())
- return 0;
-
- /* Setup the daemon process real and effective group. */
-
- if (setgid(daemon->group->gid) == -1) {
- ap_log_error(APLOG_MARK, APLOG_ALERT, errno, wsgi_server,
- "mod_wsgi (pid=%d): Unable to set group id to gid=%u.",
- getpid(), (unsigned)daemon->group->gid);
-
- return -1;
- }
- else {
- if (daemon->group->groups) {
- if (setgroups(daemon->group->groups_count,
- daemon->group->groups) == -1) {
- ap_log_error(APLOG_MARK, APLOG_ALERT, errno,
- wsgi_server, "mod_wsgi (pid=%d): Unable "
- "to set supplementary groups for uname=%s "
- "of '%s'.", getpid(), daemon->group->user,
- daemon->group->groups_list);
-
- return -1;
- }
- }
- else if (initgroups(daemon->group->user, daemon->group->gid) == -1) {
- ap_log_error(APLOG_MARK, APLOG_ALERT, errno,
- wsgi_server, "mod_wsgi (pid=%d): Unable "
- "to set groups for uname=%s and gid=%u.", getpid(),
- daemon->group->user, (unsigned)daemon->group->gid);
+ "directory for uid=%ld.", getpid(), (long)geteuid());
return -1;
}
}
- /* Setup the daemon process real and effective user. */
-
- if (setuid(daemon->group->uid) == -1) {
- ap_log_error(APLOG_MARK, APLOG_ALERT, errno, wsgi_server,
- "mod_wsgi (pid=%d): Unable to change to uid=%ld.",
- getpid(), (long)daemon->group->uid);
-
- /*
- * On true UNIX systems this should always succeed at
- * this point. With certain Linux kernel versions though
- * we can get back EAGAIN where the target user had
- * reached their process limit. In that case will be left
- * running as wrong user. Just exit on all failures to be
- * safe. Don't die immediately to avoid a fork bomb.
- *
- * We could just return -1 here and let the caller do the
- * sleep() and exit() but this failure is critical enough
- * that we still do it here so it is obvious that the issue
- * is being addressed.
- */
-
- ap_log_error(APLOG_MARK, APLOG_ALERT, 0, wsgi_server,
- "mod_wsgi (pid=%d): Failure to configure the "
- "daemon process correctly and process left in "
- "unspecified state. Restarting daemon process "
- "after delay.", getpid());
-
- sleep(20);
+ /* Setup the umask for the effective user. */
- wsgi_exit_daemon_process(-1);
- }
+ if (daemon->group->umask != -1)
+ umask(daemon->group->umask);
/*
* Linux prevents generation of core dumps after setuid()
@@ -7347,6 +7192,7 @@ static int wsgi_setup_access(WSGIDaemonProcess *daemon)
#if defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE)
/* This applies to Linux 2.4 and later. */
+
if (ap_coredumpdir_configured) {
if (prctl(PR_SET_DUMPABLE, 1)) {
ap_log_error(APLOG_MARK, APLOG_ALERT, errno, wsgi_server,
@@ -9496,7 +9342,16 @@ static int wsgi_connect_daemon(request_rec *r, WSGIDaemonSocket *daemon)
rv = wsgi_socket_connect_un(daemon->socket, &addr);
if (rv != APR_SUCCESS) {
- if (APR_STATUS_IS_ECONNREFUSED(rv)) {
+ /*
+ * We need to check for both connection refused and
+ * connection unavailable as Linux systems when
+ * connecting to a UNIX listener socket in non
+ * blocking mode, where the listener backlog is full
+ * will return the error EAGAIN rather than returning
+ * ECONNREFUSED as is supposedly dictated by POSIX.
+ */
+
+ if (APR_STATUS_IS_ECONNREFUSED(rv) || APR_STATUS_IS_EAGAIN(rv)) {
if ((apr_time_now()-start_time) < daemon->connect_timeout) {
if (wsgi_server_config->verbose_debugging) {
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r,
diff --git a/src/server/wsgi_interp.c b/src/server/wsgi_interp.c
index 6d8e765..7d0c1a7 100644
--- a/src/server/wsgi_interp.c
+++ b/src/server/wsgi_interp.c
@@ -1935,6 +1935,8 @@ void wsgi_python_init(apr_pool_t *p)
{
const char *python_home = 0;
+ int is_pyvenv = 0;
+
/* Perform initialisation if required. */
if (!Py_IsInitialized()) {
@@ -2003,19 +2005,16 @@ void wsgi_python_init(apr_pool_t *p)
python_home = wsgi_server_config->python_home;
-#if defined(MOD_WSGI_WITH_DAEMONS)
- if (wsgi_daemon_process && wsgi_daemon_process->group->python_home)
- python_home = wsgi_daemon_process->group->python_home;
-#endif
-
-#if PY_MAJOR_VERSION >= 3
if (python_home) {
- wchar_t *s = NULL;
- int len = strlen(python_home)+1;
-
ap_log_error(APLOG_MARK, APLOG_INFO, 0, wsgi_server,
"mod_wsgi (pid=%d): Python home %s.", getpid(),
python_home);
+ }
+
+ if (python_home) {
+#if PY_MAJOR_VERSION >= 3
+ wchar_t *s = NULL;
+ int len = strlen(python_home)+1;
s = (wchar_t *)apr_palloc(p, len*sizeof(wchar_t));
@@ -2025,23 +2024,21 @@ void wsgi_python_init(apr_pool_t *p)
mbstowcs(s, python_home, len);
#endif
Py_SetPythonHome(s);
- }
#else
- if (python_home) {
- ap_log_error(APLOG_MARK, APLOG_INFO, 0, wsgi_server,
- "mod_wsgi (pid=%d): Python home %s.", getpid(),
- python_home);
-
Py_SetPythonHome((char *)python_home);
- }
#endif
+ }
+
#else
/*
- * Check for Python HOME being overridden. What we are actually
- * going to do though is work out where the Python executable
- * would be that the designated installation and set the
- * location for where it is. This avoids bugs in pyvenv support
- * for embedded systems.
+ * Now for the UNIX version of the code to set the Python HOME.
+ * For this things are a mess. If using pyvenv with Python 3.3+
+ * then setting Python HOME doesn't work. For it we need to use
+ * Python executable location. Everything else seems to be cool
+ * with setting Python HOME. We therefore need to detect when we
+ * have a pyvenv by looking for the presence of pyvenv.cfg file.
+ * We can simply just set Python executable everywhere as that
+ * doesn't work with brew Python on MacOS X.
*/
python_home = wsgi_server_config->python_home;
@@ -2051,43 +2048,99 @@ void wsgi_python_init(apr_pool_t *p)
python_home = wsgi_daemon_process->group->python_home;
#endif
-#if PY_MAJOR_VERSION >= 3
if (python_home) {
+ apr_status_t rv;
+ apr_finfo_t finfo;
+
+ char *pyvenv_cfg;
+
const char *python_exe = 0;
+
+#if PY_MAJOR_VERSION >= 3
wchar_t *s = NULL;
int len = 0;
+#endif
- python_exe = apr_pstrcat(p, python_home, "/bin/python", NULL);
-
- len = strlen(python_exe)+1;
+ /*
+ * Is common to see people set the directory to an incorrect
+ * location, including to a location within an inaccessible
+ * user home directory, or to the 'python' executable itself.
+ * Try and validate that the location is accessible and is a
+ * directory.
+ */
ap_log_error(APLOG_MARK, APLOG_INFO, 0, wsgi_server,
"mod_wsgi (pid=%d): Python home %s.", getpid(),
python_home);
- s = (wchar_t *)apr_palloc(p, len*sizeof(wchar_t));
+ rv = apr_stat(&finfo, python_home, APR_FINFO_NORM, p);
-#if defined(WIN32) && defined(APR_HAS_UNICODE_FS)
- wsgi_utf8_to_unicode_path(s, len, python_exe);
-#else
- mbstowcs(s, python_exe, len);
-#endif
- Py_SetProgramName(s);
- }
-#else
- if (python_home) {
- const char *python_exe = 0;
+ if (rv != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_WARNING, rv, wsgi_server,
+ "mod_wsgi (pid=%d): Unable to stat Python home "
+ "%s. Python interpreter may not be able to be "
+ "initialized correctly. Verify the supplied path "
+ "and access permissions for whole of the path.",
+ getpid(), python_home);
+ }
+ else {
+ if (finfo.filetype != APR_DIR) {
+ ap_log_error(APLOG_MARK, APLOG_WARNING, rv, wsgi_server,
+ "mod_wsgi (pid=%d): Python home %s is not "
+ "a directory. Python interpreter may not "
+ "be able to be initialized correctly. "
+ "Verify the supplied path.", getpid(),
+ python_home);
+ }
+ else if (access(python_home, X_OK) == -1) {
+ ap_log_error(APLOG_MARK, APLOG_WARNING, rv, wsgi_server,
+ "mod_wsgi (pid=%d): Python home %s is not "
+ "accessible. Python interpreter may not "
+ "be able to be initialized correctly. "
+ "Verify the supplied path and access "
+ "permissions on the directory.", getpid(),
+ python_home);
+ }
+ }
- python_exe = apr_pstrcat(p, python_home, "/bin/python", NULL);
+ /* Now detect whether have a pyvenv with Python 3.3+. */
- ap_log_error(APLOG_MARK, APLOG_INFO, 0, wsgi_server,
- "mod_wsgi (pid=%d): Python home %s.", getpid(),
- python_home);
+ pyvenv_cfg = apr_pstrcat(p, python_home, "/pyvenv.cfg", NULL);
- Py_SetProgramName((char *)python_exe);
- }
+ if (access(pyvenv_cfg, R_OK) == 0)
+ is_pyvenv = 1;
+
+ if (is_pyvenv) {
+ /*
+ * Embedded support for pyvenv is broken so need to
+ * set Python executable location and cannot set the
+ * Python HOME as is more desirable.
+ */
+
+ python_exe = apr_pstrcat(p, python_home, "/bin/python", NULL);
+#if PY_MAJOR_VERSION >= 3
+ len = strlen(python_exe)+1;
+ s = (wchar_t *)apr_palloc(p, len*sizeof(wchar_t));
+ mbstowcs(s, python_exe, len);
+
+ Py_SetProgramName(s);
+#else
+ Py_SetProgramName((char *)python_exe);
+#endif
+ }
+ else {
+#if PY_MAJOR_VERSION >= 3
+ len = strlen(python_home)+1;
+ s = (wchar_t *)apr_palloc(p, len*sizeof(wchar_t));
+ mbstowcs(s, python_home, len);
+
+ Py_SetPythonHome(s);
+#else
+ Py_SetPythonHome((char *)python_home);
#endif
+ }
#endif
+ }
/*
* Set environment variable PYTHONHASHSEED. We need to
diff --git a/src/server/wsgi_version.h b/src/server/wsgi_version.h
index c71f4a7..4f91475 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 3
-#define MOD_WSGI_MICROVERSION_NUMBER 1
-#define MOD_WSGI_VERSION_STRING "4.3.1"
+#define MOD_WSGI_MICROVERSION_NUMBER 2
+#define MOD_WSGI_VERSION_STRING "4.3.2"
/* ------------------------------------------------------------------------- */
diff --git a/tests/environ.wsgi b/tests/environ.wsgi
index c26eae7..3a478ec 100644
--- a/tests/environ.wsgi
+++ b/tests/environ.wsgi
@@ -22,6 +22,7 @@ def application(environ, start_response):
print('PID: %s' % os.getpid(), file=output)
print('UID: %s' % os.getuid(), file=output)
print('GID: %s' % os.getgid(), file=output)
+ print('CWD: %s' % os.getcwd(), file=output)
print(file=output)
print('python.version: %r' % (sys.version,), file=output)