Added type finalize and destructor into start_response (#40)

This commit is contained in:
Oleg S
2023-04-04 23:31:53 +03:00
committed by GitHub
parent 6574f5e96e
commit 4d3c10f4dd
4 changed files with 96 additions and 78 deletions

View File

@@ -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)

View File

@@ -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;

View File

@@ -1,94 +1,104 @@
#include <stdbool.h>
#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
};

View File

@@ -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();