From 4d3c10f4dd4927a6cf4657887e01e997ad7ecf43 Mon Sep 17 00:00:00 2001 From: Oleg S Date: Tue, 4 Apr 2023 23:31:53 +0300 Subject: [PATCH] Added type finalize and destructor into start_response (#40) --- fastwsgi/request.c | 7 +- fastwsgi/server.c | 1 + fastwsgi/start_response.c | 142 ++++++++++++++++++++++---------------- fastwsgi/start_response.h | 24 ++++--- 4 files changed, 96 insertions(+), 78 deletions(-) diff --git a/fastwsgi/request.c b/fastwsgi/request.c index 162a92d..d0e601b 100644 --- a/fastwsgi/request.c +++ b/fastwsgi/request.c @@ -93,12 +93,7 @@ int reset_wsgi_input(client_t * client) void free_start_response(client_t * client) { - if (client->start_response) { - Py_CLEAR(client->start_response->headers); - Py_CLEAR(client->start_response->status); - Py_CLEAR(client->start_response->exc_info); - Py_CLEAR(client->start_response); - } + Py_CLEAR(client->start_response); } void reset_response_preload(client_t * client) diff --git a/fastwsgi/server.c b/fastwsgi/server.c index 7e4ba51..028bfc6 100644 --- a/fastwsgi/server.c +++ b/fastwsgi/server.c @@ -623,6 +623,7 @@ int init_srv() configure_parser_settings(&g_srv.parser_settings); init_constants(); init_request_dict(); + PyType_Ready(&StartResponse_Type); sockaddr_t addr; int tcp_flags = 0; diff --git a/fastwsgi/start_response.c b/fastwsgi/start_response.c index 79ad91b..84d10f8 100644 --- a/fastwsgi/start_response.c +++ b/fastwsgi/start_response.c @@ -1,94 +1,104 @@ #include #include "start_response.h" -void set_status_error() { - char* err_msg = "'status' must be a 3-digit string"; +void set_status_error() +{ + const char * err_msg = "'status' must be a 3-digit string"; PyErr_SetString(PyExc_ValueError, err_msg); } -void set_header_tuple_error() { - char* err_msg = "start_response argument 2 expects a list of 2-tuples (str, str)"; +void set_header_tuple_error() +{ + const char * err_msg = "start_response: argument 2 expects a list of 2-tuples (str, str)"; PyErr_SetString(PyExc_TypeError, err_msg); } -void set_header_list_error(PyObject* headers) { - PyErr_Format( - PyExc_TypeError, - "start_response argument 2 expects a list of 2-tuples, got '%s' instead.", - Py_TYPE(headers)->tp_name - ); +void set_header_list_error(PyObject * headers) +{ + const char * err_msg = "start_response: argument 2 expects a list of 2-tuples, got '%s' instead."; + PyErr_Format(PyExc_TypeError, err_msg, Py_TYPE(headers)->tp_name); } -void set_exc_info_type_error(PyObject* exc_info) { - PyErr_Format( - PyExc_TypeError, - "start_response argument 3 expects a 3-tuple, got '%s' instead.", - Py_TYPE(exc_info)->tp_name - ); +void set_exc_info_type_error(PyObject * exc_info) +{ + const char * err_msg = "start_response: argument 3 expects a 3-tuple, got '%s' instead."; + PyErr_Format(PyExc_TypeError, err_msg, Py_TYPE(exc_info)->tp_name); } -void set_exc_info_missing_error() { +void set_exc_info_missing_error() +{ char* err_msg = "'exc_info' is required in the second call of 'start_response'"; PyErr_SetString(PyExc_TypeError, err_msg); } -bool is_valid_status(PyObject* status) { - bool valid = PyUnicode_Check(status) && PyUnicode_GET_LENGTH(status) >= 3; - if (!valid) set_status_error(); - return valid; +static +bool is_valid_status(PyObject * status) +{ + if (PyUnicode_Check(status)) + if (PyUnicode_GET_LENGTH(status) >= 3) + return true; + + set_status_error(); + return false; } -bool is_valid_header_tuple(PyObject* tuple) { - bool valid = false; +static +bool is_valid_header_tuple(PyObject * tuple) +{ + if (PyTuple_Check(tuple)) + if (PyTuple_GET_SIZE(tuple) == 2) + if (PyUnicode_Check(PyTuple_GET_ITEM(tuple, 0))) + if (PyUnicode_Check(PyTuple_GET_ITEM(tuple, 1))) + return true; - if (PyTuple_Check(tuple) && PyTuple_GET_SIZE(tuple) == 2) { - int field = PyUnicode_Check(PyTuple_GET_ITEM(tuple, 0)); - int value = PyUnicode_Check(PyTuple_GET_ITEM(tuple, 1)); - valid = field && value; - } - if (!valid) set_header_tuple_error(); - return valid; + set_header_tuple_error(); + return false; } -bool is_valid_headers(PyObject* headers) { - bool valid = PyList_Check(headers); - - if (!valid) { - set_header_list_error(headers); - return valid; +static +bool is_valid_headers(PyObject * headers) +{ + if (PyList_Check(headers)) { + Py_ssize_t len = PyList_GET_SIZE(headers); + for (Py_ssize_t i = 0; i < len; i++) { + if (!is_valid_header_tuple(PyList_GET_ITEM(headers, i))) + return false; + } + return true; } - - for (Py_ssize_t i = 0; i < PyList_GET_SIZE(headers); i++) { - valid = is_valid_header_tuple(PyList_GET_ITEM(headers, i)); - if (!valid) break; - } - return valid; + set_header_list_error(headers); + return false; } -bool is_valid_exc_info(StartResponse* sr) { - bool valid = true; - +static +bool is_valid_exc_info(StartResponse * sr) +{ if (sr->exc_info && sr->exc_info != Py_None) { - valid = PyTuple_Check(sr->exc_info) && PyTuple_GET_SIZE(sr->exc_info); - if (!valid) set_exc_info_type_error(sr->exc_info); + if (PyTuple_Check(sr->exc_info)) + if (PyTuple_GET_SIZE(sr->exc_info) == 3) + return true; + + set_exc_info_type_error(sr->exc_info); + return false; } - else if (sr->called == 1) { + if (sr->called == 1) { set_exc_info_missing_error(); - valid = false; + return false; } - return valid; + return true; } -PyObject* start_response_call(PyObject* self, PyObject* args, PyObject* kwargs) { - StartResponse* sr = (StartResponse*)self; - +static +PyObject * start_response_call(StartResponse * sr, PyObject * args, PyObject * kwargs) +{ if (sr->called == 1) { Py_CLEAR(sr->status); Py_CLEAR(sr->headers); } - sr->exc_info = NULL; - if (!PyArg_UnpackTuple(args, "start_response", 2, 3, &sr->status, &sr->headers, &sr->exc_info)) + + int rc = PyArg_UnpackTuple(args, "start_response", 2, 3, &sr->status, &sr->headers, &sr->exc_info); + if (rc == (int)false) return NULL; if (!is_valid_status(sr->status)) @@ -109,12 +119,22 @@ PyObject* start_response_call(PyObject* self, PyObject* args, PyObject* kwargs) Py_RETURN_NONE; } +static +void start_response_dealloc(StartResponse * self) +{ + Py_CLEAR(self->status); + Py_CLEAR(self->headers); + Py_CLEAR(self->exc_info); + PyObject_Del(self); +} + PyTypeObject StartResponse_Type = { PyVarObject_HEAD_INIT(NULL, 0) - "start_response", - sizeof(StartResponse), - 0, - (destructor)PyObject_FREE, - 0, 0, 0, 0, 0, 0, 0, 0, 0, - start_response_call + .tp_name = "start_response", + .tp_basicsize = sizeof(StartResponse), + .tp_itemsize = 0, + .tp_dealloc = (destructor) start_response_dealloc, + .tp_call = (ternaryfunc) start_response_call, + .tp_flags = Py_TPFLAGS_DEFAULT, + .tp_finalize = NULL }; diff --git a/fastwsgi/start_response.h b/fastwsgi/start_response.h index cdee962..187bcf1 100644 --- a/fastwsgi/start_response.h +++ b/fastwsgi/start_response.h @@ -4,11 +4,11 @@ #include "common.h" typedef struct { - PyObject ob_base; - PyObject* status; - PyObject* headers; - PyObject* exc_info; - int called; + PyObject ob_base; + PyObject * status; + PyObject * headers; + PyObject * exc_info; + int called; } StartResponse; extern PyTypeObject StartResponse_Type; @@ -16,12 +16,14 @@ extern PyTypeObject StartResponse_Type; INLINE static StartResponse * create_start_response(void) { - StartResponse * response = PyObject_NEW(StartResponse, &StartResponse_Type); - response->status = NULL; - response->headers = NULL; - response->exc_info = NULL; - response->called = 0; - return response; + StartResponse * sr = PyObject_NEW(StartResponse, &StartResponse_Type); + if (sr) { + sr->status = NULL; + sr->headers = NULL; + sr->exc_info = NULL; + sr->called = 0; + } + return sr; } void set_status_error();