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

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * http.c: HTTP input module
  3.  *****************************************************************************
  4.  * Copyright (C) 2001-2008 the VideoLAN team
  5.  * $Id: da8d80868270a0b863af8b73fb080a1e76851ba4 $
  6.  *
  7.  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  8.  *          Christophe Massiot <massiot@via.ecp.fr>
  9.  *          Rémi Denis-Courmont <rem # videolan.org>
  10.  *          Antoine Cellerier <dionoea at videolan dot org>
  11.  *
  12.  * This program is free software; you can redistribute it and/or modify
  13.  * it under the terms of the GNU General Public License as published by
  14.  * the Free Software Foundation; either version 2 of the License, or
  15.  * (at your option) any later version.
  16.  *
  17.  * This program is distributed in the hope that it will be useful,
  18.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20.  * GNU General Public License for more details.
  21.  *
  22.  * You should have received a copy of the GNU General Public License
  23.  * along with this program; if not, write to the Free Software
  24.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  25.  *****************************************************************************/
  26. /*****************************************************************************
  27.  * Preamble
  28.  *****************************************************************************/
  29. #ifdef HAVE_CONFIG_H
  30. # include "config.h"
  31. #endif
  32. #include <vlc_common.h>
  33. #include <vlc_plugin.h>
  34. #include <vlc_access.h>
  35. #include <vlc_dialog.h>
  36. #include <vlc_meta.h>
  37. #include <vlc_network.h>
  38. #include <vlc_url.h>
  39. #include <vlc_tls.h>
  40. #include <vlc_strings.h>
  41. #include <vlc_charset.h>
  42. #include <vlc_input.h>
  43. #include <vlc_md5.h>
  44. #ifdef HAVE_ZLIB_H
  45. #   include <zlib.h>
  46. #endif
  47. #include <assert.h>
  48. #ifdef HAVE_LIBPROXY
  49. #    include <proxy.h>
  50. #endif
  51. /*****************************************************************************
  52.  * Module descriptor
  53.  *****************************************************************************/
  54. static int  Open ( vlc_object_t * );
  55. static void Close( vlc_object_t * );
  56. #define PROXY_TEXT N_("HTTP proxy")
  57. #define PROXY_LONGTEXT N_( 
  58.     "HTTP proxy to be used It must be of the form " 
  59.     "http://[user@]myproxy.mydomain:myport/ ; " 
  60.     "if empty, the http_proxy environment variable will be tried." )
  61. #define PROXY_PASS_TEXT N_("HTTP proxy password")
  62. #define PROXY_PASS_LONGTEXT N_( 
  63.     "If your HTTP proxy requires a password, set it here." )
  64. #define CACHING_TEXT N_("Caching value in ms")
  65. #define CACHING_LONGTEXT N_( 
  66.     "Caching value for HTTP streams. This " 
  67.     "value should be set in milliseconds." )
  68. #define AGENT_TEXT N_("HTTP user agent")
  69. #define AGENT_LONGTEXT N_("User agent that will be " 
  70.     "used for the connection.")
  71. #define RECONNECT_TEXT N_("Auto re-connect")
  72. #define RECONNECT_LONGTEXT N_( 
  73.     "Automatically try to reconnect to the stream in case of a sudden " 
  74.     "disconnect." )
  75. #define CONTINUOUS_TEXT N_("Continuous stream")
  76. #define CONTINUOUS_LONGTEXT N_("Read a file that is " 
  77.     "being constantly updated (for example, a JPG file on a server). " 
  78.     "You should not globally enable this option as it will break all other " 
  79.     "types of HTTP streams." )
  80. #define FORWARD_COOKIES_TEXT N_("Forward Cookies")
  81. #define FORWARD_COOKIES_LONGTEXT N_("Forward Cookies across http redirections ")
  82. vlc_module_begin ()
  83.     set_description( N_("HTTP input") )
  84.     set_capability( "access", 0 )
  85.     set_shortname( N_( "HTTP(S)" ) )
  86.     set_category( CAT_INPUT )
  87.     set_subcategory( SUBCAT_INPUT_ACCESS )
  88.     add_string( "http-proxy", NULL, NULL, PROXY_TEXT, PROXY_LONGTEXT,
  89.                 false )
  90.     add_password( "http-proxy-pwd", NULL, NULL,
  91.                   PROXY_PASS_TEXT, PROXY_PASS_LONGTEXT, false )
  92.     add_integer( "http-caching", 4 * DEFAULT_PTS_DELAY / 1000, NULL,
  93.                  CACHING_TEXT, CACHING_LONGTEXT, true )
  94.         change_safe()
  95.     add_string( "http-user-agent", COPYRIGHT_MESSAGE , NULL, AGENT_TEXT,
  96.                 AGENT_LONGTEXT, true )
  97.         change_safe()
  98.     add_bool( "http-reconnect", 0, NULL, RECONNECT_TEXT,
  99.               RECONNECT_LONGTEXT, true )
  100.     add_bool( "http-continuous", 0, NULL, CONTINUOUS_TEXT,
  101.               CONTINUOUS_LONGTEXT, true )
  102.         change_safe()
  103.     add_bool( "http-forward-cookies", true, NULL, FORWARD_COOKIES_TEXT,
  104.               FORWARD_COOKIES_LONGTEXT, true )
  105.     add_obsolete_string("http-user")
  106.     add_obsolete_string("http-pwd")
  107.     add_shortcut( "http" )
  108.     add_shortcut( "https" )
  109.     add_shortcut( "unsv" )
  110.     add_shortcut( "itpc" ) /* iTunes Podcast */
  111.     add_shortcut( "icyx" )
  112.     set_callbacks( Open, Close )
  113. vlc_module_end ()
  114. /*****************************************************************************
  115.  * Local prototypes
  116.  *****************************************************************************/
  117. /* RFC 2617: Basic and Digest Access Authentication */
  118. typedef struct http_auth_t
  119. {
  120.     char *psz_realm;
  121.     char *psz_domain;
  122.     char *psz_nonce;
  123.     char *psz_opaque;
  124.     char *psz_stale;
  125.     char *psz_algorithm;
  126.     char *psz_qop;
  127.     int i_nonce;
  128.     char *psz_cnonce;
  129.     char *psz_HA1; /* stored H(A1) value if algorithm = "MD5-sess" */
  130. } http_auth_t;
  131. struct access_sys_t
  132. {
  133.     int fd;
  134.     tls_session_t *p_tls;
  135.     v_socket_t    *p_vs;
  136.     /* From uri */
  137.     vlc_url_t url;
  138.     char    *psz_user_agent;
  139.     http_auth_t auth;
  140.     /* Proxy */
  141.     bool b_proxy;
  142.     vlc_url_t  proxy;
  143.     http_auth_t proxy_auth;
  144.     char       *psz_proxy_passbuf;
  145.     /* */
  146.     int        i_code;
  147.     const char *psz_protocol;
  148.     int        i_version;
  149.     char       *psz_mime;
  150.     char       *psz_pragma;
  151.     char       *psz_location;
  152.     bool b_mms;
  153.     bool b_icecast;
  154.     bool b_ssl;
  155. #ifdef HAVE_ZLIB_H
  156.     bool b_compressed;
  157.     struct
  158.     {
  159.         z_stream   stream;
  160.         uint8_t   *p_buffer;
  161.     } inflate;
  162. #endif
  163.     bool b_chunked;
  164.     int64_t    i_chunk;
  165.     int        i_icy_meta;
  166.     int64_t    i_icy_offset;
  167.     char       *psz_icy_name;
  168.     char       *psz_icy_genre;
  169.     char       *psz_icy_title;
  170.     int64_t i_remaining;
  171.     bool b_seekable;
  172.     bool b_reconnect;
  173.     bool b_continuous;
  174.     bool b_pace_control;
  175.     bool b_persist;
  176.     vlc_array_t * cookies;
  177. };
  178. /* */
  179. static int OpenWithCookies( vlc_object_t *p_this, const char *psz_access,
  180.                             vlc_array_t *cookies );
  181. /* */
  182. static ssize_t Read( access_t *, uint8_t *, size_t );
  183. static ssize_t ReadCompressed( access_t *, uint8_t *, size_t );
  184. static int Seek( access_t *, int64_t );
  185. static int Control( access_t *, int, va_list );
  186. /* */
  187. static int Connect( access_t *, int64_t );
  188. static int Request( access_t *p_access, int64_t i_tell );
  189. static void Disconnect( access_t * );
  190. /* Small Cookie utilities. Cookies support is partial. */
  191. static char * cookie_get_content( const char * cookie );
  192. static char * cookie_get_domain( const char * cookie );
  193. static char * cookie_get_name( const char * cookie );
  194. static void cookie_append( vlc_array_t * cookies, char * cookie );
  195. static void AuthParseHeader( access_t *p_access, const char *psz_header,
  196.                              http_auth_t *p_auth );
  197. static void AuthReply( access_t *p_acces, const char *psz_prefix,
  198.                        vlc_url_t *p_url, http_auth_t *p_auth );
  199. static int AuthCheckReply( access_t *p_access, const char *psz_header,
  200.                            vlc_url_t *p_url, http_auth_t *p_auth );
  201. static void AuthReset( http_auth_t *p_auth );
  202. /*****************************************************************************
  203.  * Open:
  204.  *****************************************************************************/
  205. static int Open( vlc_object_t *p_this )
  206. {
  207.     access_t *p_access = (access_t*)p_this;
  208.     return OpenWithCookies( p_this, p_access->psz_access, NULL );
  209. }
  210. /**
  211.  * Open the given url using the given cookies
  212.  * @param p_this: the vlc object
  213.  * @psz_access: the acces to use (http, https, ...) (this value must be used
  214.  *              instead of p_access->psz_access)
  215.  * @cookies: the available cookies
  216.  * @return vlc error codes
  217.  */
  218. static int OpenWithCookies( vlc_object_t *p_this, const char *psz_access,
  219.                             vlc_array_t *cookies )
  220. {
  221.     access_t     *p_access = (access_t*)p_this;
  222.     access_sys_t *p_sys;
  223.     char         *psz, *p;
  224.     /* Only forward an store cookies if the corresponding option is activated */
  225.     bool   b_forward_cookies = var_CreateGetBool( p_access, "http-forward-cookies" );
  226.     vlc_array_t * saved_cookies = b_forward_cookies ? (cookies ? cookies : vlc_array_new()) : NULL;
  227.     /* Set up p_access */
  228.     STANDARD_READ_ACCESS_INIT;
  229. #ifdef HAVE_ZLIB_H
  230.     p_access->pf_read = ReadCompressed;
  231. #endif
  232.     p_sys->fd = -1;
  233.     p_sys->b_proxy = false;
  234.     p_sys->psz_proxy_passbuf = NULL;
  235.     p_sys->i_version = 1;
  236.     p_sys->b_seekable = true;
  237.     p_sys->psz_mime = NULL;
  238.     p_sys->psz_pragma = NULL;
  239.     p_sys->b_mms = false;
  240.     p_sys->b_icecast = false;
  241.     p_sys->psz_location = NULL;
  242.     p_sys->psz_user_agent = NULL;
  243.     p_sys->b_pace_control = true;
  244.     p_sys->b_ssl = false;
  245. #ifdef HAVE_ZLIB_H
  246.     p_sys->b_compressed = false;
  247.     /* 15 is the max windowBits, +32 to enable optional gzip decoding */
  248.     if( inflateInit2( &p_sys->inflate.stream, 32+15 ) != Z_OK )
  249.         msg_Warn( p_access, "Error during zlib initialisation: %s",
  250.                   p_sys->inflate.stream.msg );
  251.     if( zlibCompileFlags() & (1<<17) )
  252.         msg_Warn( p_access, "Your zlib was compiled without gzip support." );
  253.     p_sys->inflate.p_buffer = NULL;
  254. #endif
  255.     p_sys->p_tls = NULL;
  256.     p_sys->p_vs = NULL;
  257.     p_sys->i_icy_meta = 0;
  258.     p_sys->i_icy_offset = 0;
  259.     p_sys->psz_icy_name = NULL;
  260.     p_sys->psz_icy_genre = NULL;
  261.     p_sys->psz_icy_title = NULL;
  262.     p_sys->i_remaining = 0;
  263.     p_sys->b_persist = false;
  264.     p_access->info.i_size = -1;
  265.     p_access->info.i_pos  = 0;
  266.     p_access->info.b_eof  = false;
  267.     p_sys->cookies = saved_cookies;
  268.     /* Parse URI - remove spaces */
  269.     p = psz = strdup( p_access->psz_path );
  270.     while( (p = strchr( p, ' ' )) != NULL )
  271.         *p = '+';
  272.     vlc_UrlParse( &p_sys->url, psz, 0 );
  273.     free( psz );
  274.     if( p_sys->url.psz_host == NULL || *p_sys->url.psz_host == '' )
  275.     {
  276.         msg_Warn( p_access, "invalid host" );
  277.         goto error;
  278.     }
  279.     if( !strncmp( psz_access, "https", 5 ) )
  280.     {
  281.         /* HTTP over SSL */
  282.         p_sys->b_ssl = true;
  283.         if( p_sys->url.i_port <= 0 )
  284.             p_sys->url.i_port = 443;
  285.     }
  286.     else
  287.     {
  288.         if( p_sys->url.i_port <= 0 )
  289.             p_sys->url.i_port = 80;
  290.     }
  291.     /* Do user agent */
  292.     p_sys->psz_user_agent = var_CreateGetString( p_access, "http-user-agent" );
  293.     /* Check proxy */
  294.     psz = var_CreateGetNonEmptyString( p_access, "http-proxy" );
  295.     if( psz )
  296.     {
  297.         p_sys->b_proxy = true;
  298.         vlc_UrlParse( &p_sys->proxy, psz, 0 );
  299.         free( psz );
  300.     }
  301. #ifdef HAVE_LIBPROXY
  302.     else
  303.     {
  304.         pxProxyFactory *pf = px_proxy_factory_new();
  305.         if (pf)
  306.         {
  307.             char *buf;
  308.             int i;
  309.             i=asprintf(&buf, "%s://%s", psz_access, p_access->psz_path);
  310.             if (i >= 0)
  311.             {
  312.                 msg_Dbg(p_access, "asking libproxy about url '%s'", buf);
  313.                 char **proxies = px_proxy_factory_get_proxies(pf, buf);
  314.                 if (proxies[0])
  315.                 {
  316.                     msg_Dbg(p_access, "libproxy suggest to use '%s'", proxies[0]);
  317.                     if(strcmp(proxies[0],"direct://") != 0)
  318.                     {
  319.                         p_sys->b_proxy = true;
  320.                         vlc_UrlParse( &p_sys->proxy, proxies[0], 0);
  321.                     }
  322.                 }
  323.                 for(i=0;proxies[i];i++) free(proxies[i]);
  324.                 free(proxies);
  325.                 free(buf);
  326.             }
  327.             px_proxy_factory_free(pf);
  328.         }
  329.         else
  330.         {
  331.             msg_Err(p_access, "Allocating memory for libproxy failed");
  332.         }
  333.     }
  334. #elif HAVE_GETENV
  335.     else
  336.     {
  337.         psz = getenv( "http_proxy" );
  338.         if( psz )
  339.         {
  340.             p_sys->b_proxy = true;
  341.             vlc_UrlParse( &p_sys->proxy, psz, 0 );
  342.         }
  343.     }
  344. #endif
  345.     if( psz ) /* No, this is NOT a use-after-free error */
  346.     {
  347.         psz = var_CreateGetNonEmptyString( p_access, "http-proxy-pwd" );
  348.         if( psz )
  349.             p_sys->proxy.psz_password = p_sys->psz_proxy_passbuf = psz;
  350.     }
  351.     if( p_sys->b_proxy )
  352.     {
  353.         if( p_sys->proxy.psz_host == NULL || *p_sys->proxy.psz_host == '' )
  354.         {
  355.             msg_Warn( p_access, "invalid proxy host" );
  356.             goto error;
  357.         }
  358.         if( p_sys->proxy.i_port <= 0 )
  359.         {
  360.             p_sys->proxy.i_port = 80;
  361.         }
  362.     }
  363.     msg_Dbg( p_access, "http: server='%s' port=%d file='%s",
  364.              p_sys->url.psz_host, p_sys->url.i_port, p_sys->url.psz_path );
  365.     if( p_sys->b_proxy )
  366.     {
  367.         msg_Dbg( p_access, "      proxy %s:%d", p_sys->proxy.psz_host,
  368.                  p_sys->proxy.i_port );
  369.     }
  370.     if( p_sys->url.psz_username && *p_sys->url.psz_username )
  371.     {
  372.         msg_Dbg( p_access, "      user='%s'", p_sys->url.psz_username );
  373.     }
  374.     p_sys->b_reconnect = var_CreateGetBool( p_access, "http-reconnect" );
  375.     p_sys->b_continuous = var_CreateGetBool( p_access, "http-continuous" );
  376. connect:
  377.     /* Connect */
  378.     switch( Connect( p_access, 0 ) )
  379.     {
  380.         case -1:
  381.             goto error;
  382.         case -2:
  383.             /* Retry with http 1.0 */
  384.             msg_Dbg( p_access, "switching to HTTP version 1.0" );
  385.             p_sys->i_version = 0;
  386.             p_sys->b_seekable = false;
  387.             if( !vlc_object_alive (p_access) || Connect( p_access, 0 ) )
  388.                 goto error;
  389. #ifndef NDEBUG
  390.         case 0:
  391.             break;
  392.         default:
  393.             msg_Err( p_access, "You should not be here" );
  394.             abort();
  395. #endif
  396.     }
  397.     if( p_sys->i_code == 401 )
  398.     {
  399.         char *psz_login, *psz_password;
  400.         /* FIXME ? */
  401.         if( p_sys->url.psz_username && p_sys->url.psz_password &&
  402.             p_sys->auth.psz_nonce && p_sys->auth.i_nonce == 0 )
  403.         {
  404.             Disconnect( p_access );
  405.             goto connect;
  406.         }
  407.         msg_Dbg( p_access, "authentication failed for realm %s",
  408.                  p_sys->auth.psz_realm );
  409.         dialog_Login( p_access, &psz_login, &psz_password,
  410.                       _("HTTP authentication"),
  411.              _("Please enter a valid login name and a password for realm %s."),
  412.                       p_sys->auth.psz_realm );
  413.         if( psz_login != NULL && psz_password != NULL )
  414.         {
  415.             msg_Dbg( p_access, "retrying with user=%s", psz_login );
  416.             p_sys->url.psz_username = psz_login;
  417.             p_sys->url.psz_password = psz_password;
  418.             Disconnect( p_access );
  419.             goto connect;
  420.         }
  421.         else
  422.         {
  423.             free( psz_login );
  424.             free( psz_password );
  425.             goto error;
  426.         }
  427.     }
  428.     if( ( p_sys->i_code == 301 || p_sys->i_code == 302 ||
  429.           p_sys->i_code == 303 || p_sys->i_code == 307 ) &&
  430.         p_sys->psz_location && *p_sys->psz_location )
  431.     {
  432.         msg_Dbg( p_access, "redirection to %s", p_sys->psz_location );
  433.         /* Do not accept redirection outside of HTTP works */
  434.         const char *psz_protocol;
  435.         if( !strncmp( p_sys->psz_location, "http:", 5 ) )
  436.             psz_protocol = "http";
  437.         else if( !strncmp( p_sys->psz_location, "https:", 6 ) )
  438.             psz_protocol = "https";
  439.         else
  440.         {
  441.             msg_Err( p_access, "insecure redirection ignored" );
  442.             goto error;
  443.         }
  444.         free( p_access->psz_path );
  445.         p_access->psz_path = strdup( p_sys->psz_location );
  446.         /* Clean up current Open() run */
  447.         vlc_UrlClean( &p_sys->url );
  448.         AuthReset( &p_sys->auth );
  449.         vlc_UrlClean( &p_sys->proxy );
  450.         free( p_sys->psz_proxy_passbuf );
  451.         AuthReset( &p_sys->proxy_auth );
  452.         free( p_sys->psz_mime );
  453.         free( p_sys->psz_pragma );
  454.         free( p_sys->psz_location );
  455.         free( p_sys->psz_user_agent );
  456.         Disconnect( p_access );
  457.         cookies = p_sys->cookies;
  458. #ifdef HAVE_ZLIB_H
  459.         inflateEnd( &p_sys->inflate.stream );
  460. #endif
  461.         free( p_sys );
  462.         /* Do new Open() run with new data */
  463.         return OpenWithCookies( p_this, psz_protocol, cookies );
  464.     }
  465.     if( p_sys->b_mms )
  466.     {
  467.         msg_Dbg( p_access, "this is actually a live mms server, BAIL" );
  468.         goto error;
  469.     }
  470.     if( !strcmp( p_sys->psz_protocol, "ICY" ) || p_sys->b_icecast )
  471.     {
  472.         if( p_sys->psz_mime && strcasecmp( p_sys->psz_mime, "application/ogg" ) )
  473.         {
  474.             if( !strcasecmp( p_sys->psz_mime, "video/nsv" ) ||
  475.                 !strcasecmp( p_sys->psz_mime, "video/nsa" ) )
  476.             {
  477.                 free( p_access->psz_demux );
  478.                 p_access->psz_demux = strdup( "nsv" );
  479.             }
  480.             else if( !strcasecmp( p_sys->psz_mime, "audio/aac" ) ||
  481.                      !strcasecmp( p_sys->psz_mime, "audio/aacp" ) )
  482.             {
  483.                 free( p_access->psz_demux );
  484.                 p_access->psz_demux = strdup( "m4a" );
  485.             }
  486.             else if( !strcasecmp( p_sys->psz_mime, "audio/mpeg" ) )
  487.             {
  488.                 free( p_access->psz_demux );
  489.                 p_access->psz_demux = strdup( "mp3" );
  490.             }
  491.             msg_Info( p_access, "Raw-audio server found, %s demuxer selected",
  492.                       p_access->psz_demux );
  493. #if 0       /* Doesn't work really well because of the pre-buffering in
  494.              * shoutcast servers (the buffer content will be sent as fast as
  495.              * possible). */
  496.             p_sys->b_pace_control = false;
  497. #endif
  498.         }
  499.         else if( !p_sys->psz_mime )
  500.         {
  501.             free( p_access->psz_demux );
  502.             /* Shoutcast */
  503.             p_access->psz_demux = strdup( "mp3" );
  504.         }
  505.         /* else probably Ogg Vorbis */
  506.     }
  507.     else if( !strcasecmp( psz_access, "unsv" ) &&
  508.              p_sys->psz_mime &&
  509.              !strcasecmp( p_sys->psz_mime, "misc/ultravox" ) )
  510.     {
  511.         free( p_access->psz_demux );
  512.         /* Grrrr! detect ultravox server and force NSV demuxer */
  513.         p_access->psz_demux = strdup( "nsv" );
  514.     }
  515.     else if( !strcmp( psz_access, "itpc" ) )
  516.     {
  517.         free( p_access->psz_demux );
  518.         p_access->psz_demux = strdup( "podcast" );
  519.     }
  520.     else if( p_sys->psz_mime &&
  521.              !strncasecmp( p_sys->psz_mime, "application/xspf+xml", 20 ) &&
  522.              ( memchr( " ;t", p_sys->psz_mime[20], 4 ) != NULL ) )
  523.     {
  524.         free( p_access->psz_demux );
  525.         p_access->psz_demux = strdup( "xspf-open" );
  526.     }
  527.     if( p_sys->b_reconnect ) msg_Dbg( p_access, "auto re-connect enabled" );
  528.     /* PTS delay */
  529.     var_Create( p_access, "http-caching", VLC_VAR_INTEGER |VLC_VAR_DOINHERIT );
  530.     return VLC_SUCCESS;
  531. error:
  532.     vlc_UrlClean( &p_sys->url );
  533.     vlc_UrlClean( &p_sys->proxy );
  534.     free( p_sys->psz_proxy_passbuf );
  535.     free( p_sys->psz_mime );
  536.     free( p_sys->psz_pragma );
  537.     free( p_sys->psz_location );
  538.     free( p_sys->psz_user_agent );
  539.     Disconnect( p_access );
  540.     if( p_sys->cookies )
  541.     {
  542.         int i;
  543.         for( i = 0; i < vlc_array_count( p_sys->cookies ); i++ )
  544.             free(vlc_array_item_at_index( p_sys->cookies, i ));
  545.         vlc_array_destroy( p_sys->cookies );
  546.     }
  547. #ifdef HAVE_ZLIB_H
  548.     inflateEnd( &p_sys->inflate.stream );
  549. #endif
  550.     free( p_sys );
  551.     return VLC_EGENERIC;
  552. }
  553. /*****************************************************************************
  554.  * Close:
  555.  *****************************************************************************/
  556. static void Close( vlc_object_t *p_this )
  557. {
  558.     access_t     *p_access = (access_t*)p_this;
  559.     access_sys_t *p_sys = p_access->p_sys;
  560.     vlc_UrlClean( &p_sys->url );
  561.     AuthReset( &p_sys->auth );
  562.     vlc_UrlClean( &p_sys->proxy );
  563.     AuthReset( &p_sys->proxy_auth );
  564.     free( p_sys->psz_mime );
  565.     free( p_sys->psz_pragma );
  566.     free( p_sys->psz_location );
  567.     free( p_sys->psz_icy_name );
  568.     free( p_sys->psz_icy_genre );
  569.     free( p_sys->psz_icy_title );
  570.     free( p_sys->psz_user_agent );
  571.     Disconnect( p_access );
  572.     if( p_sys->cookies )
  573.     {
  574.         int i;
  575.         for( i = 0; i < vlc_array_count( p_sys->cookies ); i++ )
  576.             free(vlc_array_item_at_index( p_sys->cookies, i ));
  577.         vlc_array_destroy( p_sys->cookies );
  578.     }
  579. #ifdef HAVE_ZLIB_H
  580.     inflateEnd( &p_sys->inflate.stream );
  581.     free( p_sys->inflate.p_buffer );
  582. #endif
  583.     free( p_sys );
  584. }
  585. /*****************************************************************************
  586.  * Read: Read up to i_len bytes from the http connection and place in
  587.  * p_buffer. Return the actual number of bytes read
  588.  *****************************************************************************/
  589. static int ReadICYMeta( access_t *p_access );
  590. static ssize_t Read( access_t *p_access, uint8_t *p_buffer, size_t i_len )
  591. {
  592.     access_sys_t *p_sys = p_access->p_sys;
  593.     int i_read;
  594.     if( p_sys->fd == -1 )
  595.     {
  596.         p_access->info.b_eof = true;
  597.         return 0;
  598.     }
  599.     if( p_access->info.i_size >= 0 &&
  600.         i_len + p_access->info.i_pos > p_access->info.i_size )
  601.     {
  602.         if( ( i_len = p_access->info.i_size - p_access->info.i_pos ) == 0 )
  603.         {
  604.             p_access->info.b_eof = true;
  605.             return 0;
  606.         }
  607.     }
  608.     if( p_sys->b_chunked )
  609.     {
  610.         if( p_sys->i_chunk < 0 )
  611.         {
  612.             p_access->info.b_eof = true;
  613.             return 0;
  614.         }
  615.         if( p_sys->i_chunk <= 0 )
  616.         {
  617.             char *psz = net_Gets( VLC_OBJECT(p_access), p_sys->fd, p_sys->p_vs );
  618.             /* read the chunk header */
  619.             if( psz == NULL )
  620.             {
  621.                 /* fatal error - end of file */
  622.                 msg_Dbg( p_access, "failed reading chunk-header line" );
  623.                 return 0;
  624.             }
  625.             p_sys->i_chunk = strtoll( psz, NULL, 16 );
  626.             free( psz );
  627.             if( p_sys->i_chunk <= 0 )   /* eof */
  628.             {
  629.                 p_sys->i_chunk = -1;
  630.                 p_access->info.b_eof = true;
  631.                 return 0;
  632.             }
  633.         }
  634.         if( i_len > p_sys->i_chunk )
  635.         {
  636.             i_len = p_sys->i_chunk;
  637.         }
  638.     }
  639.     else if( p_access->info.i_size != -1 && (int64_t)i_len > p_sys->i_remaining) {
  640.         /* Only ask for the remaining length */
  641.         i_len = (size_t)p_sys->i_remaining;
  642.         if(i_len == 0) {
  643.             p_access->info.b_eof = true;
  644.             return 0;
  645.         }
  646.     }
  647.     if( p_sys->i_icy_meta > 0 && p_access->info.i_pos-p_sys->i_icy_offset > 0 )
  648.     {
  649.         int64_t i_next = p_sys->i_icy_meta -
  650.                                     (p_access->info.i_pos - p_sys->i_icy_offset ) % p_sys->i_icy_meta;
  651.         if( i_next == p_sys->i_icy_meta )
  652.         {
  653.             if( ReadICYMeta( p_access ) )
  654.             {
  655.                 p_access->info.b_eof = true;
  656.                 return -1;
  657.             }
  658.         }
  659.         if( i_len > i_next )
  660.             i_len = i_next;
  661.     }
  662.     i_read = net_Read( p_access, p_sys->fd, p_sys->p_vs, p_buffer, i_len, false );
  663.     if( i_read > 0 )
  664.     {
  665.         p_access->info.i_pos += i_read;
  666.         if( p_sys->b_chunked )
  667.         {
  668.             p_sys->i_chunk -= i_read;
  669.             if( p_sys->i_chunk <= 0 )
  670.             {
  671.                 /* read the empty line */
  672.                 char *psz = net_Gets( VLC_OBJECT(p_access), p_sys->fd, p_sys->p_vs );
  673.                 free( psz );
  674.             }
  675.         }
  676.     }
  677.     else if( i_read <= 0 )
  678.     {
  679.         /*
  680.          * I very much doubt that this will work.
  681.          * If i_read == 0, the connection *IS* dead, so the only
  682.          * sensible thing to do is Disconnect() and then retry.
  683.          * Otherwise, I got recv() completely wrong. -- Courmisch
  684.          */
  685.         if( p_sys->b_continuous )
  686.         {
  687.             Request( p_access, 0 );
  688.             p_sys->b_continuous = false;
  689.             i_read = Read( p_access, p_buffer, i_len );
  690.             p_sys->b_continuous = true;
  691.         }
  692.         Disconnect( p_access );
  693.         if( p_sys->b_reconnect )
  694.         {
  695.             msg_Dbg( p_access, "got disconnected, trying to reconnect" );
  696.             if( Connect( p_access, p_access->info.i_pos ) )
  697.             {
  698.                 msg_Dbg( p_access, "reconnection failed" );
  699.             }
  700.             else
  701.             {
  702.                 p_sys->b_reconnect = false;
  703.                 i_read = Read( p_access, p_buffer, i_len );
  704.                 p_sys->b_reconnect = true;
  705.             }
  706.         }
  707.         if( i_read == 0 )
  708.             p_access->info.b_eof = true;
  709.         else if( i_read < 0 )
  710.             p_access->b_error = true;
  711.     }
  712.     if( p_access->info.i_size != -1 )
  713.     {
  714.         p_sys->i_remaining -= i_read;
  715.     }
  716.     return i_read;
  717. }
  718. static int ReadICYMeta( access_t *p_access )
  719. {
  720.     access_sys_t *p_sys = p_access->p_sys;
  721.     uint8_t buffer;
  722.     char *p, *psz_meta;
  723.     int i_read;
  724.     /* Read meta data length */
  725.     i_read = net_Read( p_access, p_sys->fd, p_sys->p_vs, &buffer, 1,
  726.                        true );
  727.     if( i_read <= 0 )
  728.         return VLC_EGENERIC;
  729.     if( buffer == 0 )
  730.         return VLC_SUCCESS;
  731.     i_read = buffer << 4;
  732.     /* msg_Dbg( p_access, "ICY meta size=%u", i_read); */
  733.     psz_meta = malloc( i_read + 1 );
  734.     if( net_Read( p_access, p_sys->fd, p_sys->p_vs,
  735.                   (uint8_t *)psz_meta, i_read, true ) != i_read )
  736.     {
  737.         free( psz_meta );
  738.         return VLC_EGENERIC;
  739.     }
  740.     psz_meta[i_read] = ''; /* Just in case */
  741.     /* msg_Dbg( p_access, "icy-meta=%s", psz_meta ); */
  742.     /* Now parse the meta */
  743.     /* Look for StreamTitle= */
  744.     p = strcasestr( (char *)psz_meta, "StreamTitle=" );
  745.     if( p )
  746.     {
  747.         p += strlen( "StreamTitle=" );
  748.         if( *p == ''' || *p == '"' )
  749.         {
  750.             char closing[] = { p[0], ';', '' };
  751.             char *psz = strstr( &p[1], closing );
  752.             if( !psz )
  753.                 psz = strchr( &p[1], ';' );
  754.             if( psz ) *psz = '';
  755.         }
  756.         else
  757.         {
  758.             char *psz = strchr( &p[1], ';' );
  759.             if( psz ) *psz = '';
  760.         }
  761.         if( !p_sys->psz_icy_title ||
  762.             strcmp( p_sys->psz_icy_title, &p[1] ) )
  763.         {
  764.             free( p_sys->psz_icy_title );
  765.             char *psz_tmp = strdup( &p[1] );
  766.             p_sys->psz_icy_title = EnsureUTF8( psz_tmp );
  767.             if( !p_sys->psz_icy_title )
  768.                 free( psz_tmp );
  769.             p_access->info.i_update |= INPUT_UPDATE_META;
  770.             msg_Dbg( p_access, "New Title=%s", p_sys->psz_icy_title );
  771.         }
  772.     }
  773.     free( psz_meta );
  774.     return VLC_SUCCESS;
  775. }
  776. #ifdef HAVE_ZLIB_H
  777. static ssize_t ReadCompressed( access_t *p_access, uint8_t *p_buffer,
  778.                                size_t i_len )
  779. {
  780.     access_sys_t *p_sys = p_access->p_sys;
  781.     if( p_sys->b_compressed )
  782.     {
  783.         int i_ret;
  784.         if( !p_sys->inflate.p_buffer )
  785.             p_sys->inflate.p_buffer = malloc( 256 * 1024 );
  786.         if( p_sys->inflate.stream.avail_in == 0 )
  787.         {
  788.             ssize_t i_read = Read( p_access, p_sys->inflate.p_buffer + p_sys->inflate.stream.avail_in, 256 * 1024 );
  789.             if( i_read <= 0 ) return i_read;
  790.             p_sys->inflate.stream.next_in = p_sys->inflate.p_buffer;
  791.             p_sys->inflate.stream.avail_in = i_read;
  792.         }
  793.         p_sys->inflate.stream.avail_out = i_len;
  794.         p_sys->inflate.stream.next_out = p_buffer;
  795.         i_ret = inflate( &p_sys->inflate.stream, Z_SYNC_FLUSH );
  796.         msg_Warn( p_access, "inflate return value: %d, %s", i_ret, p_sys->inflate.stream.msg );
  797.         return i_len - p_sys->inflate.stream.avail_out;
  798.     }
  799.     else
  800.     {
  801.         return Read( p_access, p_buffer, i_len );
  802.     }
  803. }
  804. #endif
  805. /*****************************************************************************
  806.  * Seek: close and re-open a connection at the right place
  807.  *****************************************************************************/
  808. static int Seek( access_t *p_access, int64_t i_pos )
  809. {
  810.     msg_Dbg( p_access, "trying to seek to %"PRId64, i_pos );
  811.     Disconnect( p_access );
  812.     if( p_access->info.i_size
  813.      && (uint64_t)i_pos >= (uint64_t)p_access->info.i_size ) {
  814.         msg_Err( p_access, "seek to far" );
  815.         int retval = Seek( p_access, p_access->info.i_size - 1 );
  816.         if( retval == VLC_SUCCESS ) {
  817.             uint8_t p_buffer[2];
  818.             Read( p_access, p_buffer, 1);
  819.             p_access->info.b_eof  = false;
  820.         }
  821.         return retval;
  822.     }
  823.     if( Connect( p_access, i_pos ) )
  824.     {
  825.         msg_Err( p_access, "seek failed" );
  826.         p_access->info.b_eof = true;
  827.         return VLC_EGENERIC;
  828.     }
  829.     return VLC_SUCCESS;
  830. }
  831. /*****************************************************************************
  832.  * Control:
  833.  *****************************************************************************/
  834. static int Control( access_t *p_access, int i_query, va_list args )
  835. {
  836.     access_sys_t *p_sys = p_access->p_sys;
  837.     bool       *pb_bool;
  838.     int64_t    *pi_64;
  839.     vlc_meta_t *p_meta;
  840.     switch( i_query )
  841.     {
  842.         /* */
  843.         case ACCESS_CAN_SEEK:
  844.             pb_bool = (bool*)va_arg( args, bool* );
  845.             *pb_bool = p_sys->b_seekable;
  846.             break;
  847.         case ACCESS_CAN_FASTSEEK:
  848.             pb_bool = (bool*)va_arg( args, bool* );
  849.             *pb_bool = false;
  850.             break;
  851.         case ACCESS_CAN_PAUSE:
  852.         case ACCESS_CAN_CONTROL_PACE:
  853.             pb_bool = (bool*)va_arg( args, bool* );
  854. #if 0       /* Disable for now until we have a clock synchro algo
  855.              * which works with something else than MPEG over UDP */
  856.             *pb_bool = p_sys->b_pace_control;
  857. #endif
  858.             *pb_bool = true;
  859.             break;
  860.         /* */
  861.         case ACCESS_GET_PTS_DELAY:
  862.             pi_64 = (int64_t*)va_arg( args, int64_t * );
  863.             *pi_64 = (int64_t)var_GetInteger( p_access, "http-caching" ) * 1000;
  864.             break;
  865.         /* */
  866.         case ACCESS_SET_PAUSE_STATE:
  867.             break;
  868.         case ACCESS_GET_META:
  869.             p_meta = (vlc_meta_t*)va_arg( args, vlc_meta_t* );
  870.             if( p_sys->psz_icy_name )
  871.                 vlc_meta_Set( p_meta, vlc_meta_Title, p_sys->psz_icy_name );
  872.             if( p_sys->psz_icy_genre )
  873.                 vlc_meta_Set( p_meta, vlc_meta_Genre, p_sys->psz_icy_genre );
  874.             if( p_sys->psz_icy_title )
  875.                 vlc_meta_Set( p_meta, vlc_meta_NowPlaying, p_sys->psz_icy_title );
  876.             break;
  877.         case ACCESS_GET_CONTENT_TYPE:
  878.             *va_arg( args, char ** ) =
  879.                 p_sys->psz_mime ? strdup( p_sys->psz_mime ) : NULL;
  880.             break;
  881.         case ACCESS_GET_TITLE_INFO:
  882.         case ACCESS_SET_TITLE:
  883.         case ACCESS_SET_SEEKPOINT:
  884.         case ACCESS_SET_PRIVATE_ID_STATE:
  885.             return VLC_EGENERIC;
  886.         default:
  887.             msg_Warn( p_access, "unimplemented query in control" );
  888.             return VLC_EGENERIC;
  889.     }
  890.     return VLC_SUCCESS;
  891. }
  892. /*****************************************************************************
  893.  * Connect:
  894.  *****************************************************************************/
  895. static int Connect( access_t *p_access, int64_t i_tell )
  896. {
  897.     access_sys_t   *p_sys = p_access->p_sys;
  898.     vlc_url_t      srv = p_sys->b_proxy ? p_sys->proxy : p_sys->url;
  899.     /* Clean info */
  900.     free( p_sys->psz_location );
  901.     free( p_sys->psz_mime );
  902.     free( p_sys->psz_pragma );
  903.     free( p_sys->psz_icy_genre );
  904.     free( p_sys->psz_icy_name );
  905.     free( p_sys->psz_icy_title );
  906.     p_sys->psz_location = NULL;
  907.     p_sys->psz_mime = NULL;
  908.     p_sys->psz_pragma = NULL;
  909.     p_sys->b_mms = false;
  910.     p_sys->b_chunked = false;
  911.     p_sys->i_chunk = 0;
  912.     p_sys->i_icy_meta = 0;
  913.     p_sys->i_icy_offset = i_tell;
  914.     p_sys->psz_icy_name = NULL;
  915.     p_sys->psz_icy_genre = NULL;
  916.     p_sys->psz_icy_title = NULL;
  917.     p_sys->i_remaining = 0;
  918.     p_sys->b_persist = false;
  919.     p_access->info.i_size = -1;
  920.     p_access->info.i_pos  = i_tell;
  921.     p_access->info.b_eof  = false;
  922.     /* Open connection */
  923.     assert( p_sys->fd == -1 ); /* No open sockets (leaking fds is BAD) */
  924.     p_sys->fd = net_ConnectTCP( p_access, srv.psz_host, srv.i_port );
  925.     if( p_sys->fd == -1 )
  926.     {
  927.         msg_Err( p_access, "cannot connect to %s:%d", srv.psz_host, srv.i_port );
  928.         return -1;
  929.     }
  930.     setsockopt (p_sys->fd, SOL_SOCKET, SO_KEEPALIVE, &(int){ 1 }, sizeof (int));
  931.     /* Initialize TLS/SSL session */
  932.     if( p_sys->b_ssl == true )
  933.     {
  934.         /* CONNECT to establish TLS tunnel through HTTP proxy */
  935.         if( p_sys->b_proxy )
  936.         {
  937.             char *psz;
  938.             unsigned i_status = 0;
  939.             if( p_sys->i_version == 0 )
  940.             {
  941.                 /* CONNECT is not in HTTP/1.0 */
  942.                 Disconnect( p_access );
  943.                 return -1;
  944.             }
  945.             net_Printf( VLC_OBJECT(p_access), p_sys->fd, NULL,
  946.                         "CONNECT %s:%d HTTP/1.%drnHost: %s:%drnrn",
  947.                         p_sys->url.psz_host, p_sys->url.i_port,
  948.                         p_sys->i_version,
  949.                         p_sys->url.psz_host, p_sys->url.i_port);
  950.             psz = net_Gets( VLC_OBJECT(p_access), p_sys->fd, NULL );
  951.             if( psz == NULL )
  952.             {
  953.                 msg_Err( p_access, "cannot establish HTTP/TLS tunnel" );
  954.                 Disconnect( p_access );
  955.                 return -1;
  956.             }
  957.             sscanf( psz, "HTTP/%*u.%*u %3u", &i_status );
  958.             free( psz );
  959.             if( ( i_status / 100 ) != 2 )
  960.             {
  961.                 msg_Err( p_access, "HTTP/TLS tunnel through proxy denied" );
  962.                 Disconnect( p_access );
  963.                 return -1;
  964.             }
  965.             do
  966.             {
  967.                 psz = net_Gets( VLC_OBJECT(p_access), p_sys->fd, NULL );
  968.                 if( psz == NULL )
  969.                 {
  970.                     msg_Err( p_access, "HTTP proxy connection failed" );
  971.                     Disconnect( p_access );
  972.                     return -1;
  973.                 }
  974.                 if( *psz == '' )
  975.                     i_status = 0;
  976.                 free( psz );
  977.                 if( !vlc_object_alive (p_access) || p_access->b_error )
  978.                 {
  979.                     Disconnect( p_access );
  980.                     return -1;
  981.                 }
  982.             }
  983.             while( i_status );
  984.         }
  985.         /* TLS/SSL handshake */
  986.         p_sys->p_tls = tls_ClientCreate( VLC_OBJECT(p_access), p_sys->fd,
  987.                                          p_sys->url.psz_host );
  988.         if( p_sys->p_tls == NULL )
  989.         {
  990.             msg_Err( p_access, "cannot establish HTTP/TLS session" );
  991.             Disconnect( p_access );
  992.             return -1;
  993.         }
  994.         p_sys->p_vs = &p_sys->p_tls->sock;
  995.     }
  996.     return Request( p_access, i_tell ) ? -2 : 0;
  997. }
  998. static int Request( access_t *p_access, int64_t i_tell )
  999. {
  1000.     access_sys_t   *p_sys = p_access->p_sys;
  1001.     char           *psz ;
  1002.     v_socket_t     *pvs = p_sys->p_vs;
  1003.     p_sys->b_persist = false;
  1004.     p_sys->i_remaining = 0;
  1005.     if( p_sys->b_proxy )
  1006.     {
  1007.         if( p_sys->url.psz_path )
  1008.         {
  1009.             net_Printf( VLC_OBJECT(p_access), p_sys->fd, NULL,
  1010.                         "GET http://%s:%d%s HTTP/1.%drn",
  1011.                         p_sys->url.psz_host, p_sys->url.i_port,
  1012.                         p_sys->url.psz_path, p_sys->i_version );
  1013.         }
  1014.         else
  1015.         {
  1016.             net_Printf( VLC_OBJECT(p_access), p_sys->fd, NULL,
  1017.                         "GET http://%s:%d/ HTTP/1.%drn",
  1018.                         p_sys->url.psz_host, p_sys->url.i_port,
  1019.                         p_sys->i_version );
  1020.         }
  1021.     }
  1022.     else
  1023.     {
  1024.         const char *psz_path = p_sys->url.psz_path;
  1025.         if( !psz_path || !*psz_path )
  1026.         {
  1027.             psz_path = "/";
  1028.         }
  1029.         if( p_sys->url.i_port != (pvs ? 443 : 80) )
  1030.         {
  1031.             net_Printf( VLC_OBJECT(p_access), p_sys->fd, pvs,
  1032.                         "GET %s HTTP/1.%drnHost: %s:%drn",
  1033.                         psz_path, p_sys->i_version, p_sys->url.psz_host,
  1034.                         p_sys->url.i_port );
  1035.         }
  1036.         else
  1037.         {
  1038.             net_Printf( VLC_OBJECT(p_access), p_sys->fd, pvs,
  1039.                         "GET %s HTTP/1.%drnHost: %srn",
  1040.                         psz_path, p_sys->i_version, p_sys->url.psz_host );
  1041.         }
  1042.     }
  1043.     /* User Agent */
  1044.     net_Printf( VLC_OBJECT(p_access), p_sys->fd, pvs, "User-Agent: %srn",
  1045.                 p_sys->psz_user_agent );
  1046.     /* Offset */
  1047.     if( p_sys->i_version == 1 && ! p_sys->b_continuous )
  1048.     {
  1049.         p_sys->b_persist = true;
  1050.         net_Printf( VLC_OBJECT(p_access), p_sys->fd, pvs,
  1051.                     "Range: bytes=%"PRIu64"-rn", i_tell );
  1052.     }
  1053.     /* Cookies */
  1054.     if( p_sys->cookies )
  1055.     {
  1056.         int i;
  1057.         for( i = 0; i < vlc_array_count( p_sys->cookies ); i++ )
  1058.         {
  1059.             const char * cookie = vlc_array_item_at_index( p_sys->cookies, i );
  1060.             char * psz_cookie_content = cookie_get_content( cookie );
  1061.             char * psz_cookie_domain = cookie_get_domain( cookie );
  1062.             assert( psz_cookie_content );
  1063.             /* FIXME: This is clearly not conforming to the rfc */
  1064.             bool is_in_right_domain = (!psz_cookie_domain || strstr( p_sys->url.psz_host, psz_cookie_domain ));
  1065.             if( is_in_right_domain )
  1066.             {
  1067.                 msg_Dbg( p_access, "Sending Cookie %s", psz_cookie_content );
  1068.                 if( net_Printf( VLC_OBJECT(p_access), p_sys->fd, pvs, "Cookie: %srn", psz_cookie_content ) < 0 )
  1069.                     msg_Err( p_access, "failed to send Cookie" );
  1070.             }
  1071.             free( psz_cookie_content );
  1072.             free( psz_cookie_domain );
  1073.         }
  1074.     }
  1075.     /* Authentication */
  1076.     if( p_sys->url.psz_username || p_sys->url.psz_password )
  1077.         AuthReply( p_access, "", &p_sys->url, &p_sys->auth );
  1078.     /* Proxy Authentication */
  1079.     if( p_sys->proxy.psz_username || p_sys->proxy.psz_password )
  1080.         AuthReply( p_access, "Proxy-", &p_sys->proxy, &p_sys->proxy_auth );
  1081.     /* ICY meta data request */
  1082.     net_Printf( VLC_OBJECT(p_access), p_sys->fd, pvs, "Icy-MetaData: 1rn" );
  1083.     if( net_Printf( VLC_OBJECT(p_access), p_sys->fd, pvs, "rn" ) < 0 )
  1084.     {
  1085.         msg_Err( p_access, "failed to send request" );
  1086.         Disconnect( p_access );
  1087.         return VLC_EGENERIC;
  1088.     }
  1089.     /* Read Answer */
  1090.     if( ( psz = net_Gets( VLC_OBJECT(p_access), p_sys->fd, pvs ) ) == NULL )
  1091.     {
  1092.         msg_Err( p_access, "failed to read answer" );
  1093.         goto error;
  1094.     }
  1095.     if( !strncmp( psz, "HTTP/1.", 7 ) )
  1096.     {
  1097.         p_sys->psz_protocol = "HTTP";
  1098.         p_sys->i_code = atoi( &psz[9] );
  1099.     }
  1100.     else if( !strncmp( psz, "ICY", 3 ) )
  1101.     {
  1102.         p_sys->psz_protocol = "ICY";
  1103.         p_sys->i_code = atoi( &psz[4] );
  1104.         p_sys->b_reconnect = true;
  1105.     }
  1106.     else
  1107.     {
  1108.         msg_Err( p_access, "invalid HTTP reply '%s'", psz );
  1109.         free( psz );
  1110.         goto error;
  1111.     }
  1112.     msg_Dbg( p_access, "protocol '%s' answer code %d",
  1113.              p_sys->psz_protocol, p_sys->i_code );
  1114.     if( !strcmp( p_sys->psz_protocol, "ICY" ) )
  1115.     {
  1116.         p_sys->b_seekable = false;
  1117.     }
  1118.     if( p_sys->i_code != 206 && p_sys->i_code != 401 )
  1119.     {
  1120.         p_sys->b_seekable = false;
  1121.     }
  1122.     /* Authentication error - We'll have to display the dialog */
  1123.     if( p_sys->i_code == 401 )
  1124.     {
  1125.     }
  1126.     /* Other fatal error */
  1127.     else if( p_sys->i_code >= 400 )
  1128.     {
  1129.         msg_Err( p_access, "error: %s", psz );
  1130.         free( psz );
  1131.         goto error;
  1132.     }
  1133.     free( psz );
  1134.     for( ;; )
  1135.     {
  1136.         char *psz = net_Gets( VLC_OBJECT(p_access), p_sys->fd, pvs );
  1137.         char *p;
  1138.         if( psz == NULL )
  1139.         {
  1140.             msg_Err( p_access, "failed to read answer" );
  1141.             goto error;
  1142.         }
  1143.         if( !vlc_object_alive (p_access) || p_access->b_error )
  1144.         {
  1145.             free( psz );
  1146.             goto error;
  1147.         }
  1148.         /* msg_Dbg( p_input, "Line=%s", psz ); */
  1149.         if( *psz == '' )
  1150.         {
  1151.             free( psz );
  1152.             break;
  1153.         }
  1154.         if( ( p = strchr( psz, ':' ) ) == NULL )
  1155.         {
  1156.             msg_Err( p_access, "malformed header line: %s", psz );
  1157.             free( psz );
  1158.             goto error;
  1159.         }
  1160.         *p++ = '';
  1161.         while( *p == ' ' ) p++;
  1162.         if( !strcasecmp( psz, "Content-Length" ) )
  1163.         {
  1164.             int64_t i_size = i_tell + (p_sys->i_remaining = atoll( p ));
  1165.             if(i_size > p_access->info.i_size) {
  1166.                 p_access->info.i_size = i_size;
  1167.             }
  1168.             msg_Dbg( p_access, "this frame size=%"PRId64, p_sys->i_remaining );
  1169.         }
  1170.         else if( !strcasecmp( psz, "Content-Range" ) ) {
  1171.             int64_t i_ntell = i_tell;
  1172.             int64_t i_nend = (p_access->info.i_size > 0)?(p_access->info.i_size - 1):i_tell;
  1173.             int64_t i_nsize = p_access->info.i_size;
  1174.             sscanf(p,"bytes %"PRId64"-%"PRId64"/%"PRId64,&i_ntell,&i_nend,&i_nsize);
  1175.             if(i_nend > i_ntell ) {
  1176.                 p_access->info.i_pos = i_ntell;
  1177.                 p_sys->i_remaining = i_nend+1-i_ntell;
  1178.                 int64_t i_size = (i_nsize > i_nend) ? i_nsize : (i_nend + 1);
  1179.                 if(i_size > p_access->info.i_size) {
  1180.                     p_access->info.i_size = i_size;
  1181.                 }
  1182.                 msg_Dbg( p_access, "stream size=%"PRId64",pos=%"PRId64",remaining=%"PRId64,i_nsize,i_ntell,p_sys->i_remaining);
  1183.             }
  1184.         }
  1185.         else if( !strcasecmp( psz, "Connection" ) ) {
  1186.             msg_Dbg( p_access, "Connection: %s",p );
  1187.             int i = -1;
  1188.             sscanf(p, "close%n",&i);
  1189.             if( i >= 0 ) {
  1190.                 p_sys->b_persist = false;
  1191.             }
  1192.         }
  1193.         else if( !strcasecmp( psz, "Location" ) )
  1194.         {
  1195.             char * psz_new_loc;
  1196.             /* This does not follow RFC 2068, but yet if the url is not absolute,
  1197.              * handle it as everyone does. */
  1198.             if( p[0] == '/' )
  1199.             {
  1200.                 const char *psz_http_ext = p_sys->b_ssl ? "s" : "" ;
  1201.                 if( p_sys->url.i_port == ( p_sys->b_ssl ? 443 : 80 ) )
  1202.                 {
  1203.                     if( asprintf(&psz_new_loc, "http%s://%s%s", psz_http_ext,
  1204.                                  p_sys->url.psz_host, p) < 0 )
  1205.                         goto error;
  1206.                 }
  1207.                 else
  1208.                 {
  1209.                     if( asprintf(&psz_new_loc, "http%s://%s:%d%s", psz_http_ext,
  1210.                                  p_sys->url.psz_host, p_sys->url.i_port, p) < 0 )
  1211.                         goto error;
  1212.                 }
  1213.             }
  1214.             else
  1215.             {
  1216.                 psz_new_loc = strdup( p );
  1217.             }
  1218.             free( p_sys->psz_location );
  1219.             p_sys->psz_location = psz_new_loc;
  1220.         }
  1221.         else if( !strcasecmp( psz, "Content-Type" ) )
  1222.         {
  1223.             free( p_sys->psz_mime );
  1224.             p_sys->psz_mime = strdup( p );
  1225.             msg_Dbg( p_access, "Content-Type: %s", p_sys->psz_mime );
  1226.         }
  1227.         else if( !strcasecmp( psz, "Content-Encoding" ) )
  1228.         {
  1229.             msg_Dbg( p_access, "Content-Encoding: %s", p );
  1230.             if( !strcasecmp( p, "identity" ) )
  1231.                 ;
  1232. #ifdef HAVE_ZLIB_H
  1233.             else if( !strcasecmp( p, "gzip" ) || !strcasecmp( p, "deflate" ) )
  1234.                 p_sys->b_compressed = true;
  1235. #endif
  1236.             else
  1237.                 msg_Warn( p_access, "Unknown content coding: %s", p );
  1238.         }
  1239.         else if( !strcasecmp( psz, "Pragma" ) )
  1240.         {
  1241.             if( !strcasecmp( psz, "Pragma: features" ) )
  1242.                 p_sys->b_mms = true;
  1243.             free( p_sys->psz_pragma );
  1244.             p_sys->psz_pragma = strdup( p );
  1245.             msg_Dbg( p_access, "Pragma: %s", p_sys->psz_pragma );
  1246.         }
  1247.         else if( !strcasecmp( psz, "Server" ) )
  1248.         {
  1249.             msg_Dbg( p_access, "Server: %s", p );
  1250.             if( !strncasecmp( p, "Icecast", 7 ) ||
  1251.                 !strncasecmp( p, "Nanocaster", 10 ) )
  1252.             {
  1253.                 /* Remember if this is Icecast
  1254.                  * we need to force demux in this case without breaking
  1255.                  *  autodetection */
  1256.                 /* Let live 365 streams (nanocaster) piggyback on the icecast
  1257.                  * routine. They look very similar */
  1258.                 p_sys->b_reconnect = true;
  1259.                 p_sys->b_pace_control = false;
  1260.                 p_sys->b_icecast = true;
  1261.             }
  1262.         }
  1263.         else if( !strcasecmp( psz, "Transfer-Encoding" ) )
  1264.         {
  1265.             msg_Dbg( p_access, "Transfer-Encoding: %s", p );
  1266.             if( !strncasecmp( p, "chunked", 7 ) )
  1267.             {
  1268.                 p_sys->b_chunked = true;
  1269.             }
  1270.         }
  1271.         else if( !strcasecmp( psz, "Icy-MetaInt" ) )
  1272.         {
  1273.             msg_Dbg( p_access, "Icy-MetaInt: %s", p );
  1274.             p_sys->i_icy_meta = atoi( p );
  1275.             if( p_sys->i_icy_meta < 0 )
  1276.                 p_sys->i_icy_meta = 0;
  1277.             if( p_sys->i_icy_meta > 0 )
  1278.                 p_sys->b_icecast = true;
  1279.             msg_Warn( p_access, "ICY metaint=%d", p_sys->i_icy_meta );
  1280.         }
  1281.         else if( !strcasecmp( psz, "Icy-Name" ) )
  1282.         {
  1283.             free( p_sys->psz_icy_name );
  1284.             char *psz_tmp = strdup( p );
  1285.             p_sys->psz_icy_name = EnsureUTF8( psz_tmp );
  1286.             if( !p_sys->psz_icy_name )
  1287.                 free( psz_tmp );
  1288.             msg_Dbg( p_access, "Icy-Name: %s", p_sys->psz_icy_name );
  1289.             p_sys->b_icecast = true; /* be on the safeside. set it here as well. */
  1290.             p_sys->b_reconnect = true;
  1291.             p_sys->b_pace_control = false;
  1292.         }
  1293.         else if( !strcasecmp( psz, "Icy-Genre" ) )
  1294.         {
  1295.             free( p_sys->psz_icy_genre );
  1296.             char *psz_tmp = strdup( p );
  1297.             p_sys->psz_icy_genre = EnsureUTF8( psz_tmp );
  1298.             if( !p_sys->psz_icy_genre )
  1299.                 free( psz_tmp );
  1300.             msg_Dbg( p_access, "Icy-Genre: %s", p_sys->psz_icy_genre );
  1301.         }
  1302.         else if( !strncasecmp( psz, "Icy-Notice", 10 ) )
  1303.         {
  1304.             msg_Dbg( p_access, "Icy-Notice: %s", p );
  1305.         }
  1306.         else if( !strncasecmp( psz, "icy-", 4 ) ||
  1307.                  !strncasecmp( psz, "ice-", 4 ) ||
  1308.                  !strncasecmp( psz, "x-audiocast", 11 ) )
  1309.         {
  1310.             msg_Dbg( p_access, "Meta-Info: %s: %s", psz, p );
  1311.         }
  1312.         else if( !strcasecmp( psz, "Set-Cookie" ) )
  1313.         {
  1314.             if( p_sys->cookies )
  1315.             {
  1316.                 msg_Dbg( p_access, "Accepting Cookie: %s", p );
  1317.                 cookie_append( p_sys->cookies, strdup(p) );
  1318.             }
  1319.             else
  1320.                 msg_Dbg( p_access, "We have a Cookie we won't remember: %s", p );
  1321.         }
  1322.         else if( !strcasecmp( psz, "www-authenticate" ) )
  1323.         {
  1324.             msg_Dbg( p_access, "Authentication header: %s", p );
  1325.             AuthParseHeader( p_access, p, &p_sys->auth );
  1326.         }
  1327.         else if( !strcasecmp( psz, "proxy-authenticate" ) )
  1328.         {
  1329.             msg_Dbg( p_access, "Proxy authentication header: %s", p );
  1330.             AuthParseHeader( p_access, p, &p_sys->proxy_auth );
  1331.         }
  1332.         else if( !strcasecmp( psz, "authentication-info" ) )
  1333.         {
  1334.             msg_Dbg( p_access, "Authentication Info header: %s", p );
  1335.             if( AuthCheckReply( p_access, p, &p_sys->url, &p_sys->auth ) )
  1336.                 goto error;
  1337.         }
  1338.         else if( !strcasecmp( psz, "proxy-authentication-info" ) )
  1339.         {
  1340.             msg_Dbg( p_access, "Proxy Authentication Info header: %s", p );
  1341.             if( AuthCheckReply( p_access, p, &p_sys->proxy, &p_sys->proxy_auth ) )
  1342.                 goto error;
  1343.         }
  1344.         free( psz );
  1345.     }
  1346.     /* We close the stream for zero length data, unless of course the
  1347.      * server has already promised to do this for us.
  1348.      */
  1349.     if( p_access->info.i_size != -1 && p_sys->i_remaining == 0 && p_sys->b_persist ) {
  1350.         Disconnect( p_access );
  1351.     }
  1352.     return VLC_SUCCESS;
  1353. error:
  1354.     Disconnect( p_access );
  1355.     return VLC_EGENERIC;
  1356. }
  1357. /*****************************************************************************
  1358.  * Disconnect:
  1359.  *****************************************************************************/
  1360. static void Disconnect( access_t *p_access )
  1361. {
  1362.     access_sys_t *p_sys = p_access->p_sys;
  1363.     if( p_sys->p_tls != NULL)
  1364.     {
  1365.         tls_ClientDelete( p_sys->p_tls );
  1366.         p_sys->p_tls = NULL;
  1367.         p_sys->p_vs = NULL;
  1368.     }
  1369.     if( p_sys->fd != -1)
  1370.     {
  1371.         net_Close(p_sys->fd);
  1372.         p_sys->fd = -1;
  1373.     }
  1374. }
  1375. /*****************************************************************************
  1376.  * Cookies (FIXME: we may want to rewrite that using a nice structure to hold
  1377.  * them) (FIXME: only support the "domain=" param)
  1378.  *****************************************************************************/
  1379. /* Get the NAME=VALUE part of the Cookie */
  1380. static char * cookie_get_content( const char * cookie )
  1381. {
  1382.     char * ret = strdup( cookie );
  1383.     if( !ret ) return NULL;
  1384.     char * str = ret;
  1385.     /* Look for a ';' */
  1386.     while( *str && *str != ';' ) str++;
  1387.     /* Replace it by a end-char */
  1388.     if( *str == ';' ) *str = 0;
  1389.     return ret;
  1390. }
  1391. /* Get the domain where the cookie is stored */
  1392. static char * cookie_get_domain( const char * cookie )
  1393. {
  1394.     const char * str = cookie;
  1395.     static const char domain[] = "domain=";
  1396.     if( !str )
  1397.         return NULL;
  1398.     /* Look for a ';' */
  1399.     while( *str )
  1400.     {
  1401.         if( !strncmp( str, domain, sizeof(domain) - 1 /* minus  */ ) )
  1402.         {
  1403.             str += sizeof(domain) - 1 /* minus  */;
  1404.             char * ret = strdup( str );
  1405.             /* Now remove the next ';' if present */
  1406.             char * ret_iter = ret;
  1407.             while( *ret_iter && *ret_iter != ';' ) ret_iter++;
  1408.             if( *ret_iter == ';' )
  1409.                 *ret_iter = 0;
  1410.             return ret;
  1411.         }
  1412.         /* Go to next ';' field */
  1413.         while( *str && *str != ';' ) str++;
  1414.         if( *str == ';' ) str++;
  1415.         /* skip blank */
  1416.         while( *str && *str == ' ' ) str++;
  1417.     }
  1418.     return NULL;
  1419. }
  1420. /* Get NAME in the NAME=VALUE field */
  1421. static char * cookie_get_name( const char * cookie )
  1422. {
  1423.     char * ret = cookie_get_content( cookie ); /* NAME=VALUE */
  1424.     if( !ret ) return NULL;
  1425.     char * str = ret;
  1426.     while( *str && *str != '=' ) str++;
  1427.     *str = 0;
  1428.     return ret;
  1429. }
  1430. /* Add a cookie in cookies, checking to see how it should be added */
  1431. static void cookie_append( vlc_array_t * cookies, char * cookie )
  1432. {
  1433.     int i;
  1434.     if( !cookie )
  1435.         return;
  1436.     char * cookie_name = cookie_get_name( cookie );
  1437.     /* Don't send invalid cookies */
  1438.     if( !cookie_name )
  1439.         return;
  1440.     char * cookie_domain = cookie_get_domain( cookie );
  1441.     for( i = 0; i < vlc_array_count( cookies ); i++ )
  1442.     {
  1443.         char * current_cookie = vlc_array_item_at_index( cookies, i );
  1444.         char * current_cookie_name = cookie_get_name( current_cookie );
  1445.         char * current_cookie_domain = cookie_get_domain( current_cookie );
  1446.         assert( current_cookie_name );
  1447.         bool is_domain_matching = ( cookie_domain && current_cookie_domain &&
  1448.                                          !strcmp( cookie_domain, current_cookie_domain ) );
  1449.         if( is_domain_matching && !strcmp( cookie_name, current_cookie_name )  )
  1450.         {
  1451.             /* Remove previous value for this cookie */
  1452.             free( current_cookie );
  1453.             vlc_array_remove( cookies, i );
  1454.             /* Clean */
  1455.             free( current_cookie_name );
  1456.             free( current_cookie_domain );
  1457.             break;
  1458.         }
  1459.         free( current_cookie_name );
  1460.         free( current_cookie_domain );
  1461.     }
  1462.     free( cookie_name );
  1463.     free( cookie_domain );
  1464.     vlc_array_append( cookies, cookie );
  1465. }
  1466. /*****************************************************************************
  1467.  * "RFC 2617: Basic and Digest Access Authentication" header parsing
  1468.  *****************************************************************************/
  1469. static char *AuthGetParam( const char *psz_header, const char *psz_param )
  1470. {
  1471.     char psz_what[strlen(psz_param)+3];
  1472.     sprintf( psz_what, "%s="", psz_param );
  1473.     psz_header = strstr( psz_header, psz_what );
  1474.     if( psz_header )
  1475.     {
  1476.         const char *psz_end;
  1477.         psz_header += strlen( psz_what );
  1478.         psz_end = strchr( psz_header, '"' );
  1479.         if( !psz_end ) /* Invalid since we should have a closing quote */
  1480.             return strdup( psz_header );
  1481.         return strndup( psz_header, psz_end - psz_header );
  1482.     }
  1483.     else
  1484.     {
  1485.         return NULL;
  1486.     }
  1487. }
  1488. static char *AuthGetParamNoQuotes( const char *psz_header, const char *psz_param )
  1489. {
  1490.     char psz_what[strlen(psz_param)+2];
  1491.     sprintf( psz_what, "%s=", psz_param );
  1492.     psz_header = strstr( psz_header, psz_what );
  1493.     if( psz_header )
  1494.     {
  1495.         const char *psz_end;
  1496.         psz_header += strlen( psz_what );
  1497.         psz_end = strchr( psz_header, ',' );
  1498.         /* XXX: Do we need to filter out trailing space between the value and
  1499.          * the comma/end of line? */
  1500.         if( !psz_end ) /* Can be valid if this is the last parameter */
  1501.             return strdup( psz_header );
  1502.         return strndup( psz_header, psz_end - psz_header );
  1503.     }
  1504.     else
  1505.     {
  1506.         return NULL;
  1507.     }
  1508. }
  1509. static void AuthParseHeader( access_t *p_access, const char *psz_header,
  1510.                              http_auth_t *p_auth )
  1511. {
  1512.     /* FIXME: multiple auth methods can be listed (comma seperated) */
  1513.     /* 2 Basic Authentication Scheme */
  1514.     if( !strncasecmp( psz_header, "Basic ", strlen( "Basic " ) ) )
  1515.     {
  1516.         msg_Dbg( p_access, "Using Basic Authentication" );
  1517.         psz_header += strlen( "Basic " );
  1518.         p_auth->psz_realm = AuthGetParam( psz_header, "realm" );
  1519.         if( !p_auth->psz_realm )
  1520.             msg_Warn( p_access, "Basic Authentication: "
  1521.                       "Mandatory 'realm' parameter is missing" );
  1522.     }
  1523.     /* 3 Digest Access Authentication Scheme */
  1524.     else if( !strncasecmp( psz_header, "Digest ", strlen( "Digest " ) ) )
  1525.     {
  1526.         msg_Dbg( p_access, "Using Digest Access Authentication" );
  1527.         if( p_auth->psz_nonce ) return; /* FIXME */
  1528.         psz_header += strlen( "Digest " );
  1529.         p_auth->psz_realm = AuthGetParam( psz_header, "realm" );
  1530.         p_auth->psz_domain = AuthGetParam( psz_header, "domain" );
  1531.         p_auth->psz_nonce = AuthGetParam( psz_header, "nonce" );
  1532.         p_auth->psz_opaque = AuthGetParam( psz_header, "opaque" );
  1533.         p_auth->psz_stale = AuthGetParamNoQuotes( psz_header, "stale" );
  1534.         p_auth->psz_algorithm = AuthGetParamNoQuotes( psz_header, "algorithm" );
  1535.         p_auth->psz_qop = AuthGetParam( psz_header, "qop" );
  1536.         p_auth->i_nonce = 0;
  1537.         /* printf("realm: |%s|ndomain: |%s|nnonce: |%s|nopaque: |%s|n"
  1538.                   "stale: |%s|nalgorithm: |%s|nqop: |%s|n",
  1539.                   p_auth->psz_realm,p_auth->psz_domain,p_auth->psz_nonce,
  1540.                   p_auth->psz_opaque,p_auth->psz_stale,p_auth->psz_algorithm,
  1541.                   p_auth->psz_qop); */
  1542.         if( !p_auth->psz_realm )
  1543.             msg_Warn( p_access, "Digest Access Authentication: "
  1544.                       "Mandatory 'realm' parameter is missing" );
  1545.         if( !p_auth->psz_nonce )
  1546.             msg_Warn( p_access, "Digest Access Authentication: "
  1547.                       "Mandatory 'nonce' parameter is missing" );
  1548.         if( p_auth->psz_qop ) /* FIXME: parse the qop list */
  1549.         {
  1550.             char *psz_tmp = strchr( p_auth->psz_qop, ',' );
  1551.             if( psz_tmp ) *psz_tmp = '';
  1552.         }
  1553.     }
  1554.     else
  1555.     {
  1556.         const char *psz_end = strchr( psz_header, ' ' );
  1557.         if( psz_end )
  1558.             msg_Warn( p_access, "Unknown authentication scheme: '%*s'",
  1559.                       (int)(psz_end - psz_header), psz_header );
  1560.         else
  1561.             msg_Warn( p_access, "Unknown authentication scheme: '%s'",
  1562.                       psz_header );
  1563.     }
  1564. }
  1565. static char *AuthDigest( access_t *p_access, vlc_url_t *p_url,
  1566.                          http_auth_t *p_auth, const char *psz_method )
  1567. {
  1568.     (void)p_access;
  1569.     const char *psz_username = p_url->psz_username ? p_url->psz_username : "";
  1570.     const char *psz_password = p_url->psz_password ? p_url->psz_password : "";
  1571.     char *psz_HA1 = NULL;
  1572.     char *psz_HA2 = NULL;
  1573.     char *psz_response = NULL;
  1574.     struct md5_s md5;
  1575.     /* H(A1) */
  1576.     if( p_auth->psz_HA1 )
  1577.     {
  1578.         psz_HA1 = strdup( p_auth->psz_HA1 );
  1579.         if( !psz_HA1 ) goto error;
  1580.     }
  1581.     else
  1582.     {
  1583.         InitMD5( &md5 );
  1584.         AddMD5( &md5, psz_username, strlen( psz_username ) );
  1585.         AddMD5( &md5, ":", 1 );
  1586.         AddMD5( &md5, p_auth->psz_realm, strlen( p_auth->psz_realm ) );
  1587.         AddMD5( &md5, ":", 1 );
  1588.         AddMD5( &md5, psz_password, strlen( psz_password ) );
  1589.         EndMD5( &md5 );
  1590.         psz_HA1 = psz_md5_hash( &md5 );
  1591.         if( !psz_HA1 ) goto error;
  1592.         if( p_auth->psz_algorithm
  1593.             && !strcmp( p_auth->psz_algorithm, "MD5-sess" ) )
  1594.         {
  1595.             InitMD5( &md5 );
  1596.             AddMD5( &md5, psz_HA1, 32 );
  1597.             free( psz_HA1 );
  1598.             AddMD5( &md5, ":", 1 );
  1599.             AddMD5( &md5, p_auth->psz_nonce, strlen( p_auth->psz_nonce ) );
  1600.             AddMD5( &md5, ":", 1 );
  1601.             AddMD5( &md5, p_auth->psz_cnonce, strlen( p_auth->psz_cnonce ) );
  1602.             EndMD5( &md5 );
  1603.             psz_HA1 = psz_md5_hash( &md5 );
  1604.             if( !psz_HA1 ) goto error;
  1605.             p_auth->psz_HA1 = strdup( psz_HA1 );
  1606.             if( !p_auth->psz_HA1 ) goto error;
  1607.         }
  1608.     }
  1609.     /* H(A2) */
  1610.     InitMD5( &md5 );
  1611.     if( *psz_method )
  1612.         AddMD5( &md5, psz_method, strlen( psz_method ) );
  1613.     AddMD5( &md5, ":", 1 );
  1614.     if( p_url->psz_path )
  1615.         AddMD5( &md5, p_url->psz_path, strlen( p_url->psz_path ) );
  1616.     else
  1617.         AddMD5( &md5, "/", 1 );
  1618.     if( p_auth->psz_qop && !strcmp( p_auth->psz_qop, "auth-int" ) )
  1619.     {
  1620.         char *psz_ent;
  1621.         struct md5_s ent;
  1622.         InitMD5( &ent );
  1623.         AddMD5( &ent, "", 0 ); /* XXX: entity-body. should be ok for GET */
  1624.         EndMD5( &ent );
  1625.         psz_ent = psz_md5_hash( &ent );
  1626.         if( !psz_ent ) goto error;
  1627.         AddMD5( &md5, ":", 1 );
  1628.         AddMD5( &md5, psz_ent, 32 );
  1629.         free( psz_ent );
  1630.     }
  1631.     EndMD5( &md5 );
  1632.     psz_HA2 = psz_md5_hash( &md5 );
  1633.     if( !psz_HA2 ) goto error;
  1634.     /* Request digest */
  1635.     InitMD5( &md5 );
  1636.     AddMD5( &md5, psz_HA1, 32 );
  1637.     AddMD5( &md5, ":", 1 );
  1638.     AddMD5( &md5, p_auth->psz_nonce, strlen( p_auth->psz_nonce ) );
  1639.     AddMD5( &md5, ":", 1 );
  1640.     if( p_auth->psz_qop
  1641.         && ( !strcmp( p_auth->psz_qop, "auth" )
  1642.              || !strcmp( p_auth->psz_qop, "auth-int" ) ) )
  1643.     {
  1644.         char psz_inonce[9];
  1645.         snprintf( psz_inonce, 9, "%08x", p_auth->i_nonce );
  1646.         AddMD5( &md5, psz_inonce, 8 );
  1647.         AddMD5( &md5, ":", 1 );
  1648.         AddMD5( &md5, p_auth->psz_cnonce, strlen( p_auth->psz_cnonce ) );
  1649.         AddMD5( &md5, ":", 1 );
  1650.         AddMD5( &md5, p_auth->psz_qop, strlen( p_auth->psz_qop ) );
  1651.         AddMD5( &md5, ":", 1 );
  1652.     }
  1653.     AddMD5( &md5, psz_HA2, 32 );
  1654.     EndMD5( &md5 );
  1655.     psz_response = psz_md5_hash( &md5 );
  1656.     error:
  1657.         free( psz_HA1 );
  1658.         free( psz_HA2 );
  1659.         return psz_response;
  1660. }
  1661. static void AuthReply( access_t *p_access, const char *psz_prefix,
  1662.                        vlc_url_t *p_url, http_auth_t *p_auth )
  1663. {
  1664.     access_sys_t *p_sys = p_access->p_sys;
  1665.     v_socket_t     *pvs = p_sys->p_vs;
  1666.     const char *psz_username = p_url->psz_username ? p_url->psz_username : "";
  1667.     const char *psz_password = p_url->psz_password ? p_url->psz_password : "";
  1668.     if( p_auth->psz_nonce )
  1669.     {
  1670.         /* Digest Access Authentication */
  1671.         char *psz_response;
  1672.         if(    p_auth->psz_algorithm
  1673.             && strcmp( p_auth->psz_algorithm, "MD5" )
  1674.             && strcmp( p_auth->psz_algorithm, "MD5-sess" ) )
  1675.         {
  1676.             msg_Err( p_access, "Digest Access Authentication: "
  1677.                      "Unknown algorithm '%s'", p_auth->psz_algorithm );
  1678.             return;
  1679.         }
  1680.         if( p_auth->psz_qop || !p_auth->psz_cnonce )
  1681.         {
  1682.             /* FIXME: needs to be really random to prevent man in the middle
  1683.              * attacks */
  1684.             free( p_auth->psz_cnonce );
  1685.             p_auth->psz_cnonce = strdup( "Some random string FIXME" );
  1686.         }
  1687.         p_auth->i_nonce ++;
  1688.         psz_response = AuthDigest( p_access, p_url, p_auth, "GET" );
  1689.         if( !psz_response ) return;
  1690.         net_Printf( VLC_OBJECT(p_access), p_sys->fd, pvs,
  1691.                     "%sAuthorization: Digest "
  1692.                     /* Mandatory parameters */
  1693.                     "username="%s", "
  1694.                     "realm="%s", "
  1695.                     "nonce="%s", "
  1696.                     "uri="%s", "
  1697.                     "response="%s", "
  1698.                     /* Optional parameters */
  1699.                     "%s%s%s" /* algorithm */
  1700.                     "%s%s%s" /* cnonce */
  1701.                     "%s%s%s" /* opaque */
  1702.                     "%s%s%s" /* message qop */
  1703.                     "%s%08x%s" /* nonce count */
  1704.                     "rn",
  1705.                     /* Mandatory parameters */
  1706.                     psz_prefix,
  1707.                     psz_username,
  1708.                     p_auth->psz_realm,
  1709.                     p_auth->psz_nonce,
  1710.                     p_url->psz_path ? p_url->psz_path : "/",
  1711.                     psz_response,
  1712.                     /* Optional parameters */
  1713.                     p_auth->psz_algorithm ? "algorithm="" : "",
  1714.                     p_auth->psz_algorithm ? p_auth->psz_algorithm : "",
  1715.                     p_auth->psz_algorithm ? "", " : "",
  1716.                     p_auth->psz_cnonce ? "cnonce="" : "",
  1717.                     p_auth->psz_cnonce ? p_auth->psz_cnonce : "",
  1718.                     p_auth->psz_cnonce ? "", " : "",
  1719.                     p_auth->psz_opaque ? "opaque="" : "",
  1720.                     p_auth->psz_opaque ? p_auth->psz_opaque : "",
  1721.                     p_auth->psz_opaque ? "", " : "",
  1722.                     p_auth->psz_qop ? "qop="" : "",
  1723.                     p_auth->psz_qop ? p_auth->psz_qop : "",
  1724.                     p_auth->psz_qop ? "", " : "",
  1725.                     p_auth->i_nonce ? "nc="" : "uglyhack="", /* Will be parsed as an unhandled extension */
  1726.                     p_auth->i_nonce,
  1727.                     p_auth->i_nonce ? """ : """
  1728.                   );
  1729.         free( psz_response );
  1730.     }
  1731.     else
  1732.     {
  1733.         /* Basic Access Authentication */
  1734.         char buf[strlen( psz_username ) + strlen( psz_password ) + 2];
  1735.         char *b64;
  1736.         snprintf( buf, sizeof( buf ), "%s:%s", psz_username, psz_password );
  1737.         b64 = vlc_b64_encode( buf );
  1738.         if( b64 != NULL )
  1739.         {
  1740.              net_Printf( VLC_OBJECT(p_access), p_sys->fd, pvs,
  1741.                          "%sAuthorization: Basic %srn", psz_prefix, b64 );
  1742.              free( b64 );
  1743.         }
  1744.     }
  1745. }
  1746. static int AuthCheckReply( access_t *p_access, const char *psz_header,
  1747.                            vlc_url_t *p_url, http_auth_t *p_auth )
  1748. {
  1749.     int i_ret = VLC_EGENERIC;
  1750.     char *psz_nextnonce = AuthGetParam( psz_header, "nextnonce" );
  1751.     char *psz_qop = AuthGetParamNoQuotes( psz_header, "qop" );
  1752.     char *psz_rspauth = AuthGetParam( psz_header, "rspauth" );
  1753.     char *psz_cnonce = AuthGetParam( psz_header, "cnonce" );
  1754.     char *psz_nc = AuthGetParamNoQuotes( psz_header, "nc" );
  1755.     if( psz_cnonce )
  1756.     {
  1757.         char *psz_digest;
  1758.         if( strcmp( psz_cnonce, p_auth->psz_cnonce ) )
  1759.         {
  1760.             msg_Err( p_access, "HTTP Digest Access Authentication: server replied with a different client nonce value." );
  1761.             goto error;
  1762.         }
  1763.         if( psz_nc )
  1764.         {
  1765.             int i_nonce;
  1766.             i_nonce = strtol( psz_nc, NULL, 16 );
  1767.             if( i_nonce != p_auth->i_nonce )
  1768.             {
  1769.                 msg_Err( p_access, "HTTP Digest Access Authentication: server replied with a different nonce count value." );
  1770.                 goto error;
  1771.             }
  1772.         }
  1773.         if( psz_qop && p_auth->psz_qop && strcmp( psz_qop, p_auth->psz_qop ) )
  1774.             msg_Warn( p_access, "HTTP Digest Access Authentication: server replied using a different 'quality of protection' option" );
  1775.         /* All the clear text values match, let's now check the response
  1776.          * digest */
  1777.         psz_digest = AuthDigest( p_access, p_url, p_auth, "" );
  1778.         if( strcmp( psz_digest, psz_rspauth ) )
  1779.         {
  1780.             msg_Err( p_access, "HTTP Digest Access Authentication: server replied with an invalid response digest (expected value: %s).", psz_digest );
  1781.             free( psz_digest );
  1782.             goto error;
  1783.         }
  1784.         free( psz_digest );
  1785.     }
  1786.     if( psz_nextnonce )
  1787.     {
  1788.         free( p_auth->psz_nonce );
  1789.         p_auth->psz_nonce = psz_nextnonce;
  1790.         psz_nextnonce = NULL;
  1791.     }
  1792.     i_ret = VLC_SUCCESS;
  1793.     error:
  1794.         free( psz_nextnonce );
  1795.         free( psz_qop );
  1796.         free( psz_rspauth );
  1797.         free( psz_cnonce );
  1798.         free( psz_nc );
  1799.     return i_ret;
  1800. }
  1801. static void AuthReset( http_auth_t *p_auth )
  1802. {
  1803.     FREENULL( p_auth->psz_realm );
  1804.     FREENULL( p_auth->psz_domain );
  1805.     FREENULL( p_auth->psz_nonce );
  1806.     FREENULL( p_auth->psz_opaque );
  1807.     FREENULL( p_auth->psz_stale );
  1808.     FREENULL( p_auth->psz_algorithm );
  1809.     FREENULL( p_auth->psz_qop );
  1810.     p_auth->i_nonce = 0;
  1811.     FREENULL( p_auth->psz_cnonce );
  1812.     FREENULL( p_auth->psz_HA1 );
  1813. }