Don't include config.h from the headers - refs #297.
[vlc.git] / 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/vlc.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 <errno.h>
42
43 /* Include dvbpsi headers */
44 #ifdef HAVE_DVBPSI_DR_H
45 #   include <dvbpsi/dvbpsi.h>
46 #   include <dvbpsi/descriptor.h>
47 #   include <dvbpsi/pat.h>
48 #   include <dvbpsi/pmt.h>
49 #   include <dvbpsi/dr.h>
50 #   include <dvbpsi/psi.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 #endif
59
60 #ifdef ENABLE_HTTPD
61 #   include "vlc_httpd.h"
62 #   include "vlc_acl.h"
63 #endif
64
65 #include "dvb.h"
66
67 #ifdef ENABLE_HTTPD
68 struct httpd_file_sys_t
69 {
70     access_t         *p_access;
71     httpd_file_t     *p_file;
72 };
73
74 static int HttpCallback( httpd_file_sys_t *p_args,
75                          httpd_file_t *p_file,
76                          uint8_t *_p_request,
77                          uint8_t **_pp_data, int *pi_data );
78
79 /*****************************************************************************
80  * HTTPOpen: Start the internal HTTP server
81  *****************************************************************************/
82 int E_(HTTPOpen)( access_t *p_access )
83 {
84     access_sys_t *p_sys = p_access->p_sys;
85     char          *psz_address, *psz_cert = NULL, *psz_key = NULL,
86                   *psz_ca = NULL, *psz_crl = NULL, *psz_user = NULL,
87                   *psz_password = NULL, *psz_acl = NULL;
88     int           i_port       = 0;
89     char          psz_tmp[10];
90     vlc_acl_t     *p_acl = NULL;
91     httpd_file_sys_t *f;
92
93     vlc_mutex_init( p_access, &p_sys->httpd_mutex );
94     vlc_cond_init( p_access, &p_sys->httpd_cond );
95     p_sys->b_request_frontend_info = p_sys->b_request_mmi_info = VLC_FALSE;
96     p_sys->i_httpd_timeout = 0;
97
98     psz_address = var_GetNonEmptyString( p_access, "dvb-http-host" );
99     if( psz_address != NULL )
100     {
101         char *psz_parser = strchr( psz_address, ':' );
102         if( psz_parser )
103         {
104             *psz_parser++ = '\0';
105             i_port = atoi( psz_parser );
106         }
107     }
108     else
109         return VLC_SUCCESS;
110
111     /* determine SSL configuration */
112     psz_cert = var_GetNonEmptyString( p_access, "dvb-http-intf-cert" );
113     if ( psz_cert != NULL )
114     {
115         msg_Dbg( p_access, "enabling TLS for HTTP interface (cert file: %s)",
116                  psz_cert );
117         psz_key = config_GetPsz( p_access, "dvb-http-intf-key" );
118         psz_ca = config_GetPsz( p_access, "dvb-http-intf-ca" );
119         psz_crl = config_GetPsz( p_access, "dvb-http-intf-crl" );
120
121         if ( i_port <= 0 )
122             i_port = 8443;
123     }
124     else
125     {
126         if ( i_port <= 0 )
127             i_port= 8082;
128     }
129
130     /* Ugly hack to allow to run several HTTP servers on different ports. */
131     sprintf( psz_tmp, ":%d", i_port + 1 );
132     config_PutPsz( p_access, "dvb-http-host", psz_tmp );
133
134     msg_Dbg( p_access, "base %s:%d", psz_address, i_port );
135
136     p_sys->p_httpd_host = httpd_TLSHostNew( VLC_OBJECT(p_access), psz_address,
137                                             i_port, psz_cert, psz_key, psz_ca,
138                                             psz_crl );
139     free( psz_cert );
140     free( psz_key );
141     free( psz_ca );
142     free( psz_crl );
143
144     if ( p_sys->p_httpd_host == NULL )
145     {
146         msg_Err( p_access, "cannot listen on %s:%d", psz_address, i_port );
147         free( psz_address );
148         return VLC_EGENERIC;
149     }
150     free( psz_address );
151
152     psz_user = var_GetNonEmptyString( p_access, "dvb-http-user" );
153     psz_password = var_GetNonEmptyString( p_access, "dvb-http-password" );
154     psz_acl = var_GetNonEmptyString( p_access, "dvb-http-acl" );
155
156     if ( psz_acl != NULL )
157     {
158         p_acl = ACL_Create( p_access, VLC_FALSE );
159         if( ACL_LoadFile( p_acl, psz_acl ) )
160         {
161             ACL_Destroy( p_acl );
162             p_acl = NULL;
163         }
164     }
165
166     /* Declare an index.html file. */
167     f = malloc( sizeof(httpd_file_sys_t) );
168     f->p_access = p_access;
169     f->p_file = httpd_FileNew( p_sys->p_httpd_host, "/index.html",
170                                "text/html; charset=UTF-8",
171                                psz_user, psz_password, p_acl,
172                                HttpCallback, f );
173
174     free( psz_user );
175     free( psz_password );
176     free( psz_acl );
177     if ( p_acl != NULL )
178         ACL_Destroy( p_acl );
179
180     if ( f->p_file == NULL )
181     {
182         free( f );
183         p_sys->p_httpd_file = NULL;
184         return VLC_EGENERIC;
185     }
186
187     p_sys->p_httpd_file = f;
188     p_sys->p_httpd_redir = httpd_RedirectNew( p_sys->p_httpd_host,
189                                               "/index.html", "/" );
190
191     return VLC_SUCCESS;
192 }
193
194 /*****************************************************************************
195  * HTTPClose: Stop the internal HTTP server
196  *****************************************************************************/
197 void E_(HTTPClose)( access_t *p_access )
198 {
199     access_sys_t *p_sys = p_access->p_sys;
200
201     if ( p_sys->p_httpd_host != NULL )
202     {
203         if ( p_sys->p_httpd_file != NULL )
204         {
205             /* Unlock the thread if it is stuck in HttpCallback */
206             vlc_mutex_lock( &p_sys->httpd_mutex );
207             if ( p_sys->b_request_frontend_info == VLC_TRUE )
208             {
209                 p_sys->b_request_frontend_info = VLC_FALSE;
210                 p_sys->psz_frontend_info = strdup("");
211             }
212             if ( p_sys->b_request_mmi_info == VLC_TRUE )
213             {
214                 p_sys->b_request_mmi_info = VLC_FALSE;
215                 p_sys->psz_mmi_info = strdup("");
216             }
217             vlc_cond_signal( &p_sys->httpd_cond );
218             vlc_mutex_unlock( &p_sys->httpd_mutex );
219
220             httpd_FileDelete( p_sys->p_httpd_file->p_file );
221             httpd_RedirectDelete( p_sys->p_httpd_redir );
222         }
223
224         httpd_HostDelete( p_sys->p_httpd_host );
225     }
226
227     vlc_mutex_destroy( &p_sys->httpd_mutex );
228     vlc_cond_destroy( &p_sys->httpd_cond );
229 }
230
231
232 static const char *psz_constant_header =
233     "<html>\n"
234     "<head><title>VLC DVB monitoring interface</title></head>\n"
235     "<body><a href=\"index.html\">Reload this page</a>\n"
236     "<h1>CAM info</h1>\n";
237
238 static const char *psz_constant_middle =
239     "<hr><h1>Frontend Info</h1>\n";
240
241 static const char *psz_constant_footer =
242     "</body></html>\n";
243
244 /****************************************************************************
245  * HttpCallback: Return the index.html file
246  ****************************************************************************/
247 static int HttpCallback( httpd_file_sys_t *p_args,
248                          httpd_file_t *p_file,
249                          uint8_t *_psz_request,
250                          uint8_t **_pp_data, int *pi_data )
251 {
252     access_sys_t *p_sys = p_args->p_access->p_sys;
253     char *psz_request = (char *)_psz_request;
254     char **pp_data = (char **)_pp_data;
255
256     vlc_mutex_lock( &p_sys->httpd_mutex );
257
258     p_sys->i_httpd_timeout = mdate() + I64C(3000000); /* 3 s */
259     p_sys->psz_request = psz_request;
260     p_sys->b_request_frontend_info = VLC_TRUE;
261     if ( p_sys->i_ca_handle )
262     {
263         p_sys->b_request_mmi_info = VLC_TRUE;
264     }
265     else
266     {
267         p_sys->psz_mmi_info = strdup( "No available CAM interface\n" );
268     }
269
270     do
271     {
272         vlc_cond_wait( &p_sys->httpd_cond, &p_sys->httpd_mutex );
273     }
274     while ( p_sys->b_request_frontend_info || p_sys->b_request_mmi_info );
275
276     p_sys->i_httpd_timeout = 0;
277     vlc_mutex_unlock( &p_sys->httpd_mutex );
278
279     *pi_data = strlen( psz_constant_header )
280                 + strlen( p_sys->psz_mmi_info )
281                 + strlen( psz_constant_middle )
282                 + strlen( p_sys->psz_frontend_info )
283                 + strlen( psz_constant_footer ) + 1;
284     *pp_data = malloc( *pi_data );
285
286     sprintf( *pp_data, "%s%s%s%s%s", psz_constant_header,
287              p_sys->psz_mmi_info, psz_constant_middle,
288              p_sys->psz_frontend_info, psz_constant_footer );
289     free( p_sys->psz_frontend_info );
290     free( p_sys->psz_mmi_info );
291
292     return VLC_SUCCESS;
293 }
294
295 /****************************************************************************
296  * HTTPExtractValue: Extract a GET variable from psz_request
297  ****************************************************************************/
298 char *E_(HTTPExtractValue)( char *psz_uri, const char *psz_name,
299                             char *psz_value, int i_value_max )
300 {
301     char *p = psz_uri;
302
303     while( (p = strstr( p, psz_name )) )
304     {
305         /* Verify that we are dealing with a post/get argument */
306         if( (p == psz_uri || *(p - 1) == '&' || *(p - 1) == '\n')
307               && p[strlen(psz_name)] == '=' )
308             break;
309         p++;
310     }
311
312     if( p )
313     {
314         int i_len;
315
316         p += strlen( psz_name );
317         if( *p == '=' ) p++;
318
319         if( strchr( p, '&' ) )
320         {
321             i_len = strchr( p, '&' ) - p;
322         }
323         else
324         {
325             /* for POST method */
326             if( strchr( p, '\n' ) )
327             {
328                 i_len = strchr( p, '\n' ) - p;
329                 if( i_len && *(p+i_len-1) == '\r' ) i_len--;
330             }
331             else
332             {
333                 i_len = strlen( p );
334             }
335         }
336         i_len = __MIN( i_value_max - 1, i_len );
337         if( i_len > 0 )
338         {
339             strncpy( psz_value, p, i_len );
340             psz_value[i_len] = '\0';
341         }
342         else
343         {
344             strncpy( psz_value, "", i_value_max );
345         }
346         p += i_len;
347     }
348     else
349     {
350         strncpy( psz_value, "", i_value_max );
351     }
352
353     return p;
354 }
355
356 #endif /* ENABLE_HTTPD */