Remove legacy parameter from add_string()
[vlc/asuraparaju-public.git] / modules / control / http / http.c
blobe9b7298637fc85d68c32f723a6db827e3df5ceb7
1 /*****************************************************************************
2 * http.c : HTTP/HTTPS Remote control interface
3 *****************************************************************************
4 * Copyright (C) 2001-2006 the VideoLAN team
6 * Authors: Gildas Bazin <gbazin@netcourrier.com>
7 * Laurent Aimar <fenrir@via.ecp.fr>
8 * Christophe Massiot <massiot@via.ecp.fr>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
28 #include "http.h"
29 #include <vlc_plugin.h>
30 #include <vlc_url.h>
31 #include <vlc_fs.h>
33 #include <assert.h>
35 /*****************************************************************************
36 * Module descriptor
37 *****************************************************************************/
38 static int Open ( vlc_object_t * );
39 static void Close( vlc_object_t * );
41 #define HOST_TEXT N_( "Host address" )
42 #define HOST_LONGTEXT N_( \
43 "Address and port the HTTP interface will listen on. It defaults to " \
44 "all network interfaces (0.0.0.0)." \
45 " If you want the HTTP interface to be available only on the local " \
46 "machine, enter 127.0.0.1" )
47 #define SRC_TEXT N_( "Source directory" )
48 #define SRC_LONGTEXT N_( "Source directory" )
49 #define HANDLERS_TEXT N_( "Handlers" )
50 #define HANDLERS_LONGTEXT N_( \
51 "List of handler extensions and executable paths (for instance: " \
52 "php=/usr/bin/php,pl=/usr/bin/perl)." )
53 #define ART_TEXT N_( "Export album art as /art" )
54 #define ART_LONGTEXT N_( \
55 "Allow exporting album art for current playlist items at the " \
56 "/art and /art?id=<id> URLs." )
57 #define CERT_TEXT N_( "Certificate file" )
58 #define CERT_LONGTEXT N_( "HTTP interface x509 PEM certificate file " \
59 "(enables SSL)." )
60 #define KEY_TEXT N_( "Private key file" )
61 #define KEY_LONGTEXT N_( "HTTP interface x509 PEM private key file." )
62 #define CA_TEXT N_( "Root CA file" )
63 #define CA_LONGTEXT N_( "HTTP interface x509 PEM trusted root CA " \
64 "certificates file." )
65 #define CRL_TEXT N_( "CRL file" )
66 #define CRL_LONGTEXT N_( "HTTP interace Certificates Revocation List file." )
68 vlc_module_begin ()
69 set_shortname( N_("HTTP"))
70 set_description( N_("HTTP remote control interface") )
71 set_category( CAT_INTERFACE )
72 set_subcategory( SUBCAT_INTERFACE_MAIN )
73 add_string ( "http-host", NULL, HOST_TEXT, HOST_LONGTEXT, true )
74 add_string ( "http-src", NULL, SRC_TEXT, SRC_LONGTEXT, true )
75 add_obsolete_string ( "http-charset" )
76 #if defined( HAVE_FORK ) || defined( WIN32 )
77 add_string ( "http-handlers", NULL, HANDLERS_TEXT, HANDLERS_LONGTEXT, true )
78 #endif
79 add_bool ( "http-album-art", false, NULL, ART_TEXT, ART_LONGTEXT, true )
80 set_section( N_("HTTP SSL" ), 0 )
81 add_string ( "http-intf-cert", NULL, CERT_TEXT, CERT_LONGTEXT, true )
82 add_string ( "http-intf-key", NULL, KEY_TEXT, KEY_LONGTEXT, true )
83 add_string ( "http-intf-ca", NULL, CA_TEXT, CA_LONGTEXT, true )
84 add_string ( "http-intf-crl", NULL, CRL_TEXT, CRL_LONGTEXT, true )
85 set_capability( "interface", 0 )
86 set_callbacks( Open, Close )
87 add_shortcut( "http" )
88 vlc_module_end ()
91 /*****************************************************************************
92 * Local prototypes
93 *****************************************************************************/
94 int ArtCallback( httpd_handler_sys_t *p_args,
95 httpd_handler_t *p_handler, char *_p_url,
96 uint8_t *_p_request, int i_type,
97 uint8_t *_p_in, int i_in,
98 char *psz_remote_addr, char *psz_remote_host,
99 uint8_t **pp_data, int *pi_data );
101 /*****************************************************************************
102 * Activate: initialize and create stuff
103 *****************************************************************************/
104 static int Open( vlc_object_t *p_this )
106 intf_thread_t *p_intf = (intf_thread_t*)p_this;
107 intf_sys_t *p_sys;
108 char *psz_address;
109 char *psz_cert = NULL, *psz_key = NULL, *psz_ca = NULL,
110 *psz_crl = NULL;
111 int i_port = 0;
112 char *psz_src = NULL;
114 psz_address = var_CreateGetNonEmptyString( p_intf, "http-host" );
115 if( psz_address != NULL )
117 char *psz_parser = strrchr( psz_address, ':' );
118 if( psz_parser )
120 *psz_parser++ = '\0';
121 i_port = atoi( psz_parser );
124 else
125 psz_address = strdup("");
127 p_intf->p_sys = p_sys = malloc( sizeof( intf_sys_t ) );
128 if( !p_intf->p_sys )
130 free( psz_address );
131 return( VLC_ENOMEM );
134 p_sys->p_playlist = pl_Get( p_this );
135 p_sys->p_input = NULL;
136 p_sys->p_vlm = NULL;
137 p_sys->psz_address = psz_address;
138 p_sys->i_port = i_port;
139 p_sys->p_art_handler = NULL;
141 /* determine file handler associations */
142 p_sys->i_handlers = 0;
143 p_sys->pp_handlers = NULL;
144 #if defined( HAVE_FORK ) || defined( WIN32 )
145 psz_src = var_InheritString( p_intf, "http-handlers" );
146 if( psz_src != NULL )
148 char *p = psz_src;
149 while( p != NULL )
151 http_association_t *p_handler;
152 char *psz_ext = p;
153 char *psz_program, *psz_options;
154 p = strchr( p, '=' );
155 if( p == NULL ) break;
156 *p++ = '\0';
157 psz_program = p;
158 p = strchr( p, ',' );
159 if( p != NULL )
160 *p++ = '\0';
162 p_handler = malloc( sizeof( http_association_t ) );
163 p_handler->psz_ext = strdup( psz_ext );
164 psz_options = FirstWord( psz_program, psz_program );
165 p_handler->i_argc = 0;
166 p_handler->ppsz_argv = NULL;
167 TAB_APPEND( p_handler->i_argc, p_handler->ppsz_argv,
168 strdup( psz_program ) );
169 while( psz_options != NULL && *psz_options )
171 char *psz_next = FirstWord( psz_options, psz_options );
172 TAB_APPEND( p_handler->i_argc, p_handler->ppsz_argv,
173 strdup( psz_options ) );
174 psz_options = psz_next;
176 /* NULL will be appended later on */
178 TAB_APPEND( p_sys->i_handlers, p_sys->pp_handlers, p_handler );
180 free( psz_src );
182 #endif
184 /* determine SSL configuration */
185 psz_cert = var_InheritString( p_intf, "http-intf-cert" );
186 if ( psz_cert != NULL )
188 msg_Dbg( p_intf, "enabling TLS for HTTP interface (cert file: %s)",
189 psz_cert );
190 psz_key = var_InheritString( p_intf, "http-intf-key" );
191 psz_ca = var_InheritString( p_intf, "http-intf-ca" );
192 psz_crl = var_InheritString( p_intf, "http-intf-crl" );
194 if( i_port <= 0 )
195 i_port = 8443;
197 else
199 if( i_port <= 0 )
200 i_port= 8080;
203 msg_Dbg( p_intf, "base %s:%d", psz_address, i_port );
205 p_sys->p_httpd_host = httpd_TLSHostNew( VLC_OBJECT(p_intf), psz_address,
206 i_port, psz_cert, psz_key, psz_ca,
207 psz_crl );
208 free( psz_cert );
209 free( psz_key );
210 free( psz_ca );
211 free( psz_crl );
213 if( p_sys->p_httpd_host == NULL )
215 msg_Err( p_intf, "cannot listen on %s:%d", psz_address, i_port );
216 free( p_sys->psz_address );
217 free( p_sys );
218 return VLC_EGENERIC;
220 else
222 char psz_tmp[NI_MAXHOST + 6];
224 /* Ugly hack to run several HTTP servers on different ports */
225 snprintf( psz_tmp, sizeof (psz_tmp), "%s:%d", psz_address, i_port + 1 );
226 var_Create(p_intf->p_libvlc, "http-host", VLC_VAR_STRING );
227 var_SetString( p_intf->p_libvlc, "http-host", psz_tmp );
230 p_sys->i_files = 0;
231 p_sys->pp_files = NULL;
233 psz_src = var_InheritString( p_intf, "http-src" );
234 if( psz_src == NULL )
236 char *data_path = config_GetDataDir( p_intf );
237 if( asprintf( &psz_src, "%s" DIR_SEP "http", data_path ) == -1 )
238 psz_src = NULL;
239 free( data_path );
242 if( psz_src == NULL )
244 msg_Err( p_intf, "invalid web interface source directory" );
245 goto failed;
248 /* remove trainling \ or / */
249 if( psz_src[strlen( psz_src ) - 1] == '\\' ||
250 psz_src[strlen( psz_src ) - 1] == '/' )
252 psz_src[strlen( psz_src ) - 1] = '\0';
255 ParseDirectory( p_intf, psz_src, psz_src );
256 if( p_sys->i_files <= 0 )
258 msg_Err( p_intf, "cannot find any file in directory %s", psz_src );
259 goto failed;
262 free( psz_src );
264 if( var_InheritBool( p_intf, "http-album-art" ) )
266 /* FIXME: we're leaking h */
267 httpd_handler_sys_t *h = malloc( sizeof( httpd_handler_sys_t ) );
268 if( !h )
269 goto failed;
270 h->file.p_intf = p_intf;
271 h->file.file = NULL;
272 h->file.name = NULL;
273 /* TODO: use ACL and login/password stuff here too */
274 h->p_handler = httpd_HandlerNew( p_sys->p_httpd_host,
275 "/art", NULL, NULL, NULL,
276 ArtCallback, h );
277 p_sys->p_art_handler = h->p_handler;
280 return VLC_SUCCESS;
282 failed:
283 free( psz_src );
284 free( p_sys->pp_files );
285 httpd_HostDelete( p_sys->p_httpd_host );
286 free( p_sys->psz_address );
287 free( p_sys );
288 return VLC_EGENERIC;
291 /*****************************************************************************
292 * Close: destroy interface
293 *****************************************************************************/
294 static void Close ( vlc_object_t *p_this )
296 intf_thread_t *p_intf = (intf_thread_t *)p_this;
297 intf_sys_t *p_sys = p_intf->p_sys;
298 int i;
300 #ifdef ENABLE_VLM
301 if( p_sys->p_vlm )
302 vlm_Delete( p_sys->p_vlm );
303 #endif
304 for( i = 0; i < p_sys->i_files; i++ )
306 if( p_sys->pp_files[i]->b_handler )
307 httpd_HandlerDelete( ((httpd_handler_sys_t *)p_sys->pp_files[i])->p_handler );
308 else
309 httpd_FileDelete( p_sys->pp_files[i]->p_file );
310 if( p_sys->pp_files[i]->p_redir )
311 httpd_RedirectDelete( p_sys->pp_files[i]->p_redir );
312 if( p_sys->pp_files[i]->p_redir2 )
313 httpd_RedirectDelete( p_sys->pp_files[i]->p_redir2 );
315 free( p_sys->pp_files[i]->file );
316 free( p_sys->pp_files[i]->name );
317 free( p_sys->pp_files[i] );
319 free( p_sys->pp_files );
320 for( i = 0; i < p_sys->i_handlers; i++ )
322 http_association_t *p_handler = p_sys->pp_handlers[i];
323 int j;
324 free( p_handler->psz_ext );
325 for( j = 0; j < p_handler->i_argc; j++ )
326 free( p_handler->ppsz_argv[j] );
327 if( p_handler->i_argc )
328 free( p_handler->ppsz_argv );
329 free( p_handler );
331 if( p_sys->i_handlers )
332 free( p_sys->pp_handlers );
333 if( p_sys->p_art_handler )
334 httpd_HandlerDelete( p_sys->p_art_handler );
335 httpd_HostDelete( p_sys->p_httpd_host );
336 free( p_sys->psz_address );
337 free( p_sys );
340 /****************************************************************************
341 * HttpCallback:
342 ****************************************************************************
343 * a file with b_html is parsed and all "macro" replaced
344 ****************************************************************************/
345 static void Callback404( httpd_file_sys_t *p_args, char **pp_data,
346 int *pi_data )
348 char *p = *pp_data = malloc( 10240 );
349 if( !p )
351 return;
353 p += sprintf( p, "Content-Type: text/html\n" );
354 p += sprintf( p, "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n" );
355 p += sprintf( p, "<head>\n" );
356 p += sprintf( p, "<title>Error loading %s</title>\n", p_args->file );
357 p += sprintf( p, "</head>\n" );
358 p += sprintf( p, "<body>\n" );
359 p += sprintf( p, "<h1><center>Error loading %s for %s</center></h1>\n", p_args->file, p_args->name );
360 p += sprintf( p, "<a href=\"http://www.videolan.org/\">VideoLAN</a>\n" );
361 p += sprintf( p, "</body>\n" );
362 p += sprintf( p, "</html>\n" );
364 *pi_data = strlen( *pp_data );
367 static void ParseExecute( httpd_file_sys_t *p_args, char *p_buffer,
368 int i_buffer, char *p_request,
369 char **pp_data, int *pi_data )
371 intf_sys_t *p_sys = p_args->p_intf->p_sys;
372 int i_request = p_request != NULL ? strlen( p_request ) : 0;
373 char *dst;
374 char position[4]; /* percentage */
375 char time[12]; /* in seconds */
376 char length[12]; /* in seconds */
377 audio_volume_t i_volume;
378 char volume[5];
379 const char *state;
380 char stats[20];
382 assert( p_sys->p_input == NULL );
383 /* FIXME: proper locking anyone? */
384 p_sys->p_input = playlist_CurrentInput( p_sys->p_playlist );
385 if( p_sys->p_input )
387 snprintf( position, sizeof(position), "%d",
388 (int)(var_GetFloat( p_sys->p_input, "position" ) * 100.));
389 snprintf( time, sizeof(time), "%"PRIi64,
390 var_GetTime( p_sys->p_input, "time" ) / CLOCK_FREQ );
391 snprintf( length, sizeof(length), "%"PRIi64,
392 var_GetTime( p_sys->p_input, "length" ) / CLOCK_FREQ );
394 switch( var_GetInteger( p_sys->p_input, "state" ) )
396 case PLAYING_S: state = "playing"; break;
397 case OPENING_S: state = "opening/connecting"; break;
398 case PAUSE_S: state = "paused"; break;
399 default: state = "stop"; break;
402 else
404 strcpy( position, "0" );
405 strcpy( time, "0" );
406 strcpy( length, "0" );
407 state = "stop";
410 aout_VolumeGet( p_sys->p_playlist, &i_volume );
411 snprintf( volume, sizeof(volume), "%d", (int)i_volume );
413 p_args->vars = mvar_New( "variables", "" );
414 mvar_AppendNewVar( p_args->vars, "url_param",
415 i_request > 0 ? "1" : "0" );
416 mvar_AppendNewVar( p_args->vars, "url_value", p_request );
417 mvar_AppendNewVar( p_args->vars, "version", VLC_Version() );
418 mvar_AppendNewVar( p_args->vars, "copyright", COPYRIGHT_MESSAGE );
419 mvar_AppendNewVar( p_args->vars, "vlc_compile_by", VLC_CompileBy() );
420 mvar_AppendNewVar( p_args->vars, "vlc_compile_host",
421 VLC_CompileHost() );
422 mvar_AppendNewVar( p_args->vars, "vlc_compiler", VLC_Compiler() );
423 mvar_AppendNewVar( p_args->vars, "stream_position", position );
424 mvar_AppendNewVar( p_args->vars, "stream_time", time );
425 mvar_AppendNewVar( p_args->vars, "stream_length", length );
426 mvar_AppendNewVar( p_args->vars, "volume", volume );
427 mvar_AppendNewVar( p_args->vars, "stream_state", state );
428 mvar_AppendNewVar( p_args->vars, "charset", "UTF-8" );
430 /* Stats */
431 if( p_sys->p_input )
433 /* FIXME: Workarround a stupid assert in input_GetItem */
434 input_item_t *p_item = p_sys->p_input && p_sys->p_input->p
435 ? input_GetItem( p_sys->p_input )
436 : NULL;
438 if( p_item )
440 vlc_mutex_lock( &p_item->p_stats->lock );
441 #define STATS_INT( n ) sprintf( stats, "%"PRIi64, p_item->p_stats->i_ ## n ); \
442 mvar_AppendNewVar( p_args->vars, #n, stats );
443 #define STATS_FLOAT( n ) sprintf( stats, "%f", p_item->p_stats->f_ ## n ); \
444 mvar_AppendNewVar( p_args->vars, #n, stats );
445 STATS_INT( read_bytes )
446 STATS_FLOAT( input_bitrate )
447 STATS_INT( demux_read_bytes )
448 STATS_FLOAT( demux_bitrate )
449 STATS_INT( decoded_video )
450 STATS_INT( displayed_pictures )
451 STATS_INT( lost_pictures )
452 STATS_INT( decoded_audio )
453 STATS_INT( played_abuffers )
454 STATS_INT( lost_abuffers )
455 STATS_INT( sent_packets )
456 STATS_INT( sent_bytes )
457 STATS_FLOAT( send_bitrate )
458 #undef STATS_INT
459 #undef STATS_FLOAT
460 vlc_mutex_unlock( &p_item->p_stats->lock );
464 SSInit( &p_args->stack );
466 /* allocate output */
467 *pi_data = i_buffer + 1000;
468 dst = *pp_data = malloc( *pi_data );
470 /* we parse executing all <vlc /> macros */
471 Execute( p_args, p_request, i_request, pp_data, pi_data, &dst,
472 &p_buffer[0], &p_buffer[i_buffer] );
474 *dst = '\0';
475 *pi_data = dst - *pp_data;
477 if( p_sys->p_input != NULL )
479 vlc_object_release( p_sys->p_input );
480 p_sys->p_input = NULL;
482 SSClean( &p_args->stack );
483 mvar_Delete( p_args->vars );
486 int HttpCallback( httpd_file_sys_t *p_args,
487 httpd_file_t *p_file,
488 uint8_t *_p_request,
489 uint8_t **_pp_data, int *pi_data )
491 VLC_UNUSED(p_file);
492 char *p_request = (char *)_p_request;
493 char **pp_data = (char **)_pp_data;
494 FILE *f;
496 if( ( f = vlc_fopen( p_args->file, "r" ) ) == NULL )
498 Callback404( p_args, pp_data, pi_data );
499 return VLC_SUCCESS;
502 if( !p_args->b_html )
504 FileLoad( f, pp_data, pi_data );
506 else
508 int i_buffer;
509 char *p_buffer;
511 /* first we load in a temporary buffer */
512 FileLoad( f, &p_buffer, &i_buffer );
514 ParseExecute( p_args, p_buffer, i_buffer, p_request, pp_data, pi_data );
516 free( p_buffer );
519 fclose( f );
521 return VLC_SUCCESS;
524 /****************************************************************************
525 * HandlerCallback:
526 ****************************************************************************
527 * call the external handler and parse vlc macros if Content-Type is HTML
528 ****************************************************************************/
529 int HandlerCallback( httpd_handler_sys_t *p_args,
530 httpd_handler_t *p_handler, char *_p_url,
531 uint8_t *_p_request, int i_type,
532 uint8_t *_p_in, int i_in,
533 char *psz_remote_addr, char *psz_remote_host,
534 uint8_t **_pp_data, int *pi_data )
536 VLC_UNUSED(p_handler); VLC_UNUSED(_p_in);
537 char *p_url = (char *)_p_url;
538 char *p_request = (char *)_p_request;
539 char **pp_data = (char **)_pp_data;
540 char *p_in = (char *)_p_in;
541 int i_request = p_request != NULL ? strlen( p_request ) : 0;
542 char *p;
543 int i_env = 0;
544 char **ppsz_env = NULL;
545 char *psz_tmp;
546 size_t i_buffer;
547 char *p_buffer;
548 char *psz_cwd, *psz_file = NULL;
549 int i_ret;
551 /* Create environment for the CGI */
552 TAB_APPEND( i_env, ppsz_env, strdup("GATEWAY_INTERFACE=CGI/1.1") );
553 TAB_APPEND( i_env, ppsz_env, strdup("SERVER_PROTOCOL=HTTP/1.1") );
554 TAB_APPEND( i_env, ppsz_env, strdup("SERVER_SOFTWARE=VLC "VERSION) );
556 switch( i_type )
558 case HTTPD_MSG_GET:
559 TAB_APPEND( i_env, ppsz_env, strdup("REQUEST_METHOD=GET") );
560 break;
561 case HTTPD_MSG_POST:
562 TAB_APPEND( i_env, ppsz_env, strdup("REQUEST_METHOD=POST") );
563 break;
564 case HTTPD_MSG_HEAD:
565 TAB_APPEND( i_env, ppsz_env, strdup("REQUEST_METHOD=HEAD") );
566 break;
567 default:
568 break;
571 if( i_request )
573 if( -1==asprintf( &psz_tmp, "QUERY_STRING=%s", p_request ) )
574 psz_tmp = NULL;
575 TAB_APPEND( i_env, ppsz_env, psz_tmp );
577 if( -1==asprintf( &psz_tmp, "REQUEST_URI=%s?%s", p_url, p_request ) )
578 psz_tmp = NULL;
579 TAB_APPEND( i_env, ppsz_env, psz_tmp );
581 else
583 if( -1==asprintf( &psz_tmp, "REQUEST_URI=%s", p_url ) )
584 psz_tmp = NULL;
585 TAB_APPEND( i_env, ppsz_env, psz_tmp );
588 if( -1==asprintf( &psz_tmp, "SCRIPT_NAME=%s", p_url ) )
589 psz_tmp = NULL;
590 TAB_APPEND( i_env, ppsz_env, psz_tmp );
592 #define p_sys p_args->file.p_intf->p_sys
593 if( -1==asprintf( &psz_tmp, "SERVER_NAME=%s", p_sys->psz_address ) )
594 psz_tmp = NULL;
595 TAB_APPEND( i_env, ppsz_env, psz_tmp );
597 if( -1==asprintf( &psz_tmp, "SERVER_PORT=%u", p_sys->i_port ) )
598 psz_tmp = NULL;
599 TAB_APPEND( i_env, ppsz_env, psz_tmp );
600 #undef p_sys
602 p = getenv( "PATH" );
603 if( p != NULL )
605 if( -1==asprintf( &psz_tmp, "PATH=%s", p ) )
606 psz_tmp = NULL;
607 TAB_APPEND( i_env, ppsz_env, psz_tmp );
610 #ifdef WIN32
611 p = getenv( "windir" );
612 if( p != NULL )
614 if( -1==asprintf( &psz_tmp, "SYSTEMROOT=%s", p ) )
615 psz_tmp = NULL;
616 TAB_APPEND( i_env, ppsz_env, psz_tmp );
618 #endif
620 if( psz_remote_addr != NULL && *psz_remote_addr )
622 if( -1==asprintf( &psz_tmp, "REMOTE_ADDR=%s", psz_remote_addr ) )
623 psz_tmp = NULL;
624 TAB_APPEND( i_env, ppsz_env, psz_tmp );
627 if( psz_remote_host != NULL && *psz_remote_host )
629 if( -1==asprintf( &psz_tmp, "REMOTE_HOST=%s", psz_remote_host ) )
630 psz_tmp = NULL;
631 TAB_APPEND( i_env, ppsz_env, psz_tmp );
634 if( i_in )
636 p = p_in;
637 for ( ; ; )
639 if( !strncasecmp( p, "Content-Type: ", strlen("Content-Type: ") ) )
641 char *end = strchr( p, '\r' );
642 if( end == NULL )
643 break;
644 *end = '\0';
645 if( -1==asprintf( &psz_tmp, "CONTENT_TYPE=%s", p ) )
646 psz_tmp = NULL;
647 TAB_APPEND( i_env, ppsz_env, psz_tmp );
648 *end = '\r';
650 if( !strncasecmp( p, "Content-Length: ",
651 strlen("Content-Length: ") ) )
653 char *end = strchr( p, '\r' );
654 if( end == NULL )
655 break;
656 *end = '\0';
657 if( -1==asprintf( &psz_tmp, "CONTENT_LENGTH=%s", p ) )
658 psz_tmp = NULL;
659 TAB_APPEND( i_env, ppsz_env, psz_tmp );
660 *end = '\r';
663 p = strchr( p, '\n' );
664 if( p == NULL || p[1] == '\r' )
666 p = NULL;
667 break;
669 p++;
673 psz_file = strrchr( p_args->file.file, DIR_SEP_CHAR );
674 if( psz_file != NULL )
676 psz_file++;
677 if( -1==asprintf( &psz_tmp, "SCRIPT_FILENAME=%s", psz_file ) )
678 psz_tmp = NULL;
679 TAB_APPEND( i_env, ppsz_env, psz_tmp );
681 TAB_APPEND( p_args->p_association->i_argc,
682 p_args->p_association->ppsz_argv, psz_file );
685 TAB_APPEND( i_env, ppsz_env, NULL );
687 TAB_APPEND( p_args->p_association->i_argc, p_args->p_association->ppsz_argv,
688 NULL );
690 psz_tmp = strdup( p_args->file.file );
691 p = strrchr( psz_tmp, DIR_SEP_CHAR );
692 if( p != NULL )
694 *p = '\0';
695 psz_cwd = psz_tmp;
697 else
699 free( psz_tmp );
700 psz_cwd = NULL;
703 i_ret = vlc_execve( p_args->file.p_intf, p_args->p_association->i_argc,
704 p_args->p_association->ppsz_argv, ppsz_env, psz_cwd,
705 (char *)p_in, i_in, &p_buffer, &i_buffer );
706 TAB_REMOVE( p_args->p_association->i_argc, p_args->p_association->ppsz_argv,
707 NULL );
708 TAB_REMOVE( p_args->p_association->i_argc, p_args->p_association->ppsz_argv,
709 psz_file );
710 free( psz_cwd );
711 while( i_env )
712 TAB_REMOVE( i_env, ppsz_env, ppsz_env[0] );
714 if( i_ret == -1 )
716 Callback404( (httpd_file_sys_t *)p_args, pp_data, pi_data );
717 return VLC_SUCCESS;
719 p = p_buffer;
720 while( strncasecmp( p, "Content-Type: text/html",
721 strlen("Content-Type: text/html") ) )
723 p = strchr( p, '\n' );
724 if( p == NULL || p[1] == '\r' )
726 p = NULL;
727 break;
729 p++;
732 if( p == NULL )
734 *pp_data = p_buffer;
735 *pi_data = i_buffer;
737 else
739 ParseExecute( (httpd_file_sys_t *)p_args, p_buffer, i_buffer,
740 p_request, pp_data, pi_data );
742 free( p_buffer );
745 return VLC_SUCCESS;
748 int ArtCallback( httpd_handler_sys_t *p_args,
749 httpd_handler_t *p_handler, char *_p_url,
750 uint8_t *p_request, int i_type,
751 uint8_t *p_in, int i_in,
752 char *psz_remote_addr, char *psz_remote_host,
753 uint8_t **pp_data, int *pi_data )
755 VLC_UNUSED(p_handler); VLC_UNUSED(_p_url); VLC_UNUSED(i_type);
756 VLC_UNUSED(p_in); VLC_UNUSED(i_in); VLC_UNUSED(psz_remote_addr);
757 VLC_UNUSED(psz_remote_host);
759 char *psz_art = NULL;
760 intf_thread_t *p_intf = p_args->file.p_intf;
761 intf_sys_t *p_sys = p_intf->p_sys;
762 char psz_id[16];
763 input_item_t *p_item = NULL;
764 int i_id;
766 psz_id[0] = '\0';
767 if( p_request )
768 ExtractURIValue( (char *)p_request, "id", psz_id, 15 );
769 i_id = atoi( psz_id );
770 if( i_id )
772 playlist_Lock( p_sys->p_playlist );
773 playlist_item_t *p_pl_item = playlist_ItemGetById( p_sys->p_playlist,
774 i_id );
775 if( p_pl_item )
776 p_item = p_pl_item->p_input;
777 playlist_Unlock( p_sys->p_playlist );
779 else
781 /* FIXME: Workarround a stupid assert in input_GetItem */
782 if( p_sys->p_input && p_sys->p_input->p )
783 p_item = input_GetItem( p_sys->p_input );
786 if( p_item )
788 psz_art = input_item_GetArtURL( p_item );
791 if( psz_art )
793 char *psz = make_path( psz_art );
794 free( psz_art );
795 psz_art = psz;
798 if( psz_art == NULL )
800 msg_Dbg( p_intf, "No album art found" );
801 Callback404( &p_args->file, (char**)pp_data, pi_data );
802 return VLC_SUCCESS;
805 FILE *f = vlc_fopen( psz_art, "r" );
806 if( f == NULL )
808 msg_Dbg( p_intf, "Couldn't open album art file %s", psz_art );
809 Callback404( &p_args->file, (char**)pp_data, pi_data );
810 free( psz_art );
811 return VLC_SUCCESS;
813 free( psz_art );
815 char *p_data = NULL;
816 int i_data;
817 FileLoad( f, &p_data, &i_data );
818 fclose( f );
820 char *psz_ext = strrchr( psz_art, '.' );
821 if( psz_ext ) psz_ext++;
823 #define HEADER "Content-Type: image/%s\n" \
824 "Content-Length: %d\n" \
825 "\n"
826 char *psz_header;
827 int i_header_size = asprintf( &psz_header, HEADER, psz_ext, i_data );
828 #undef HEADER
829 if( likely(i_header_size != -1) )
831 *pp_data = malloc( i_header_size + i_data );
832 if( likely(*pp_data != NULL) )
834 *pi_data = i_header_size + i_data;
835 memcpy( *pp_data, psz_header, i_header_size );
836 memcpy( *pp_data+i_header_size, p_data, i_data );
838 free( psz_header );
840 free( p_data );
842 return VLC_SUCCESS;