]> git.sesse.net Git - vlc/blob - modules/access/http.c
tls: add ALPN parameters
[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 #include "httpcookies.h"
51
52 #ifdef HAVE_ZLIB_H
53 #   include <zlib.h>
54 #endif
55
56 #include <assert.h>
57 #include <limits.h>
58
59 /*****************************************************************************
60  * Module descriptor
61  *****************************************************************************/
62 static int  Open ( vlc_object_t * );
63 static void Close( vlc_object_t * );
64
65 #define PROXY_TEXT N_("HTTP proxy")
66 #define PROXY_LONGTEXT N_( \
67     "HTTP proxy to be used It must be of the form " \
68     "http://[user@]myproxy.mydomain:myport/ ; " \
69     "if empty, the http_proxy environment variable will be tried." )
70
71 #define PROXY_PASS_TEXT N_("HTTP proxy password")
72 #define PROXY_PASS_LONGTEXT N_( \
73     "If your HTTP proxy requires a password, set it here." )
74
75 #define RECONNECT_TEXT N_("Auto re-connect")
76 #define RECONNECT_LONGTEXT N_( \
77     "Automatically try to reconnect to the stream in case of a sudden " \
78     "disconnect." )
79
80 #define CONTINUOUS_TEXT N_("Continuous stream")
81 #define CONTINUOUS_LONGTEXT N_("Read a file that is " \
82     "being constantly updated (for example, a JPG file on a server). " \
83     "You should not globally enable this option as it will break all other " \
84     "types of HTTP streams." )
85
86 #define FORWARD_COOKIES_TEXT N_("Forward Cookies")
87 #define FORWARD_COOKIES_LONGTEXT N_("Forward Cookies across http redirections.")
88
89 #define REFERER_TEXT N_("HTTP referer value")
90 #define REFERER_LONGTEXT N_("Customize the HTTP referer, simulating a previous document")
91
92 #define UA_TEXT N_("User Agent")
93 #define UA_LONGTEXT N_("The name and version of the program will be " \
94     "provided to the HTTP server. They must be separated by a forward " \
95     "slash, e.g. FooBar/1.2.3. This option can only be specified per input " \
96     "item, not globally.")
97
98 vlc_module_begin ()
99     set_description( N_("HTTP input") )
100     set_capability( "access", 0 )
101     set_shortname( N_( "HTTP(S)" ) )
102     set_category( CAT_INPUT )
103     set_subcategory( SUBCAT_INPUT_ACCESS )
104
105     add_string( "http-proxy", NULL, PROXY_TEXT, PROXY_LONGTEXT,
106                 false )
107     add_password( "http-proxy-pwd", NULL,
108                   PROXY_PASS_TEXT, PROXY_PASS_LONGTEXT, false )
109     add_obsolete_bool( "http-use-IE-proxy" )
110     add_string( "http-referrer", NULL, REFERER_TEXT, REFERER_LONGTEXT, false )
111         change_safe()
112     add_string( "http-user-agent", NULL, UA_TEXT, UA_LONGTEXT, false )
113         change_safe()
114         change_private()
115     add_bool( "http-reconnect", false, RECONNECT_TEXT,
116               RECONNECT_LONGTEXT, true )
117     add_bool( "http-continuous", false, CONTINUOUS_TEXT,
118               CONTINUOUS_LONGTEXT, true )
119         change_safe()
120     add_bool( "http-forward-cookies", true, FORWARD_COOKIES_TEXT,
121               FORWARD_COOKIES_LONGTEXT, true )
122     /* 'itpc' = iTunes Podcast */
123     add_shortcut( "http", "https", "unsv", "itpc", "icyx" )
124     set_callbacks( Open, Close )
125 vlc_module_end ()
126
127 /*****************************************************************************
128  * Local prototypes
129  *****************************************************************************/
130
131 struct access_sys_t
132 {
133     int fd;
134     bool b_error;
135     vlc_tls_creds_t *p_creds;
136     vlc_tls_t *p_tls;
137     v_socket_t *p_vs;
138
139     /* From uri */
140     vlc_url_t url;
141     char    *psz_user_agent;
142     char    *psz_referrer;
143     http_auth_t auth;
144
145     /* Proxy */
146     bool b_proxy;
147     vlc_url_t  proxy;
148     http_auth_t proxy_auth;
149     char       *psz_proxy_passbuf;
150
151     /* */
152     int        i_code;
153     const char *psz_protocol;
154     int        i_version;
155
156     char       *psz_mime;
157     char       *psz_pragma;
158     char       *psz_location;
159     bool b_mms;
160     bool b_icecast;
161 #ifdef HAVE_ZLIB_H
162     bool b_compressed;
163     struct
164     {
165         z_stream   stream;
166         uint8_t   *p_buffer;
167     } inflate;
168 #endif
169
170     bool b_chunked;
171     int64_t    i_chunk;
172
173     int        i_icy_meta;
174     uint64_t   i_icy_offset;
175     char       *psz_icy_name;
176     char       *psz_icy_genre;
177     char       *psz_icy_title;
178
179     uint64_t i_remaining;
180     uint64_t size;
181
182     bool b_seekable;
183     bool b_reconnect;
184     bool b_continuous;
185     bool b_pace_control;
186     bool b_persist;
187     bool b_has_size;
188
189     http_cookie_jar_t * cookies;
190 };
191
192 /* */
193 static int OpenWithCookies( vlc_object_t *p_this, const char *psz_access,
194                             unsigned i_redirect, http_cookie_jar_t *cookies );
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
213 /*****************************************************************************
214  * Open:
215  *****************************************************************************/
216 static int Open( vlc_object_t *p_this )
217 {
218     access_t *p_access = (access_t*)p_this;
219     return OpenWithCookies( p_this, p_access->psz_access, 5, NULL );
220 }
221
222 /**
223  * Open the given url using the given cookies
224  * @param p_this: the vlc object
225  * @psz_access: the acces to use (http, https, ...) (this value must be used
226  *              instead of p_access->psz_access)
227  * @i_redirect: number of redirections remaining
228  * @cookies: the available cookies
229  * @return vlc error codes
230  */
231 static int OpenWithCookies( vlc_object_t *p_this, const char *psz_access,
232                             unsigned i_redirect, http_cookie_jar_t *cookies )
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 = (cookies != NULL) ? cookies : http_cookies_new();
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             assert(0);
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         cookies = p_sys->cookies;
514 #ifdef HAVE_ZLIB_H
515         inflateEnd( &p_sys->inflate.stream );
516 #endif
517         free( p_sys );
518
519         /* Do new Open() run with new data */
520         return OpenWithCookies( p_this, psz_protocol, i_redirect - 1,
521                                 cookies );
522     }
523
524     if( p_sys->b_mms )
525     {
526         msg_Dbg( p_access, "this is actually a live mms server, BAIL" );
527         goto error;
528     }
529
530     if( !strcmp( p_sys->psz_protocol, "ICY" ) || p_sys->b_icecast )
531     {
532         if( p_sys->psz_mime && strcasecmp( p_sys->psz_mime, "application/ogg" ) )
533         {
534             if( !strcasecmp( p_sys->psz_mime, "video/nsv" ) ||
535                 !strcasecmp( p_sys->psz_mime, "video/nsa" ) )
536             {
537                 free( p_access->psz_demux );
538                 p_access->psz_demux = strdup( "nsv" );
539             }
540             else if( !strcasecmp( p_sys->psz_mime, "audio/aac" ) ||
541                      !strcasecmp( p_sys->psz_mime, "audio/aacp" ) )
542             {
543                 free( p_access->psz_demux );
544                 p_access->psz_demux = strdup( "m4a" );
545             }
546             else if( !strcasecmp( p_sys->psz_mime, "audio/mpeg" ) )
547             {
548                 free( p_access->psz_demux );
549                 p_access->psz_demux = strdup( "mp3" );
550             }
551
552             msg_Info( p_access, "Raw-audio server found, %s demuxer selected",
553                       p_access->psz_demux );
554
555 #if 0       /* Doesn't work really well because of the pre-buffering in
556              * shoutcast servers (the buffer content will be sent as fast as
557              * possible). */
558             p_sys->b_pace_control = false;
559 #endif
560         }
561         else if( !p_sys->psz_mime )
562         {
563             free( p_access->psz_demux );
564             /* Shoutcast */
565             p_access->psz_demux = strdup( "mp3" );
566         }
567         /* else probably Ogg Vorbis */
568     }
569     else if( !strcasecmp( psz_access, "unsv" ) &&
570              p_sys->psz_mime &&
571              !strcasecmp( p_sys->psz_mime, "misc/ultravox" ) )
572     {
573         free( p_access->psz_demux );
574         /* Grrrr! detect ultravox server and force NSV demuxer */
575         p_access->psz_demux = strdup( "nsv" );
576     }
577     else if( !strcmp( psz_access, "itpc" ) )
578     {
579         free( p_access->psz_demux );
580         p_access->psz_demux = strdup( "podcast" );
581     }
582
583     if( p_sys->b_reconnect ) msg_Dbg( p_access, "auto re-connect enabled" );
584
585     return VLC_SUCCESS;
586
587 error:
588     vlc_UrlClean( &p_sys->url );
589     vlc_UrlClean( &p_sys->proxy );
590     free( p_sys->psz_proxy_passbuf );
591     free( p_sys->psz_mime );
592     free( p_sys->psz_pragma );
593     free( p_sys->psz_location );
594     free( p_sys->psz_user_agent );
595     free( p_sys->psz_referrer );
596
597     Disconnect( p_access );
598     vlc_tls_Delete( p_sys->p_creds );
599
600     http_cookies_destroy( p_sys->cookies );
601
602 #ifdef HAVE_ZLIB_H
603     inflateEnd( &p_sys->inflate.stream );
604 #endif
605     free( p_sys );
606     return VLC_EGENERIC;
607 }
608
609 /*****************************************************************************
610  * Close:
611  *****************************************************************************/
612 static void Close( vlc_object_t *p_this )
613 {
614     access_t     *p_access = (access_t*)p_this;
615     access_sys_t *p_sys = p_access->p_sys;
616
617     vlc_UrlClean( &p_sys->url );
618     http_auth_Reset( &p_sys->auth );
619     vlc_UrlClean( &p_sys->proxy );
620     http_auth_Reset( &p_sys->proxy_auth );
621
622     free( p_sys->psz_mime );
623     free( p_sys->psz_pragma );
624     free( p_sys->psz_location );
625
626     free( p_sys->psz_icy_name );
627     free( p_sys->psz_icy_genre );
628     free( p_sys->psz_icy_title );
629
630     free( p_sys->psz_user_agent );
631     free( p_sys->psz_referrer );
632
633     Disconnect( p_access );
634     vlc_tls_Delete( p_sys->p_creds );
635
636     http_cookies_destroy( p_sys->cookies );
637
638 #ifdef HAVE_ZLIB_H
639     inflateEnd( &p_sys->inflate.stream );
640     free( p_sys->inflate.p_buffer );
641 #endif
642
643     free( p_sys );
644 }
645
646 /* Read data from the socket taking care of chunked transfer if needed */
647 static int ReadData( access_t *p_access, int *pi_read,
648                      uint8_t *p_buffer, size_t i_len )
649 {
650     access_sys_t *p_sys = p_access->p_sys;
651     if( p_sys->b_chunked )
652     {
653         if( p_sys->i_chunk < 0 )
654             return VLC_EGENERIC;
655
656         if( p_sys->i_chunk <= 0 )
657         {
658             char *psz = net_Gets( p_access, p_sys->fd, p_sys->p_vs );
659             /* read the chunk header */
660             if( psz == NULL )
661             {
662                 /* fatal error - end of file */
663                 msg_Dbg( p_access, "failed reading chunk-header line" );
664                 return VLC_EGENERIC;
665             }
666             p_sys->i_chunk = strtoll( psz, NULL, 16 );
667             free( psz );
668
669             if( p_sys->i_chunk <= 0 )   /* eof */
670             {
671                 p_sys->i_chunk = -1;
672                 return VLC_EGENERIC;
673             }
674         }
675
676         if( i_len > p_sys->i_chunk )
677             i_len = p_sys->i_chunk;
678     }
679     *pi_read = net_Read( p_access, p_sys->fd, p_sys->p_vs, p_buffer, i_len, false );
680     if( *pi_read <= 0 )
681         return VLC_SUCCESS;
682
683     if( p_sys->b_chunked )
684     {
685         p_sys->i_chunk -= *pi_read;
686         if( p_sys->i_chunk <= 0 )
687         {
688             /* read the empty line */
689             char *psz = net_Gets( p_access, p_sys->fd, p_sys->p_vs );
690             free( psz );
691         }
692     }
693     return VLC_SUCCESS;
694 }
695
696 /*****************************************************************************
697  * Read: Read up to i_len bytes from the http connection and place in
698  * p_buffer. Return the actual number of bytes read
699  *****************************************************************************/
700 static int ReadICYMeta( access_t *p_access );
701 static ssize_t Read( access_t *p_access, uint8_t *p_buffer, size_t i_len )
702 {
703     access_sys_t *p_sys = p_access->p_sys;
704     int i_read;
705
706     if( p_sys->fd == -1 )
707         goto fatal;
708
709     if( p_sys->b_has_size )
710     {
711         /* Remaining bytes in the file */
712         uint64_t remainder = p_sys->size - p_access->info.i_pos;
713         if( remainder < i_len )
714             i_len = remainder;
715
716         /* Remaining bytes in the response */
717         if( p_sys->i_remaining < i_len )
718             i_len = p_sys->i_remaining;
719     }
720     if( i_len == 0 )
721         goto fatal;
722
723     if( p_sys->i_icy_meta > 0 && p_access->info.i_pos - p_sys->i_icy_offset > 0 )
724     {
725         int64_t i_next = p_sys->i_icy_meta -
726                                     (p_access->info.i_pos - p_sys->i_icy_offset ) % p_sys->i_icy_meta;
727
728         if( i_next == p_sys->i_icy_meta )
729         {
730             if( ReadICYMeta( p_access ) )
731                 goto fatal;
732         }
733         if( i_len > i_next )
734             i_len = i_next;
735     }
736
737     if( ReadData( p_access, &i_read, p_buffer, i_len ) )
738         goto fatal;
739
740     if( i_read <= 0 )
741     {
742         /*
743          * I very much doubt that this will work.
744          * If i_read == 0, the connection *IS* dead, so the only
745          * sensible thing to do is Disconnect() and then retry.
746          * Otherwise, I got recv() completely wrong. -- Courmisch
747          */
748         if( p_sys->b_continuous )
749         {
750             Request( p_access, 0 );
751             p_sys->b_continuous = false;
752             i_read = Read( p_access, p_buffer, i_len );
753             p_sys->b_continuous = true;
754         }
755         Disconnect( p_access );
756         if( p_sys->b_reconnect && vlc_object_alive( p_access ) )
757         {
758             msg_Dbg( p_access, "got disconnected, trying to reconnect" );
759             if( Connect( p_access, p_access->info.i_pos ) )
760             {
761                 msg_Dbg( p_access, "reconnection failed" );
762             }
763             else
764             {
765                 p_sys->b_reconnect = false;
766                 i_read = Read( p_access, p_buffer, i_len );
767                 p_sys->b_reconnect = true;
768
769                 return i_read;
770             }
771         }
772
773         if( i_read <= 0 )
774         {
775             if( i_read < 0 )
776                 p_sys->b_error = true;
777             goto fatal;
778         }
779     }
780
781     assert( i_read >= 0 );
782     p_access->info.i_pos += i_read;
783     if( p_sys->b_has_size )
784     {
785         assert( p_access->info.i_pos <= p_sys->size );
786         assert( (unsigned)i_read <= p_sys->i_remaining );
787         p_sys->i_remaining -= i_read;
788     }
789
790     return i_read;
791
792 fatal:
793     p_access->info.b_eof = true;
794     return 0;
795 }
796
797 static int ReadICYMeta( access_t *p_access )
798 {
799     access_sys_t *p_sys = p_access->p_sys;
800
801     uint8_t buffer;
802     char *p, *psz_meta;
803     int i_read;
804
805     /* Read meta data length */
806     if( ReadData( p_access, &i_read, &buffer, 1 ) )
807         return VLC_EGENERIC;
808     if( i_read != 1 )
809         return VLC_EGENERIC;
810     const int i_size = buffer << 4;
811     /* msg_Dbg( p_access, "ICY meta size=%u", i_size); */
812
813     psz_meta = malloc( i_size + 1 );
814     for( i_read = 0; i_read < i_size; )
815     {
816         int i_tmp;
817         if( ReadData( p_access, &i_tmp, (uint8_t *)&psz_meta[i_read], i_size - i_read ) || i_tmp <= 0 )
818         {
819             free( psz_meta );
820             return VLC_EGENERIC;
821         }
822         i_read += i_tmp;
823     }
824     psz_meta[i_read] = '\0'; /* Just in case */
825
826     /* msg_Dbg( p_access, "icy-meta=%s", psz_meta ); */
827
828     /* Now parse the meta */
829     /* Look for StreamTitle= */
830     p = strcasestr( (char *)psz_meta, "StreamTitle=" );
831     if( p )
832     {
833         p += strlen( "StreamTitle=" );
834         if( *p == '\'' || *p == '"' )
835         {
836             char closing[] = { p[0], ';', '\0' };
837             char *psz = strstr( &p[1], closing );
838             if( !psz )
839                 psz = strchr( &p[1], ';' );
840
841             if( psz ) *psz = '\0';
842         }
843         else
844         {
845             char *psz = strchr( &p[1], ';' );
846             if( psz ) *psz = '\0';
847         }
848
849         if( !p_sys->psz_icy_title ||
850             strcmp( p_sys->psz_icy_title, &p[1] ) )
851         {
852             free( p_sys->psz_icy_title );
853             char *psz_tmp = strdup( &p[1] );
854             p_sys->psz_icy_title = EnsureUTF8( psz_tmp );
855             if( !p_sys->psz_icy_title )
856                 free( psz_tmp );
857
858             msg_Dbg( p_access, "New Icy-Title=%s", p_sys->psz_icy_title );
859             input_thread_t *p_input = access_GetParentInput( p_access );
860             if( p_input )
861             {
862                 input_item_t *p_input_item = input_GetItem( p_access->p_input );
863                 if( p_input_item )
864                     input_item_SetMeta( p_input_item, vlc_meta_NowPlaying, p_sys->psz_icy_title );
865                 vlc_object_release( p_input );
866             }
867         }
868     }
869     free( psz_meta );
870
871     return VLC_SUCCESS;
872 }
873
874 #ifdef HAVE_ZLIB_H
875 static ssize_t ReadCompressed( access_t *p_access, uint8_t *p_buffer,
876                                size_t i_len )
877 {
878     access_sys_t *p_sys = p_access->p_sys;
879
880     if( p_sys->b_compressed )
881     {
882         int i_ret;
883
884         if( !p_sys->inflate.p_buffer )
885             p_sys->inflate.p_buffer = malloc( 256 * 1024 );
886
887         if( p_sys->inflate.stream.avail_in == 0 )
888         {
889             ssize_t i_read = Read( p_access, p_sys->inflate.p_buffer, 256 * 1024 );
890             if( i_read <= 0 ) return i_read;
891             p_sys->inflate.stream.next_in = p_sys->inflate.p_buffer;
892             p_sys->inflate.stream.avail_in = i_read;
893         }
894
895         p_sys->inflate.stream.avail_out = i_len;
896         p_sys->inflate.stream.next_out = p_buffer;
897
898         i_ret = inflate( &p_sys->inflate.stream, Z_SYNC_FLUSH );
899         if ( i_ret != Z_OK && i_ret != Z_STREAM_END )
900             msg_Warn( p_access, "inflate return value: %d, %s", i_ret, p_sys->inflate.stream.msg );
901
902         return i_len - p_sys->inflate.stream.avail_out;
903     }
904     else
905     {
906         return Read( p_access, p_buffer, i_len );
907     }
908 }
909 #endif
910
911 /*****************************************************************************
912  * Seek: close and re-open a connection at the right place
913  *****************************************************************************/
914 static int Seek( access_t *p_access, uint64_t i_pos )
915 {
916     access_sys_t *p_sys = p_access->p_sys;
917
918     msg_Dbg( p_access, "trying to seek to %"PRId64, i_pos );
919     Disconnect( p_access );
920
921     if( p_sys->size && i_pos >= p_sys->size )
922     {
923         msg_Err( p_access, "seek too far" );
924         int retval = Seek( p_access, p_sys->size - 1 );
925         if( retval == VLC_SUCCESS ) {
926             uint8_t p_buffer[2];
927             Read( p_access, p_buffer, 1);
928             p_access->info.b_eof  = false;
929         }
930         return retval;
931     }
932     if( Connect( p_access, i_pos ) )
933     {
934         msg_Err( p_access, "seek failed" );
935         p_access->info.b_eof = true;
936         return VLC_EGENERIC;
937     }
938     return VLC_SUCCESS;
939 }
940
941 /*****************************************************************************
942  * Control:
943  *****************************************************************************/
944 static int Control( access_t *p_access, int i_query, va_list args )
945 {
946     access_sys_t *p_sys = p_access->p_sys;
947     bool       *pb_bool;
948     int64_t    *pi_64;
949
950     switch( i_query )
951     {
952         /* */
953         case ACCESS_CAN_SEEK:
954             pb_bool = (bool*)va_arg( args, bool* );
955             *pb_bool = p_sys->b_seekable;
956             break;
957         case ACCESS_CAN_FASTSEEK:
958             pb_bool = (bool*)va_arg( args, bool* );
959             *pb_bool = false;
960             break;
961         case ACCESS_CAN_PAUSE:
962         case ACCESS_CAN_CONTROL_PACE:
963             pb_bool = (bool*)va_arg( args, bool* );
964
965 #if 0       /* Disable for now until we have a clock synchro algo
966              * which works with something else than MPEG over UDP */
967             *pb_bool = p_sys->b_pace_control;
968 #endif
969             *pb_bool = true;
970             break;
971
972         /* */
973         case ACCESS_GET_PTS_DELAY:
974             pi_64 = (int64_t*)va_arg( args, int64_t * );
975             *pi_64 = INT64_C(1000)
976                 * var_InheritInteger( p_access, "network-caching" );
977             break;
978
979         case ACCESS_GET_SIZE:
980             pi_64 = (int64_t*)va_arg( args, int64_t * );
981             *pi_64 = p_sys->size;
982            break;
983
984         /* */
985         case ACCESS_SET_PAUSE_STATE:
986             break;
987
988         case ACCESS_GET_CONTENT_TYPE:
989             *va_arg( args, char ** ) =
990                 p_sys->psz_mime ? strdup( p_sys->psz_mime ) : NULL;
991             break;
992
993         default:
994             return VLC_EGENERIC;
995
996     }
997     return VLC_SUCCESS;
998 }
999
1000 /*****************************************************************************
1001  * Connect:
1002  *****************************************************************************/
1003 static int Connect( access_t *p_access, uint64_t i_tell )
1004 {
1005     access_sys_t   *p_sys = p_access->p_sys;
1006     vlc_url_t      srv = p_sys->b_proxy ? p_sys->proxy : p_sys->url;
1007
1008     /* Clean info */
1009     free( p_sys->psz_location );
1010     free( p_sys->psz_mime );
1011     free( p_sys->psz_pragma );
1012
1013     free( p_sys->psz_icy_genre );
1014     free( p_sys->psz_icy_name );
1015     free( p_sys->psz_icy_title );
1016
1017
1018     p_sys->psz_location = NULL;
1019     p_sys->psz_mime = NULL;
1020     p_sys->psz_pragma = NULL;
1021     p_sys->b_mms = false;
1022     p_sys->b_chunked = false;
1023     p_sys->i_chunk = 0;
1024     p_sys->i_icy_meta = 0;
1025     p_sys->i_icy_offset = i_tell;
1026     p_sys->psz_icy_name = NULL;
1027     p_sys->psz_icy_genre = NULL;
1028     p_sys->psz_icy_title = NULL;
1029     p_sys->i_remaining = 0;
1030     p_sys->b_persist = false;
1031     p_sys->b_has_size = false;
1032     p_sys->size = 0;
1033     p_access->info.i_pos  = i_tell;
1034     p_access->info.b_eof  = false;
1035
1036     /* Open connection */
1037     assert( p_sys->fd == -1 ); /* No open sockets (leaking fds is BAD) */
1038     p_sys->fd = net_ConnectTCP( p_access, srv.psz_host, srv.i_port );
1039     if( p_sys->fd == -1 )
1040     {
1041         msg_Err( p_access, "cannot connect to %s:%d", srv.psz_host, srv.i_port );
1042         return -1;
1043     }
1044     setsockopt (p_sys->fd, SOL_SOCKET, SO_KEEPALIVE, &(int){ 1 }, sizeof (int));
1045
1046     /* Initialize TLS/SSL session */
1047     if( p_sys->p_creds != NULL )
1048     {
1049         /* CONNECT to establish TLS tunnel through HTTP proxy */
1050         if( p_sys->b_proxy )
1051         {
1052             char *psz;
1053             unsigned i_status = 0;
1054
1055             if( p_sys->i_version == 0 )
1056             {
1057                 /* CONNECT is not in HTTP/1.0 */
1058                 Disconnect( p_access );
1059                 return -1;
1060             }
1061
1062             net_Printf( p_access, p_sys->fd, NULL,
1063                         "CONNECT %s:%d HTTP/1.%d\r\nHost: %s:%d\r\n\r\n",
1064                         p_sys->url.psz_host, p_sys->url.i_port,
1065                         p_sys->i_version,
1066                         p_sys->url.psz_host, p_sys->url.i_port);
1067
1068             psz = net_Gets( p_access, p_sys->fd, NULL );
1069             if( psz == NULL )
1070             {
1071                 msg_Err( p_access, "cannot establish HTTP/TLS tunnel" );
1072                 Disconnect( p_access );
1073                 return -1;
1074             }
1075
1076             sscanf( psz, "HTTP/%*u.%*u %3u", &i_status );
1077             free( psz );
1078
1079             if( ( i_status / 100 ) != 2 )
1080             {
1081                 msg_Err( p_access, "HTTP/TLS tunnel through proxy denied" );
1082                 Disconnect( p_access );
1083                 return -1;
1084             }
1085
1086             do
1087             {
1088                 psz = net_Gets( p_access, p_sys->fd, NULL );
1089                 if( psz == NULL )
1090                 {
1091                     msg_Err( p_access, "HTTP proxy connection failed" );
1092                     Disconnect( p_access );
1093                     return -1;
1094                 }
1095
1096                 if( *psz == '\0' )
1097                     i_status = 0;
1098
1099                 free( psz );
1100
1101                 if( !vlc_object_alive (p_access) || p_sys->b_error )
1102                 {
1103                     Disconnect( p_access );
1104                     return -1;
1105                 }
1106             }
1107             while( i_status );
1108         }
1109
1110         /* TLS/SSL handshake */
1111         p_sys->p_tls = vlc_tls_ClientSessionCreate( p_sys->p_creds, p_sys->fd,
1112                                     p_sys->url.psz_host, "https", NULL, NULL );
1113         if( p_sys->p_tls == NULL )
1114         {
1115             msg_Err( p_access, "cannot establish HTTP/TLS session" );
1116             Disconnect( p_access );
1117             return -1;
1118         }
1119         p_sys->p_vs = &p_sys->p_tls->sock;
1120     }
1121
1122     return Request( p_access, i_tell ) ? -2 : 0;
1123 }
1124
1125
1126 static int Request( access_t *p_access, uint64_t i_tell )
1127 {
1128     access_sys_t   *p_sys = p_access->p_sys;
1129     char           *psz ;
1130     v_socket_t     *pvs = p_sys->p_vs;
1131     p_sys->b_persist = false;
1132
1133     p_sys->i_remaining = 0;
1134
1135     const char *psz_path = p_sys->url.psz_path;
1136     if( !psz_path || !*psz_path )
1137         psz_path = "/";
1138     if( p_sys->b_proxy && pvs == NULL )
1139         net_Printf( p_access, p_sys->fd, NULL,
1140                     "GET http://%s:%d%s HTTP/1.%d\r\n",
1141                     p_sys->url.psz_host, p_sys->url.i_port,
1142                     psz_path, p_sys->i_version );
1143     else
1144         net_Printf( p_access, p_sys->fd, pvs, "GET %s HTTP/1.%d\r\n",
1145                     psz_path, p_sys->i_version );
1146     if( p_sys->url.i_port != (pvs ? 443 : 80) )
1147         net_Printf( p_access, p_sys->fd, pvs, "Host: %s:%d\r\n",
1148                     p_sys->url.psz_host, p_sys->url.i_port );
1149     else
1150         net_Printf( p_access, p_sys->fd, pvs, "Host: %s\r\n",
1151                     p_sys->url.psz_host );
1152     /* User Agent */
1153     net_Printf( p_access, p_sys->fd, pvs, "User-Agent: %s\r\n",
1154                 p_sys->psz_user_agent );
1155     /* Referrer */
1156     if (p_sys->psz_referrer)
1157     {
1158         net_Printf( p_access, p_sys->fd, pvs, "Referer: %s\r\n",
1159                     p_sys->psz_referrer);
1160     }
1161     /* Offset */
1162     if( p_sys->i_version == 1 && ! p_sys->b_continuous )
1163     {
1164         p_sys->b_persist = true;
1165         net_Printf( p_access, p_sys->fd, pvs,
1166                     "Range: bytes=%"PRIu64"-\r\n", i_tell );
1167         net_Printf( p_access, p_sys->fd, pvs, "Connection: close\r\n" );
1168     }
1169
1170     /* Cookies */
1171     if( p_sys->cookies )
1172     {
1173         char * psz_cookiestring = http_cookies_for_url( p_sys->cookies, &p_sys->url );
1174         if ( psz_cookiestring )
1175         {
1176             msg_Dbg( p_access, "Sending Cookie %s", psz_cookiestring );
1177             if( net_Printf( p_access, p_sys->fd, pvs, "Cookie: %s\r\n", psz_cookiestring ) < 0 )
1178                 msg_Err( p_access, "failed to send Cookie" );
1179             free( psz_cookiestring );
1180         }
1181     }
1182
1183     /* Authentication */
1184     if( p_sys->url.psz_username && p_sys->url.psz_password )
1185         AuthReply( p_access, "", &p_sys->url, &p_sys->auth );
1186
1187     /* Proxy Authentication */
1188     if( p_sys->proxy.psz_username && p_sys->proxy.psz_password )
1189         AuthReply( p_access, "Proxy-", &p_sys->proxy, &p_sys->proxy_auth );
1190
1191     /* ICY meta data request */
1192     net_Printf( p_access, p_sys->fd, pvs, "Icy-MetaData: 1\r\n" );
1193
1194
1195     if( net_Printf( p_access, p_sys->fd, pvs, "\r\n" ) < 0 )
1196     {
1197         msg_Err( p_access, "failed to send request" );
1198         Disconnect( p_access );
1199         return VLC_EGENERIC;
1200     }
1201
1202     /* Read Answer */
1203     if( ( psz = net_Gets( p_access, p_sys->fd, pvs ) ) == NULL )
1204     {
1205         msg_Err( p_access, "failed to read answer" );
1206         goto error;
1207     }
1208     if( !strncmp( psz, "HTTP/1.", 7 ) )
1209     {
1210         p_sys->psz_protocol = "HTTP";
1211         p_sys->i_code = atoi( &psz[9] );
1212     }
1213     else if( !strncmp( psz, "ICY", 3 ) )
1214     {
1215         p_sys->psz_protocol = "ICY";
1216         p_sys->i_code = atoi( &psz[4] );
1217         p_sys->b_reconnect = true;
1218     }
1219     else
1220     {
1221         msg_Err( p_access, "invalid HTTP reply '%s'", psz );
1222         free( psz );
1223         goto error;
1224     }
1225     msg_Dbg( p_access, "protocol '%s' answer code %d",
1226              p_sys->psz_protocol, p_sys->i_code );
1227     if( !strcmp( p_sys->psz_protocol, "ICY" ) )
1228     {
1229         p_sys->b_seekable = false;
1230     }
1231     if( p_sys->i_code != 206 && p_sys->i_code != 401 )
1232     {
1233         p_sys->b_seekable = false;
1234     }
1235     /* Authentication error - We'll have to display the dialog */
1236     if( p_sys->i_code == 401 )
1237     {
1238
1239     }
1240     /* Other fatal error */
1241     else if( p_sys->i_code >= 400 )
1242     {
1243         msg_Err( p_access, "error: %s", psz );
1244         free( psz );
1245         goto error;
1246     }
1247     free( psz );
1248
1249     for( ;; )
1250     {
1251         char *psz = net_Gets( p_access, p_sys->fd, pvs );
1252         char *p;
1253         char *p_trailing;
1254
1255         if( psz == NULL )
1256         {
1257             msg_Err( p_access, "failed to read answer" );
1258             goto error;
1259         }
1260
1261         if( !vlc_object_alive (p_access) || p_sys->b_error )
1262         {
1263             free( psz );
1264             goto error;
1265         }
1266
1267         /* msg_Dbg( p_input, "Line=%s", psz ); */
1268         if( *psz == '\0' )
1269         {
1270             free( psz );
1271             break;
1272         }
1273
1274         if( ( p = strchr( psz, ':' ) ) == NULL )
1275         {
1276             msg_Err( p_access, "malformed header line: %s", psz );
1277             free( psz );
1278             goto error;
1279         }
1280         *p++ = '\0';
1281         p += strspn( p, " \t" );
1282
1283         /* trim trailing white space */
1284         p_trailing = p + strlen( p );
1285         if( p_trailing > p )
1286         {
1287             p_trailing--;
1288             while( ( *p_trailing == ' ' || *p_trailing == '\t' ) && p_trailing > p )
1289             {
1290                 *p_trailing = '\0';
1291                 p_trailing--;
1292             }
1293         }
1294
1295         if( !strcasecmp( psz, "Content-Length" ) )
1296         {
1297             uint64_t i_size = i_tell + (p_sys->i_remaining = (uint64_t)atoll( p ));
1298             if(i_size > p_sys->size) {
1299                 p_sys->b_has_size = true;
1300                 p_sys->size = i_size;
1301             }
1302             msg_Dbg( p_access, "this frame size=%"PRIu64, p_sys->i_remaining );
1303         }
1304         else if( !strcasecmp( psz, "Content-Range" ) ) {
1305             uint64_t i_ntell = i_tell;
1306             uint64_t i_nend = (p_sys->size > 0) ? (p_sys->size - 1) : i_tell;
1307             uint64_t i_nsize = p_sys->size;
1308             sscanf(p,"bytes %"SCNu64"-%"SCNu64"/%"SCNu64,&i_ntell,&i_nend,&i_nsize);
1309             if(i_nend > i_ntell ) {
1310                 p_access->info.i_pos = i_ntell;
1311                 p_sys->i_icy_offset  = i_ntell;
1312                 p_sys->i_remaining = i_nend+1-i_ntell;
1313                 uint64_t i_size = (i_nsize > i_nend) ? i_nsize : (i_nend + 1);
1314                 if(i_size > p_sys->size) {
1315                     p_sys->b_has_size = true;
1316                     p_sys->size = i_size;
1317                 }
1318                 msg_Dbg( p_access, "stream size=%"PRIu64",pos=%"PRIu64",remaining=%"PRIu64,
1319                          i_nsize, i_ntell, p_sys->i_remaining);
1320             }
1321         }
1322         else if( !strcasecmp( psz, "Connection" ) ) {
1323             msg_Dbg( p_access, "Connection: %s",p );
1324             int i = -1;
1325             sscanf(p, "close%n",&i);
1326             if( i >= 0 ) {
1327                 p_sys->b_persist = false;
1328             }
1329         }
1330         else if( !strcasecmp( psz, "Location" ) )
1331         {
1332             char * psz_new_loc;
1333
1334             /* This does not follow RFC 2068, but yet if the url is not absolute,
1335              * handle it as everyone does. */
1336             if( p[0] == '/' )
1337             {
1338                 const char *psz_http_ext = p_sys->p_tls ? "s" : "" ;
1339
1340                 if( p_sys->url.i_port == ( p_sys->p_tls ? 443 : 80 ) )
1341                 {
1342                     if( asprintf(&psz_new_loc, "http%s://%s%s", psz_http_ext,
1343                                  p_sys->url.psz_host, p) < 0 )
1344                         goto error;
1345                 }
1346                 else
1347                 {
1348                     if( asprintf(&psz_new_loc, "http%s://%s:%d%s", psz_http_ext,
1349                                  p_sys->url.psz_host, p_sys->url.i_port, p) < 0 )
1350                         goto error;
1351                 }
1352             }
1353             else
1354             {
1355                 psz_new_loc = strdup( p );
1356             }
1357
1358             free( p_sys->psz_location );
1359             p_sys->psz_location = psz_new_loc;
1360         }
1361         else if( !strcasecmp( psz, "Content-Type" ) )
1362         {
1363             free( p_sys->psz_mime );
1364             p_sys->psz_mime = strdup( p );
1365             msg_Dbg( p_access, "Content-Type: %s", p_sys->psz_mime );
1366         }
1367         else if( !strcasecmp( psz, "Content-Encoding" ) )
1368         {
1369             msg_Dbg( p_access, "Content-Encoding: %s", p );
1370             if( !strcasecmp( p, "identity" ) )
1371                 ;
1372 #ifdef HAVE_ZLIB_H
1373             else if( !strcasecmp( p, "gzip" ) || !strcasecmp( p, "deflate" ) )
1374                 p_sys->b_compressed = true;
1375 #endif
1376             else
1377                 msg_Warn( p_access, "Unknown content coding: %s", p );
1378         }
1379         else if( !strcasecmp( psz, "Pragma" ) )
1380         {
1381             if( !strcasecmp( psz, "Pragma: features" ) )
1382                 p_sys->b_mms = true;
1383             free( p_sys->psz_pragma );
1384             p_sys->psz_pragma = strdup( p );
1385             msg_Dbg( p_access, "Pragma: %s", p_sys->psz_pragma );
1386         }
1387         else if( !strcasecmp( psz, "Server" ) )
1388         {
1389             msg_Dbg( p_access, "Server: %s", p );
1390             if( !strncasecmp( p, "Icecast", 7 ) ||
1391                 !strncasecmp( p, "Nanocaster", 10 ) )
1392             {
1393                 /* Remember if this is Icecast
1394                  * we need to force demux in this case without breaking
1395                  *  autodetection */
1396
1397                 /* Let live 365 streams (nanocaster) piggyback on the icecast
1398                  * routine. They look very similar */
1399
1400                 p_sys->b_reconnect = true;
1401                 p_sys->b_pace_control = false;
1402                 p_sys->b_icecast = true;
1403             }
1404         }
1405         else if( !strcasecmp( psz, "Transfer-Encoding" ) )
1406         {
1407             msg_Dbg( p_access, "Transfer-Encoding: %s", p );
1408             if( !strncasecmp( p, "chunked", 7 ) )
1409             {
1410                 p_sys->b_chunked = true;
1411             }
1412         }
1413         else if( !strcasecmp( psz, "Icy-MetaInt" ) )
1414         {
1415             msg_Dbg( p_access, "Icy-MetaInt: %s", p );
1416             p_sys->i_icy_meta = atoi( p );
1417             if( p_sys->i_icy_meta < 0 )
1418                 p_sys->i_icy_meta = 0;
1419             if( p_sys->i_icy_meta > 0 )
1420                 p_sys->b_icecast = true;
1421
1422             msg_Warn( p_access, "ICY metaint=%d", p_sys->i_icy_meta );
1423         }
1424         else if( !strcasecmp( psz, "Icy-Name" ) )
1425         {
1426             free( p_sys->psz_icy_name );
1427             char *psz_tmp = strdup( p );
1428             p_sys->psz_icy_name = EnsureUTF8( psz_tmp );
1429             if( !p_sys->psz_icy_name )
1430                 free( psz_tmp );
1431             msg_Dbg( p_access, "Icy-Name: %s", p_sys->psz_icy_name );
1432             input_thread_t *p_input = access_GetParentInput( p_access );
1433             if ( p_input )
1434             {
1435                 input_item_t *p_input_item = input_GetItem( p_access->p_input );
1436                 if ( p_input_item )
1437                     input_item_SetMeta( p_input_item, vlc_meta_Title, p_sys->psz_icy_name );
1438                 vlc_object_release( p_input );
1439             }
1440
1441             p_sys->b_icecast = true; /* be on the safeside. set it here as well. */
1442             p_sys->b_reconnect = true;
1443             p_sys->b_pace_control = false;
1444         }
1445         else if( !strcasecmp( psz, "Icy-Genre" ) )
1446         {
1447             free( p_sys->psz_icy_genre );
1448             char *psz_tmp = strdup( p );
1449             p_sys->psz_icy_genre = EnsureUTF8( psz_tmp );
1450             if( !p_sys->psz_icy_genre )
1451                 free( psz_tmp );
1452             msg_Dbg( p_access, "Icy-Genre: %s", p_sys->psz_icy_genre );
1453             input_thread_t *p_input = access_GetParentInput( p_access );
1454             if( p_input )
1455             {
1456                 input_item_t *p_input_item = input_GetItem( p_access->p_input );
1457                 if( p_input_item )
1458                     input_item_SetMeta( p_input_item, vlc_meta_Genre, p_sys->psz_icy_genre );
1459                 vlc_object_release( p_input );
1460             }
1461         }
1462         else if( !strncasecmp( psz, "Icy-Notice", 10 ) )
1463         {
1464             msg_Dbg( p_access, "Icy-Notice: %s", p );
1465         }
1466         else if( !strncasecmp( psz, "icy-", 4 ) ||
1467                  !strncasecmp( psz, "ice-", 4 ) ||
1468                  !strncasecmp( psz, "x-audiocast", 11 ) )
1469         {
1470             msg_Dbg( p_access, "Meta-Info: %s: %s", psz, p );
1471         }
1472         else if( !strcasecmp( psz, "Set-Cookie" ) )
1473         {
1474             if( p_sys->cookies )
1475             {
1476                 if ( http_cookies_append( p_sys->cookies, p, &p_sys->url ) )
1477                     msg_Dbg( p_access, "Accepting Cookie: %s", p );
1478                 else
1479                     msg_Dbg( p_access, "Rejected Cookie: %s", p );
1480             }
1481             else
1482                 msg_Dbg( p_access, "We have a Cookie we won't remember: %s", p );
1483         }
1484         else if( !strcasecmp( psz, "www-authenticate" ) )
1485         {
1486             msg_Dbg( p_access, "Authentication header: %s", p );
1487             http_auth_ParseWwwAuthenticateHeader( VLC_OBJECT(p_access),
1488                                                   &p_sys->auth, p );
1489         }
1490         else if( !strcasecmp( psz, "proxy-authenticate" ) )
1491         {
1492             msg_Dbg( p_access, "Proxy authentication header: %s", p );
1493             http_auth_ParseWwwAuthenticateHeader( VLC_OBJECT(p_access),
1494                                                   &p_sys->proxy_auth, p );
1495         }
1496         else if( !strcasecmp( psz, "authentication-info" ) )
1497         {
1498             msg_Dbg( p_access, "Authentication Info header: %s", p );
1499             if( AuthCheckReply( p_access, p, &p_sys->url, &p_sys->auth ) )
1500                 goto error;
1501         }
1502         else if( !strcasecmp( psz, "proxy-authentication-info" ) )
1503         {
1504             msg_Dbg( p_access, "Proxy Authentication Info header: %s", p );
1505             if( AuthCheckReply( p_access, p, &p_sys->proxy, &p_sys->proxy_auth ) )
1506                 goto error;
1507         }
1508         else if( !strcasecmp( psz, "Accept-Ranges" ) )
1509         {
1510             if( !strcasecmp( p, "bytes" ) )
1511                 p_sys->b_seekable = true;
1512         }
1513
1514         free( psz );
1515     }
1516     /* We close the stream for zero length data, unless of course the
1517      * server has already promised to do this for us.
1518      */
1519     if( p_sys->b_has_size && p_sys->i_remaining == 0 && p_sys->b_persist ) {
1520         Disconnect( p_access );
1521     }
1522     return VLC_SUCCESS;
1523
1524 error:
1525     Disconnect( p_access );
1526     return VLC_EGENERIC;
1527 }
1528
1529 /*****************************************************************************
1530  * Disconnect:
1531  *****************************************************************************/
1532 static void Disconnect( access_t *p_access )
1533 {
1534     access_sys_t *p_sys = p_access->p_sys;
1535
1536     if( p_sys->p_tls != NULL)
1537     {
1538         vlc_tls_SessionDelete( p_sys->p_tls );
1539         p_sys->p_tls = NULL;
1540         p_sys->p_vs = NULL;
1541     }
1542     if( p_sys->fd != -1)
1543     {
1544         net_Close(p_sys->fd);
1545         p_sys->fd = -1;
1546     }
1547
1548 }
1549
1550 /*****************************************************************************
1551  * HTTP authentication
1552  *****************************************************************************/
1553
1554 static void AuthReply( access_t *p_access, const char *psz_prefix,
1555                        vlc_url_t *p_url, http_auth_t *p_auth )
1556 {
1557     access_sys_t *p_sys = p_access->p_sys;
1558     char *psz_value;
1559
1560     psz_value =
1561         http_auth_FormatAuthorizationHeader( VLC_OBJECT(p_access), p_auth,
1562                                              "GET", p_url->psz_path,
1563                                              p_url->psz_username,
1564                                              p_url->psz_password );
1565     if ( psz_value == NULL )
1566         return;
1567
1568     net_Printf( p_access, p_sys->fd, p_sys->p_vs,
1569                 "%sAuthorization: %s\r\n", psz_prefix, psz_value );
1570     free( psz_value );
1571 }
1572
1573 static int AuthCheckReply( access_t *p_access, const char *psz_header,
1574                            vlc_url_t *p_url, http_auth_t *p_auth )
1575 {
1576     return
1577         http_auth_ParseAuthenticationInfoHeader( VLC_OBJECT(p_access), p_auth,
1578                                                  psz_header, "",
1579                                                  p_url->psz_path,
1580                                                  p_url->psz_username,
1581                                                  p_url->psz_password );
1582 }