1 /*****************************************************************************
2 * httpd.c: HTTPd wrapper
3 *****************************************************************************
4 * Copyright (C) 2007-2008 the VideoLAN team
7 * Authors: Antoine Cellerier <dionoea at videolan tod org>
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.
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.
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 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
35 #include <vlc_common.h>
36 #include <vlc_httpd.h>
41 /*****************************************************************************
43 *****************************************************************************/
44 static uint8_t *vlclua_todata( lua_State
*L
, int narg
, int *i_data
);
46 static int vlclua_httpd_host_delete( lua_State
* );
47 static int vlclua_httpd_handler_new( lua_State
* );
48 static int vlclua_httpd_handler_delete( lua_State
* );
49 static int vlclua_httpd_file_new( lua_State
* );
50 static int vlclua_httpd_file_delete( lua_State
* );
51 static int vlclua_httpd_redirect_new( lua_State
* );
52 static int vlclua_httpd_redirect_delete( lua_State
* );
54 /*****************************************************************************
56 *****************************************************************************/
57 static const luaL_Reg vlclua_httpd_reg
[] = {
58 { "handler", vlclua_httpd_handler_new
},
59 { "file", vlclua_httpd_file_new
},
60 { "redirect", vlclua_httpd_redirect_new
},
64 static const char no_password_fmt
[] = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"
65 "<html xmlns=\"http://www.w3.org/1999/xhtml\">"
67 "<meta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\" />"
72 "<!-- VLC_PASSWORD_NOT_SET --></body></html>";
74 static const char no_password_body
[] = N_(
75 "<p>Password for Web interface has not been set.</p>"
76 "<p>Please use --http-password, or set a password in </p>"
77 "<p>Preferences > All > Main interfaces > Lua > Lua HTTP > Password.</p>"
80 static const char no_password_title
[] = N_("VLC media player");
82 static int vlclua_httpd_tls_host_new( lua_State
*L
)
84 vlc_object_t
*p_this
= vlclua_get_this( L
);
85 httpd_host_t
*p_host
= vlc_http_HostNew( p_this
);
87 return luaL_error( L
, "Failed to create HTTP host" );
89 httpd_host_t
**pp_host
= lua_newuserdata( L
, sizeof( httpd_host_t
* ) );
92 if( luaL_newmetatable( L
, "httpd_host" ) )
95 luaL_register( L
, NULL
, vlclua_httpd_reg
);
96 lua_setfield( L
, -2, "__index" );
97 lua_pushcfunction( L
, vlclua_httpd_host_delete
);
98 lua_setfield( L
, -2, "__gc" );
101 lua_setmetatable( L
, -2 );
105 static int vlclua_httpd_host_delete( lua_State
*L
)
107 httpd_host_t
**pp_host
= (httpd_host_t
**)luaL_checkudata( L
, 1, "httpd_host" );
108 httpd_HostDelete( *pp_host
);
112 /*****************************************************************************
114 *****************************************************************************/
120 } httpd_handler_lua_t
;
122 static int vlclua_httpd_handler_callback(
123 void *opaque
, httpd_handler_t
*p_handler
, char *psz_url
,
124 uint8_t *psz_request
, int i_type
, uint8_t *p_in
, int i_in
,
125 char *psz_remote_addr
, char *psz_remote_host
,
126 uint8_t **pp_data
, int *pi_data
)
128 VLC_UNUSED(p_handler
);
129 httpd_handler_lua_t
*p_sys
= opaque
;
130 lua_State
*L
= p_sys
->L
;
133 lua_pushvalue( L
, 1 );
134 lua_pushvalue( L
, 2 );
135 /* function data function data */
136 lua_pushstring( L
, psz_url
);
137 /* function data function data url */
138 lua_pushstring( L
, (const char *)psz_request
);
139 /* function data function data url request */
140 lua_pushinteger( L
, i_type
); /* Q: what does i_type stand for? */
141 /* function data function data url request type */
142 lua_pushlstring( L
, (const char *)p_in
, i_in
); /* Q: what do p_in contain? */
143 /* function data function data url request type in */
144 lua_pushstring( L
, psz_remote_addr
);
145 /* function data function data url request type in addr */
146 lua_pushstring( L
, psz_remote_host
);
147 /* function data function data url request type in addr host */
148 if( lua_pcall( L
, 7, 1, 0 ) )
150 /* function data err */
151 vlc_object_t
*p_this
= vlclua_get_this( L
);
152 const char *psz_err
= lua_tostring( L
, -1 );
153 msg_Err( p_this
, "Error while running the lua HTTPd handler "
154 "callback: %s", psz_err
);
159 /* function data outdata */
160 *pp_data
= vlclua_todata( L
, -1, pi_data
);
161 if (!p_sys
->password
)
164 char *no_password
= NULL
;
165 if (asprintf(&no_password
, no_password_fmt
,
166 _(no_password_title
), _(no_password_body
)) < 0) {
169 size_t s
= strlen(no_password
);
170 if (asprintf((char**)pp_data
, "Status: 403\n"
171 "Content-Length: %zu\n"
172 "Content-Type: text/html\n\n%s", s
, no_password
) < 0)
175 *pi_data
= strlen((char*)*pp_data
);
184 static int vlclua_httpd_handler_new( lua_State
* L
)
186 httpd_host_t
**pp_host
= (httpd_host_t
**)luaL_checkudata( L
, 1, "httpd_host" );
187 const char *psz_url
= luaL_checkstring( L
, 2 );
188 const char *psz_user
= luaL_nilorcheckstring( L
, 3 );
189 const char *psz_password
= luaL_nilorcheckstring( L
, 4 );
190 /* Stack item 5 is the callback function */
191 luaL_argcheck( L
, lua_isfunction( L
, 5 ), 5, "Should be a function" );
192 /* Stack item 6 is the callback data */
194 httpd_handler_lua_t
*p_sys
= malloc( sizeof( *p_sys
) );
196 return luaL_error( L
, "Failed to allocate private buffer." );
197 p_sys
->L
= lua_newthread( L
);
198 p_sys
->ref
= luaL_ref( L
, LUA_REGISTRYINDEX
); /* pops the object too */
199 p_sys
->password
= psz_password
&& *psz_password
;
200 /* use lua_xmove to move the lua callback function and data to
201 * the callback's stack. */
202 lua_xmove( L
, p_sys
->L
, 2 );
203 httpd_handler_t
*p_handler
= httpd_HandlerNew(
204 *pp_host
, psz_url
, psz_user
, psz_password
,
205 vlclua_httpd_handler_callback
, p_sys
);
209 return luaL_error( L
, "Failed to create HTTPd handler." );
212 httpd_handler_t
**pp_handler
= lua_newuserdata( L
, sizeof( httpd_handler_t
* ) );
213 *pp_handler
= p_handler
;
215 if( luaL_newmetatable( L
, "httpd_handler" ) )
217 lua_pushcfunction( L
, vlclua_httpd_handler_delete
);
218 lua_setfield( L
, -2, "__gc" );
221 lua_setmetatable( L
, -2 );
225 static int vlclua_httpd_handler_delete( lua_State
*L
)
227 httpd_handler_t
**pp_handler
= (httpd_handler_t
**)luaL_checkudata( L
, 1, "httpd_handler" );
228 httpd_handler_lua_t
*p_sys
= httpd_HandlerDelete( *pp_handler
);
229 luaL_unref( p_sys
->L
, LUA_REGISTRYINDEX
, p_sys
->ref
);
234 /*****************************************************************************
236 *****************************************************************************/
237 struct httpd_file_sys_t
244 static int vlclua_httpd_file_callback(
245 httpd_file_sys_t
*p_sys
, httpd_file_t
*p_file
, uint8_t *psz_request
,
246 uint8_t **pp_data
, int *pi_data
)
249 lua_State
*L
= p_sys
->L
;
252 lua_pushvalue( L
, 1 );
253 lua_pushvalue( L
, 2 );
254 /* function data function data */
255 lua_pushstring( L
, (const char *)psz_request
);
256 /* function data function data request */
257 if( lua_pcall( L
, 2, 1, 0 ) )
259 /* function data err */
260 vlc_object_t
*p_this
= vlclua_get_this( L
);
261 const char *psz_err
= lua_tostring( L
, -1 );
262 msg_Err( p_this
, "Error while running the lua HTTPd file callback: %s",
268 /* function data outdata */
269 *pp_data
= vlclua_todata( L
, -1, pi_data
);
270 if (!p_sys
->password
)
273 if (asprintf((char**)pp_data
, no_password_fmt
,
274 _(no_password_title
), _(no_password_body
)) < 0) {
277 *pi_data
= strlen((char*)*pp_data
);
285 static int vlclua_httpd_file_new( lua_State
*L
)
287 httpd_host_t
**pp_host
= (httpd_host_t
**)luaL_checkudata( L
, 1, "httpd_host" );
288 const char *psz_url
= luaL_checkstring( L
, 2 );
289 const char *psz_mime
= luaL_nilorcheckstring( L
, 3 );
290 const char *psz_user
= luaL_nilorcheckstring( L
, 4 );
291 const char *psz_password
= luaL_nilorcheckstring( L
, 5 );
292 /* Stack item 7 is the callback function */
293 luaL_argcheck( L
, lua_isfunction( L
, 6 ), 6, "Should be a function" );
294 /* Stack item 8 is the callback data */
295 httpd_file_sys_t
*p_sys
= (httpd_file_sys_t
*)
296 malloc( sizeof( httpd_file_sys_t
) );
298 return luaL_error( L
, "Failed to allocate private buffer." );
299 p_sys
->L
= lua_newthread( L
);
300 p_sys
->password
= psz_password
&& *psz_password
;
301 p_sys
->ref
= luaL_ref( L
, LUA_REGISTRYINDEX
); /* pops the object too */
302 lua_xmove( L
, p_sys
->L
, 2 );
303 httpd_file_t
*p_file
= httpd_FileNew( *pp_host
, psz_url
, psz_mime
,
304 psz_user
, psz_password
,
305 vlclua_httpd_file_callback
, p_sys
);
309 return luaL_error( L
, "Failed to create HTTPd file." );
312 httpd_file_t
**pp_file
= lua_newuserdata( L
, sizeof( httpd_file_t
* ) );
315 if( luaL_newmetatable( L
, "httpd_file" ) )
317 lua_pushcfunction( L
, vlclua_httpd_file_delete
);
318 lua_setfield( L
, -2, "__gc" );
321 lua_setmetatable( L
, -2 );
325 static int vlclua_httpd_file_delete( lua_State
*L
)
327 httpd_file_t
**pp_file
= (httpd_file_t
**)luaL_checkudata( L
, 1, "httpd_file" );
328 httpd_file_sys_t
*p_sys
= httpd_FileDelete( *pp_file
);
329 luaL_unref( p_sys
->L
, LUA_REGISTRYINDEX
, p_sys
->ref
);
334 /*****************************************************************************
336 *****************************************************************************/
337 static int vlclua_httpd_redirect_new( lua_State
*L
)
339 httpd_host_t
**pp_host
= (httpd_host_t
**)luaL_checkudata( L
, 1, "httpd_host" );
340 const char *psz_url_dst
= luaL_checkstring( L
, 2 );
341 const char *psz_url_src
= luaL_checkstring( L
, 3 );
342 httpd_redirect_t
*p_redirect
= httpd_RedirectNew( *pp_host
,
346 return luaL_error( L
, "Failed to create HTTPd redirect." );
348 httpd_redirect_t
**pp_redirect
= lua_newuserdata( L
, sizeof( httpd_redirect_t
* ) );
349 *pp_redirect
= p_redirect
;
351 if( luaL_newmetatable( L
, "httpd_redirect" ) )
353 lua_pushcfunction( L
, vlclua_httpd_redirect_delete
);
354 lua_setfield( L
, -2, "__gc" );
357 lua_setmetatable( L
, -2 );
361 static int vlclua_httpd_redirect_delete( lua_State
*L
)
363 httpd_redirect_t
**pp_redirect
= (httpd_redirect_t
**)luaL_checkudata( L
, 1, "httpd_redirect" );
364 httpd_RedirectDelete( *pp_redirect
);
368 /*****************************************************************************
370 *****************************************************************************/
371 static uint8_t *vlclua_todata( lua_State
*L
, int narg
, int *pi_data
)
374 const char *psz_data
= lua_tolstring( L
, narg
, &i_data
);
375 uint8_t *p_data
= vlc_alloc( i_data
, sizeof(uint8_t) );
376 *pi_data
= (int)i_data
;
379 luaL_error( L
, "Error while allocating buffer." );
380 return NULL
; /* To please gcc even though luaL_error longjmp-ed out of here */
382 memcpy( p_data
, psz_data
, i_data
);
386 /*****************************************************************************
388 *****************************************************************************/
389 void luaopen_httpd( lua_State
*L
)
391 lua_pushcfunction( L
, vlclua_httpd_tls_host_new
);
392 lua_setfield( L
, -2, "httpd" );