]> git.sesse.net Git - vlc/blob - modules/misc/lua/libs/httpd.c
lua: remove "bla ? true : false"
[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 running 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 **pp_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                             pp_acl?*pp_acl:NULL,
184                             vlclua_httpd_handler_callback, p_sys );
185     if( !p_handler )
186     {
187         free( p_sys );
188         return luaL_error( L, "Failed to create HTTPd handler." );
189     }
190
191     httpd_handler_t **pp_handler = lua_newuserdata( L, sizeof( httpd_handler_t * ) );
192     *pp_handler = p_handler;
193
194     if( luaL_newmetatable( L, "httpd_handler" ) )
195     {
196         lua_pushcfunction( L, vlclua_httpd_handler_delete );
197         lua_setfield( L, -2, "__gc" );
198     }
199
200     lua_setmetatable( L, -2 );
201     return 1;
202 }
203
204 static int vlclua_httpd_handler_delete( lua_State *L )
205 {
206     httpd_handler_t **pp_handler = (httpd_handler_t**)luaL_checkudata( L, 1, "httpd_handler" );
207     httpd_handler_sys_t *p_sys = httpd_HandlerDelete( *pp_handler );
208     luaL_unref( p_sys->L, LUA_REGISTRYINDEX, p_sys->ref );
209     free( p_sys );
210     return 0;
211 }
212
213 /*****************************************************************************
214  * HTTPd File
215  *****************************************************************************/
216 struct httpd_file_sys_t
217 {
218     lua_State *L;
219     int ref;
220 };
221
222 static int vlclua_httpd_file_callback(
223     httpd_file_sys_t *p_sys, httpd_file_t *p_file, uint8_t *psz_request,
224     uint8_t **pp_data, int *pi_data )
225 {
226     VLC_UNUSED(p_file);
227     lua_State *L = p_sys->L;
228
229     /* function data */
230     lua_pushvalue( L, 1 );
231     lua_pushvalue( L, 2 );
232     /* function data function data */
233     lua_pushstring( L, (const char *)psz_request );
234     /* function data function data request */
235     if( lua_pcall( L, 2, 1, 0 ) )
236     {
237         /* function data err */
238         vlc_object_t *p_this = vlclua_get_this( L );
239         const char *psz_err = lua_tostring( L, -1 );
240         msg_Err( p_this, "Error while running the lua HTTPd file callback: %s",
241                  psz_err );
242         lua_settop( L, 2 );
243         /* function data */
244         return VLC_EGENERIC;
245     }
246     /* function data outdata */
247     *pp_data = vlclua_todata( L, -1, pi_data );
248     lua_pop( L, 1 );
249     /* function data */
250     return VLC_SUCCESS;
251 }
252
253 static int vlclua_httpd_file_new( lua_State *L )
254 {
255     httpd_host_t **pp_host = (httpd_host_t **)luaL_checkudata( L, 1, "httpd_host" );
256     const char *psz_url = luaL_checkstring( L, 2 );
257     const char *psz_mime = luaL_nilorcheckstring( L, 3 );
258     const char *psz_user = luaL_nilorcheckstring( L, 4 );
259     const char *psz_password = luaL_nilorcheckstring( L, 5 );
260     const vlc_acl_t **pp_acl = lua_isnil( L, 6 ) ? NULL : luaL_checkudata( L, 6, "acl" );
261     /* Stack item 7 is the callback function */
262     luaL_argcheck( L, lua_isfunction( L, 7 ), 7, "Should be a function" );
263     /* Stack item 8 is the callback data */
264     httpd_file_sys_t *p_sys = (httpd_file_sys_t *)
265                               malloc( sizeof( httpd_file_sys_t ) );
266     if( !p_sys )
267         return luaL_error( L, "Failed to allocate private buffer." );
268     p_sys->L = lua_newthread( L );
269     p_sys->ref = luaL_ref( L, LUA_REGISTRYINDEX ); /* pops the object too */
270     lua_xmove( L, p_sys->L, 2 );
271     httpd_file_t *p_file = httpd_FileNew( *pp_host, psz_url, psz_mime,
272                                           psz_user, psz_password,
273                                           pp_acl?*pp_acl:NULL,
274                                           vlclua_httpd_file_callback, p_sys );
275     if( !p_file )
276     {
277         free( p_sys );
278         return luaL_error( L, "Failed to create HTTPd file." );
279     }
280
281     httpd_file_t **pp_file = lua_newuserdata( L, sizeof( httpd_file_t * ) );
282     *pp_file = p_file;
283
284     if( luaL_newmetatable( L, "httpd_file" ) )
285     {
286         lua_pushcfunction( L, vlclua_httpd_file_delete );
287         lua_setfield( L, -2, "__gc" );
288     }
289
290     lua_setmetatable( L, -2 );
291     return 1;
292 }
293
294 static int vlclua_httpd_file_delete( lua_State *L )
295 {
296     httpd_file_t **pp_file = (httpd_file_t**)luaL_checkudata( L, 1, "httpd_file" );
297     httpd_file_sys_t *p_sys = httpd_FileDelete( *pp_file );
298     luaL_unref( p_sys->L, LUA_REGISTRYINDEX, p_sys->ref );
299     free( p_sys );
300     return 0;
301 }
302
303 /*****************************************************************************
304  * HTTPd Redirect
305  *****************************************************************************/
306 static int vlclua_httpd_redirect_new( lua_State *L )
307 {
308     httpd_host_t **pp_host = (httpd_host_t **)luaL_checkudata( L, 1, "httpd_host" );
309     const char *psz_url_dst = luaL_checkstring( L, 2 );
310     const char *psz_url_src = luaL_checkstring( L, 3 );
311     httpd_redirect_t *p_redirect = httpd_RedirectNew( *pp_host,
312                                                       psz_url_dst,
313                                                       psz_url_src );
314     if( !p_redirect )
315         return luaL_error( L, "Failed to create HTTPd redirect." );
316
317     httpd_redirect_t **pp_redirect = lua_newuserdata( L, sizeof( httpd_redirect_t * ) );
318     *pp_redirect = p_redirect;
319
320     if( luaL_newmetatable( L, "httpd_redirect" ) )
321     {
322         lua_pushcfunction( L, vlclua_httpd_redirect_delete );
323         lua_setfield( L, -2, "__gc" );
324     }
325
326     lua_setmetatable( L, -2 );
327     return 1;
328 }
329
330 static int vlclua_httpd_redirect_delete( lua_State *L )
331 {
332     httpd_redirect_t **pp_redirect = (httpd_redirect_t**)luaL_checkudata( L, 1, "httpd_redirect" );
333     httpd_RedirectDelete( *pp_redirect );
334     return 0;
335 }
336
337 /*****************************************************************************
338  * Utils
339  *****************************************************************************/
340 static uint8_t *vlclua_todata( lua_State *L, int narg, int *pi_data )
341 {
342     size_t i_data;
343     const char *psz_data = lua_tolstring( L, narg, &i_data );
344     uint8_t *p_data = (uint8_t*)malloc( i_data * sizeof(uint8_t) );
345     *pi_data = (int)i_data;
346     if( !p_data )
347     {
348         luaL_error( L, "Error while allocating buffer." );
349         return NULL; /* To please gcc even though luaL_error longjmp-ed out of here */
350     }
351     memcpy( p_data, psz_data, i_data );
352     return p_data;
353 }
354
355 /*****************************************************************************
356  *
357  *****************************************************************************/
358 void luaopen_httpd( lua_State *L )
359 {
360     lua_pushcfunction( L, vlclua_httpd_tls_host_new );
361     lua_setfield( L, -2, "httpd" );
362 }