http.c
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:27k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * http.c : HTTP/HTTPS Remote control interface
  3.  *****************************************************************************
  4.  * Copyright (C) 2001-2006 the VideoLAN team
  5.  *
  6.  * Authors: Gildas Bazin <gbazin@netcourrier.com>
  7.  *          Laurent Aimar <fenrir@via.ecp.fr>
  8.  *          Christophe Massiot <massiot@via.ecp.fr>
  9.  *
  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.
  14.  *
  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.
  19.  *
  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
  27. #include "http.h"
  28. #include <vlc_plugin.h>
  29. #include <vlc_url.h>
  30. #include <assert.h>
  31. /*****************************************************************************
  32.  * Module descriptor
  33.  *****************************************************************************/
  34. static int  Open ( vlc_object_t * );
  35. static void Close( vlc_object_t * );
  36. #define HOST_TEXT N_( "Host address" )
  37. #define HOST_LONGTEXT N_( 
  38.     "Address and port the HTTP interface will listen on. It defaults to " 
  39.     "all network interfaces (0.0.0.0)." 
  40.     " If you want the HTTP interface to be available only on the local " 
  41.     "machine, enter 127.0.0.1" )
  42. #define SRC_TEXT N_( "Source directory" )
  43. #define SRC_LONGTEXT N_( "Source directory" )
  44. #define HANDLERS_TEXT N_( "Handlers" )
  45. #define HANDLERS_LONGTEXT N_( 
  46.         "List of handler extensions and executable paths (for instance: " 
  47.         "php=/usr/bin/php,pl=/usr/bin/perl)." )
  48. #define ART_TEXT N_( "Export album art as /art." )
  49. #define ART_LONGTEXT N_( 
  50.         "Allow exporting album art for current playlist items at the " 
  51.         "/art and /art?id=<id> URLs." )
  52. #define CERT_TEXT N_( "Certificate file" )
  53. #define CERT_LONGTEXT N_( "HTTP interface x509 PEM certificate file " 
  54.                           "(enables SSL)." )
  55. #define KEY_TEXT N_( "Private key file" )
  56. #define KEY_LONGTEXT N_( "HTTP interface x509 PEM private key file." )
  57. #define CA_TEXT N_( "Root CA file" )
  58. #define CA_LONGTEXT N_( "HTTP interface x509 PEM trusted root CA " 
  59.                         "certificates file." )
  60. #define CRL_TEXT N_( "CRL file" )
  61. #define CRL_LONGTEXT N_( "HTTP interace Certificates Revocation List file." )
  62. vlc_module_begin ()
  63.     set_shortname( N_("HTTP"))
  64.     set_description( N_("HTTP remote control interface") )
  65.     set_category( CAT_INTERFACE )
  66.     set_subcategory( SUBCAT_INTERFACE_MAIN )
  67.         add_string ( "http-host", NULL, NULL, HOST_TEXT, HOST_LONGTEXT, true )
  68.         add_string ( "http-src",  NULL, NULL, SRC_TEXT,  SRC_LONGTEXT,  true )
  69.         add_obsolete_string ( "http-charset" )
  70. #if defined( HAVE_FORK ) || defined( WIN32 )
  71.         add_string ( "http-handlers", NULL, NULL, HANDLERS_TEXT, HANDLERS_LONGTEXT, true )
  72. #endif
  73.         add_bool   ( "http-album-art", false, NULL, ART_TEXT, ART_LONGTEXT, true )
  74.         set_section( N_("HTTP SSL" ), 0 )
  75.         add_string ( "http-intf-cert", NULL, NULL, CERT_TEXT, CERT_LONGTEXT, true )
  76.         add_string ( "http-intf-key",  NULL, NULL, KEY_TEXT,  KEY_LONGTEXT,  true )
  77.         add_string ( "http-intf-ca",   NULL, NULL, CA_TEXT,   CA_LONGTEXT,   true )
  78.         add_string ( "http-intf-crl",  NULL, NULL, CRL_TEXT,  CRL_LONGTEXT,  true )
  79.     set_capability( "interface", 0 )
  80.     set_callbacks( Open, Close )
  81. vlc_module_end ()
  82. /*****************************************************************************
  83.  * Local prototypes
  84.  *****************************************************************************/
  85. int  ArtCallback( httpd_handler_sys_t *p_args,
  86.                           httpd_handler_t *p_handler, char *_p_url,
  87.                           uint8_t *_p_request, int i_type,
  88.                           uint8_t *_p_in, int i_in,
  89.                           char *psz_remote_addr, char *psz_remote_host,
  90.                           uint8_t **pp_data, int *pi_data );
  91. /*****************************************************************************
  92.  * Activate: initialize and create stuff
  93.  *****************************************************************************/
  94. static int Open( vlc_object_t *p_this )
  95. {
  96.     intf_thread_t *p_intf = (intf_thread_t*)p_this;
  97.     intf_sys_t    *p_sys;
  98.     char          *psz_address;
  99.     char          *psz_cert = NULL, *psz_key = NULL, *psz_ca = NULL,
  100.                   *psz_crl = NULL;
  101.     int           i_port       = 0;
  102.     char          *psz_src = NULL;
  103.     psz_address = var_CreateGetNonEmptyString( p_intf, "http-host" );
  104.     if( psz_address != NULL )
  105.     {
  106.         char *psz_parser = strrchr( psz_address, ':' );
  107.         if( psz_parser )
  108.         {
  109.             *psz_parser++ = '';
  110.             i_port = atoi( psz_parser );
  111.         }
  112.     }
  113.     else
  114.         psz_address = strdup("");
  115.     p_intf->p_sys = p_sys = malloc( sizeof( intf_sys_t ) );
  116.     if( !p_intf->p_sys )
  117.     {
  118.         free( psz_address );
  119.         return( VLC_ENOMEM );
  120.     }
  121.     p_sys->p_playlist = pl_Hold( p_this );
  122.     p_sys->p_input    = NULL;
  123.     p_sys->p_vlm      = NULL;
  124.     p_sys->psz_address = psz_address;
  125.     p_sys->i_port     = i_port;
  126.     p_sys->p_art_handler = NULL;
  127.     /* determine file handler associations */
  128.     p_sys->i_handlers = 0;
  129.     p_sys->pp_handlers = NULL;
  130. #if defined( HAVE_FORK ) || defined( WIN32 )
  131.     psz_src = config_GetPsz( p_intf, "http-handlers" );
  132.     if( psz_src != NULL && *psz_src )
  133.     {
  134.         char *p = psz_src;
  135.         while( p != NULL )
  136.         {
  137.             http_association_t *p_handler;
  138.             char *psz_ext = p;
  139.             char *psz_program, *psz_options;
  140.             p = strchr( p, '=' );
  141.             if( p == NULL ) break;
  142.             *p++ = '';
  143.             psz_program = p;
  144.             p = strchr( p, ',' );
  145.             if( p != NULL )
  146.                 *p++ = '';
  147.             p_handler = malloc( sizeof( http_association_t ) );
  148.             p_handler->psz_ext = strdup( psz_ext );
  149.             psz_options = FirstWord( psz_program, psz_program );
  150.             p_handler->i_argc = 0;
  151.             p_handler->ppsz_argv = NULL;
  152.             TAB_APPEND( p_handler->i_argc, p_handler->ppsz_argv,
  153.                         strdup( psz_program ) );
  154.             while( psz_options != NULL && *psz_options )
  155.             {
  156.                 char *psz_next = FirstWord( psz_options, psz_options );
  157.                 TAB_APPEND( p_handler->i_argc, p_handler->ppsz_argv,
  158.                             strdup( psz_options ) );
  159.                 psz_options = psz_next;
  160.             }
  161.             /* NULL will be appended later on */
  162.             TAB_APPEND( p_sys->i_handlers, p_sys->pp_handlers, p_handler );
  163.         }
  164.     }
  165.     free( psz_src );
  166. #endif
  167.     /* determine SSL configuration */
  168.     psz_cert = config_GetPsz( p_intf, "http-intf-cert" );
  169.     if ( psz_cert != NULL )
  170.     {
  171.         msg_Dbg( p_intf, "enabling TLS for HTTP interface (cert file: %s)",
  172.                  psz_cert );
  173.         psz_key = var_GetNonEmptyString( p_intf, "http-intf-key" );
  174.         psz_ca = var_GetNonEmptyString( p_intf, "http-intf-ca" );
  175.         psz_crl = var_GetNonEmptyString( p_intf, "http-intf-crl" );
  176.         if( i_port <= 0 )
  177.             i_port = 8443;
  178.     }
  179.     else
  180.     {
  181.         if( i_port <= 0 )
  182.             i_port= 8080;
  183.     }
  184.     msg_Dbg( p_intf, "base %s:%d", psz_address, i_port );
  185.     p_sys->p_httpd_host = httpd_TLSHostNew( VLC_OBJECT(p_intf), psz_address,
  186.                                             i_port, psz_cert, psz_key, psz_ca,
  187.                                             psz_crl );
  188.     free( psz_cert );
  189.     free( psz_key );
  190.     free( psz_ca );
  191.     free( psz_crl );
  192.     if( p_sys->p_httpd_host == NULL )
  193.     {
  194.         msg_Err( p_intf, "cannot listen on %s:%d", psz_address, i_port );
  195.         pl_Release( p_this );
  196.         free( p_sys->psz_address );
  197.         free( p_sys );
  198.         return VLC_EGENERIC;
  199.     }
  200.     else
  201.     {
  202.         char psz_tmp[NI_MAXHOST + 6];
  203.         /* Ugly hack to run several HTTP servers on different ports */
  204.         snprintf( psz_tmp, sizeof (psz_tmp), "%s:%d", psz_address, i_port + 1 );
  205.         var_Create(p_intf->p_libvlc, "http-host", VLC_VAR_STRING );
  206.         var_SetString( p_intf->p_libvlc, "http-host", psz_tmp );
  207.     }
  208.     p_sys->i_files  = 0;
  209.     p_sys->pp_files = NULL;
  210.     psz_src = config_GetPsz( p_intf, "http-src" );
  211.     if( ( psz_src == NULL ) || ( *psz_src == '' ) )
  212.     {
  213.         const char *data_path = config_GetDataDir ();
  214.         if( asprintf( &psz_src, "%s" DIR_SEP "http", data_path ) == -1 )
  215.             psz_src = NULL;
  216.     }
  217.     if( !psz_src || *psz_src == '' )
  218.     {
  219.         msg_Err( p_intf, "invalid web interface source directory" );
  220.         goto failed;
  221.     }
  222.     /* remove trainling  or / */
  223.     if( psz_src[strlen( psz_src ) - 1] == '\' ||
  224.         psz_src[strlen( psz_src ) - 1] == '/' )
  225.     {
  226.         psz_src[strlen( psz_src ) - 1] = '';
  227.     }
  228.     ParseDirectory( p_intf, psz_src, psz_src );
  229.     if( p_sys->i_files <= 0 )
  230.     {
  231.         msg_Err( p_intf, "cannot find any file in directory %s", psz_src );
  232.         goto failed;
  233.     }
  234.     free( psz_src );
  235.     if( config_GetInt( p_intf, "http-album-art" ) )
  236.     {
  237.         /* FIXME: we're leaking h */
  238.         httpd_handler_sys_t *h = malloc( sizeof( httpd_handler_sys_t ) );
  239.         if( !h )
  240.             goto failed;
  241.         h->file.p_intf = p_intf;
  242.         h->file.file = NULL;
  243.         h->file.name = NULL;
  244.         /* TODO: use ACL and login/password stuff here too */
  245.         h->p_handler = httpd_HandlerNew( p_sys->p_httpd_host,
  246.                                          "/art", NULL, NULL, NULL,
  247.                                          ArtCallback, h );
  248.         p_sys->p_art_handler = h->p_handler;
  249.     }
  250.     return VLC_SUCCESS;
  251. failed:
  252.     free( psz_src );
  253.     free( p_sys->pp_files );
  254.     httpd_HostDelete( p_sys->p_httpd_host );
  255.     free( p_sys->psz_address );
  256.     free( p_sys );
  257.     pl_Release( p_this );
  258.     return VLC_EGENERIC;
  259. }
  260. /*****************************************************************************
  261.  * Close: destroy interface
  262.  *****************************************************************************/
  263. static void Close ( vlc_object_t *p_this )
  264. {
  265.     intf_thread_t *p_intf = (intf_thread_t *)p_this;
  266.     intf_sys_t    *p_sys = p_intf->p_sys;
  267.     int i;
  268. #ifdef ENABLE_VLM
  269.     if( p_sys->p_vlm )
  270.         vlm_Delete( p_sys->p_vlm );
  271. #endif
  272.     for( i = 0; i < p_sys->i_files; i++ )
  273.     {
  274.         if( p_sys->pp_files[i]->b_handler )
  275.             httpd_HandlerDelete( ((httpd_handler_sys_t *)p_sys->pp_files[i])->p_handler );
  276.         else
  277.             httpd_FileDelete( p_sys->pp_files[i]->p_file );
  278.         if( p_sys->pp_files[i]->p_redir )
  279.             httpd_RedirectDelete( p_sys->pp_files[i]->p_redir );
  280.         if( p_sys->pp_files[i]->p_redir2 )
  281.             httpd_RedirectDelete( p_sys->pp_files[i]->p_redir2 );
  282.         free( p_sys->pp_files[i]->file );
  283.         free( p_sys->pp_files[i]->name );
  284.         free( p_sys->pp_files[i] );
  285.     }
  286.     free( p_sys->pp_files );
  287.     for( i = 0; i < p_sys->i_handlers; i++ )
  288.     {
  289.         http_association_t *p_handler = p_sys->pp_handlers[i];
  290.         int j;
  291.         free( p_handler->psz_ext );
  292.         for( j = 0; j < p_handler->i_argc; j++ )
  293.             free( p_handler->ppsz_argv[j] );
  294.         if( p_handler->i_argc )
  295.             free( p_handler->ppsz_argv );
  296.         free( p_handler );
  297.     }
  298.     if( p_sys->i_handlers )
  299.         free( p_sys->pp_handlers );
  300.     if( p_sys->p_art_handler )
  301.         httpd_HandlerDelete( p_sys->p_art_handler );
  302.     httpd_HostDelete( p_sys->p_httpd_host );
  303.     free( p_sys->psz_address );
  304.     free( p_sys );
  305.     pl_Release( p_this );
  306. }
  307. /****************************************************************************
  308.  * HttpCallback:
  309.  ****************************************************************************
  310.  * a file with b_html is parsed and all "macro" replaced
  311.  ****************************************************************************/
  312. static void Callback404( httpd_file_sys_t *p_args, char **pp_data,
  313.                          int *pi_data )
  314. {
  315.     char *p = *pp_data = malloc( 10240 );
  316.     if( !p )
  317.     {
  318.         return;
  319.     }
  320.     p += sprintf( p, "Content-Type: text/htmln" );
  321.     p += sprintf( p, "<html xmlns="http://www.w3.org/1999/xhtml">n" );
  322.     p += sprintf( p, "<head>n" );
  323.     p += sprintf( p, "<title>Error loading %s</title>n", p_args->file );
  324.     p += sprintf( p, "</head>n" );
  325.     p += sprintf( p, "<body>n" );
  326.     p += sprintf( p, "<h1><center>Error loading %s for %s</center></h1>n", p_args->file, p_args->name );
  327.     p += sprintf( p, "<a href="http://www.videolan.org/">VideoLAN</a>n" );
  328.     p += sprintf( p, "</body>n" );
  329.     p += sprintf( p, "</html>n" );
  330.     *pi_data = strlen( *pp_data );
  331. }
  332. static void ParseExecute( httpd_file_sys_t *p_args, char *p_buffer,
  333.                           int i_buffer, char *p_request,
  334.                           char **pp_data, int *pi_data )
  335. {
  336.     intf_sys_t *p_sys = p_args->p_intf->p_sys;
  337.     int i_request = p_request != NULL ? strlen( p_request ) : 0;
  338.     char *dst;
  339.     vlc_value_t val;
  340.     char position[4]; /* percentage */
  341.     char time[12]; /* in seconds */
  342.     char length[12]; /* in seconds */
  343.     audio_volume_t i_volume;
  344.     char volume[5];
  345.     const char *state;
  346.     char stats[20];
  347.     assert( p_sys->p_input == NULL );
  348.     /* FIXME: proper locking anyone? */
  349.     p_sys->p_input = playlist_CurrentInput( p_sys->p_playlist );
  350.     if( p_sys->p_input )
  351.     {
  352.         var_Get( p_sys->p_input, "position", &val);
  353.         sprintf( position, "%d" , (int)((val.f_float) * 100.0));
  354.         var_Get( p_sys->p_input, "time", &val);
  355.         sprintf( time, "%"PRIi64, (int64_t)val.i_time / INT64_C(1000000) );
  356.         var_Get( p_sys->p_input, "length", &val);
  357.         sprintf( length, "%"PRIi64, (int64_t)val.i_time / INT64_C(1000000) );
  358.         var_Get( p_sys->p_input, "state", &val );
  359.         if( val.i_int == PLAYING_S )
  360.         {
  361.             state = "playing";
  362.         }
  363.         else if( val.i_int == OPENING_S )
  364.         {
  365.             state = "opening/connecting";
  366.         }
  367.         else if( val.i_int == PAUSE_S )
  368.         {
  369.             state = "paused";
  370.         }
  371.         else
  372.         {
  373.             state = "stop";
  374.         }
  375.     }
  376.     else
  377.     {
  378.         sprintf( position, "%d", 0 );
  379.         sprintf( time, "%d", 0 );
  380.         sprintf( length, "%d", 0 );
  381.         state = "stop";
  382.     }
  383.     aout_VolumeGet( p_args->p_intf, &i_volume );
  384.     sprintf( volume, "%d", (int)i_volume );
  385.     p_args->vars = mvar_New( "variables", "" );
  386.     mvar_AppendNewVar( p_args->vars, "url_param",
  387.                            i_request > 0 ? "1" : "0" );
  388.     mvar_AppendNewVar( p_args->vars, "url_value", p_request );
  389.     mvar_AppendNewVar( p_args->vars, "version", VLC_Version() );
  390.     mvar_AppendNewVar( p_args->vars, "copyright", COPYRIGHT_MESSAGE );
  391.     mvar_AppendNewVar( p_args->vars, "vlc_compile_by", VLC_CompileBy() );
  392.     mvar_AppendNewVar( p_args->vars, "vlc_compile_host",
  393.                            VLC_CompileHost() );
  394.     mvar_AppendNewVar( p_args->vars, "vlc_compile_domain",
  395.                            VLC_CompileDomain() );
  396.     mvar_AppendNewVar( p_args->vars, "vlc_compiler", VLC_Compiler() );
  397.     mvar_AppendNewVar( p_args->vars, "stream_position", position );
  398.     mvar_AppendNewVar( p_args->vars, "stream_time", time );
  399.     mvar_AppendNewVar( p_args->vars, "stream_length", length );
  400.     mvar_AppendNewVar( p_args->vars, "volume", volume );
  401.     mvar_AppendNewVar( p_args->vars, "stream_state", state );
  402.     mvar_AppendNewVar( p_args->vars, "charset", "UTF-8" );
  403.     /* Stats */
  404.     if( p_sys->p_input )
  405.     {
  406.         /* FIXME: Workarround a stupid assert in input_GetItem */
  407.         input_item_t *p_item = p_sys->p_input && p_sys->p_input->p
  408.                                ? input_GetItem( p_sys->p_input )
  409.                                : NULL;
  410.         if( p_item )
  411.         {
  412.             vlc_mutex_lock( &p_item->p_stats->lock );
  413. #define STATS_INT( n ) sprintf( stats, "%d", p_item->p_stats->i_ ## n ); 
  414.                        mvar_AppendNewVar( p_args->vars, #n, stats );
  415. #define STATS_FLOAT( n ) sprintf( stats, "%f", p_item->p_stats->f_ ## n ); 
  416.                        mvar_AppendNewVar( p_args->vars, #n, stats );
  417.             STATS_INT( read_bytes )
  418.             STATS_FLOAT( input_bitrate )
  419.             STATS_INT( demux_read_bytes )
  420.             STATS_FLOAT( demux_bitrate )
  421.             STATS_INT( decoded_video )
  422.             STATS_INT( displayed_pictures )
  423.             STATS_INT( lost_pictures )
  424.             STATS_INT( decoded_audio )
  425.             STATS_INT( played_abuffers )
  426.             STATS_INT( lost_abuffers )
  427.             STATS_INT( sent_packets )
  428.             STATS_INT( sent_bytes )
  429.             STATS_FLOAT( send_bitrate )
  430. #undef STATS_INT
  431. #undef STATS_FLOAT
  432.             vlc_mutex_unlock( &p_item->p_stats->lock );
  433.         }
  434.     }
  435.     SSInit( &p_args->stack );
  436.     /* allocate output */
  437.     *pi_data = i_buffer + 1000;
  438.     dst = *pp_data = malloc( *pi_data );
  439.     /* we parse executing all  <vlc /> macros */
  440.     Execute( p_args, p_request, i_request, pp_data, pi_data, &dst,
  441.                  &p_buffer[0], &p_buffer[i_buffer] );
  442.     *dst     = '';
  443.     *pi_data = dst - *pp_data;
  444.     if( p_sys->p_input != NULL )
  445.     {
  446.         vlc_object_release( p_sys->p_input );
  447.         p_sys->p_input = NULL;
  448.     }
  449.     SSClean( &p_args->stack );
  450.     mvar_Delete( p_args->vars );
  451. }
  452. int  HttpCallback( httpd_file_sys_t *p_args,
  453.                        httpd_file_t *p_file,
  454.                        uint8_t *_p_request,
  455.                        uint8_t **_pp_data, int *pi_data )
  456. {
  457.     VLC_UNUSED(p_file);
  458.     char *p_request = (char *)_p_request;
  459.     char **pp_data = (char **)_pp_data;
  460.     FILE *f;
  461.     if( ( f = utf8_fopen( p_args->file, "r" ) ) == NULL )
  462.     {
  463.         Callback404( p_args, pp_data, pi_data );
  464.         return VLC_SUCCESS;
  465.     }
  466.     if( !p_args->b_html )
  467.     {
  468.         FileLoad( f, pp_data, pi_data );
  469.     }
  470.     else
  471.     {
  472.         int  i_buffer;
  473.         char *p_buffer;
  474.         /* first we load in a temporary buffer */
  475.         FileLoad( f, &p_buffer, &i_buffer );
  476.         ParseExecute( p_args, p_buffer, i_buffer, p_request, pp_data, pi_data );
  477.         free( p_buffer );
  478.     }
  479.     fclose( f );
  480.     return VLC_SUCCESS;
  481. }
  482. /****************************************************************************
  483.  * HandlerCallback:
  484.  ****************************************************************************
  485.  * call the external handler and parse vlc macros if Content-Type is HTML
  486.  ****************************************************************************/
  487. int  HandlerCallback( httpd_handler_sys_t *p_args,
  488.                           httpd_handler_t *p_handler, char *_p_url,
  489.                           uint8_t *_p_request, int i_type,
  490.                           uint8_t *_p_in, int i_in,
  491.                           char *psz_remote_addr, char *psz_remote_host,
  492.                           uint8_t **_pp_data, int *pi_data )
  493. {
  494.     VLC_UNUSED(p_handler); VLC_UNUSED(_p_in);
  495.     char *p_url = (char *)_p_url;
  496.     char *p_request = (char *)_p_request;
  497.     char **pp_data = (char **)_pp_data;
  498.     char *p_in = (char *)_p_in;
  499.     int i_request = p_request != NULL ? strlen( p_request ) : 0;
  500.     char *p;
  501.     int i_env = 0;
  502.     char **ppsz_env = NULL;
  503.     char *psz_tmp;
  504.     size_t i_buffer;
  505.     char *p_buffer;
  506.     char *psz_cwd, *psz_file = NULL;
  507.     int i_ret;
  508.     /* Create environment for the CGI */
  509.     TAB_APPEND( i_env, ppsz_env, strdup("GATEWAY_INTERFACE=CGI/1.1") );
  510.     TAB_APPEND( i_env, ppsz_env, strdup("SERVER_PROTOCOL=HTTP/1.1") );
  511.     TAB_APPEND( i_env, ppsz_env, strdup("SERVER_SOFTWARE=" COPYRIGHT_MESSAGE) );
  512.     switch( i_type )
  513.     {
  514.     case HTTPD_MSG_GET:
  515.         TAB_APPEND( i_env, ppsz_env, strdup("REQUEST_METHOD=GET") );
  516.         break;
  517.     case HTTPD_MSG_POST:
  518.         TAB_APPEND( i_env, ppsz_env, strdup("REQUEST_METHOD=POST") );
  519.         break;
  520.     case HTTPD_MSG_HEAD:
  521.         TAB_APPEND( i_env, ppsz_env, strdup("REQUEST_METHOD=HEAD") );
  522.         break;
  523.     default:
  524.         break;
  525.     }
  526.     if( i_request )
  527.     {
  528.         asprintf( &psz_tmp, "QUERY_STRING=%s", p_request );
  529.         TAB_APPEND( i_env, ppsz_env, psz_tmp );
  530.         asprintf( &psz_tmp, "REQUEST_URI=%s?%s", p_url, p_request );
  531.         TAB_APPEND( i_env, ppsz_env, psz_tmp );
  532.     }
  533.     else
  534.     {
  535.         asprintf( &psz_tmp, "REQUEST_URI=%s", p_url );
  536.         TAB_APPEND( i_env, ppsz_env, psz_tmp );
  537.     }
  538.     asprintf( &psz_tmp, "SCRIPT_NAME=%s", p_url );
  539.     TAB_APPEND( i_env, ppsz_env, psz_tmp );
  540. #define p_sys p_args->file.p_intf->p_sys
  541.     asprintf( &psz_tmp, "SERVER_NAME=%s", p_sys->psz_address );
  542.     TAB_APPEND( i_env, ppsz_env, psz_tmp );
  543.     asprintf( &psz_tmp, "SERVER_PORT=%u", p_sys->i_port );
  544.     TAB_APPEND( i_env, ppsz_env, psz_tmp );
  545. #undef p_sys
  546.     p = getenv( "PATH" );
  547.     if( p != NULL )
  548.     {
  549.         asprintf( &psz_tmp, "PATH=%s", p );
  550.         TAB_APPEND( i_env, ppsz_env, psz_tmp );
  551.     }
  552. #ifdef WIN32
  553.     p = getenv( "windir" );
  554.     if( p != NULL )
  555.     {
  556.         asprintf( &psz_tmp, "SYSTEMROOT=%s", p );
  557.         TAB_APPEND( i_env, ppsz_env, psz_tmp );
  558.     }
  559. #endif
  560.     if( psz_remote_addr != NULL && *psz_remote_addr )
  561.     {
  562.         asprintf( &psz_tmp, "REMOTE_ADDR=%s", psz_remote_addr );
  563.         TAB_APPEND( i_env, ppsz_env, psz_tmp );
  564.     }
  565.     if( psz_remote_host != NULL && *psz_remote_host )
  566.     {
  567.         asprintf( &psz_tmp, "REMOTE_HOST=%s", psz_remote_host );
  568.         TAB_APPEND( i_env, ppsz_env, psz_tmp );
  569.     }
  570.     if( i_in )
  571.     {
  572.         p = p_in;
  573.         for ( ; ; )
  574.         {
  575.             if( !strncasecmp( p, "Content-Type: ", strlen("Content-Type: ") ) )
  576.             {
  577.                 char *end = strchr( p, 'r' );
  578.                 if( end == NULL )
  579.                     break;
  580.                 *end = '';
  581.                 asprintf( &psz_tmp, "CONTENT_TYPE=%s", p );
  582.                 TAB_APPEND( i_env, ppsz_env, psz_tmp );
  583.                 *end = 'r';
  584.             }
  585.             if( !strncasecmp( p, "Content-Length: ",
  586.                               strlen("Content-Length: ") ) )
  587.             {
  588.                 char *end = strchr( p, 'r' );
  589.                 if( end == NULL )
  590.                     break;
  591.                 *end = '';
  592.                 asprintf( &psz_tmp, "CONTENT_LENGTH=%s", p );
  593.                 TAB_APPEND( i_env, ppsz_env, psz_tmp );
  594.                 *end = 'r';
  595.             }
  596.             p = strchr( p, 'n' );
  597.             if( p == NULL || p[1] == 'r' )
  598.             {
  599.                 p = NULL;
  600.                 break;
  601.             }
  602.             p++;
  603.         }
  604.     }
  605.     psz_file = strrchr( p_args->file.file, DIR_SEP_CHAR );
  606.     if( psz_file != NULL )
  607.     {
  608.         psz_file++;
  609.         asprintf( &psz_tmp, "SCRIPT_FILENAME=%s", psz_file );
  610.         TAB_APPEND( i_env, ppsz_env, psz_tmp );
  611.         TAB_APPEND( p_args->p_association->i_argc,
  612.                     p_args->p_association->ppsz_argv, psz_file );
  613.     }
  614.     TAB_APPEND( i_env, ppsz_env, NULL );
  615.     TAB_APPEND( p_args->p_association->i_argc, p_args->p_association->ppsz_argv,
  616.                 NULL );
  617.     psz_tmp = strdup( p_args->file.file );
  618.     p = strrchr( psz_tmp, DIR_SEP_CHAR );
  619.     if( p != NULL )
  620.     {
  621.         *p = '';
  622.         psz_cwd = psz_tmp;
  623.     }
  624.     else
  625.     {
  626.         free( psz_tmp );
  627.         psz_cwd = NULL;
  628.     }
  629.     i_ret = vlc_execve( p_args->file.p_intf, p_args->p_association->i_argc,
  630.                         p_args->p_association->ppsz_argv, ppsz_env, psz_cwd,
  631.                         (char *)p_in, i_in, &p_buffer, &i_buffer );
  632.     TAB_REMOVE( p_args->p_association->i_argc, p_args->p_association->ppsz_argv,
  633.                 NULL );
  634.     TAB_REMOVE( p_args->p_association->i_argc, p_args->p_association->ppsz_argv,
  635.                 psz_file );
  636.     free( psz_cwd );
  637.     while( i_env )
  638.         TAB_REMOVE( i_env, ppsz_env, ppsz_env[0] );
  639.     if( i_ret == -1 )
  640.     {
  641.         Callback404( (httpd_file_sys_t *)p_args, pp_data, pi_data );
  642.         return VLC_SUCCESS;
  643.     }
  644.     p = p_buffer;
  645.     while( strncasecmp( p, "Content-Type: text/html",
  646.                         strlen("Content-Type: text/html") ) )
  647.     {
  648.         p = strchr( p, 'n' );
  649.         if( p == NULL || p[1] == 'r' )
  650.         {
  651.             p = NULL;
  652.             break;
  653.         }
  654.         p++;
  655.     }
  656.     if( p == NULL )
  657.     {
  658.         *pp_data = p_buffer;
  659.         *pi_data = i_buffer;
  660.     }
  661.     else
  662.     {
  663.         ParseExecute( (httpd_file_sys_t *)p_args, p_buffer, i_buffer,
  664.                       p_request, pp_data, pi_data );
  665.         free( p_buffer );
  666.     }
  667.     return VLC_SUCCESS;
  668. }
  669. int  ArtCallback( httpd_handler_sys_t *p_args,
  670.                           httpd_handler_t *p_handler, char *_p_url,
  671.                           uint8_t *p_request, int i_type,
  672.                           uint8_t *p_in, int i_in,
  673.                           char *psz_remote_addr, char *psz_remote_host,
  674.                           uint8_t **pp_data, int *pi_data )
  675. {
  676.     VLC_UNUSED(p_handler); VLC_UNUSED(_p_url); VLC_UNUSED(i_type); 
  677.     VLC_UNUSED(p_in); VLC_UNUSED(i_in); VLC_UNUSED(psz_remote_addr); 
  678.     VLC_UNUSED(psz_remote_host); 
  679.     char *psz_art = NULL;
  680.     intf_thread_t *p_intf = p_args->file.p_intf;
  681.     intf_sys_t *p_sys = p_intf->p_sys;
  682.     char psz_id[16];
  683.     input_item_t *p_item = NULL;
  684.     int i_id;
  685.     psz_id[0] = '';
  686.     if( p_request )
  687.         ExtractURIValue( (char *)p_request, "id", psz_id, 15 );
  688.     i_id = atoi( psz_id );
  689.     if( i_id )
  690.     {
  691.         playlist_Lock( p_sys->p_playlist );
  692.         playlist_item_t *p_pl_item = playlist_ItemGetById( p_sys->p_playlist,
  693.                                                            i_id );
  694.         if( p_pl_item )
  695.             p_item = p_pl_item->p_input;
  696.         playlist_Unlock( p_sys->p_playlist );
  697.     }
  698.     else
  699.     {
  700.         /* FIXME: Workarround a stupid assert in input_GetItem */
  701.         if( p_sys->p_input && p_sys->p_input->p )
  702.             p_item = input_GetItem( p_sys->p_input );
  703.     }
  704.     if( p_item )
  705.     {
  706.         psz_art = input_item_GetArtURL( p_item );
  707.     }
  708.     if( psz_art && !strncmp( psz_art, "file://", strlen( "file://" ) ) &&
  709.         decode_URI( psz_art + 7 ) )
  710.     {
  711.         FILE *f;
  712.         char *psz_ext;
  713.         char *psz_header;
  714.         char *p_data = NULL;
  715.         int i_header_size, i_data;
  716.         if( ( f = utf8_fopen( psz_art + strlen( "file://" ), "r" ) ) == NULL )
  717.         {
  718.             msg_Dbg( p_intf, "Couldn't open album art file %s",
  719.                      psz_art + strlen( "file://" ) );
  720.             Callback404( &p_args->file, (char**)pp_data, pi_data );
  721.             free( psz_art );
  722.             return VLC_SUCCESS;
  723.         }
  724.         FileLoad( f, &p_data, &i_data );
  725.         fclose( f );
  726.         psz_ext = strrchr( psz_art, '.' );
  727.         if( psz_ext ) psz_ext++;
  728. #define HEADER  "Content-Type: image/%sn" 
  729.                 "Content-Length: %dn" 
  730.                 "n"
  731.         i_header_size = asprintf( &psz_header, HEADER, psz_ext, i_data );
  732. #undef HEADER
  733.         *pi_data = i_header_size + i_data;
  734.         *pp_data = (uint8_t*)malloc( *pi_data );
  735.         memcpy( *pp_data, psz_header, i_header_size );
  736.         memcpy( *pp_data+i_header_size, p_data, i_data );
  737.         free( psz_header );
  738.         free( p_data );
  739.     }
  740.     else
  741.     {
  742.         msg_Dbg( p_intf, "No album art found" );
  743.         Callback404( &p_args->file, (char**)pp_data, pi_data );
  744.     }
  745.     free( psz_art );
  746.     return VLC_SUCCESS;
  747. }