/* * Copyright (C) 2019 Weber Yann * * This file is part of PyFCGI. * * PyFCGI is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * PyFCGI is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with PyFCGI. If not, see . */ /**@defgroup libpyfcgi libpyfcgi python module * @brief The libpyfcgi python module * * PyFCGI defines a python module : libpyfcgi for PEP333 implementation. * This module contains 2 methods : start_response() and write_body() * * The first one is given as argument to the application function, and * the second one is returned when start_method() is called. */ /**@file python_pyfcgi.h * @ingroup libpyfcgi */ #ifndef _PYTHON_PYFCGI__H__ #define _PYTHON_PYFCGI__H__ #include "config.h" #include #include /* fcgi library; put it first*/ #define PY_SSIZE_T_CLEAN #include #include "structmember.h" #include "logger.h" #include "python_ioin.h" #define LIBPYFCGI_TIMEOUT_HEADERS "Content-Type: text/plain\r\nStatus: 504 Gateway Timeout\r\n\r\n" #define LIBPYFCGI_DEFAULT_HEADERS "Content-Type: text/html\r\nStatus: %s\r\n\r\n" #define LIBPYFCGI_DEFAULT_STATUS "200 OK" #define LIBPYFCGI_DEFAULT_CTYPE "Content-Type: text/html\r\n" #define LIBPYFCGI_STATUS_SZ 128 struct libpyfcgi_context_s { /**@brief PEP333 handling python module reference * @ingroup libpyfcgi */ PyObject *self; /**@brief PEP333 status ref * @ingroup libpyfcgi */ PyObject *status; /**@brief PEP333 headers ref * @ingroup libpyfcgi */ PyObject *headers; /**@brief libpyfcgi.IoIn instance */ PyIO_t *ioin; /**@brief libpyfcgi.IoOut instances for stdout & stderr */ PyIO_t *stdio[2]; /**@brief Indicate if headers was sent in a PEP333 application * @ingroup libpyfcgi */ short headers_sent; /**@brief Stores the libFCGI stream for PEP333 application * @ingroup libpyfcgi */ FCGX_Stream *out; /**@brief Stores the libFCGI stream from wich HTTP request can be read * @ingroup libpyfcgi */ FCGX_Stream *in; /**@brief Persistent buffer (avoid malloc) for PEP333 headers */ char *heads_buf; /**@brief Buffer size */ size_t heads_buf_sz; /**@brief Persistent buffer for PEP333 status */ char status_buf[LIBPYFCGI_STATUS_SZ]; size_t rep_sz; }; typedef struct libpyfcgi_context_s libpyfcgi_context_t; /**@brief Stores python module context */ extern libpyfcgi_context_t libpyfcgi; /**@brief libpyfcgi methods */ extern PyMethodDef pyfcgimodule_methods[]; /**@brief libpyfcgi module structure */ extern PyModuleDef pyfcgimodule; /**@brief Clean response_status & response_headers globals */ static inline void libpyfcgi_clean_response() { if(libpyfcgi.status) { Py_DECREF(libpyfcgi.status); } libpyfcgi.status = NULL; if(libpyfcgi.headers) { Py_DECREF(libpyfcgi.headers); } libpyfcgi.headers = NULL; libpyfcgi.headers_sent = 0; libpyfcgi.rep_sz = 0; libpyfcgi.ioin->eof=0; libpyfcgi.ioin->closed=Py_False; } /**@brief Send headers stored in @ref libpyfcgi context * @note Set python error if called from outside a valid context */ void libpyfcgi_send_headers(); /**@brief Send body to fcgi * @param body_data the body data object (returned by PEP333 app) * @return Python None */ PyObject* _pyfcgi_write_body(PyObject *body_data); /**@brief Called by the SIGALRM sighandler @ref worker_sigalrmhandler() * * If no headers sent send a timeout header. * * Attempt to generate a python exception and to log exception before * exiting. */ void libpyfcgi_timeout(); /* Defining Python module */ /**@brief Public module initialisation function * @ingroup libpyfcgi * @return A python module (PyObject*) */ PyMODINIT_FUNC PyInit_libpyfcgi(void); /**@brief libpyfcgi.start_response() python callable * @ingroup libpyfcgi * @note This python callable is a fastcall C method of libpyfcgi module. * * The python function header is : * start_response(status, response_headers, exc_info = None) * @param self * @param argv * @param argc * @return A PyObject* referencing a callable allowing to write data without * cache : libpyfcgi.write_body() */ PyObject* pyfcgi_start_response(PyObject* self, PyObject** argv, Py_ssize_t argc); /**@brief libpyfcgi.write_body() python callable * @ingroup libpyfcgi * @note This python callable is a fastcall C method of libpyfcgi module. * * The python function header is : write_body(body_data) * @param self * @param argv * @param argc * @return ??? */ PyObject* pyfcgi_write_body(PyObject* self, PyObject** argv, Py_ssize_t argc); int _libpyfcgi_stdout_write(const char*, size_t); int _libpyfcgi_stderr_write(const char*, size_t); #endif