2008-05-23 21:21:07 +02:00
/*
Unix SMB / CIFS implementation .
Samba utility functions
Copyright © Jelmer Vernooij < jelmer @ samba . org > 2008
Implementation of the WSGI interface described in PEP0333
( http : //www.python.org/dev/peps/pep-0333)
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 3 of the License , or
( at your option ) any later version .
This program 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 General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
2009-10-23 16:23:01 +11:00
# include <Python.h>
2008-05-23 21:21:07 +02:00
# include "includes.h"
2008-05-24 18:13:30 +02:00
# include "web_server/web_server.h"
2008-10-11 21:31:42 +02:00
# include "../lib/util/dlinklist.h"
# include "../lib/util/data_blob.h"
2008-09-21 20:01:00 +02:00
# include "lib/tls/tls.h"
2010-04-28 14:52:40 +02:00
# include "lib/tsocket/tsocket.h"
2009-01-08 12:20:20 +01:00
2008-09-21 18:45:09 +02:00
typedef struct {
PyObject_HEAD
struct websrv_context * web ;
} web_request_Object ;
2008-05-24 18:13:30 +02:00
static PyObject * start_response ( PyObject * self , PyObject * args , PyObject * kwargs )
2008-05-23 21:21:07 +02:00
{
2008-09-21 18:45:09 +02:00
PyObject * response_header , * exc_info = NULL ;
2008-05-23 21:21:07 +02:00
char * status ;
2008-09-21 18:45:09 +02:00
int i ;
2008-05-23 21:21:07 +02:00
const char * kwnames [ ] = {
" status " , " response_header " , " exc_info " , NULL
} ;
2008-09-21 18:45:09 +02:00
web_request_Object * py_web = ( web_request_Object * ) self ;
struct websrv_context * web = py_web - > web ;
struct http_header * headers = NULL ;
2008-05-23 21:21:07 +02:00
2008-09-21 18:45:09 +02:00
if ( ! PyArg_ParseTupleAndKeywords ( args , kwargs , " sO|O:start_response " , discard_const_p ( char * , kwnames ) , & status , & response_header , & exc_info ) ) {
2008-05-23 21:21:07 +02:00
return NULL ;
}
2008-09-21 18:45:09 +02:00
/* FIXME: exc_info */
2008-05-23 21:21:07 +02:00
2008-09-21 18:45:09 +02:00
if ( ! PyList_Check ( response_header ) ) {
PyErr_SetString ( PyExc_TypeError , " response_header should be list " ) ;
return NULL ;
}
for ( i = 0 ; i < PyList_Size ( response_header ) ; i + + ) {
struct http_header * hdr = talloc_zero ( web , struct http_header ) ;
PyObject * item = PyList_GetItem ( response_header , i ) ;
PyObject * py_name , * py_value ;
if ( ! PyTuple_Check ( item ) ) {
PyErr_SetString ( PyExc_TypeError , " Expected tuple " ) ;
return NULL ;
}
if ( PyTuple_Size ( item ) ! = 2 ) {
PyErr_SetString ( PyExc_TypeError , " header tuple has invalid size, expected 2 " ) ;
return NULL ;
}
py_name = PyTuple_GetItem ( item , 0 ) ;
if ( ! PyString_Check ( py_name ) ) {
PyErr_SetString ( PyExc_TypeError , " header name should be string " ) ;
return NULL ;
}
py_value = PyTuple_GetItem ( item , 1 ) ;
if ( ! PyString_Check ( py_value ) ) {
PyErr_SetString ( PyExc_TypeError , " header value should be string " ) ;
return NULL ;
}
hdr - > name = talloc_strdup ( hdr , PyString_AsString ( py_name ) ) ;
hdr - > value = talloc_strdup ( hdr , PyString_AsString ( py_value ) ) ;
DLIST_ADD ( headers , hdr ) ;
}
websrv_output_headers ( web , status , headers ) ;
2009-01-06 04:13:57 +01:00
Py_RETURN_NONE ;
2008-05-23 21:21:07 +02:00
}
2008-09-21 18:45:09 +02:00
static PyMethodDef web_request_methods [ ] = {
{ " start_response " , ( PyCFunction ) start_response , METH_VARARGS | METH_KEYWORDS , NULL } ,
{ NULL }
} ;
PyTypeObject web_request_Type = {
PyObject_HEAD_INIT ( NULL ) 0 ,
. tp_name = " wsgi.Request " ,
. tp_methods = web_request_methods ,
. tp_basicsize = sizeof ( web_request_Object ) ,
. tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE ,
} ;
2008-05-24 15:43:37 +02:00
typedef struct {
PyObject_HEAD
} error_Stream_Object ;
2008-05-24 03:54:47 +02:00
2008-05-24 15:43:37 +02:00
static PyObject * py_error_flush ( PyObject * self , PyObject * args , PyObject * kwargs )
{
/* Nothing to do here */
2009-01-06 04:13:57 +01:00
Py_RETURN_NONE ;
2008-05-24 15:43:37 +02:00
}
static PyObject * py_error_write ( PyObject * self , PyObject * args , PyObject * kwargs )
{
const char * kwnames [ ] = { " str " , NULL } ;
char * str = NULL ;
2008-09-21 16:53:29 +02:00
if ( ! PyArg_ParseTupleAndKeywords ( args , kwargs , " s:write " , discard_const_p ( char * , kwnames ) , & str ) ) {
2008-05-24 15:43:37 +02:00
return NULL ;
}
DEBUG ( 0 , ( " WSGI App: %s " , str ) ) ;
2009-01-06 04:13:57 +01:00
Py_RETURN_NONE ;
2008-05-24 15:43:37 +02:00
}
static PyObject * py_error_writelines ( PyObject * self , PyObject * args , PyObject * kwargs )
{
const char * kwnames [ ] = { " seq " , NULL } ;
PyObject * seq = NULL , * item ;
2008-09-21 16:53:29 +02:00
if ( ! PyArg_ParseTupleAndKeywords ( args , kwargs , " O:writelines " , discard_const_p ( char * , kwnames ) , & seq ) ) {
2008-05-24 15:43:37 +02:00
return NULL ;
}
while ( ( item = PyIter_Next ( seq ) ) ) {
char * str = PyString_AsString ( item ) ;
DEBUG ( 0 , ( " WSGI App: %s " , str ) ) ;
}
2009-01-06 04:13:57 +01:00
Py_RETURN_NONE ;
2008-05-24 15:43:37 +02:00
}
static PyMethodDef error_Stream_methods [ ] = {
2008-09-21 18:45:09 +02:00
{ " flush " , ( PyCFunction ) py_error_flush , METH_VARARGS | METH_KEYWORDS , NULL } ,
{ " write " , ( PyCFunction ) py_error_write , METH_VARARGS | METH_KEYWORDS , NULL } ,
{ " writelines " , ( PyCFunction ) py_error_writelines , METH_VARARGS | METH_KEYWORDS , NULL } ,
2008-05-24 15:43:37 +02:00
{ NULL , NULL , 0 , NULL }
} ;
PyTypeObject error_Stream_Type = {
PyObject_HEAD_INIT ( NULL ) 0 ,
. tp_name = " wsgi.ErrorStream " ,
. tp_basicsize = sizeof ( error_Stream_Object ) ,
. tp_methods = error_Stream_methods ,
. tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE ,
} ;
typedef struct {
PyObject_HEAD
2008-09-21 20:01:00 +02:00
struct websrv_context * web ;
size_t offset ;
2008-05-24 15:43:37 +02:00
} input_Stream_Object ;
2008-09-21 20:01:00 +02:00
static PyObject * py_input_read ( PyObject * _self , PyObject * args , PyObject * kwargs )
2008-05-24 03:54:47 +02:00
{
2008-09-21 20:01:00 +02:00
const char * kwnames [ ] = { " size " , NULL } ;
PyObject * ret ;
input_Stream_Object * self = ( input_Stream_Object * ) _self ;
int size = - 1 ;
if ( ! PyArg_ParseTupleAndKeywords ( args , kwargs , " |i " , discard_const_p ( char * , kwnames ) , & size ) )
return NULL ;
/* Don't read beyond buffer boundaries */
if ( size = = - 1 )
size = self - > web - > input . partial . length - self - > offset ;
else
size = MIN ( size , self - > web - > input . partial . length - self - > offset ) ;
ret = PyString_FromStringAndSize ( ( char * ) self - > web - > input . partial . data + self - > offset , size ) ;
self - > offset + = size ;
return ret ;
2008-05-24 03:54:47 +02:00
}
2008-09-21 20:01:00 +02:00
static PyObject * py_input_readline ( PyObject * _self )
2008-05-24 15:43:37 +02:00
{
2008-09-21 18:45:09 +02:00
/* FIXME */
2008-09-21 20:01:00 +02:00
PyErr_SetString ( PyExc_NotImplementedError ,
" readline() not yet implemented " ) ;
2008-05-24 15:43:37 +02:00
return NULL ;
}
2008-09-21 20:01:00 +02:00
static PyObject * py_input_readlines ( PyObject * _self , PyObject * args , PyObject * kwargs )
2008-05-24 15:43:37 +02:00
{
2008-09-21 20:01:00 +02:00
const char * kwnames [ ] = { " hint " , NULL } ;
int hint ;
if ( ! PyArg_ParseTupleAndKeywords ( args , kwargs , " |i " , discard_const_p ( char * , kwnames ) , & hint ) )
return NULL ;
2008-09-21 18:45:09 +02:00
/* FIXME */
2008-09-21 20:01:00 +02:00
PyErr_SetString ( PyExc_NotImplementedError ,
" readlines() not yet implemented " ) ;
2008-05-24 15:43:37 +02:00
return NULL ;
}
2008-09-21 20:01:00 +02:00
static PyObject * py_input___iter__ ( PyObject * _self )
2008-05-24 03:54:47 +02:00
{
2008-09-21 18:45:09 +02:00
/* FIXME */
2008-09-21 20:01:00 +02:00
PyErr_SetString ( PyExc_NotImplementedError ,
" __iter__() not yet implemented " ) ;
2008-05-24 03:54:47 +02:00
return NULL ;
}
2008-05-24 15:43:37 +02:00
static PyMethodDef input_Stream_methods [ ] = {
2008-09-21 18:45:09 +02:00
{ " read " , ( PyCFunction ) py_input_read , METH_VARARGS | METH_KEYWORDS , NULL } ,
2008-09-21 20:01:00 +02:00
{ " readline " , ( PyCFunction ) py_input_readline , METH_NOARGS , NULL } ,
2008-09-21 18:45:09 +02:00
{ " readlines " , ( PyCFunction ) py_input_readlines , METH_VARARGS | METH_KEYWORDS , NULL } ,
2008-09-21 20:01:00 +02:00
{ " __iter__ " , ( PyCFunction ) py_input___iter__ , METH_NOARGS , NULL } ,
2008-05-24 15:43:37 +02:00
{ NULL , NULL , 0 , NULL }
} ;
PyTypeObject input_Stream_Type = {
PyObject_HEAD_INIT ( NULL ) 0 ,
. tp_name = " wsgi.InputStream " ,
. tp_basicsize = sizeof ( input_Stream_Object ) ,
. tp_methods = input_Stream_methods ,
. tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE ,
} ;
2008-09-21 20:01:00 +02:00
static PyObject * Py_InputHttpStream ( struct websrv_context * web )
2008-05-24 15:43:37 +02:00
{
2008-09-21 16:53:29 +02:00
input_Stream_Object * ret = PyObject_New ( input_Stream_Object , & input_Stream_Type ) ;
2008-09-21 20:01:00 +02:00
ret - > web = web ;
ret - > offset = 0 ;
2008-09-21 16:53:29 +02:00
return ( PyObject * ) ret ;
2008-05-24 15:43:37 +02:00
}
static PyObject * Py_ErrorHttpStream ( void )
{
2008-09-21 16:53:29 +02:00
error_Stream_Object * ret = PyObject_New ( error_Stream_Object , & error_Stream_Type ) ;
return ( PyObject * ) ret ;
2008-05-24 15:43:37 +02:00
}
2008-09-21 20:01:00 +02:00
static PyObject * create_environ ( bool tls , int content_length , struct http_header * headers , const char * request_method , const char * servername , int serverport , PyObject * inputstream , const char * request_string )
2008-05-23 21:21:07 +02:00
{
2008-09-21 18:45:09 +02:00
PyObject * env ;
2008-09-21 20:01:00 +02:00
PyObject * errorstream ;
2008-09-21 18:45:09 +02:00
PyObject * py_scheme ;
struct http_header * hdr ;
2008-09-21 20:01:00 +02:00
char * questionmark ;
2008-09-21 18:45:09 +02:00
env = PyDict_New ( ) ;
if ( env = = NULL ) {
2008-05-23 21:21:07 +02:00
return NULL ;
2008-09-21 18:45:09 +02:00
}
2008-05-24 03:54:47 +02:00
errorstream = Py_ErrorHttpStream ( ) ;
if ( errorstream = = NULL ) {
Py_DECREF ( env ) ;
Py_DECREF ( inputstream ) ;
return NULL ;
}
PyDict_SetItemString ( env , " wsgi.input " , inputstream ) ;
PyDict_SetItemString ( env , " wsgi.errors " , errorstream ) ;
2008-05-23 21:21:07 +02:00
PyDict_SetItemString ( env , " wsgi.version " , Py_BuildValue ( " (i,i) " , 1 , 0 ) ) ;
PyDict_SetItemString ( env , " wsgi.multithread " , Py_False ) ;
PyDict_SetItemString ( env , " wsgi.multiprocess " , Py_True ) ;
PyDict_SetItemString ( env , " wsgi.run_once " , Py_False ) ;
2008-09-21 18:45:09 +02:00
PyDict_SetItemString ( env , " SERVER_PROTOCOL " , PyString_FromString ( " HTTP/1.0 " ) ) ;
if ( content_length > 0 ) {
PyDict_SetItemString ( env , " CONTENT_LENGTH " , PyLong_FromLong ( content_length ) ) ;
}
PyDict_SetItemString ( env , " REQUEST_METHOD " , PyString_FromString ( request_method ) ) ;
2008-09-21 20:01:00 +02:00
questionmark = strchr ( request_string , ' ? ' ) ;
if ( questionmark = = NULL ) {
PyDict_SetItemString ( env , " SCRIPT_NAME " , PyString_FromString ( request_string ) ) ;
} else {
PyDict_SetItemString ( env , " QUERY_STRING " , PyString_FromString ( questionmark + 1 ) ) ;
PyDict_SetItemString ( env , " SCRIPT_NAME " , PyString_FromStringAndSize ( request_string , questionmark - request_string ) ) ;
}
PyDict_SetItemString ( env , " SERVER_NAME " , PyString_FromString ( servername ) ) ;
PyDict_SetItemString ( env , " SERVER_PORT " , PyInt_FromLong ( serverport ) ) ;
2008-09-21 18:45:09 +02:00
for ( hdr = headers ; hdr ; hdr = hdr - > next ) {
char * name ;
2008-09-21 20:01:00 +02:00
if ( ! strcasecmp ( hdr - > name , " Content-Type " ) ) {
PyDict_SetItemString ( env , " CONTENT_TYPE " , PyString_FromString ( hdr - > value ) ) ;
} else {
2010-05-27 17:45:19 +02:00
if ( asprintf ( & name , " HTTP_%s " , hdr - > name ) < 0 ) {
2010-05-30 11:01:25 +02:00
Py_DECREF ( env ) ;
Py_DECREF ( inputstream ) ;
2010-05-28 18:58:45 +02:00
PyErr_NoMemory ( ) ;
return NULL ;
2010-05-27 17:45:19 +02:00
}
2008-09-21 20:01:00 +02:00
PyDict_SetItemString ( env , name , PyString_FromString ( hdr - > value ) ) ;
free ( name ) ;
}
2008-09-21 18:45:09 +02:00
}
2008-05-23 21:21:07 +02:00
2008-09-21 18:45:09 +02:00
if ( tls ) {
py_scheme = PyString_FromString ( " https " ) ;
} else {
py_scheme = PyString_FromString ( " http " ) ;
}
PyDict_SetItemString ( env , " wsgi.url_scheme " , py_scheme ) ;
2008-05-23 21:21:07 +02:00
return env ;
}
2008-05-24 18:13:30 +02:00
2008-09-21 18:45:09 +02:00
static void wsgi_process_http_input ( struct web_server_data * wdata ,
struct websrv_context * web )
{
PyObject * py_environ , * result , * item , * iter ;
2009-02-02 10:13:43 +01:00
PyObject * request_handler = ( PyObject * ) wdata - > private_data ;
2010-04-28 14:52:40 +02:00
struct tsocket_address * my_address = web - > conn - > local_address ;
const char * addr = " 0.0.0.0 " ;
uint16_t port = 0 ;
2008-09-21 18:45:09 +02:00
web_request_Object * py_web = PyObject_New ( web_request_Object , & web_request_Type ) ;
py_web - > web = web ;
2010-04-28 14:52:40 +02:00
if ( tsocket_address_is_inet ( my_address , " ip " ) ) {
addr = tsocket_address_inet_addr_string ( my_address , wdata ) ;
port = tsocket_address_inet_port ( my_address ) ;
}
2008-09-21 20:01:00 +02:00
py_environ = create_environ ( tls_enabled ( web - > conn - > socket ) ,
2008-09-21 18:45:09 +02:00
web - > input . content_length ,
web - > input . headers ,
2008-09-21 20:01:00 +02:00
web - > input . post_request ? " POST " : " GET " ,
2010-04-28 14:52:40 +02:00
addr ,
port ,
2008-09-21 20:01:00 +02:00
Py_InputHttpStream ( web ) ,
web - > input . url
) ;
2008-09-21 18:45:09 +02:00
if ( py_environ = = NULL ) {
DEBUG ( 0 , ( " Unable to create WSGI environment object \n " ) ) ;
return ;
}
result = PyObject_CallMethod ( request_handler , discard_const_p ( char , " __call__ " ) , discard_const_p ( char , " OO " ) ,
py_environ , PyObject_GetAttrString ( ( PyObject * ) py_web , " start_response " ) ) ;
if ( result = = NULL ) {
DEBUG ( 0 , ( " error while running WSGI code \n " ) ) ;
return ;
}
iter = PyObject_GetIter ( result ) ;
Py_DECREF ( result ) ;
/* Now, iter over all the data returned */
while ( ( item = PyIter_Next ( iter ) ) ) {
2008-09-21 19:03:12 +02:00
websrv_output ( web , PyString_AsString ( item ) , PyString_Size ( item ) ) ;
2008-09-21 18:45:09 +02:00
Py_DECREF ( item ) ;
}
Py_DECREF ( iter ) ;
}
bool wsgi_initialize ( struct web_server_data * wdata )
2008-05-24 18:13:30 +02:00
{
2008-09-21 18:45:09 +02:00
PyObject * py_swat ;
2008-05-24 18:13:30 +02:00
2008-09-21 18:45:09 +02:00
Py_Initialize ( ) ;
if ( PyType_Ready ( & web_request_Type ) < 0 )
return false ;
if ( PyType_Ready ( & input_Stream_Type ) < 0 )
return false ;
if ( PyType_Ready ( & error_Stream_Type ) < 0 )
return false ;
wdata - > http_process_input = wsgi_process_http_input ;
py_swat = PyImport_Import ( PyString_FromString ( " swat " ) ) ;
if ( py_swat = = NULL ) {
DEBUG ( 0 , ( " Unable to find SWAT \n " ) ) ;
return false ;
}
2009-02-02 10:13:43 +01:00
wdata - > private_data = py_swat ;
2008-09-21 18:45:09 +02:00
return true ;
2008-05-24 18:13:30 +02:00
}