]> git.sesse.net Git - vlc/blob - modules/access/dvb/http.c
f79216dd94fc73ff874b1d5224117315103fdf31
[vlc] / modules / access / dvb / http.c
1 /*****************************************************************************
2  * http.c: HTTP interface
3  *****************************************************************************
4  * Copyright (C) 2005 the VideoLAN team
5  *
6  * Authors: Christophe Massiot <massiot@via.ecp.fr>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21  *****************************************************************************/
22
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <vlc_common.h>
32 #include <vlc_access.h>
33
34 #ifdef HAVE_UNISTD_H
35 #   include <unistd.h>
36 #endif
37
38 #include <fcntl.h>
39 #include <sys/types.h>
40
41 /* Include dvbpsi headers */
42 #ifdef HAVE_DVBPSI_DR_H
43 #   include <dvbpsi/dvbpsi.h>
44 #   include <dvbpsi/descriptor.h>
45 #   include <dvbpsi/pat.h>
46 #   include <dvbpsi/pmt.h>
47 #   include <dvbpsi/dr.h>
48 #   include <dvbpsi/psi.h>
49 #   include <dvbpsi/demux.h>
50 #   include <dvbpsi/sdt.h>
51 #else
52 #   include "dvbpsi.h"
53 #   include "descriptor.h"
54 #   include "tables/pat.h"
55 #   include "tables/pmt.h"
56 #   include "descriptors/dr.h"
57 #   include "psi.h"
58 #   include "demux.h"
59 #   include "tables/sdt.h"
60 #endif
61
62 #ifdef ENABLE_HTTPD
63 #   include <vlc_httpd.h>
64 #   include <vlc_acl.h>
65 #endif
66
67 #include "dvb.h"
68
69 #ifdef ENABLE_HTTPD
70 struct httpd_file_sys_t
71 {
72     access_t         *p_access;
73     httpd_file_t     *p_file;
74 };
75
76 static int HttpCallback( httpd_file_sys_t *p_args,
77                          httpd_file_t *p_file,
78                          uint8_t *_p_request,
79                          uint8_t **_pp_data, int *pi_data );
80
81 /*****************************************************************************
82  * HTTPOpen: Start the internal HTTP server
83  *****************************************************************************/
84 int HTTPOpen( access_t *p_access )
85 {
86     access_sys_t *p_sys = p_access->p_sys;
87     char          *psz_address, *psz_cert = NULL, *psz_key = NULL,
88                   *psz_ca = NULL, *psz_crl = NULL, *psz_user = NULL,
89                   *psz_password = NULL, *psz_acl = NULL;
90     int           i_port       = 0;
91     char          psz_tmp[10];
92     vlc_acl_t     *p_acl = NULL;
93     httpd_file_sys_t *f;
94
95     vlc_mutex_init( &p_sys->httpd_mutex );
96     vlc_cond_init( &p_sys->httpd_cond );
97     p_sys->b_request_frontend_info = p_sys->b_request_mmi_info = false;
98     p_sys->i_httpd_timeout = 0;
99
100     psz_address = var_GetNonEmptyString( p_access, "dvb-http-host" );
101     if( psz_address != NULL )
102     {
103         char *psz_parser = strchr( psz_address, ':' );
104         if( psz_parser )
105         {
106             *psz_parser++ = '\0';
107             i_port = atoi( psz_parser );
108         }
109     }
110     else
111         return VLC_SUCCESS;
112
113     /* determine SSL configuration */
114     psz_cert = var_InheritString( p_access, "dvb-http-intf-cert" );
115     if ( psz_cert != NULL )
116     {
117         msg_Dbg( p_access, "enabling TLS for HTTP interface (cert file: %s)",
118                  psz_cert );
119         psz_key = var_InheritString( p_access, "dvb-http-intf-key" );
120         psz_ca = var_InheritString( p_access, "dvb-http-intf-ca" );
121         psz_crl = var_InheritString( p_access, "dvb-http-intf-crl" );
122
123         if ( i_port <= 0 )
124             i_port = 8443;
125     }
126     else
127     {
128         if ( i_port <= 0 )
129             i_port= 8082;
130     }
131
132     /* Ugly hack to allow to run several HTTP servers on different ports. */
133     sprintf( psz_tmp, ":%d", i_port + 1 );
134     config_PutPsz( p_access, "dvb-http-host", psz_tmp );
135
136     msg_Dbg( p_access, "base %s:%d", psz_address, i_port );
137
138     p_sys->p_httpd_host = httpd_TLSHostNew( VLC_OBJECT(p_access), psz_address,
139                                             i_port, psz_cert, psz_key, psz_ca,
140                                             psz_crl );
141     free( psz_cert );
142     free( psz_key );
143     free( psz_ca );
144     free( psz_crl );
145
146     if ( p_sys->p_httpd_host == NULL )
147     {
148         msg_Err( p_access, "cannot listen on %s:%d", psz_address, i_port );
149         free( psz_address );
150         return VLC_EGENERIC;
151     }
152     free( psz_address );
153
154     psz_user = var_GetNonEmptyString( p_access, "dvb-http-user" );
155     psz_password = var_GetNonEmptyString( p_access, "dvb-http-password" );
156     psz_acl = var_GetNonEmptyString( p_access, "dvb-http-acl" );
157
158     if ( psz_acl != NULL )
159     {
160         p_acl = ACL_Create( p_access, false );
161         if( ACL_LoadFile( p_acl, psz_acl ) )
162         {
163             ACL_Destroy( p_acl );
164             p_acl = NULL;
165         }
166     }
167
168     /* Declare an index.html file. */
169     f = malloc( sizeof(httpd_file_sys_t) );
170     f->p_access = p_access;
171     f->p_file = httpd_FileNew( p_sys->p_httpd_host, "/index.html",
172                                "text/html; charset=UTF-8",
173                                psz_user, psz_password, p_acl,
174                                HttpCallback, f );
175
176     free( psz_user );
177     free( psz_password );
178     free( psz_acl );
179     if ( p_acl != NULL )
180         ACL_Destroy( p_acl );
181
182     if ( f->p_file == NULL )
183     {
184         free( f );
185         p_sys->p_httpd_file = NULL;
186         return VLC_EGENERIC;
187     }
188
189     p_sys->p_httpd_file = f;
190     p_sys->p_httpd_redir = httpd_RedirectNew( p_sys->p_httpd_host,
191                                               "/index.html", "/" );
192
193     return VLC_SUCCESS;
194 }
195
196 /*****************************************************************************
197  * HTTPClose: Stop the internal HTTP server
198  *****************************************************************************/
199 void HTTPClose( access_t *p_access )
200 {
201     access_sys_t *p_sys = p_access->p_sys;
202
203     if ( p_sys->p_httpd_host != NULL )
204     {
205         if ( p_sys->p_httpd_file != NULL )
206         {
207             /* Unlock the thread if it is stuck in HttpCallback */
208             vlc_mutex_lock( &p_sys->httpd_mutex );
209             if ( p_sys->b_request_frontend_info == true )
210             {
211                 p_sys->b_request_frontend_info = false;
212                 p_sys->psz_frontend_info = strdup("");
213             }
214             if ( p_sys->b_request_mmi_info == true )
215             {
216                 p_sys->b_request_mmi_info = false;
217                 p_sys->psz_mmi_info = strdup("");
218             }
219             vlc_cond_signal( &p_sys->httpd_cond );
220             vlc_mutex_unlock( &p_sys->httpd_mutex );
221
222             httpd_FileDelete( p_sys->p_httpd_file->p_file );
223             httpd_RedirectDelete( p_sys->p_httpd_redir );
224         }
225
226         httpd_HostDelete( p_sys->p_httpd_host );
227     }
228
229     vlc_mutex_destroy( &p_sys->httpd_mutex );
230     vlc_cond_destroy( &p_sys->httpd_cond );
231 }
232
233
234 static const char *psz_constant_header =
235     "<html>\n"
236     "<head><title>VLC DVB monitoring interface</title></head>\n"
237     "<body><a href=\"index.html\">Reload this page</a>\n"
238     "<h1>CAM info</h1>\n";
239
240 static const char *psz_constant_middle =
241     "<hr><h1>Frontend Info</h1>\n";
242
243 static const char *psz_constant_footer =
244     "</body></html>\n";
245
246 /****************************************************************************
247  * HttpCallback: Return the index.html file
248  ****************************************************************************/
249 static int HttpCallback( httpd_file_sys_t *p_args,
250                          httpd_file_t *p_file,
251                          uint8_t *_psz_request,
252                          uint8_t **_pp_data, int *pi_data )
253 {
254     VLC_UNUSED(p_file);
255     access_sys_t *p_sys = p_args->p_access->p_sys;
256     char *psz_request = (char *)_psz_request;
257     char **pp_data = (char **)_pp_data;
258
259     vlc_mutex_lock( &p_sys->httpd_mutex );
260
261     p_sys->i_httpd_timeout = mdate() + INT64_C(3000000); /* 3 s */
262     p_sys->psz_request = psz_request;
263     p_sys->b_request_frontend_info = true;
264     if ( p_sys->i_ca_handle )
265     {
266         p_sys->b_request_mmi_info = true;
267     }
268     else
269     {
270         p_sys->psz_mmi_info = strdup( "No available CAM interface\n" );
271     }
272
273     do
274     {
275         vlc_cond_wait( &p_sys->httpd_cond, &p_sys->httpd_mutex );
276     }
277     while ( p_sys->b_request_frontend_info || p_sys->b_request_mmi_info );
278
279     p_sys->i_httpd_timeout = 0;
280     vlc_mutex_unlock( &p_sys->httpd_mutex );
281
282     *pi_data = strlen( psz_constant_header )
283                 + strlen( p_sys->psz_mmi_info )
284                 + strlen( psz_constant_middle )
285                 + strlen( p_sys->psz_frontend_info )
286                 + strlen( psz_constant_footer ) + 1;
287     *pp_data = malloc( *pi_data );
288
289     sprintf( *pp_data, "%s%s%s%s%s", psz_constant_header,
290              p_sys->psz_mmi_info, psz_constant_middle,
291              p_sys->psz_frontend_info, psz_constant_footer );
292     free( p_sys->psz_frontend_info );
293     free( p_sys->psz_mmi_info );
294
295     return VLC_SUCCESS;
296 }
297
298 /****************************************************************************
299  * HTTPExtractValue: Extract a GET variable from psz_request
300  ****************************************************************************/
301 const char *HTTPExtractValue( const char *psz_uri, const char *psz_name,
302                         char *psz_value, int i_value_max )
303 {
304     const char *p = psz_uri;
305
306     while( (p = strstr( p, psz_name )) )
307     {
308         /* Verify that we are dealing with a post/get argument */
309         if( (p == psz_uri || *(p - 1) == '&' || *(p - 1) == '\n')
310               && p[strlen(psz_name)] == '=' )
311             break;
312         p++;
313     }
314
315     if( p )
316     {
317         int i_len;
318
319         p += strlen( psz_name );
320         if( *p == '=' ) p++;
321
322         if( strchr( p, '&' ) )
323         {
324             i_len = strchr( p, '&' ) - p;
325         }
326         else
327         {
328             /* for POST method */
329             if( strchr( p, '\n' ) )
330             {
331                 i_len = strchr( p, '\n' ) - p;
332                 if( i_len && *(p+i_len-1) == '\r' ) i_len--;
333             }
334             else
335             {
336                 i_len = strlen( p );
337             }
338         }
339         i_len = __MIN( i_value_max - 1, i_len );
340         if( i_len > 0 )
341         {
342             strncpy( psz_value, p, i_len );
343             psz_value[i_len] = '\0';
344         }
345         else
346         {
347             strncpy( psz_value, "", i_value_max );
348         }
349         p += i_len;
350     }
351     else
352     {
353         strncpy( psz_value, "", i_value_max );
354     }
355
356     return p;
357 }
358
359 #endif /* ENABLE_HTTPD */