]> git.sesse.net Git - vlc/blob - modules/misc/lua/libs/httpd.c
Fix test program.
[vlc] / modules / misc / lua / libs / httpd.c
1 /*****************************************************************************
2  * httpd.c: HTTPd wrapper
3  *****************************************************************************
4  * Copyright (C) 2007-2008 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 #include "../libs.h"
44
45 /*****************************************************************************
46  * Local prototypes
47  *****************************************************************************/
48 static uint8_t *vlclua_todata( lua_State *L, int narg, int *i_data );
49
50 static int vlclua_httpd_host_delete( lua_State * );
51 static int vlclua_httpd_handler_new( lua_State * );
52 static int vlclua_httpd_handler_delete( lua_State * );
53 static int vlclua_httpd_file_new( lua_State * );
54 static int vlclua_httpd_file_delete( lua_State * );
55 static int vlclua_httpd_redirect_new( lua_State * );
56 static int vlclua_httpd_redirect_delete( lua_State * );
57
58 /*****************************************************************************
59  * HTTPD Host
60  *****************************************************************************/
61 static const luaL_Reg vlclua_httpd_reg[] = {
62     { "handler", vlclua_httpd_handler_new },
63     { "file", vlclua_httpd_file_new },
64     { "redirect", vlclua_httpd_redirect_new },
65     { NULL, NULL }
66 };
67
68 static int vlclua_httpd_tls_host_new( lua_State *L )
69 {
70     vlc_object_t *p_this = vlclua_get_this( L );
71     const char *psz_host = luaL_checkstring( L, 1 );
72     int i_port = luaL_checkint( L, 2 );
73     const char *psz_cert = luaL_optstring( L, 3, NULL );
74     const char *psz_key = luaL_optstring( L, 4, NULL );
75     const char *psz_ca = luaL_optstring( L, 5, NULL );
76     const char *psz_crl = luaL_optstring( L, 6, NULL );
77     httpd_host_t *p_host = httpd_TLSHostNew( p_this, psz_host, i_port,
78                                                    psz_cert, psz_key,
79                                                    psz_ca, psz_crl );
80     if( !p_host )
81         return luaL_error( L, "Failed to create HTTP TLS host \"%s:%d\" "
82                            "(cert: \"%s\", key: \"%s\", ca: \"%s\", "
83                            "crl: \"%s\").", psz_host, i_port,
84                            psz_cert, psz_key, psz_ca, psz_crl );
85
86     httpd_host_t **pp_host = lua_newuserdata( L, sizeof( httpd_host_t * ) );
87     *pp_host = p_host;
88
89     if( luaL_newmetatable( L, "httpd_host" ) )
90     {
91         lua_newtable( L );
92         luaL_register( L, NULL, vlclua_httpd_reg );
93         lua_setfield( L, -2, "__index" );
94         lua_pushcfunction( L, vlclua_httpd_host_delete );
95         lua_setfield( L, -2, "__gc" );
96     }
97
98     lua_setmetatable( L, -2 );
99     return 1;
100 }
101
102 static int vlclua_httpd_host_delete( lua_State *L )
103 {
104     httpd_host_t **pp_host = (httpd_host_t **)luaL_checkudata( L, 1, "httpd_host" );
105     httpd_HostDelete( *pp_host );
106     return 0;
107 }
108
109 /*****************************************************************************
110  * HTTPd Handler
111  *****************************************************************************/
112 struct httpd_handler_sys_t
113 {
114     lua_State *L;
115     int ref;
116 };
117
118 static int vlclua_httpd_handler_callback(
119      httpd_handler_sys_t *p_sys, httpd_handler_t *p_handler, char *psz_url,
120      uint8_t *psz_request, int i_type, uint8_t *p_in, int i_in,
121      char *psz_remote_addr, char *psz_remote_host,
122      uint8_t **pp_data, int *pi_data )
123 {
124     VLC_UNUSED(p_handler);
125     lua_State *L = p_sys->L;
126
127     /* function data */
128     lua_pushvalue( L, 1 );
129     lua_pushvalue( L, 2 );
130     /* function data function data */
131     lua_pushstring( L, psz_url );
132     /* function data function data url */
133     lua_pushstring( L, (const char *)psz_request );
134     /* function data function data url request */
135     lua_pushinteger( L, i_type ); /* Q: what does i_type stand for? */
136     /* function data function data url request type */
137     lua_pushlstring( L, (const char *)p_in, i_in ); /* Q: what do p_in contain? */
138     /* function data function data url request type in */
139     lua_pushstring( L, psz_remote_addr );
140     /* function data function data url request type in addr */
141     lua_pushstring( L, psz_remote_host );
142     /* function data function data url request type in addr host */
143     if( lua_pcall( L, 7, 1, 0 ) )
144     {
145         /* function data err */
146         vlc_object_t *p_this = vlclua_get_this( L );
147         const char *psz_err = lua_tostring( L, -1 );
148         msg_Err( p_this, "Error while runing the lua HTTPd handler "
149                  "callback: %s", psz_err );
150         lua_settop( L, 2 );
151         /* function data */
152         return VLC_EGENERIC;
153     }
154     /* function data outdata */
155     *pp_data = vlclua_todata( L, -1, pi_data );
156     lua_pop( L, 1 );
157     /* function data */
158     return VLC_SUCCESS;
159 }
160
161 static int vlclua_httpd_handler_new( lua_State * L )
162 {
163     httpd_host_t **pp_host = (httpd_host_t **)luaL_checkudata( L, 1, "httpd_host" );
164     const char *psz_url = luaL_checkstring( L, 2 );
165     const char *psz_user = luaL_nilorcheckstring( L, 3 );
166     const char *psz_password = luaL_nilorcheckstring( L, 4 );
167     const vlc_acl_t *p_acl = lua_isnil( L, 5 ) ? NULL : luaL_checkudata( L, 5, "acl" );
168     /* Stack item 6 is the callback function */
169     luaL_argcheck( L, lua_isfunction( L, 6 ), 6, "Should be a function" );
170     /* Stack item 7 is the callback data */
171     lua_settop( L, 7 );
172     httpd_handler_sys_t *p_sys = (httpd_handler_sys_t*)
173                                  malloc( sizeof( httpd_handler_sys_t ) );
174     if( !p_sys )
175         return luaL_error( L, "Failed to allocate private buffer." );
176     p_sys->L = lua_newthread( L );
177     p_sys->ref = luaL_ref( L, LUA_REGISTRYINDEX ); /* pops the object too */
178     /* use lua_xmove to move the lua callback function and data to
179      * the callback's stack. */
180     lua_xmove( L, p_sys->L, 2 );
181     httpd_handler_t *p_handler = httpd_HandlerNew(
182                             *pp_host, psz_url, psz_user, psz_password,
183                             p_acl, vlclua_httpd_handler_callback, p_sys );
184     if( !p_handler )
185     {
186         free( p_sys );
187         return luaL_error( L, "Failed to create HTTPd handler." );
188     }
189
190     httpd_handler_t **pp_handler = lua_newuserdata( L, sizeof( httpd_handler_t * ) );
191     *pp_handler = p_handler;
192
193     if( luaL_newmetatable( L, "httpd_handler" ) )
194     {
195         lua_pushcfunction( L, vlclua_httpd_handler_delete );
196         lua_setfield( L, -2, "__gc" );
197     }
198
199     lua_setmetatable( L, -2 );
200     return 1;
201 }
202
203 static int vlclua_httpd_handler_delete( lua_State *L )
204 {
205     httpd_handler_t **pp_handler = (httpd_handler_t**)luaL_checkudata( L, 1, "httpd_handler" );
206     httpd_handler_sys_t *p_sys = httpd_HandlerDelete( *pp_handler );
207     luaL_unref( p_sys->L, LUA_REGISTRYINDEX, p_sys->ref );
208     free( p_sys );
209     return 0;
210 }
211
212 /*****************************************************************************
213  * HTTPd File
214  *****************************************************************************/
215 struct httpd_file_sys_t
216 {
217     lua_State *L;
218     int ref;
219 };
220
221 static int vlclua_httpd_file_callback(
222     httpd_file_sys_t *p_sys, httpd_file_t *p_file, uint8_t *psz_request,
223     uint8_t **pp_data, int *pi_data )
224 {
225     VLC_UNUSED(p_file);
226     lua_State *L = p_sys->L;
227
228     /* function data */
229     lua_pushvalue( L, 1 );
230     lua_pushvalue( L, 2 );
231     /* function data function data */
232     lua_pushstring( L, (const char *)psz_request );
233     /* function data function data request */
234     if( lua_pcall( L, 2, 1, 0 ) )
235     {
236         /* function data err */
237         vlc_object_t *p_this = vlclua_get_this( L );
238         const char *psz_err = lua_tostring( L, -1 );
239         msg_Err( p_this, "Error while runing the lua HTTPd file callback: %s",
240                  psz_err );
241         lua_settop( L, 2 );
242         /* function data */
243         return VLC_EGENERIC;
244     }
245     /* function data outdata */
246     *pp_data = vlclua_todata( L, -1, pi_data );
247     lua_pop( L, 1 );
248     /* function data */
249     return VLC_SUCCESS;
250 }
251
252 static int vlclua_httpd_file_new( lua_State *L )
253 {
254     httpd_host_t **pp_host = (httpd_host_t **)luaL_checkudata( L, 1, "httpd_host" );
255     const char *psz_url = luaL_checkstring( L, 2 );
256     const char *psz_mime = luaL_nilorcheckstring( L, 3 );
257     const char *psz_user = luaL_nilorcheckstring( L, 4 );
258     const char *psz_password = luaL_nilorcheckstring( L, 5 );
259     const vlc_acl_t *p_acl = lua_isnil( L, 6 ) ? NULL : luaL_checkudata( L, 6, "acl" );
260     /* Stack item 7 is the callback function */
261     luaL_argcheck( L, lua_isfunction( L, 7 ), 7, "Should be a function" );
262     /* Stack item 8 is the callback data */
263     httpd_file_sys_t *p_sys = (httpd_file_sys_t *)
264                               malloc( sizeof( httpd_file_sys_t ) );
265     if( !p_sys )
266         return luaL_error( L, "Failed to allocate private buffer." );
267     p_sys->L = lua_newthread( L );
268     p_sys->ref = luaL_ref( L, LUA_REGISTRYINDEX ); /* pops the object too */
269     lua_xmove( L, p_sys->L, 2 );
270     httpd_file_t *p_file = httpd_FileNew( *pp_host, psz_url, psz_mime,
271                                           psz_user, psz_password, p_acl,
272                                           vlclua_httpd_file_callback, p_sys );
273     if( !p_file )
274     {
275         free( p_sys );
276         return luaL_error( L, "Failed to create HTTPd file." );
277     }
278
279     httpd_file_t **pp_file = lua_newuserdata( L, sizeof( httpd_file_t * ) );
280     *pp_file = p_file;
281
282     if( luaL_newmetatable( L, "httpd_file" ) )
283     {
284         lua_pushcfunction( L, vlclua_httpd_file_delete );
285         lua_setfield( L, -2, "__gc" );
286     }
287
288     lua_setmetatable( L, -2 );
289     return 1;
290 }
291
292 static int vlclua_httpd_file_delete( lua_State *L )
293 {
294     httpd_file_t **pp_file = (httpd_file_t**)luaL_checkudata( L, 1, "httpd_file" );
295     httpd_file_sys_t *p_sys = httpd_FileDelete( *pp_file );
296     luaL_unref( p_sys->L, LUA_REGISTRYINDEX, p_sys->ref );
297     free( p_sys );
298     return 0;
299 }
300
301 /*****************************************************************************
302  * HTTPd Redirect
303  *****************************************************************************/
304 static int vlclua_httpd_redirect_new( lua_State *L )
305 {
306     httpd_host_t **pp_host = (httpd_host_t **)luaL_checkudata( L, 1, "httpd_host" );
307     const char *psz_url_dst = luaL_checkstring( L, 2 );
308     const char *psz_url_src = luaL_checkstring( L, 3 );
309     httpd_redirect_t *p_redirect = httpd_RedirectNew( *pp_host,
310                                                       psz_url_dst,
311                                                       psz_url_src );
312     if( !p_redirect )
313         return luaL_error( L, "Failed to create HTTPd redirect." );
314
315     httpd_redirect_t **pp_redirect = lua_newuserdata( L, sizeof( httpd_redirect_t * ) );
316     *pp_redirect = p_redirect;
317
318     if( luaL_newmetatable( L, "httpd_redirect" ) )
319     {
320         lua_pushcfunction( L, vlclua_httpd_redirect_delete );
321         lua_setfield( L, -2, "__gc" );
322     }
323
324     lua_setmetatable( L, -2 );
325     return 1;
326 }
327
328 static int vlclua_httpd_redirect_delete( lua_State *L )
329 {
330     httpd_redirect_t **pp_redirect = (httpd_redirect_t**)luaL_checkudata( L, 1, "httpd_redirect" );
331     httpd_RedirectDelete( *pp_redirect );
332     return 0;
333 }
334
335 /*****************************************************************************
336  * Utils
337  *****************************************************************************/
338 static uint8_t *vlclua_todata( lua_State *L, int narg, int *pi_data )
339 {
340     size_t i_data;
341     const char *psz_data = lua_tolstring( L, narg, &i_data );
342     uint8_t *p_data = (uint8_t*)malloc( i_data * sizeof(uint8_t) );
343     *pi_data = (int)i_data;
344     if( !p_data )
345     {
346         luaL_error( L, "Error while allocating buffer." );
347         return NULL; /* To please gcc even though luaL_error longjmp-ed out of here */
348     }
349     memcpy( p_data, psz_data, i_data );
350     return p_data;
351 }
352
353 /*****************************************************************************
354  *
355  *****************************************************************************/
356 void luaopen_httpd( lua_State *L )
357 {
358     lua_pushcfunction( L, vlclua_httpd_tls_host_new );
359     lua_setfield( L, -2, "httpd" );
360 }