Blob Blame History Raw
From b439f1c411a9479ccc03c16465cdff50fede79d3 Mon Sep 17 00:00:00 2001
From: Petr Viktorin <encukou@gmail.com>
Date: Thu, 10 Jun 2021 15:45:03 +0200
Subject: [PATCH 1/7] Use Py_CompileString rather than
 PyParser_SimpleParseFile/PyNode_Compile

---
 src/server/mod_wsgi.c    | 68 +++++++++++++++++++++++++++++++---------
 src/server/wsgi_python.h |  1 -
 2 files changed, 53 insertions(+), 16 deletions(-)

diff --git a/src/server/mod_wsgi.c b/src/server/mod_wsgi.c
index b657a748..4f1d8765 100644
--- a/src/server/mod_wsgi.c
+++ b/src/server/mod_wsgi.c
@@ -3645,7 +3645,10 @@ static PyObject *wsgi_load_source(apr_pool_t *pool, request_rec *r,
     FILE *fp = NULL;
     PyObject *m = NULL;
     PyObject *co = NULL;
-    struct _node *n = NULL;
+    char *source;
+    size_t pos = 0;
+    size_t allocated = 1024;
+    size_t nread;
 
 #if defined(WIN32) && defined(APR_HAS_UNICODE_FS)
     apr_wchar_t wfilename[APR_PATH_MAX];
@@ -3730,36 +3733,71 @@ static PyObject *wsgi_load_source(apr_pool_t *pool, request_rec *r,
         return NULL;
     }
 
-    n = PyParser_SimpleParseFile(fp, filename, Py_file_input);
-
+    source = malloc(allocated);
+    if (source != NULL) {
+        do {
+            nread = fread(source + pos, 1, allocated - pos, fp);
+            pos += nread;
+            if (nread == 0) {
+                if (ferror(fp)) {
+                    free(source);
+                    source = NULL;
+                }
+                break;
+            }
+            if (pos == allocated) {
+                allocated *= 2;
+                char *reallocated_source = realloc(source, allocated);
+                if (reallocated_source == NULL) {
+                    free(source);
+                    source = NULL;
+                    break;
+                }
+                source = reallocated_source;
+            }
+        } while (!feof(fp));
+    }
     fclose(fp);
-
-    if (!n) {
+    if (source == NULL) {
         Py_BEGIN_ALLOW_THREADS
         if (r) {
-            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+            ap_log_rerror(APLOG_MARK, APLOG_ERR, errno, r,
                           "mod_wsgi (pid=%d, process='%s', application='%s'): "
-                          "Failed to parse Python script file '%s'.", getpid(),
+                          "Could not read source file '%s'.", getpid(),
                           process_group, application_group, filename);
         }
         else {
-            ap_log_error(APLOG_MARK, APLOG_ERR, 0, wsgi_server,
+            ap_log_error(APLOG_MARK, APLOG_ERR, errno, wsgi_server,
                          "mod_wsgi (pid=%d, process='%s', application='%s'): "
-                         "Failed to parse Python script file '%s'.", getpid(),
+                         "Could not read source file '%s'.", getpid(),
                          process_group, application_group, filename);
         }
         Py_END_ALLOW_THREADS
+        return NULL;
+    }
 
-        wsgi_log_python_error(r, NULL, filename, 0);
+    co = Py_CompileString(filename, source, 0);
+    free(source);
 
+    if (!co) {
+        Py_BEGIN_ALLOW_THREADS
+        if (r) {
+            ap_log_rerror(APLOG_MARK, APLOG_ERR, errno, r,
+                          "mod_wsgi (pid=%d, process='%s', application='%s'): "
+                          "Could not compile source file '%s'.", getpid(),
+                          process_group, application_group, filename);
+        }
+        else {
+            ap_log_error(APLOG_MARK, APLOG_ERR, errno, wsgi_server,
+                         "mod_wsgi (pid=%d, process='%s', application='%s'): "
+                         "Could not compile source file '%s'.", getpid(),
+                         process_group, application_group, filename);
+        }
+        Py_END_ALLOW_THREADS
         return NULL;
     }
 
-    co = (PyObject *)PyNode_Compile(n, filename);
-    PyNode_Free(n);
-
-    if (co)
-        m = PyImport_ExecCodeModuleEx((char *)name, co, (char *)filename);
+    m = PyImport_ExecCodeModuleEx((char *)name, co, (char *)filename);
 
     Py_XDECREF(co);
 
diff --git a/src/server/wsgi_python.h b/src/server/wsgi_python.h
index fa06e2cb..3b34b731 100644
--- a/src/server/wsgi_python.h
+++ b/src/server/wsgi_python.h
@@ -43,7 +43,6 @@
 
 #include "structmember.h"
 #include "compile.h"
-#include "node.h"
 #include "osdefs.h"
 #include "frameobject.h"
 

From a73166e01394bbbbaad7cda18418dd7cb37fd45e Mon Sep 17 00:00:00 2001
From: Petr Viktorin <encukou@gmail.com>
Date: Thu, 10 Jun 2021 15:55:50 +0200
Subject: [PATCH 2/7] Don't call PyEval_InitThreads on Python 3.9+

---
 src/server/wsgi_interp.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/server/wsgi_interp.c b/src/server/wsgi_interp.c
index bb91b69c..5fc38d1a 100644
--- a/src/server/wsgi_interp.c
+++ b/src/server/wsgi_interp.c
@@ -2433,10 +2433,10 @@ void wsgi_python_init(apr_pool_t *p)
 
         Py_Initialize();
 
+#if PY_VERSION_HEX < 0x03090000
         /* Initialise threading. */
-
         PyEval_InitThreads();
-
+#endif
         /*
          * Remove the environment variable we set for the hash
          * seed. This has to be done in os.environ, which will

From 8dbf81e0280c902cd6af6b254d233ecead10b56c Mon Sep 17 00:00:00 2001
From: Petr Viktorin <encukou@gmail.com>
Date: Thu, 10 Jun 2021 15:58:25 +0200
Subject: [PATCH 3/7] Replace undocumented PyEval_CallObject with
 PyObject_CallObject

---
 src/server/mod_wsgi.c     | 44 +++++++++++++++++----------------------
 src/server/wsgi_interp.c  | 24 ++++++++++-----------
 src/server/wsgi_logger.c  |  4 ++--
 src/server/wsgi_metrics.c |  2 +-
 src/server/wsgi_stream.c  |  4 ++--
 5 files changed, 36 insertions(+), 42 deletions(-)

diff --git a/src/server/mod_wsgi.c b/src/server/mod_wsgi.c
index 4f1d8765..903d8572 100644
--- a/src/server/mod_wsgi.c
+++ b/src/server/mod_wsgi.c
@@ -2897,7 +2897,7 @@ static int Adapter_process_file_wrapper(AdapterObject *self)
     if (!method)
         return 0;
 
-    object = PyEval_CallObject(method, NULL);
+    object = PyObject_CallObject(method, NULL);
     Py_DECREF(method);
 
     if (!object) {
@@ -3179,7 +3179,7 @@ static int Adapter_run(AdapterObject *self, PyObject *object)
 
     args = Py_BuildValue("(OO)", vars, start);
 
-    self->sequence = PyEval_CallObject(object, args);
+    self->sequence = PyObject_CallObject(object, args);
 
     if (self->sequence != NULL) {
         if (!Adapter_process_file_wrapper(self)) {
@@ -3301,7 +3301,7 @@ static int Adapter_run(AdapterObject *self, PyObject *object)
             close = PyObject_GetAttrString(self->sequence, "close");
 
             args = Py_BuildValue("()");
-            data = PyEval_CallObject(close, args);
+            data = PyObject_CallObject(close, args);
 
             Py_DECREF(args);
             Py_XDECREF(data);
@@ -3910,7 +3910,7 @@ static int wsgi_reload_required(apr_pool_t *pool, request_rec *r,
 
             Py_INCREF(object);
             args = Py_BuildValue("(s)", resource);
-            result = PyEval_CallObject(object, args);
+            result = PyObject_CallObject(object, args);
             Py_DECREF(args);
             Py_DECREF(object);
 
@@ -4283,7 +4283,7 @@ static int wsgi_execute_script(request_rec *r)
                 }
                 else {
                     args = PyTuple_New(0);
-                    object = PyEval_CallObject(method, args);
+                    object = PyObject_CallObject(method, args);
                     Py_DECREF(args);
                 }
 
@@ -6892,7 +6892,7 @@ static int wsgi_execute_dispatch(request_rec *r)
                 if (adapter) {
                     Py_INCREF(object);
                     args = Py_BuildValue("(O)", vars);
-                    result = PyEval_CallObject(object, args);
+                    result = PyObject_CallObject(object, args);
                     Py_DECREF(args);
                     Py_DECREF(object);
 
@@ -6974,7 +6974,7 @@ static int wsgi_execute_dispatch(request_rec *r)
                 if (adapter) {
                     Py_INCREF(object);
                     args = Py_BuildValue("(O)", vars);
-                    result = PyEval_CallObject(object, args);
+                    result = PyObject_CallObject(object, args);
                     Py_DECREF(args);
                     Py_DECREF(object);
 
@@ -7056,7 +7056,7 @@ static int wsgi_execute_dispatch(request_rec *r)
                 if (adapter) {
                     Py_INCREF(object);
                     args = Py_BuildValue("(O)", vars);
-                    result = PyEval_CallObject(object, args);
+                    result = PyObject_CallObject(object, args);
                     Py_DECREF(args);
                     Py_DECREF(object);
 
@@ -7147,9 +7147,7 @@ static int wsgi_execute_dispatch(request_rec *r)
                              adapter->log->ob_type->tp_name);
             }
             else {
-                args = PyTuple_New(0);
-                object = PyEval_CallObject(method, args);
-                Py_DECREF(args);
+                object = PyObject_CallObject(method, NULL);
             }
 
             Py_XDECREF(object);
@@ -14841,7 +14839,7 @@ static authn_status wsgi_check_password(request_rec *r, const char *user,
 
                 Py_INCREF(object);
                 args = Py_BuildValue("(Oss)", vars, user, password);
-                result = PyEval_CallObject(object, args);
+                result = PyObject_CallObject(object, args);
                 Py_DECREF(args);
                 Py_DECREF(object);
                 Py_DECREF(vars);
@@ -14911,10 +14909,8 @@ static authn_status wsgi_check_password(request_rec *r, const char *user,
                                  adapter->log->ob_type->tp_name);
                 }
                 else {
-                    args = PyTuple_New(0);
-                    result = PyEval_CallObject(method, args);
+                    result = PyObject_CallObject(method, NULL);
                     Py_XDECREF(result);
-                    Py_DECREF(args);
                 }
 
                 /* Log any details of exceptions if execution failed. */
@@ -15086,7 +15082,7 @@ static authn_status wsgi_get_realm_hash(request_rec *r, const char *user,
 
                 Py_INCREF(object);
                 args = Py_BuildValue("(Oss)", vars, user, realm);
-                result = PyEval_CallObject(object, args);
+                result = PyObject_CallObject(object, args);
                 Py_DECREF(args);
                 Py_DECREF(object);
                 Py_DECREF(vars);
@@ -15158,7 +15154,7 @@ static authn_status wsgi_get_realm_hash(request_rec *r, const char *user,
                 }
                 else {
                     args = PyTuple_New(0);
-                    result = PyEval_CallObject(method, args);
+                    result = PyObject_CallObject(method, args);
                     Py_XDECREF(result);
                     Py_DECREF(args);
                 }
@@ -15337,7 +15333,7 @@ static int wsgi_groups_for_user(request_rec *r, WSGIRequestConfig *config,
 
                 Py_INCREF(object);
                 args = Py_BuildValue("(Os)", vars, r->user);
-                result = PyEval_CallObject(object, args);
+                result = PyObject_CallObject(object, args);
                 Py_DECREF(args);
                 Py_DECREF(object);
                 Py_DECREF(vars);
@@ -15450,7 +15446,7 @@ static int wsgi_groups_for_user(request_rec *r, WSGIRequestConfig *config,
                 }
                 else {
                     args = PyTuple_New(0);
-                    result = PyEval_CallObject(method, args);
+                    result = PyObject_CallObject(method, args);
                     Py_XDECREF(result);
                     Py_DECREF(args);
                 }
@@ -15623,7 +15619,7 @@ static int wsgi_allow_access(request_rec *r, WSGIRequestConfig *config,
 
                 Py_INCREF(object);
                 args = Py_BuildValue("(Oz)", vars, host);
-                result = PyEval_CallObject(object, args);
+                result = PyObject_CallObject(object, args);
                 Py_DECREF(args);
                 Py_DECREF(object);
                 Py_DECREF(vars);
@@ -15675,7 +15671,7 @@ static int wsgi_allow_access(request_rec *r, WSGIRequestConfig *config,
                 }
                 else {
                     args = PyTuple_New(0);
-                    result = PyEval_CallObject(method, args);
+                    result = PyObject_CallObject(method, args);
                     Py_XDECREF(result);
                     Py_DECREF(args);
                 }
@@ -15888,7 +15884,7 @@ static int wsgi_hook_check_user_id(request_rec *r)
 
                 Py_INCREF(object);
                 args = Py_BuildValue("(Oss)", vars, r->user, password);
-                result = PyEval_CallObject(object, args);
+                result = PyObject_CallObject(object, args);
                 Py_DECREF(args);
                 Py_DECREF(object);
                 Py_DECREF(vars);
@@ -15956,10 +15952,8 @@ static int wsgi_hook_check_user_id(request_rec *r)
                                  adapter->log->ob_type->tp_name);
                 }
                 else {
-                    args = PyTuple_New(0);
-                    result = PyEval_CallObject(method, args);
+                    result = PyObject_CallObject(method, NULL);
                     Py_XDECREF(result);
-                    Py_DECREF(args);
                 }
 
                 /* Log any details of exceptions if execution failed. */
diff --git a/src/server/wsgi_interp.c b/src/server/wsgi_interp.c
index 5fc38d1a..027325fd 100644
--- a/src/server/wsgi_interp.c
+++ b/src/server/wsgi_interp.c
@@ -100,7 +100,7 @@ static PyObject *SignalIntercept_call(
             Py_INCREF(o);
             log = newLogObject(NULL, APLOG_WARNING, NULL, 0);
             args = Py_BuildValue("(OOO)", Py_None, Py_None, log);
-            result = PyEval_CallObject(o, args);
+            result = PyObject_CallObject(o, args);
             Py_XDECREF(result);
             Py_DECREF(args);
             Py_DECREF(log);
@@ -238,7 +238,7 @@ static PyObject *ShutdownInterpreter_call(
             PyObject *res = NULL;
             Py_INCREF(exitfunc);
             PySys_SetObject("exitfunc", (PyObject *)NULL);
-            res = PyEval_CallObject(exitfunc, (PyObject *)NULL);
+            res = PyObject_CallObject(exitfunc, (PyObject *)NULL);
 
             if (res == NULL) {
                 PyObject *m = NULL;
@@ -290,7 +290,7 @@ static PyObject *ShutdownInterpreter_call(
                         log = newLogObject(NULL, APLOG_ERR, NULL, 0);
                         args = Py_BuildValue("(OOOOO)", type, value,
                                              traceback, Py_None, log);
-                        result = PyEval_CallObject(o, args);
+                        result = PyObject_CallObject(o, args);
                         Py_DECREF(args);
                         Py_DECREF(log);
                         Py_DECREF(o);
@@ -639,7 +639,7 @@ InterpreterObject *newInterpreterObject(const char *name)
                 callback = PyCFunction_New(&wsgi_system_exit_method[0], NULL);
 
                 args = Py_BuildValue("(iO)", SIGTERM, callback);
-                res = PyEval_CallObject(func, args);
+                res = PyObject_CallObject(func, args);
 
                 if (!res) {
                     Py_BEGIN_ALLOW_THREADS
@@ -984,7 +984,7 @@ InterpreterObject *newInterpreterObject(const char *name)
                     Py_END_ALLOW_THREADS
 
                     args = Py_BuildValue("(O)", item);
-                    result = PyEval_CallObject(object, args);
+                    result = PyObject_CallObject(object, args);
 
                     if (!result) {
                         Py_BEGIN_ALLOW_THREADS
@@ -1019,7 +1019,7 @@ InterpreterObject *newInterpreterObject(const char *name)
                         Py_END_ALLOW_THREADS
 
                         args = Py_BuildValue("(O)", item);
-                        result = PyEval_CallObject(object, args);
+                        result = PyObject_CallObject(object, args);
 
                         if (!result) {
                             Py_BEGIN_ALLOW_THREADS
@@ -1054,7 +1054,7 @@ InterpreterObject *newInterpreterObject(const char *name)
                 Py_END_ALLOW_THREADS
 
                 args = Py_BuildValue("(O)", item);
-                result = PyEval_CallObject(object, args);
+                result = PyObject_CallObject(object, args);
 
                 if (!result) {
                     Py_BEGIN_ALLOW_THREADS
@@ -1672,7 +1672,7 @@ static void Interpreter_dealloc(InterpreterObject *self)
         if (func) {
             PyObject *res = NULL;
             Py_INCREF(func);
-            res = PyEval_CallObject(func, (PyObject *)NULL);
+            res = PyObject_CallObject(func, (PyObject *)NULL);
             if (!res) {
                 PyErr_Clear();
             }
@@ -1699,7 +1699,7 @@ static void Interpreter_dealloc(InterpreterObject *self)
         if (func) {
             PyObject *res = NULL;
             Py_INCREF(func);
-            res = PyEval_CallObject(func, (PyObject *)NULL);
+            res = PyObject_CallObject(func, (PyObject *)NULL);
 
             if (res == NULL) {
                 PyObject *m = NULL;
@@ -1742,7 +1742,7 @@ static void Interpreter_dealloc(InterpreterObject *self)
                         log = newLogObject(NULL, APLOG_ERR, NULL, 0);
                         args = Py_BuildValue("(OOOOO)", type, value,
                                              traceback, Py_None, log);
-                        result = PyEval_CallObject(o, args);
+                        result = PyObject_CallObject(o, args);
                         Py_DECREF(args);
                         Py_DECREF(log);
                         Py_DECREF(o);
@@ -1823,7 +1823,7 @@ static void Interpreter_dealloc(InterpreterObject *self)
         PyObject *res = NULL;
         Py_INCREF(exitfunc);
         PySys_SetObject("exitfunc", (PyObject *)NULL);
-        res = PyEval_CallObject(exitfunc, (PyObject *)NULL);
+        res = PyObject_CallObject(exitfunc, (PyObject *)NULL);
 
         if (res == NULL) {
             PyObject *m = NULL;
@@ -1875,7 +1875,7 @@ static void Interpreter_dealloc(InterpreterObject *self)
                     log = newLogObject(NULL, APLOG_ERR, NULL, 0);
                     args = Py_BuildValue("(OOOOO)", type, value,
                                          traceback, Py_None, log);
-                    result = PyEval_CallObject(o, args);
+                    result = PyObject_CallObject(o, args);
                     Py_DECREF(args);
                     Py_DECREF(log);
                     Py_DECREF(o);
diff --git a/src/server/wsgi_logger.c b/src/server/wsgi_logger.c
index f47a720f..c7470a53 100644
--- a/src/server/wsgi_logger.c
+++ b/src/server/wsgi_logger.c
@@ -96,7 +96,7 @@ PyObject *newLogWrapperObject(PyObject *buffer)
     args = Py_BuildValue("(OssOOO)", buffer, "utf-8", "replace",
                          Py_None, Py_True, Py_True);
 
-    wrapper = PyEval_CallObject(object, args);
+    wrapper = PyObject_CallObject(object, args);
 
     Py_DECREF(args);
     Py_DECREF(object);
@@ -662,7 +662,7 @@ void wsgi_log_python_error(request_rec *r, PyObject *log,
             Py_INCREF(o);
             args = Py_BuildValue("(OOOOO)", type, value, traceback,
                                  Py_None, log);
-            result = PyEval_CallObject(o, args);
+            result = PyObject_CallObject(o, args);
             Py_DECREF(args);
             Py_DECREF(o);
         }
diff --git a/src/server/wsgi_metrics.c b/src/server/wsgi_metrics.c
index 29ee7e69..7b628596 100644
--- a/src/server/wsgi_metrics.c
+++ b/src/server/wsgi_metrics.c
@@ -1269,7 +1269,7 @@ void wsgi_call_callbacks(const char *name, PyObject *callbacks,
                     log = newLogObject(NULL, APLOG_ERR, NULL, 0);
                     args = Py_BuildValue("(OOOOO)", type, value,
                                          traceback, Py_None, log);
-                    result = PyEval_CallObject(o, args);
+                    result = PyObject_CallObject(o, args);
                     Py_DECREF(args);
                     Py_DECREF(log);
                     Py_DECREF(o);
diff --git a/src/server/wsgi_stream.c b/src/server/wsgi_stream.c
index e40c8049..39d58428 100644
--- a/src/server/wsgi_stream.c
+++ b/src/server/wsgi_stream.c
@@ -124,7 +124,7 @@ static PyObject *Stream_iternext(StreamObject *self)
     }
 
     args = Py_BuildValue("(O)", attribute);
-    result = PyEval_CallObject(method, args);
+    result = PyObject_CallObject(method, args);
 
     Py_DECREF(args);
     Py_DECREF(method);
@@ -164,7 +164,7 @@ static PyObject *Stream_close(StreamObject *self, PyObject *args)
     method = PyObject_GetAttrString(self->filelike, "close");
 
     if (method) {
-        result = PyEval_CallObject(method, (PyObject *)NULL);
+        result = PyObject_CallObject(method, (PyObject *)NULL);
         if (!result)
             PyErr_Clear();
         Py_DECREF(method);

From 744558fff7130229a50ac89a35038ccde0c94b70 Mon Sep 17 00:00:00 2001
From: Petr Viktorin <encukou@gmail.com>
Date: Thu, 10 Jun 2021 16:01:28 +0200
Subject: [PATCH 4/7] Remove unused variable

---
 src/server/wsgi_metrics.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/src/server/wsgi_metrics.c b/src/server/wsgi_metrics.c
index 7b628596..5c6d8762 100644
--- a/src/server/wsgi_metrics.c
+++ b/src/server/wsgi_metrics.c
@@ -420,7 +420,6 @@ static PyObject *wsgi_request_metrics(void)
     double application_time_total = 0;
     double application_time_avg = 0;
 
-    WSGIThreadInfo **thread_info = NULL;
     int request_threads_active = 0;
 
     int i;
@@ -583,8 +582,6 @@ static PyObject *wsgi_request_metrics(void)
             WSGI_INTERNED_STRING(request_threads_started), object);
     Py_DECREF(object);
 
-    thread_info = (WSGIThreadInfo **)wsgi_thread_details->elts;
-
     request_busy_time = stop_request_busy_time - start_request_busy_time;
 
     capacity_utilization = (request_busy_time / sample_period /

From e3c31e518e6d02bab293b2394d1e8ece8a8de444 Mon Sep 17 00:00:00 2001
From: Petr Viktorin <encukou@gmail.com>
Date: Fri, 11 Jun 2021 12:59:08 +0200
Subject: [PATCH 5/7] Correct Py_CompileString usage

---
 src/server/mod_wsgi.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/server/mod_wsgi.c b/src/server/mod_wsgi.c
index 903d8572..705c470f 100644
--- a/src/server/mod_wsgi.c
+++ b/src/server/mod_wsgi.c
@@ -3776,7 +3776,7 @@ static PyObject *wsgi_load_source(apr_pool_t *pool, request_rec *r,
         return NULL;
     }
 
-    co = Py_CompileString(filename, source, 0);
+    co = Py_CompileString(source, filename, Py_file_input);
     free(source);
 
     if (!co) {

From 715a1327ad19658ee9b8a3233ae150875a10334e Mon Sep 17 00:00:00 2001
From: Petr Viktorin <encukou@gmail.com>
Date: Fri, 11 Jun 2021 13:00:09 +0200
Subject: [PATCH 6/7] Use Python API to read source files

---
 src/server/mod_wsgi.c | 155 ++++++++----------------------------------
 1 file changed, 29 insertions(+), 126 deletions(-)

diff --git a/src/server/mod_wsgi.c b/src/server/mod_wsgi.c
index 705c470f..9ebd6856 100644
--- a/src/server/mod_wsgi.c
+++ b/src/server/mod_wsgi.c
@@ -3642,155 +3642,58 @@ static PyObject *wsgi_load_source(apr_pool_t *pool, request_rec *r,
                                   const char *application_group,
                                   int ignore_system_exit)
 {
-    FILE *fp = NULL;
     PyObject *m = NULL;
     PyObject *co = NULL;
-    char *source;
-    size_t pos = 0;
-    size_t allocated = 1024;
-    size_t nread;
-
-#if defined(WIN32) && defined(APR_HAS_UNICODE_FS)
-    apr_wchar_t wfilename[APR_PATH_MAX];
-#endif
+    PyObject *io_module = NULL;
+    PyObject *fileobject = NULL;
+    PyObject *source_bytes_object = NULL;
+    PyObject *result = NULL;
+    char *source_buf = NULL;
 
-    if (exists) {
-        Py_BEGIN_ALLOW_THREADS
-        if (r) {
-            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
-                          "mod_wsgi (pid=%d, process='%s', application='%s'): "
-                          "Reloading WSGI script '%s'.", getpid(),
-                          process_group, application_group, filename);
-        }
-        else {
-            ap_log_error(APLOG_MARK, APLOG_INFO, 0, wsgi_server,
-                         "mod_wsgi (pid=%d, process='%s', application='%s'): "
-                         "Reloading WSGI script '%s'.", getpid(),
-                         process_group, application_group, filename);
-        }
-        Py_END_ALLOW_THREADS
+    io_module = PyImport_AddModule("io");
+    if (!io_module) {
+        goto load_source_finally;
     }
-    else {
-        Py_BEGIN_ALLOW_THREADS
-        if (r) {
-            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
-                          "mod_wsgi (pid=%d, process='%s', application='%s'): "
-                          "Loading Python script file '%s'.", getpid(),
-                          process_group, application_group, filename);
-        }
-        else {
-            ap_log_error(APLOG_MARK, APLOG_INFO, 0, wsgi_server,
-                         "mod_wsgi (pid=%d, process='%s', application='%s'): "
-                         "Loading Python script file '%s'.", getpid(),
-                         process_group, application_group, filename);
-        }
-        Py_END_ALLOW_THREADS
-    }
-
-#if defined(WIN32) && defined(APR_HAS_UNICODE_FS)
-    if (wsgi_utf8_to_unicode_path(wfilename, sizeof(wfilename) /
-                                  sizeof(apr_wchar_t), filename)) {
 
-        Py_BEGIN_ALLOW_THREADS
-        if (r) {
-            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
-                          "mod_wsgi (pid=%d, process='%s', "
-                          "application='%s'): Failed to convert '%s' "
-                          "to UCS2 filename.", getpid(),
-                          process_group, application_group, filename);
-        }
-        else {
-            ap_log_error(APLOG_MARK, APLOG_ERR, 0, wsgi_server,
-                         "mod_wsgi (pid=%d, process='%s', "
-                         "application='%s'): Failed to convert '%s' "
-                         "to UCS2 filename.", getpid(),
-                         process_group, application_group, filename);
-        }
-        Py_END_ALLOW_THREADS
-        return NULL;
+    fileobject = PyObject_CallMethod(io_module, "open", "ss", filename, "rb");
+    if (!fileobject) {
+        goto load_source_finally;
     }
 
-    fp = _wfopen(wfilename, L"r");
-#else
-    fp = fopen(filename, "r");
-#endif
-
-    if (!fp) {
-        Py_BEGIN_ALLOW_THREADS
-        if (r) {
-            ap_log_rerror(APLOG_MARK, APLOG_ERR, errno, r,
-                          "mod_wsgi (pid=%d, process='%s', application='%s'): "
-                          "Call to fopen() failed for '%s'.", getpid(),
-                          process_group, application_group, filename);
-        }
-        else {
-            ap_log_error(APLOG_MARK, APLOG_ERR, errno, wsgi_server,
-                         "mod_wsgi (pid=%d, process='%s', application='%s'): "
-                         "Call to fopen() failed for '%s'.", getpid(),
-                         process_group, application_group, filename);
-        }
-        Py_END_ALLOW_THREADS
-        return NULL;
+    source_bytes_object = PyObject_CallMethod(fileobject, "read", "");
+    if (!source_bytes_object) {
+        goto load_source_finally;
     }
 
-    source = malloc(allocated);
-    if (source != NULL) {
-        do {
-            nread = fread(source + pos, 1, allocated - pos, fp);
-            pos += nread;
-            if (nread == 0) {
-                if (ferror(fp)) {
-                    free(source);
-                    source = NULL;
-                }
-                break;
-            }
-            if (pos == allocated) {
-                allocated *= 2;
-                char *reallocated_source = realloc(source, allocated);
-                if (reallocated_source == NULL) {
-                    free(source);
-                    source = NULL;
-                    break;
-                }
-                source = reallocated_source;
-            }
-        } while (!feof(fp));
+    result = PyObject_CallMethod(fileobject, "close", "");
+    if (!result) {
+        goto load_source_finally;
     }
-    fclose(fp);
-    if (source == NULL) {
-        Py_BEGIN_ALLOW_THREADS
-        if (r) {
-            ap_log_rerror(APLOG_MARK, APLOG_ERR, errno, r,
-                          "mod_wsgi (pid=%d, process='%s', application='%s'): "
-                          "Could not read source file '%s'.", getpid(),
-                          process_group, application_group, filename);
-        }
-        else {
-            ap_log_error(APLOG_MARK, APLOG_ERR, errno, wsgi_server,
-                         "mod_wsgi (pid=%d, process='%s', application='%s'): "
-                         "Could not read source file '%s'.", getpid(),
-                         process_group, application_group, filename);
-        }
-        Py_END_ALLOW_THREADS
-        return NULL;
+
+    source_buf = PyBytes_AsString(source_bytes_object);
+    if (!source_buf) {
+        goto load_source_finally;
     }
 
-    co = Py_CompileString(source, filename, Py_file_input);
-    free(source);
+    co = Py_CompileString(source_buf, filename, Py_file_input);
 
+load_source_finally:
+    Py_XDECREF(io_module);
+    Py_XDECREF(fileobject);
+    Py_XDECREF(source_bytes_object);
+    Py_XDECREF(result);
     if (!co) {
         Py_BEGIN_ALLOW_THREADS
         if (r) {
             ap_log_rerror(APLOG_MARK, APLOG_ERR, errno, r,
                           "mod_wsgi (pid=%d, process='%s', application='%s'): "
-                          "Could not compile source file '%s'.", getpid(),
+                          "Could not read/compile source file '%s'.", getpid(),
                           process_group, application_group, filename);
         }
         else {
             ap_log_error(APLOG_MARK, APLOG_ERR, errno, wsgi_server,
                          "mod_wsgi (pid=%d, process='%s', application='%s'): "
-                         "Could not compile source file '%s'.", getpid(),
+                         "Could not read/compile source file '%s'.", getpid(),
                          process_group, application_group, filename);
         }
         Py_END_ALLOW_THREADS

From ad1bd9f00eaf0ffa04df62914c1bd7e9f00d1b09 Mon Sep 17 00:00:00 2001
From: Petr Viktorin <encukou@gmail.com>
Date: Fri, 11 Jun 2021 13:00:34 +0200
Subject: [PATCH 7/7] configure: Use sysconfig rather than the deprecated
 distutils.sysconfig

---
 configure.ac | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/configure.ac b/configure.ac
index 0db345f4..9d4f779e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -106,11 +106,11 @@ fi
 AC_SUBST(PYTHON)
 
 PYTHON_VERSION=`${PYTHON} -c 'from sys import stdout; \
-    from distutils import sysconfig; \
+    import sysconfig; \
     stdout.write(sysconfig.get_config_var("VERSION"))'`
 
 PYTHON_LDVERSION=`${PYTHON} -c 'from sys import stdout; \
-    from distutils import sysconfig; \
+    import sysconfig; \
     stdout.write(sysconfig.get_config_var("LDVERSION") or "")'`
 
 if test x"${PYTHON_LDVERSION}" = x""; then
@@ -118,11 +118,11 @@ if test x"${PYTHON_LDVERSION}" = x""; then
 fi
 
 CPPFLAGS1=`${PYTHON} -c 'from sys import stdout; \
-    from distutils import sysconfig; \
+    import sysconfig; \
     stdout.write("-I" + sysconfig.get_config_var("INCLUDEPY"))'`
 
 CPPFLAGS2=`${PYTHON} -c 'from sys import stdout; \
-    from distutils import sysconfig; \
+    import sysconfig; \
     stdout.write(" ".join(filter(lambda x: x.startswith("-D"), \
     sysconfig.get_config_var("CFLAGS").split())))'`
 
@@ -137,20 +137,20 @@ CPPFLAGS="${CPPFLAGS} ${CPPFLAGS1} ${CPPFLAGS2} ${CPPFLAGS3}"
 AC_SUBST(CPPFLAGS)
 
 PYTHONLIBDIR=`${PYTHON} -c 'from sys import stdout; \
-    from distutils import sysconfig; \
+    import sysconfig; \
     stdout.write(sysconfig.get_config_var("LIBDIR"))'`
 PYTHONCFGDIR=`${PYTHON} -c 'from sys import stdout; \
     import distutils.sysconfig; \
     stdout.write(distutils.sysconfig.get_python_lib(plat_specific=1, \
     standard_lib=1) +"/config")'`
 PYTHONFRAMEWORKDIR=`${PYTHON} -c 'from sys import stdout; \
-    from distutils import sysconfig; \
+    import sysconfig; \
     stdout.write(sysconfig.get_config_var("PYTHONFRAMEWORKDIR"))'`
 PYTHONFRAMEWORKPREFIX=`${PYTHON} -c 'from sys import stdout; \
-    from distutils import sysconfig; \
+    import sysconfig; \
     stdout.write(sysconfig.get_config_var("PYTHONFRAMEWORKPREFIX"))'`
 PYTHONFRAMEWORK=`${PYTHON} -c 'from sys import stdout; \
-    from distutils import sysconfig; \
+    import sysconfig; \
     stdout.write(sysconfig.get_config_var("PYTHONFRAMEWORK"))'`
 
 if test "${PYTHON_LDVERSION}" != "${PYTHON_VERSION}"; then
@@ -176,10 +176,10 @@ if test "${PYTHONFRAMEWORKDIR}" = "no-framework" -o \
     fi
 
     LDLIBS2=`${PYTHON} -c 'from sys import stdout; \
-        from distutils import sysconfig; \
+        import sysconfig; \
         stdout.write(sysconfig.get_config_var("LIBS"))'`
     LDLIBS3=`${PYTHON} -c 'from sys import stdout; \
-        from distutils import sysconfig; \
+        import sysconfig; \
         stdout.write(sysconfig.get_config_var("SYSLIBS"))'`
 else
     LDFLAGS1="-Wl,-F${PYTHONFRAMEWORKPREFIX} -framework ${PYTHONFRAMEWORK}"
@@ -187,13 +187,13 @@ else
     VERSION="${PYTHON_VERSION}"
     STRING="${PYTHONFRAMEWORKDIR}/Versions/${VERSION}/${PYTHONFRAMEWORK}"
     LDFLAGS2=`${PYTHON} -c "from sys import stdout; \
-        from distutils import sysconfig; \
+        import sysconfig; \
         stdout.write(sysconfig.get_config_var(
         \"LINKFORSHARED\").replace(\"${STRING}\", ''))" | \
         sed -e 's/-Wl,-stack_size,[[0-9]]*//'`
 
     LDLIBS1=`${PYTHON} -c 'from sys import stdout; \
-        from distutils import sysconfig; \
+        import sysconfig; \
         stdout.write(sysconfig.get_config_var("LIBS"))'`
 fi