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