]> git.sesse.net Git - vlc/blob - modules/misc/lua/httpd.c
5538b799b1036b642e45bb46295ab2aa7eb0d23e
[vlc] / modules / misc / lua / httpd.c
1 /*****************************************************************************
2  * httpd.c: HTTPd wrapper
3  *****************************************************************************
4  * Copyright (C) 2007 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Antoine Cellerier <dionoea at videolan tod org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #ifndef  _GNU_SOURCE
28 #   define  _GNU_SOURCE
29 #endif
30
31 #ifdef HAVE_CONFIG_H
32 # include "config.h"
33 #endif
34
35 #include <vlc_common.h>
36 #include <vlc_httpd.h>
37
38 #include <lua.h>        /* Low level lua C API */
39 #include <lauxlib.h>    /* Higher level C API */
40 #include <lualib.h>     /* Lua libs */
41
42 #include "vlc.h"
43
44 /*****************************************************************************
45  * Local prototypes
46  *****************************************************************************/
47 static uint8_t *vlclua_todata( lua_State *L, int narg, int *i_data );
48
49 /*****************************************************************************
50  * HTTPD Host
51  *****************************************************************************/
52 #if 0
53 /* This is kind of a useless function since TLS with the 4 last args
54  * unset does the same thing as far as I know. */
55 int vlclua_httpd_host_new( lua_State *L )
56 {
57     vlc_object_t *p_this = vlclua_get_this( L );
58     const char *psz_host = luaL_checkstring( L, 1 );
59     int i_port = luaL_checkint( L, 2 );
60     httpd_host_t *p_httpd_host = httpd_HostNew( p_this, psz_host, i_port );
61     if( !p_httpd_host )
62         return luaL_error( L, "Failed to create HTTP host \"%s:%d\".",
63                            psz_host, i_port );
64     vlclua_push_vlc_object( L, p_httpd_host, vlclua_httpd_host_delete );
65     return 1;
66 }
67 #endif
68
69 int vlclua_httpd_tls_host_new( lua_State *L )
70 {
71     vlc_object_t *p_this = vlclua_get_this( L );
72     const char *psz_host = luaL_checkstring( L, 1 );
73     int i_port = luaL_checkint( L, 2 );
74     const char *psz_cert = luaL_optstring( L, 3, NULL );
75     const char *psz_key = luaL_optstring( L, 4, NULL );
76     const char *psz_ca = luaL_optstring( L, 5, NULL );
77     const char *psz_crl = luaL_optstring( L, 6, NULL );
78     httpd_host_t *p_httpd_host = httpd_TLSHostNew( p_this, psz_host, i_port,
79                                                    psz_cert, psz_key,
80                                                    psz_ca, psz_crl );
81     if( !p_httpd_host )
82         return luaL_error( L, "Failed to create HTTP TLS host \"%s:%d\" "
83                            "(cert: \"%s\", key: \"%s\", ca: \"%s\", "
84                            "crl: \"%s\").", psz_host, i_port,
85                            psz_cert, psz_key, psz_ca, psz_crl );
86     vlclua_push_vlc_object( L, (vlc_object_t*)p_httpd_host, vlclua_httpd_host_delete );
87     return 1;
88 }
89
90 #define ARG_1_IS_HTTPD_HOST httpd_host_t *p_httpd_host = \
91     (httpd_host_t*)vlclua_checkobject( L, 1, VLC_OBJECT_HTTPD_HOST );
92 int vlclua_httpd_host_delete( lua_State *L )
93 {
94     ARG_1_IS_HTTPD_HOST
95     httpd_HostDelete( p_httpd_host );
96     return 0;
97 }
98
99 /*****************************************************************************
100  * HTTPd Handler
101  *****************************************************************************/
102 struct httpd_handler_sys_t
103 {
104     lua_State *L;
105     int ref;
106 };
107
108 static int vlclua_httpd_handler_callback(
109      httpd_handler_sys_t *p_sys, httpd_handler_t *p_handler, char *psz_url,
110      uint8_t *psz_request, int i_type, uint8_t *p_in, int i_in,
111      char *psz_remote_addr, char *psz_remote_host,
112      uint8_t **pp_data, int *pi_data )
113 {
114     VLC_UNUSED(p_handler);
115     lua_State *L = p_sys->L;
116
117     /* function data */
118     lua_pushvalue( L, 1 );
119     lua_pushvalue( L, 2 );
120     /* function data function data */
121     lua_pushstring( L, psz_url );
122     /* function data function data url */
123     lua_pushstring( L, (const char *)psz_request );
124     /* function data function data url request */
125     lua_pushinteger( L, i_type ); /* Q: what does i_type stand for? */
126     /* function data function data url request type */
127     lua_pushlstring( L, (const char *)p_in, i_in ); /* Q: what do p_in contain? */
128     /* function data function data url request type in */
129     lua_pushstring( L, psz_remote_addr );
130     /* function data function data url request type in addr */
131     lua_pushstring( L, psz_remote_host );
132     /* function data function data url request type in addr host */
133     if( lua_pcall( L, 7, 1, 0 ) )
134     {
135         /* function data err */
136         vlc_object_t *p_this = vlclua_get_this( L );
137         const char *psz_err = lua_tostring( L, -1 );
138         msg_Err( p_this, "Error while runing the lua HTTPd handler "
139                  "callback: %s", psz_err );
140         lua_settop( L, 2 );
141         /* function data */
142         return VLC_EGENERIC;
143     }
144     /* function data outdata */
145     *pp_data = vlclua_todata( L, -1, pi_data );
146     lua_pop( L, 1 );
147     /* function data */
148     return VLC_SUCCESS;
149 }
150
151 int vlclua_httpd_handler_new( lua_State * L )
152 {
153     ARG_1_IS_HTTPD_HOST
154     const char *psz_url = luaL_checkstring( L, 2 );
155     const char *psz_user = luaL_nilorcheckstring( L, 3 );
156     const char *psz_password = luaL_nilorcheckstring( L, 4 );
157     const vlc_acl_t *p_acl = NULL; /* FIXME 5 */
158     /* Stack item 6 is the callback function */
159     luaL_argcheck( L, lua_isfunction( L, 6 ), 6, "Should be a function" );
160     /* Stack item 7 is the callback data */
161     lua_settop( L, 7 );
162     httpd_handler_sys_t *p_sys = (httpd_handler_sys_t*)
163                                  malloc( sizeof( httpd_handler_sys_t ) );
164     if( !p_sys )
165         return luaL_error( L, "Failed to allocate private buffer." );
166     p_sys->L = lua_newthread( L );
167     p_sys->ref = luaL_ref( L, LUA_REGISTRYINDEX ); /* pops the object too */
168     /* use lua_xmove to move the lua callback function and data to
169      * the callback's stack. */
170     lua_xmove( L, p_sys->L, 2 );
171     httpd_handler_t *p_handler = httpd_HandlerNew(
172                             p_httpd_host, psz_url, psz_user, psz_password,
173                             p_acl, vlclua_httpd_handler_callback, p_sys );
174     if( !p_handler )
175         return luaL_error( L, "Failed to create HTTPd handler." );
176     lua_pushlightuserdata( L, p_handler ); /* FIXME */
177     return 1;
178 }
179
180 int vlclua_httpd_handler_delete( lua_State *L )
181 {
182     httpd_handler_t *p_handler = (httpd_handler_t*)luaL_checklightuserdata( L, 1 ); /* FIXME */
183     httpd_handler_sys_t *p_sys = httpd_HandlerDelete( p_handler );
184     luaL_unref( p_sys->L, LUA_REGISTRYINDEX, p_sys->ref );
185     free( p_sys );
186     return 0;
187 }
188
189 /*****************************************************************************
190  * HTTPd File
191  *****************************************************************************/
192 struct httpd_file_sys_t
193 {
194     lua_State *L;
195     int ref;
196 };
197
198 static int vlclua_httpd_file_callback(
199     httpd_file_sys_t *p_sys, httpd_file_t *p_file, uint8_t *psz_request,
200     uint8_t **pp_data, int *pi_data )
201 {
202     VLC_UNUSED(p_file);
203     lua_State *L = p_sys->L;
204
205     /* function data */
206     lua_pushvalue( L, 1 );
207     lua_pushvalue( L, 2 );
208     /* function data function data */
209     lua_pushstring( L, (const char *)psz_request );
210     /* function data function data request */
211     if( lua_pcall( L, 2, 1, 0 ) )
212     {
213         /* function data err */
214         vlc_object_t *p_this = vlclua_get_this( L );
215         const char *psz_err = lua_tostring( L, -1 );
216         msg_Err( p_this, "Error while runing the lua HTTPd file callback: %s",
217                  psz_err );
218         lua_settop( L, 2 );
219         /* function data */
220         return VLC_EGENERIC;
221     }
222     /* function data outdata */
223     *pp_data = vlclua_todata( L, -1, pi_data );
224     lua_pop( L, 1 );
225     /* function data */
226     return VLC_SUCCESS;
227 }
228
229 int vlclua_httpd_file_new( lua_State *L )
230 {
231     ARG_1_IS_HTTPD_HOST
232     const char *psz_url = luaL_checkstring( L, 2 );
233     const char *psz_mime = luaL_nilorcheckstring( L, 3 );
234     const char *psz_user = luaL_nilorcheckstring( L, 4 );
235     const char *psz_password = luaL_nilorcheckstring( L, 5 );
236     const vlc_acl_t *p_acl = lua_isnil( L, 6 ) ? NULL : luaL_checklightuserdata( L, 6 );
237     /* Stack item 7 is the callback function */
238     luaL_argcheck( L, lua_isfunction( L, 7 ), 7, "Should be a function" );
239     /* Stack item 8 is the callback data */
240     httpd_file_sys_t *p_sys = (httpd_file_sys_t *)
241                               malloc( sizeof( httpd_file_sys_t ) );
242     if( !p_sys )
243         return luaL_error( L, "Failed to allocate private buffer." );
244     p_sys->L = lua_newthread( L );
245     p_sys->ref = luaL_ref( L, LUA_REGISTRYINDEX ); /* pops the object too */
246     lua_xmove( L, p_sys->L, 2 );
247     httpd_file_t *p_file = httpd_FileNew( p_httpd_host, psz_url, psz_mime,
248                                           psz_user, psz_password, p_acl,
249                                           vlclua_httpd_file_callback, p_sys );
250     if( !p_file )
251         return luaL_error( L, "Failed to create HTTPd file." );
252     lua_pushlightuserdata( L, p_file ); /* FIXME */
253     return 1;
254 }
255
256 int vlclua_httpd_file_delete( lua_State *L )
257 {
258     httpd_file_t *p_file = (httpd_file_t*)luaL_checklightuserdata( L, 1 ); /* FIXME */
259     /* FIXME: How do we delete p_sys ? the struct is hidden in the VLC core */
260     httpd_file_sys_t *p_sys = httpd_FileDelete( p_file );
261     luaL_unref( p_sys->L, LUA_REGISTRYINDEX, p_sys->ref );
262     free( p_sys );
263     return 0;
264 }
265
266 /*****************************************************************************
267  * HTTPd Redirect
268  *****************************************************************************/
269 int vlclua_httpd_redirect_new( lua_State *L )
270 {
271     ARG_1_IS_HTTPD_HOST
272     const char *psz_url_dst = luaL_checkstring( L, 2 );
273     const char *psz_url_src = luaL_checkstring( L, 3 );
274     httpd_redirect_t *p_redirect = httpd_RedirectNew( p_httpd_host,
275                                                       psz_url_dst,
276                                                       psz_url_src );
277     if( !p_redirect )
278         return luaL_error( L, "Failed to create HTTPd redirect." );
279     lua_pushlightuserdata( L, p_redirect ); /* FIXME */
280     return 1;
281 }
282
283 int vlclua_httpd_redirect_delete( lua_State *L )
284 {
285     httpd_redirect_t *p_redirect = (httpd_redirect_t*)luaL_checklightuserdata( L, 1 ); /* FIXME */
286     httpd_RedirectDelete( p_redirect );
287     return 0;
288 }
289
290 /*****************************************************************************
291  * Utils
292  *****************************************************************************/
293 static uint8_t *vlclua_todata( lua_State *L, int narg, int *pi_data )
294 {
295     size_t i_data;
296     const char *psz_data = lua_tolstring( L, narg, &i_data );
297     uint8_t *p_data = (uint8_t*)malloc( i_data * sizeof(uint8_t) );
298     *pi_data = (int)i_data;
299     if( !p_data )
300     {
301         luaL_error( L, "Error while allocating buffer." );
302         return NULL; /* To please gcc even though luaL_error longjmp-ed out of here */
303     }
304     memcpy( p_data, psz_data, i_data );
305     return p_data;
306 }