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