kore

An easy to use, scalable and secure web application framework for writing web APIs in C.
Commits | Files | Refs | README | LICENSE | git clone https://git.kore.io/kore.git

commit 6578fc65894026cb3fdbb49adf7f4a3f225c2aae
parent 0250c8ecba08681b98839d5f00defa3b25d153aa
Author: Joris Vink <joris@coders.se>
Date:   Wed,  1 Feb 2017 21:23:56 +0100

expose http_file interface to python.

Diffstat:
includes/python_methods.h | 37+++++++++++++++++++++++++++++++++++++
src/python.c | 111+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 148 insertions(+), 0 deletions(-)

diff --git a/includes/python_methods.h b/includes/python_methods.h @@ -70,13 +70,21 @@ struct pyhttp_request { struct http_request *req; }; +struct pyhttp_file { + PyObject_HEAD + struct http_file *file; +}; + static void pyhttp_dealloc(struct pyhttp_request *); +static void pyhttp_file_dealloc(struct pyhttp_file *); static PyObject *pyhttp_response(struct pyhttp_request *, PyObject *); static PyObject *pyhttp_argument(struct pyhttp_request *, PyObject *); static PyObject *pyhttp_body_read(struct pyhttp_request *, PyObject *); +static PyObject *pyhttp_file_lookup(struct pyhttp_request *, PyObject *); static PyObject *pyhttp_populate_get(struct pyhttp_request *, PyObject *); static PyObject *pyhttp_populate_post(struct pyhttp_request *, PyObject *); +static PyObject *pyhttp_populate_multi(struct pyhttp_request *, PyObject *); static PyObject *pyhttp_request_header(struct pyhttp_request *, PyObject *); static PyObject *pyhttp_response_header(struct pyhttp_request *, PyObject *); static PyObject *pyhttp_websocket_handshake(struct pyhttp_request *, @@ -86,8 +94,10 @@ static PyMethodDef pyhttp_request_methods[] = { METHOD("response", pyhttp_response, METH_VARARGS), METHOD("argument", pyhttp_argument, METH_VARARGS), METHOD("body_read", pyhttp_body_read, METH_VARARGS), + METHOD("file_lookup", pyhttp_file_lookup, METH_VARARGS), METHOD("populate_get", pyhttp_populate_get, METH_NOARGS), METHOD("populate_post", pyhttp_populate_post, METH_NOARGS), + METHOD("populate_multi", pyhttp_populate_multi, METH_NOARGS), METHOD("request_header", pyhttp_request_header, METH_VARARGS), METHOD("response_header", pyhttp_response_header, METH_VARARGS), METHOD("websocket_handshake", pyhttp_websocket_handshake, METH_VARARGS), @@ -125,4 +135,31 @@ static PyTypeObject pyhttp_request_type = { .tp_basicsize = sizeof(struct pyhttp_request), .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, }; + +static PyObject *pyhttp_file_read(struct pyhttp_file *, PyObject *); + +static PyMethodDef pyhttp_file_methods[] = { + METHOD("read", pyhttp_file_read, METH_VARARGS), + METHOD(NULL, NULL, -1) +}; + +static PyObject *pyhttp_file_get_name(struct pyhttp_file *, void *); +static PyObject *pyhttp_file_get_filename(struct pyhttp_file *, void *); + +static PyGetSetDef pyhttp_file_getset[] = { + GETTER("name", pyhttp_file_get_name), + GETTER("filename", pyhttp_file_get_filename), + GETTER(NULL, NULL) +}; + +static PyTypeObject pyhttp_file_type = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "kore.http_file", + .tp_doc = "struct http_file", + .tp_getset = pyhttp_file_getset, + .tp_methods = pyhttp_file_methods, + .tp_dealloc = (destructor)pyhttp_file_dealloc, + .tp_basicsize = sizeof(struct pyhttp_file), + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, +}; #endif diff --git a/src/python.c b/src/python.c @@ -35,6 +35,7 @@ static PyObject *pyconnection_alloc(struct connection *); static PyObject *python_callable(PyObject *, const char *); #if !defined(KORE_NO_HTTP) +static PyObject *pyhttp_file_alloc(struct http_file *); static PyObject *pyhttp_request_alloc(struct http_request *); #endif @@ -247,6 +248,12 @@ pyhttp_dealloc(struct pyhttp_request *pyreq) PyObject_Del((PyObject *)pyreq); } +static void +pyhttp_file_dealloc(struct pyhttp_file *pyfile) +{ + PyObject_Del((PyObject *)pyfile); +} + static int python_runtime_http_request(void *addr, struct http_request *req) { @@ -469,6 +476,7 @@ python_module_init(void) } #if !defined(KORE_NO_HTTP) + python_push_type("pyhttp_file", pykore, &pyhttp_file_type); python_push_type("pyhttp_request", pykore, &pyhttp_request_type); #endif @@ -634,6 +642,20 @@ pyhttp_request_alloc(struct http_request *req) } static PyObject * +pyhttp_file_alloc(struct http_file *file) +{ + struct pyhttp_file *pyfile; + + pyfile = PyObject_New(struct pyhttp_file, &pyhttp_file_type); + if (pyfile == NULL) + return (NULL); + + pyfile->file = file; + + return ((PyObject *)pyfile); +} + +static PyObject * pyhttp_response(struct pyhttp_request *pyreq, PyObject *args) { Py_buffer body; @@ -740,6 +762,13 @@ pyhttp_populate_post(struct pyhttp_request *pyreq, PyObject *args) } static PyObject * +pyhttp_populate_multi(struct pyhttp_request *pyreq, PyObject *args) +{ + http_populate_multipart_form(pyreq->req); + Py_RETURN_TRUE; +} + +static PyObject * pyhttp_argument(struct pyhttp_request *pyreq, PyObject *args) { const char *name; @@ -762,6 +791,66 @@ pyhttp_argument(struct pyhttp_request *pyreq, PyObject *args) } static PyObject * +pyhttp_file_lookup(struct pyhttp_request *pyreq, PyObject *args) +{ + const char *name; + struct http_file *file; + PyObject *pyfile; + + if (!PyArg_ParseTuple(args, "s", &name)) { + PyErr_SetString(PyExc_TypeError, "invalid parameters"); + return (NULL); + } + + if ((file = http_file_lookup(pyreq->req, name)) == NULL) { + Py_RETURN_NONE; + } + + if ((pyfile = pyhttp_file_alloc(file)) == NULL) + return (PyErr_NoMemory()); + + return (pyfile); +} + +static PyObject * +pyhttp_file_read(struct pyhttp_file *pyfile, PyObject *args) +{ + ssize_t ret; + size_t len; + Py_ssize_t pylen; + PyObject *result; + u_int8_t buf[1024]; + + if (!PyArg_ParseTuple(args, "n", &pylen) || pylen < 0) { + PyErr_SetString(PyExc_TypeError, "invalid parameters"); + return (NULL); + } + + len = (size_t)pylen; + if (len > sizeof(buf)) { + PyErr_SetString(PyExc_RuntimeError, "len > sizeof(buf)"); + return (NULL); + } + + ret = http_file_read(pyfile->file, buf, len); + if (ret == -1) { + PyErr_SetString(PyExc_RuntimeError, "http_file_read() failed"); + return (NULL); + } + + if (ret > INT_MAX) { + PyErr_SetString(PyExc_RuntimeError, "ret > INT_MAX"); + return (NULL); + } + + result = Py_BuildValue("ny#", ret, buf, (int)ret); + if (result == NULL) + return (PyErr_NoMemory()); + + return (result); +} + +static PyObject * pyhttp_websocket_handshake(struct pyhttp_request *pyreq, PyObject *args) { const char *onconnect, *onmsg, *ondisconnect; @@ -947,4 +1036,26 @@ pyhttp_get_connection(struct pyhttp_request *pyreq, void *closure) return (pyc); } + +static PyObject * +pyhttp_file_get_name(struct pyhttp_file *pyfile, void *closure) +{ + PyObject *name; + + if ((name = PyUnicode_FromString(pyfile->file->name)) == NULL) + return (PyErr_NoMemory()); + + return (name); +} + +static PyObject * +pyhttp_file_get_filename(struct pyhttp_file *pyfile, void *closure) +{ + PyObject *name; + + if ((name = PyUnicode_FromString(pyfile->file->filename)) == NULL) + return (PyErr_NoMemory()); + + return (name); +} #endif