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:
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);
}