diff --git a/.gitignore b/.gitignore index 2a7b110..c36cafb 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ mod_wsgi-3.2.tar.gz /mod_wsgi-4.6.6.tar.gz /mod_wsgi-4.6.8.tar.gz /mod_wsgi-4.7.1.tar.gz +/mod_wsgi-4.8.0.tar.gz diff --git a/mod_wsgi-python-3.10-support.patch b/mod_wsgi-python-3.10-support.patch new file mode 100644 index 0000000..9db5b29 --- /dev/null +++ b/mod_wsgi-python-3.10-support.patch @@ -0,0 +1,869 @@ +From b439f1c411a9479ccc03c16465cdff50fede79d3 Mon Sep 17 00:00:00 2001 +From: Petr Viktorin +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 +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 +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 +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 +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 +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 +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 + diff --git a/mod_wsgi.spec b/mod_wsgi.spec index 8b52f6e..a7b82f2 100644 --- a/mod_wsgi.spec +++ b/mod_wsgi.spec @@ -20,8 +20,8 @@ %endif Name: mod_wsgi -Version: 4.7.1 -Release: 5%{?dist} +Version: 4.8.0 +Release: 1%{?dist} Summary: A WSGI interface for Python web applications in Apache License: ASL 2.0 URL: https://modwsgi.readthedocs.io/ @@ -29,6 +29,7 @@ Source0: https://github.com/GrahamDumpleton/mod_wsgi/archive/%{version}.t Source1: wsgi.conf Source2: wsgi-python3.conf Patch1: mod_wsgi-4.5.20-exports.patch +Patch2: mod_wsgi-python-3.10-support.patch BuildRequires: make BuildRequires: httpd-devel @@ -164,6 +165,11 @@ ln -s %{_bindir}/mod_wsgi-express-2 $RPM_BUILD_ROOT%{_bindir}/mod_wsgi-express %endif %changelog +* Thu Jun 17 2021 Alexander Bokovoy - 4.8.0-1 +- update to 4.8.0 +- Add experimental Python 3.10 support (#1898158) +- Upstream PR: https://github.com/GrahamDumpleton/mod_wsgi/pull/688 + * Fri Jun 04 2021 Python Maint - 4.7.1-5 - Rebuilt for Python 3.10 diff --git a/sources b/sources index 8a0b850..d76e93e 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (mod_wsgi-4.7.1.tar.gz) = cbb5ec53d55e47a83f2b0630527c6a52b48ef21d5d2c18adcb875fc455795b39b3c93f4a86dfbf9738c0bd554d86cc4912cc9ff83c428af302ab94a61f66b5b4 +SHA512 (mod_wsgi-4.8.0.tar.gz) = cf9909c23f2cb1f7871f827977f4e4609f499cb8361e6cde362b2483bd0dd74f4503e0c56f5cb0c82e3c5a1a09b3ad97b46fd9b5bcfaf2f336665e52e06339b3