kore

a fork of the worlds most advanced web framework
Log | Files | Refs | README | LICENSE

commit 9cc58d45c18b2acb1e572a8018b45c6aca081b5a
parent 89e58fa474c9a1ef33f8ea904f5d1029df942f1e
Author: Joris Vink <joris@coders.se>
Date:   Wed,  5 Jun 2019 23:45:45 +0200

Python HTTP improvements.

1) Add @kore.prerequest python decorator.

Using this decorator on a function will cause that function
to always be executed *before* any page handler is run.

eg:

@kore.prerequest
def _check(req):
    if req.method == kore.HTTP_METHOD_POST:
        req.populate_post()

2) Allow attributes to be set on the pyhttp object.

Diffstat:
Minclude/kore/python_methods.h | 6++++++
Msrc/python.c | 53++++++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 58 insertions(+), 1 deletion(-)

diff --git a/include/kore/python_methods.h b/include/kore/python_methods.h @@ -45,6 +45,7 @@ static PyObject *python_kore_fatalx(PyObject *, PyObject *); static PyObject *python_kore_suspend(PyObject *, PyObject *); static PyObject *python_kore_shutdown(PyObject *, PyObject *); static PyObject *python_kore_bind_unix(PyObject *, PyObject *); +static PyObject *python_kore_prerequest(PyObject *, PyObject *); static PyObject *python_kore_task_create(PyObject *, PyObject *); static PyObject *python_kore_socket_wrap(PyObject *, PyObject *); static PyObject *python_kore_gather(PyObject *, PyObject *, PyObject *); @@ -80,6 +81,7 @@ static struct PyMethodDef pykore_methods[] = { METHOD("suspend", python_kore_suspend, METH_VARARGS), METHOD("shutdown", python_kore_shutdown, METH_NOARGS), METHOD("bind_unix", python_kore_bind_unix, METH_VARARGS), + METHOD("prerequest", python_kore_prerequest, METH_VARARGS), METHOD("task_create", python_kore_task_create, METH_VARARGS), METHOD("socket_wrap", python_kore_socket_wrap, METH_VARARGS), METHOD("websocket_broadcast", python_websocket_broadcast, METH_VARARGS), @@ -544,6 +546,7 @@ static PyTypeObject pyconnection_type = { struct pyhttp_request { PyObject_HEAD struct http_request *req; + PyObject *dict; PyObject *data; }; @@ -621,10 +624,13 @@ static PyTypeObject pyhttp_request_type = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "kore.http_request", .tp_doc = "struct http_request", + .tp_setattro = PyObject_GenericSetAttr, + .tp_getattro = PyObject_GenericGetAttr, .tp_getset = pyhttp_request_getset, .tp_methods = pyhttp_request_methods, .tp_dealloc = (destructor)pyhttp_dealloc, .tp_basicsize = sizeof(struct pyhttp_request), + .tp_dictoffset = offsetof(struct pyhttp_request, dict), .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, }; diff --git a/src/python.c b/src/python.c @@ -40,6 +40,13 @@ #include "python_api.h" #include "python_methods.h" +struct reqcall { + PyObject *f; + LIST_ENTRY(reqcall) list; +}; + +LIST_HEAD(reqcall_list, reqcall); + static PyMODINIT_FUNC python_module_init(void); static PyObject *python_import(const char *); static PyObject *pyconnection_alloc(struct connection *); @@ -177,6 +184,7 @@ static PyMemAllocatorEx allocator = { }; static TAILQ_HEAD(, pyproc) procs; +static struct reqcall_list prereq; static struct kore_pool coro_pool; static struct kore_pool iterobj_pool; @@ -204,6 +212,8 @@ kore_python_init(void) coro_id = 0; coro_count = 0; + LIST_INIT(&prereq); + TAILQ_INIT(&procs); TAILQ_INIT(&coro_runnable); TAILQ_INIT(&coro_suspended); @@ -620,6 +630,7 @@ pyconnection_dealloc(struct pyconnection *pyc) static void pyhttp_dealloc(struct pyhttp_request *pyreq) { + Py_XDECREF(pyreq->dict); Py_XDECREF(pyreq->data); PyObject_Del((PyObject *)pyreq); } @@ -633,7 +644,8 @@ pyhttp_file_dealloc(struct pyhttp_file *pyfile) static int python_runtime_http_request(void *addr, struct http_request *req) { - PyObject *pyret, *pyreq, *args, *callable; + struct reqcall *rq; + PyObject *pyret, *pyreq, *args, *callable; if (req->py_coro != NULL) { python_coro_wakeup(req->py_coro); @@ -650,6 +662,26 @@ python_runtime_http_request(void *addr, struct http_request *req) if ((pyreq = pyhttp_request_alloc(req)) == NULL) fatal("python_runtime_http_request: pyreq alloc failed"); + LIST_FOREACH(rq, &prereq, list) { + PyErr_Clear(); + pyret = PyObject_CallFunctionObjArgs(rq->f, pyreq, NULL); + + if (pyret == NULL) { + Py_DECREF(pyreq); + kore_python_log_error("prerequest"); + http_response(req, HTTP_STATUS_INTERNAL_ERROR, NULL, 0); + return (KORE_RESULT_OK); + } + + if (pyret == Py_False) { + Py_DECREF(pyreq); + Py_DECREF(pyret); + return (KORE_RESULT_OK); + } + + Py_DECREF(pyret); + } + if ((args = PyTuple_New(1)) == NULL) fatal("python_runtime_http_request: PyTuple_New failed"); @@ -1104,6 +1136,24 @@ python_kore_bind_unix(PyObject *self, PyObject *args) } static PyObject * +python_kore_prerequest(PyObject *self, PyObject *args) +{ + PyObject *f; + struct reqcall *rq; + + if (!PyArg_ParseTuple(args, "O", &f)) + return (NULL); + + rq = kore_calloc(1, sizeof(*rq)); + rq->f = f; + + Py_INCREF(f); + LIST_INSERT_HEAD(&prereq, rq, list); + + return (f); +} + +static PyObject * python_kore_task_create(PyObject *self, PyObject *args) { PyObject *obj; @@ -3110,6 +3160,7 @@ pyhttp_request_alloc(const struct http_request *req) ptr.cp = req; pyreq->req = ptr.p; pyreq->data = NULL; + pyreq->dict = NULL; return ((PyObject *)pyreq); }