]> git.sesse.net Git - vlc/blob - modules/control/http/http.c
* toolbox: Removed compilation information from version.c to reduce the
[vlc] / modules / control / http / http.c
1 /*****************************************************************************
2  * http.c : HTTP/HTTPS Remote control interface
3  *****************************************************************************
4  * Copyright (C) 2001-2005 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Gildas Bazin <gbazin@netcourrier.com>
8  *          Laurent Aimar <fenrir@via.ecp.fr>
9  *          Christophe Massiot <massiot@via.ecp.fr>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
24  *****************************************************************************/
25
26 #include "http.h"
27
28 /*****************************************************************************
29  * Module descriptor
30  *****************************************************************************/
31 static int  Open ( vlc_object_t * );
32 static void Close( vlc_object_t * );
33
34 #define HOST_TEXT N_( "Host address" )
35 #define HOST_LONGTEXT N_( \
36     "You can set the address and port the http interface will bind to." )
37 #define SRC_TEXT N_( "Source directory" )
38 #define SRC_LONGTEXT N_( "Source directory" )
39 #define CHARSET_TEXT N_( "Charset" )
40 #define CHARSET_LONGTEXT N_( \
41         "Charset declared in Content-Type header (default UTF-8)." )
42 #define CERT_TEXT N_( "Certificate file" )
43 #define CERT_LONGTEXT N_( "HTTP interface x509 PEM certificate file " \
44                           "(enables SSL)" )
45 #define KEY_TEXT N_( "Private key file" )
46 #define KEY_LONGTEXT N_( "HTTP interface x509 PEM private key file" )
47 #define CA_TEXT N_( "Root CA file" )
48 #define CA_LONGTEXT N_( "HTTP interface x509 PEM trusted root CA " \
49                         "certificates file" )
50 #define CRL_TEXT N_( "CRL file" )
51 #define CRL_LONGTEXT N_( "HTTP interace Certificates Revocation List file" )
52
53 vlc_module_begin();
54     set_shortname( _("HTTP"));
55     set_description( _("HTTP remote control interface") );
56     set_category( CAT_INTERFACE );
57     set_subcategory( SUBCAT_INTERFACE_GENERAL );
58         add_string ( "http-host", NULL, NULL, HOST_TEXT, HOST_LONGTEXT, VLC_TRUE );
59         add_string ( "http-src",  NULL, NULL, SRC_TEXT,  SRC_LONGTEXT,  VLC_TRUE );
60         add_string ( "http-charset", "UTF-8", NULL, CHARSET_TEXT, CHARSET_LONGTEXT, VLC_TRUE );
61         set_section( N_("HTTP SSL" ), 0 );
62         add_string ( "http-intf-cert", NULL, NULL, CERT_TEXT, CERT_LONGTEXT, VLC_TRUE );
63         add_string ( "http-intf-key",  NULL, NULL, KEY_TEXT,  KEY_LONGTEXT,  VLC_TRUE );
64         add_string ( "http-intf-ca",   NULL, NULL, CA_TEXT,   CA_LONGTEXT,   VLC_TRUE );
65         add_string ( "http-intf-crl",  NULL, NULL, CRL_TEXT,  CRL_LONGTEXT,  VLC_TRUE );
66     set_capability( "interface", 0 );
67     set_callbacks( Open, Close );
68 vlc_module_end();
69
70
71 /*****************************************************************************
72  * Local prototypes
73  *****************************************************************************/
74 static void Run          ( intf_thread_t *p_intf );
75
76 /*****************************************************************************
77  * Local functions
78  *****************************************************************************/
79 #if !defined(SYS_DARWIN) && !defined(SYS_BEOS) && !defined(WIN32)
80 static int DirectoryCheck( char *psz_dir )
81 {
82     DIR           *p_dir;
83
84 #ifdef HAVE_SYS_STAT_H
85     struct stat   stat_info;
86
87     if( stat( psz_dir, &stat_info ) == -1 || !S_ISDIR( stat_info.st_mode ) )
88     {
89         return VLC_EGENERIC;
90     }
91 #endif
92
93     if( ( p_dir = opendir( psz_dir ) ) == NULL )
94     {
95         return VLC_EGENERIC;
96     }
97     closedir( p_dir );
98
99     return VLC_SUCCESS;
100 }
101 #endif
102
103
104 /*****************************************************************************
105  * Activate: initialize and create stuff
106  *****************************************************************************/
107 static int Open( vlc_object_t *p_this )
108 {
109     intf_thread_t *p_intf = (intf_thread_t*)p_this;
110     intf_sys_t    *p_sys;
111     char          *psz_host;
112     char          *psz_address = "";
113     const char    *psz_cert = NULL, *psz_key = NULL, *psz_ca = NULL,
114                   *psz_crl = NULL;
115     int           i_port       = 0;
116     char          *psz_src;
117
118     psz_host = config_GetPsz( p_intf, "http-host" );
119     if( psz_host )
120     {
121         char *psz_parser;
122         psz_address = psz_host;
123
124         psz_parser = strchr( psz_host, ':' );
125         if( psz_parser )
126         {
127             *psz_parser++ = '\0';
128             i_port = atoi( psz_parser );
129         }
130     }
131
132     p_intf->p_sys = p_sys = malloc( sizeof( intf_sys_t ) );
133     if( !p_intf->p_sys )
134     {
135         return( VLC_ENOMEM );
136     }
137     p_sys->p_playlist = NULL;
138     p_sys->p_input    = NULL;
139     p_sys->p_vlm      = NULL;
140
141     /* determine Content-Type value for HTML pages */
142     psz_src = config_GetPsz( p_intf, "http-charset" );
143     if( psz_src == NULL || !*psz_src )
144     {
145         if( psz_src != NULL ) free( psz_src );
146         psz_src = strdup("UTF-8");
147     }
148
149     p_sys->psz_html_type = malloc( 20 + strlen( psz_src ) );
150     if( p_sys->psz_html_type == NULL )
151     {
152         free( p_sys );
153         free( psz_src );
154         return VLC_ENOMEM ;
155     }
156     sprintf( p_sys->psz_html_type, "text/html; charset=%s", psz_src );
157     msg_Dbg( p_intf, "using charset=%s", psz_src );
158
159     if( strcmp( psz_src, "UTF-8" ) )
160     {
161         p_sys->iconv_from_utf8 = vlc_iconv_open( psz_src, "UTF-8" );
162         if( p_sys->iconv_from_utf8 == (vlc_iconv_t)-1 )
163             msg_Warn( p_intf, "unable to perform charset conversion to %s",
164                       psz_src );
165         else
166         {
167             p_sys->iconv_to_utf8 = vlc_iconv_open( "UTF-8", psz_src );
168             if( p_sys->iconv_to_utf8 == (vlc_iconv_t)-1 )
169                 msg_Warn( p_intf,
170                           "unable to perform charset conversion from %s",
171                           psz_src );
172         }
173     }
174     else
175     {
176         p_sys->iconv_from_utf8 = p_sys->iconv_to_utf8 = (vlc_iconv_t)-1;
177     }
178
179     free( psz_src );
180
181     /* determine SSL configuration */
182     psz_cert = config_GetPsz( p_intf, "http-intf-cert" );
183     if ( psz_cert != NULL )
184     {
185         msg_Dbg( p_intf, "enabling TLS for HTTP interface (cert file: %s)",
186                  psz_cert );
187         psz_key = config_GetPsz( p_intf, "http-intf-key" );
188         psz_ca = config_GetPsz( p_intf, "http-intf-ca" );
189         psz_crl = config_GetPsz( p_intf, "http-intf-crl" );
190
191         if( i_port <= 0 )
192             i_port = 8443;
193     }
194     else
195     {
196         if( i_port <= 0 )
197             i_port= 8080;
198     }
199
200     msg_Dbg( p_intf, "base %s:%d", psz_address, i_port );
201
202     p_sys->p_httpd_host = httpd_TLSHostNew( VLC_OBJECT(p_intf), psz_address,
203                                             i_port, psz_cert, psz_key, psz_ca,
204                                             psz_crl );
205     if( p_sys->p_httpd_host == NULL )
206     {
207         msg_Err( p_intf, "cannot listen on %s:%d", psz_address, i_port );
208         free( p_sys->psz_html_type );
209         free( p_sys );
210         return VLC_EGENERIC;
211     }
212
213     if( psz_host )
214     {
215         free( psz_host );
216     }
217
218     p_sys->i_files  = 0;
219     p_sys->pp_files = NULL;
220
221 #if defined(SYS_DARWIN) || defined(SYS_BEOS) || defined(WIN32)
222     if ( ( psz_src = config_GetPsz( p_intf, "http-src" )) == NULL )
223     {
224         char * psz_vlcpath = p_intf->p_libvlc->psz_vlcpath;
225         psz_src = malloc( strlen(psz_vlcpath) + strlen("/share/http" ) + 1 );
226         if( !psz_src ) return VLC_ENOMEM;
227 #if defined(WIN32)
228         sprintf( psz_src, "%s/http", psz_vlcpath);
229 #else
230         sprintf( psz_src, "%s/share/http", psz_vlcpath);
231 #endif
232     }
233 #else
234     psz_src = config_GetPsz( p_intf, "http-src" );
235
236     if( !psz_src || *psz_src == '\0' )
237     {
238         if( !DirectoryCheck( "share/http" ) )
239         {
240             psz_src = strdup( "share/http" );
241         }
242         else if( !DirectoryCheck( DATA_PATH "/http" ) )
243         {
244             psz_src = strdup( DATA_PATH "/http" );
245         }
246     }
247 #endif
248
249     if( !psz_src || *psz_src == '\0' )
250     {
251         msg_Err( p_intf, "invalid src dir" );
252         goto failed;
253     }
254
255     /* remove trainling \ or / */
256     if( psz_src[strlen( psz_src ) - 1] == '\\' ||
257         psz_src[strlen( psz_src ) - 1] == '/' )
258     {
259         psz_src[strlen( psz_src ) - 1] = '\0';
260     }
261
262     E_(ParseDirectory)( p_intf, psz_src, psz_src );
263
264
265     if( p_sys->i_files <= 0 )
266     {
267         msg_Err( p_intf, "cannot find any files (%s)", psz_src );
268         goto failed;
269     }
270     p_intf->pf_run = Run;
271     free( psz_src );
272
273     return VLC_SUCCESS;
274
275 failed:
276     if( psz_src ) free( psz_src );
277     if( p_sys->pp_files )
278     {
279         free( p_sys->pp_files );
280     }
281     httpd_HostDelete( p_sys->p_httpd_host );
282     free( p_sys->psz_html_type ); 
283     if( p_sys->iconv_from_utf8 != (vlc_iconv_t)-1 )
284         vlc_iconv_close( p_sys->iconv_from_utf8 );
285     if( p_sys->iconv_to_utf8 != (vlc_iconv_t)-1 )
286         vlc_iconv_close( p_sys->iconv_to_utf8 );
287     free( p_sys );
288     return VLC_EGENERIC;
289 }
290
291 /*****************************************************************************
292  * Close: destroy interface
293  *****************************************************************************/
294 static void Close ( vlc_object_t *p_this )
295 {
296     intf_thread_t *p_intf = (intf_thread_t *)p_this;
297     intf_sys_t    *p_sys = p_intf->p_sys;
298
299     int i;
300
301     if( p_sys->p_vlm )
302     {
303         vlm_Delete( p_sys->p_vlm );
304     }
305     for( i = 0; i < p_sys->i_files; i++ )
306     {
307        httpd_FileDelete( p_sys->pp_files[i]->p_file );
308        if( p_sys->pp_files[i]->p_redir )
309            httpd_RedirectDelete( p_sys->pp_files[i]->p_redir );
310        if( p_sys->pp_files[i]->p_redir2 )
311            httpd_RedirectDelete( p_sys->pp_files[i]->p_redir2 );
312
313        free( p_sys->pp_files[i]->file );
314        free( p_sys->pp_files[i]->name );
315        free( p_sys->pp_files[i] );
316     }
317     if( p_sys->pp_files )
318     {
319         free( p_sys->pp_files );
320     }
321     httpd_HostDelete( p_sys->p_httpd_host );
322     free( p_sys->psz_html_type );
323
324     if( p_sys->iconv_from_utf8 != (vlc_iconv_t)-1 )
325         vlc_iconv_close( p_sys->iconv_from_utf8 );
326     if( p_sys->iconv_to_utf8 != (vlc_iconv_t)-1 )
327         vlc_iconv_close( p_sys->iconv_to_utf8 );
328     free( p_sys );
329 }
330
331 /*****************************************************************************
332  * Run: http interface thread
333  *****************************************************************************/
334 static void Run( intf_thread_t *p_intf )
335 {
336     intf_sys_t     *p_sys = p_intf->p_sys;
337
338     while( !p_intf->b_die )
339     {
340         /* get the playlist */
341         if( p_sys->p_playlist == NULL )
342         {
343             p_sys->p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
344         }
345
346         /* Manage the input part */
347         if( p_sys->p_input == NULL )
348         {
349             if( p_sys->p_playlist )
350             {
351                 p_sys->p_input =
352                     vlc_object_find( p_sys->p_playlist,
353                                      VLC_OBJECT_INPUT,
354                                      FIND_CHILD );
355             }
356         }
357         else if( p_sys->p_input->b_dead )
358         {
359             vlc_object_release( p_sys->p_input );
360             p_sys->p_input = NULL;
361         }
362
363
364         /* Wait a bit */
365         msleep( INTF_IDLE_SLEEP );
366     }
367
368     if( p_sys->p_input )
369     {
370         vlc_object_release( p_sys->p_input );
371         p_sys->p_input = NULL;
372     }
373
374     if( p_sys->p_playlist )
375     {
376         vlc_object_release( p_sys->p_playlist );
377         p_sys->p_playlist = NULL;
378     }
379 }
380
381 /****************************************************************************
382  * HttpCallback:
383  ****************************************************************************
384  * a file with b_html is parsed and all "macro" replaced
385  * <vlc id="macro name" [param1="" [param2=""]] />
386  * valid id are
387  *
388  ****************************************************************************/
389 int  E_(HttpCallback)( httpd_file_sys_t *p_args,
390                        httpd_file_t *p_file,
391                        uint8_t *_p_request,
392                        uint8_t **_pp_data, int *pi_data )
393 {
394     char *p_request = (char *)_p_request;
395     char **pp_data = (char **)_pp_data;
396     int i_request = p_request ? strlen( p_request ) : 0;
397     char *p;
398     FILE *f;
399
400     if( ( f = fopen( p_args->file, "r" ) ) == NULL )
401     {
402         p = *pp_data = malloc( 10240 );
403         if( !p )
404         {
405                 return VLC_EGENERIC;
406         }
407         p += sprintf( p, "<html>\n" );
408         p += sprintf( p, "<head>\n" );
409         p += sprintf( p, "<title>Error loading %s</title>\n", p_args->file );
410         p += sprintf( p, "</head>\n" );
411         p += sprintf( p, "<body>\n" );
412         p += sprintf( p, "<h1><center>Error loading %s for %s</center></h1>\n", p_args->file, p_args->name );
413         p += sprintf( p, "<hr />\n" );
414         p += sprintf( p, "<a href=\"http://www.videolan.org/\">VideoLAN</a>\n" );
415         p += sprintf( p, "</body>\n" );
416         p += sprintf( p, "</html>\n" );
417
418         *pi_data = strlen( *pp_data );
419
420         return VLC_SUCCESS;
421     }
422
423     if( !p_args->b_html )
424     {
425         E_(FileLoad)( f, pp_data, pi_data );
426     }
427     else
428     {
429         int  i_buffer;
430         char *p_buffer;
431         char *dst;
432         vlc_value_t val;
433         char position[4]; /* percentage */
434         char time[12]; /* in seconds */
435         char length[12]; /* in seconds */
436         audio_volume_t i_volume;
437         char volume[5];
438         char state[8];
439  
440 #define p_sys p_args->p_intf->p_sys
441         if( p_sys->p_input )
442         {
443             var_Get( p_sys->p_input, "position", &val);
444             sprintf( position, "%d" , (int)((val.f_float) * 100.0));
445             var_Get( p_sys->p_input, "time", &val);
446             sprintf( time, "%d" , (int)(val.i_time / 1000000) );
447             var_Get( p_sys->p_input, "length", &val);
448             sprintf( length, "%d" , (int)(val.i_time / 1000000) );
449
450             var_Get( p_sys->p_input, "state", &val );
451             if( val.i_int == PLAYING_S )
452             {
453                 sprintf( state, "playing" );
454             }
455             else if( val.i_int == PAUSE_S )
456             {
457                 sprintf( state, "paused" );
458             }
459             else
460             {
461                 sprintf( state, "stop" );
462             }
463         }
464         else
465         {
466             sprintf( position, "%d", 0 );
467             sprintf( time, "%d", 0 );
468             sprintf( length, "%d", 0 );
469             sprintf( state, "stop" );
470         }
471 #undef p_sys
472
473         aout_VolumeGet( p_args->p_intf , &i_volume );
474         sprintf( volume , "%d" , (int)i_volume );
475
476         p_args->vars = E_(mvar_New)( "variables", "" );
477         E_(mvar_AppendNewVar)( p_args->vars, "url_param",
478                            i_request > 0 ? "1" : "0" );
479         E_(mvar_AppendNewVar)( p_args->vars, "url_value", p_request );
480         E_(mvar_AppendNewVar)( p_args->vars, "version", VLC_Version() );
481         E_(mvar_AppendNewVar)( p_args->vars, "copyright", COPYRIGHT_MESSAGE );
482         E_(mvar_AppendNewVar)( p_args->vars, "vlc_compile_by", VLC_CompileBy() );
483         E_(mvar_AppendNewVar)( p_args->vars, "vlc_compile_host",
484                            VLC_CompileHost() );
485         E_(mvar_AppendNewVar)( p_args->vars, "vlc_compile_domain",
486                            VLC_CompileDomain() );
487         E_(mvar_AppendNewVar)( p_args->vars, "vlc_compiler", VLC_Compiler() );
488         E_(mvar_AppendNewVar)( p_args->vars, "vlc_changeset", VLC_Changeset() );
489         E_(mvar_AppendNewVar)( p_args->vars, "stream_position", position );
490         E_(mvar_AppendNewVar)( p_args->vars, "stream_time", time );
491         E_(mvar_AppendNewVar)( p_args->vars, "stream_length", length );
492         E_(mvar_AppendNewVar)( p_args->vars, "volume", volume );
493         E_(mvar_AppendNewVar)( p_args->vars, "stream_state", state );
494
495         E_(SSInit)( &p_args->stack );
496
497         /* first we load in a temporary buffer */
498         E_(FileLoad)( f, &p_buffer, &i_buffer );
499
500         /* allocate output */
501         *pi_data = i_buffer + 1000;
502         dst = *pp_data = malloc( *pi_data );
503
504         /* we parse executing all  <vlc /> macros */
505         E_(Execute)( p_args, p_request, i_request, pp_data, pi_data, &dst,
506                      &p_buffer[0], &p_buffer[i_buffer] );
507
508         *dst     = '\0';
509         *pi_data = dst - *pp_data;
510
511         E_(SSClean)( &p_args->stack );
512         E_(mvar_Delete)( p_args->vars );
513         free( p_buffer );
514     }
515
516     fclose( f );
517
518     return VLC_SUCCESS;
519 }
520