1 /*****************************************************************************
2 * http.c: HTTP input module
3 *****************************************************************************
4 * Copyright (C) 2001-2008 VLC authors and VideoLAN
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>
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.
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.
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 *****************************************************************************/
27 /*****************************************************************************
29 *****************************************************************************/
35 #define MODULE_STRING "oldhttp"
39 #include <vlc_common.h>
40 #include <vlc_plugin.h>
41 #include <vlc_access.h>
45 #include <vlc_strings.h>
46 #include <vlc_charset.h>
47 #include <vlc_input.h>
49 #include <vlc_interrupt.h>
50 #include <vlc_keystore.h>
51 #include <vlc_memstream.h>
56 /*****************************************************************************
58 *****************************************************************************/
59 static int Open ( vlc_object_t
* );
60 static void Close( vlc_object_t
* );
62 #define RECONNECT_TEXT N_("Auto re-connect")
63 #define RECONNECT_LONGTEXT N_( \
64 "Automatically try to reconnect to the stream in case of a sudden " \
68 set_description( N_("HTTP input") )
69 set_capability( "access", 0 )
70 set_shortname( N_( "HTTP(S)" ) )
71 set_category( CAT_INPUT
)
72 set_subcategory( SUBCAT_INPUT_ACCESS
)
74 add_bool( "http-reconnect", false, RECONNECT_TEXT
,
75 RECONNECT_LONGTEXT
, true )
76 /* 'itpc' = iTunes Podcast */
77 add_shortcut( "http", "unsv", "itpc", "icyx" )
78 set_callbacks( Open
, Close
)
81 /*****************************************************************************
83 *****************************************************************************/
100 vlc_http_auth_t proxy_auth
;
101 char *psz_proxy_passbuf
;
111 uint64_t i_icy_offset
;
124 static ssize_t
Read( stream_t
*, void *, size_t );
125 static int Seek( stream_t
*, uint64_t );
126 static int Control( stream_t
*, int, va_list );
129 static int Connect( stream_t
* );
130 static void Disconnect( stream_t
* );
133 static int AuthCheckReply( stream_t
*p_access
, const char *psz_header
,
134 vlc_url_t
*p_url
, vlc_http_auth_t
*p_auth
);
136 /*****************************************************************************
138 *****************************************************************************/
139 static int Open( vlc_object_t
*p_this
)
141 stream_t
*p_access
= (stream_t
*)p_this
;
142 const char *psz_url
= p_access
->psz_url
;
144 int ret
= VLC_EGENERIC
;
145 vlc_credential credential
;
147 access_sys_t
*p_sys
= vlc_obj_malloc( p_this
, sizeof(*p_sys
) );
148 if( unlikely(p_sys
== NULL
) )
151 p_sys
->stream
= NULL
;
152 p_sys
->b_proxy
= false;
153 p_sys
->psz_proxy_passbuf
= NULL
;
154 p_sys
->psz_mime
= NULL
;
155 p_sys
->b_icecast
= false;
156 p_sys
->psz_location
= NULL
;
157 p_sys
->psz_user_agent
= NULL
;
158 p_sys
->psz_referrer
= NULL
;
159 p_sys
->psz_username
= NULL
;
160 p_sys
->psz_password
= NULL
;
161 p_sys
->i_icy_meta
= 0;
162 p_sys
->i_icy_offset
= 0;
163 p_sys
->psz_icy_name
= NULL
;
164 p_sys
->psz_icy_genre
= NULL
;
165 p_sys
->psz_icy_title
= NULL
;
166 p_sys
->b_has_size
= false;
169 p_access
->p_sys
= p_sys
;
171 if( vlc_UrlParse( &p_sys
->url
, psz_url
) || p_sys
->url
.psz_host
== NULL
)
173 msg_Err( p_access
, "invalid URL" );
174 vlc_UrlClean( &p_sys
->url
);
177 if( p_sys
->url
.i_port
<= 0 )
178 p_sys
->url
.i_port
= 80;
180 vlc_credential_init( &credential
, &p_sys
->url
);
182 /* Determine the HTTP user agent */
183 /* See RFC2616 §2.2 token and comment definition, and §3.8 and
184 * §14.43 user-agent header */
185 p_sys
->psz_user_agent
= var_InheritString( p_access
, "http-user-agent" );
186 if (p_sys
->psz_user_agent
)
188 unsigned comment_level
= 0;
189 for( char *p
= p_sys
->psz_user_agent
; *p
; p
++ )
192 if (comment_level
== 0)
194 if( c
< 32 || strchr( ")<>@,;:\\\"[]?={}", c
) )
195 *p
= '_'; /* remove potentially harmful characters */
201 else if( c
< 32 && strchr( "\t\r\n", c
) == NULL
)
202 *p
= '_'; /* remove potentially harmful characters */
206 if (comment_level
== UINT_MAX
)
211 /* truncate evil unclosed comments */
212 if (comment_level
> 0)
214 char *p
= strchr(p_sys
->psz_user_agent
, '(');
220 p_sys
->psz_referrer
= var_InheritString( p_access
, "http-referrer" );
223 psz
= var_InheritString( p_access
, "http-proxy" );
226 msg_Dbg(p_access
, "querying proxy for %s", psz_url
);
227 psz
= vlc_getProxyUrl(psz_url
);
230 msg_Dbg(p_access
, "proxy: %s", psz
);
232 msg_Dbg(p_access
, "no proxy");
236 p_sys
->b_proxy
= true;
237 vlc_UrlParse( &p_sys
->proxy
, psz
);
240 psz
= var_InheritString( p_access
, "http-proxy-pwd" );
242 p_sys
->proxy
.psz_password
= p_sys
->psz_proxy_passbuf
= psz
;
244 if( p_sys
->proxy
.psz_host
== NULL
|| *p_sys
->proxy
.psz_host
== '\0' )
246 msg_Warn( p_access
, "invalid proxy host" );
249 if( p_sys
->proxy
.i_port
<= 0 )
251 p_sys
->proxy
.i_port
= 80;
255 msg_Dbg( p_access
, "http: server='%s' port=%d file='%s'",
256 p_sys
->url
.psz_host
, p_sys
->url
.i_port
,
257 p_sys
->url
.psz_path
!= NULL
? p_sys
->url
.psz_path
: "" );
260 msg_Dbg( p_access
, " proxy %s:%d", p_sys
->proxy
.psz_host
,
261 p_sys
->proxy
.i_port
);
263 if( p_sys
->url
.psz_username
&& *p_sys
->url
.psz_username
)
265 msg_Dbg( p_access
, " user='%s'", p_sys
->url
.psz_username
);
268 p_sys
->b_reconnect
= var_InheritBool( p_access
, "http-reconnect" );
270 if( vlc_credential_get( &credential
, p_access
, NULL
, NULL
, NULL
, NULL
) )
272 p_sys
->url
.psz_username
= (char *) credential
.psz_username
;
273 p_sys
->url
.psz_password
= (char *) credential
.psz_password
;
278 if( Connect( p_access
) )
281 if( p_sys
->i_code
== 401 )
283 if( p_sys
->auth
.psz_realm
== NULL
)
285 msg_Err( p_access
, "authentication failed without realm" );
289 if( p_sys
->url
.psz_username
&& p_sys
->url
.psz_password
&&
290 p_sys
->auth
.psz_nonce
&& p_sys
->auth
.i_nonce
== 0 )
292 Disconnect( p_access
);
295 free( p_sys
->psz_username
);
296 free( p_sys
->psz_password
);
297 p_sys
->psz_username
= p_sys
->psz_password
= NULL
;
299 msg_Dbg( p_access
, "authentication failed for realm %s",
300 p_sys
->auth
.psz_realm
);
302 credential
.psz_realm
= p_sys
->auth
.psz_realm
;
303 credential
.psz_authtype
= p_sys
->auth
.psz_nonce
? "Digest" : "Basic";
305 if( vlc_credential_get( &credential
, p_access
, NULL
, NULL
,
306 _("HTTP authentication"),
307 _("Please enter a valid login name and a "
308 "password for realm %s."), p_sys
->auth
.psz_realm
) )
310 p_sys
->psz_username
= strdup(credential
.psz_username
);
311 p_sys
->psz_password
= strdup(credential
.psz_password
);
312 if (!p_sys
->psz_username
|| !p_sys
->psz_password
)
314 msg_Err( p_access
, "retrying with user=%s", p_sys
->psz_username
);
315 p_sys
->url
.psz_username
= p_sys
->psz_username
;
316 p_sys
->url
.psz_password
= p_sys
->psz_password
;
317 Disconnect( p_access
);
324 vlc_credential_store( &credential
, p_access
);
326 if( ( p_sys
->i_code
== 301 || p_sys
->i_code
== 302 ||
327 p_sys
->i_code
== 303 || p_sys
->i_code
== 307 ) &&
328 p_sys
->psz_location
!= NULL
)
330 p_access
->psz_url
= p_sys
->psz_location
;
331 p_sys
->psz_location
= NULL
;
332 ret
= VLC_ACCESS_REDIRECT
;
336 if( p_sys
->b_reconnect
) msg_Dbg( p_access
, "auto re-connect enabled" );
338 /* Set up p_access */
339 p_access
->pf_read
= Read
;
340 p_access
->pf_control
= Control
;
341 p_access
->pf_seek
= Seek
;
343 vlc_credential_clean( &credential
);
348 Disconnect( p_access
);
351 vlc_credential_clean( &credential
);
352 vlc_UrlClean( &p_sys
->url
);
354 vlc_UrlClean( &p_sys
->proxy
);
355 free( p_sys
->psz_proxy_passbuf
);
356 free( p_sys
->psz_mime
);
357 free( p_sys
->psz_location
);
358 free( p_sys
->psz_user_agent
);
359 free( p_sys
->psz_referrer
);
360 free( p_sys
->psz_username
);
361 free( p_sys
->psz_password
);
366 /*****************************************************************************
368 *****************************************************************************/
369 static void Close( vlc_object_t
*p_this
)
371 stream_t
*p_access
= (stream_t
*)p_this
;
372 access_sys_t
*p_sys
= p_access
->p_sys
;
374 vlc_UrlClean( &p_sys
->url
);
376 vlc_UrlClean( &p_sys
->proxy
);
378 free( p_sys
->psz_mime
);
379 free( p_sys
->psz_location
);
381 free( p_sys
->psz_icy_name
);
382 free( p_sys
->psz_icy_genre
);
383 free( p_sys
->psz_icy_title
);
385 free( p_sys
->psz_user_agent
);
386 free( p_sys
->psz_referrer
);
387 free( p_sys
->psz_username
);
388 free( p_sys
->psz_password
);
390 Disconnect( p_access
);
393 /* Read data from the socket */
394 static int ReadData( stream_t
*p_access
, int *pi_read
,
395 void *p_buffer
, size_t i_len
)
397 access_sys_t
*p_sys
= p_access
->p_sys
;
399 *pi_read
= vlc_tls_Read(p_sys
->stream
, p_buffer
, i_len
, false);
400 if( *pi_read
< 0 && errno
!= EINTR
&& errno
!= EAGAIN
)
405 /*****************************************************************************
406 * Read: Read up to i_len bytes from the http connection and place in
407 * p_buffer. Return the actual number of bytes read
408 *****************************************************************************/
409 static int ReadICYMeta( stream_t
*p_access
);
411 static ssize_t
Read( stream_t
*p_access
, void *p_buffer
, size_t i_len
)
413 access_sys_t
*p_sys
= p_access
->p_sys
;
415 if (p_sys
->stream
== NULL
)
420 if( p_sys
->i_icy_meta
> 0 )
422 if( UINT64_MAX
- i_chunk
< p_sys
->offset
)
423 i_chunk
= UINT64_MAX
- p_sys
->offset
;
425 if( p_sys
->offset
+ i_chunk
> p_sys
->i_icy_offset
)
426 i_chunk
= p_sys
->i_icy_offset
- p_sys
->offset
;
430 if( ReadData( p_access
, &i_read
, (uint8_t*)p_buffer
, i_chunk
) )
434 return -1; /* EINTR / EAGAIN */
438 Disconnect( p_access
);
439 if( p_sys
->b_reconnect
)
441 msg_Dbg( p_access
, "got disconnected, trying to reconnect" );
442 if( Connect( p_access
) )
443 msg_Dbg( p_access
, "reconnection failed" );
450 assert( i_read
>= 0 );
451 p_sys
->offset
+= i_read
;
453 if( p_sys
->i_icy_meta
> 0 &&
454 p_sys
->offset
== p_sys
->i_icy_offset
)
456 if( ReadICYMeta( p_access
) )
458 p_sys
->i_icy_offset
= p_sys
->offset
+ p_sys
->i_icy_meta
;
464 static int ReadICYMeta( stream_t
*p_access
)
466 access_sys_t
*p_sys
= p_access
->p_sys
;
472 /* Read meta data length */
473 if( ReadData( p_access
, &i_read
, &buffer
, 1 ) )
477 const int i_size
= buffer
<< 4;
478 /* msg_Dbg( p_access, "ICY meta size=%u", i_size); */
480 psz_meta
= malloc( i_size
+ 1 );
481 for( i_read
= 0; i_read
< i_size
; )
484 if( ReadData( p_access
, &i_tmp
, (uint8_t *)&psz_meta
[i_read
], i_size
- i_read
) || i_tmp
<= 0 )
491 psz_meta
[i_read
] = '\0'; /* Just in case */
493 /* msg_Dbg( p_access, "icy-meta=%s", psz_meta ); */
495 /* Now parse the meta */
496 /* Look for StreamTitle= */
497 p
= strcasestr( (char *)psz_meta
, "StreamTitle=" );
500 p
+= strlen( "StreamTitle=" );
501 if( *p
== '\'' || *p
== '"' )
503 char closing
[] = { p
[0], ';', '\0' };
504 char *psz
= strstr( &p
[1], closing
);
506 psz
= strchr( &p
[1], ';' );
508 if( psz
) *psz
= '\0';
513 char *psz
= strchr( p
, ';' );
514 if( psz
) *psz
= '\0';
517 if( !p_sys
->psz_icy_title
||
518 strcmp( p_sys
->psz_icy_title
, p
) )
520 free( p_sys
->psz_icy_title
);
521 char *psz_tmp
= strdup( p
);
522 p_sys
->psz_icy_title
= EnsureUTF8( psz_tmp
);
523 if( !p_sys
->psz_icy_title
)
526 msg_Dbg( p_access
, "New Icy-Title=%s", p_sys
->psz_icy_title
);
527 if( p_access
->p_input_item
)
528 input_item_SetMeta( p_access
->p_input_item
, vlc_meta_NowPlaying
,
529 p_sys
->psz_icy_title
);
537 /*****************************************************************************
538 * Seek: close and re-open a connection at the right place
539 *****************************************************************************/
540 static int Seek( stream_t
*p_access
, uint64_t i_pos
)
542 (void) p_access
; (void) i_pos
;
546 /*****************************************************************************
548 *****************************************************************************/
549 static int Control( stream_t
*p_access
, int i_query
, va_list args
)
551 access_sys_t
*p_sys
= p_access
->p_sys
;
557 case STREAM_CAN_SEEK
:
558 case STREAM_CAN_FASTSEEK
:
559 pb_bool
= va_arg( args
, bool* );
562 case STREAM_CAN_PAUSE
:
563 case STREAM_CAN_CONTROL_PACE
:
564 pb_bool
= va_arg( args
, bool* );
569 case STREAM_GET_PTS_DELAY
:
570 *va_arg( args
, vlc_tick_t
* ) =
571 VLC_TICK_FROM_MS(var_InheritInteger( p_access
, "network-caching" ));
574 case STREAM_GET_SIZE
:
575 if( !p_sys
->b_has_size
)
577 *va_arg( args
, uint64_t*) = p_sys
->size
;
581 case STREAM_SET_PAUSE_STATE
:
584 case STREAM_GET_CONTENT_TYPE
:
586 char **type
= va_arg( args
, char ** );
588 if( p_sys
->b_icecast
&& p_sys
->psz_mime
== NULL
)
589 *type
= strdup( "audio/mpeg" );
590 else if( !strcasecmp( p_access
->psz_name
, "itpc" ) )
591 *type
= strdup( "application/rss+xml" );
592 else if( !strcasecmp( p_access
->psz_name
, "unsv" ) &&
593 p_sys
->psz_mime
!= NULL
&&
594 !strcasecmp( p_sys
->psz_mime
, "misc/ultravox" ) )
595 /* Grrrr! detect ultravox server and force NSV demuxer */
596 *type
= strdup( "video/nsa" );
597 else if( p_sys
->psz_mime
)
598 *type
= strdup( p_sys
->psz_mime
);
611 /*****************************************************************************
613 *****************************************************************************/
614 static int Connect( stream_t
*p_access
)
616 access_sys_t
*p_sys
= p_access
->p_sys
;
617 vlc_url_t srv
= p_sys
->b_proxy
? p_sys
->proxy
: p_sys
->url
;
621 free( p_sys
->psz_location
);
622 free( p_sys
->psz_mime
);
624 free( p_sys
->psz_icy_genre
);
625 free( p_sys
->psz_icy_name
);
626 free( p_sys
->psz_icy_title
);
628 vlc_http_auth_Init( &p_sys
->auth
);
629 vlc_http_auth_Init( &p_sys
->proxy_auth
);
630 p_sys
->psz_location
= NULL
;
631 p_sys
->psz_mime
= NULL
;
632 p_sys
->i_icy_meta
= 0;
633 p_sys
->i_icy_offset
= 0;
634 p_sys
->psz_icy_name
= NULL
;
635 p_sys
->psz_icy_genre
= NULL
;
636 p_sys
->psz_icy_title
= NULL
;
637 p_sys
->b_has_size
= false;
641 struct vlc_memstream stream
;
643 vlc_memstream_open(&stream
);
645 vlc_memstream_puts(&stream
, "GET ");
647 vlc_memstream_printf( &stream
, "http://%s:%d",
648 p_sys
->url
.psz_host
, p_sys
->url
.i_port
);
649 if( p_sys
->url
.psz_path
== NULL
|| p_sys
->url
.psz_path
[0] == '\0' )
650 vlc_memstream_putc( &stream
, '/' );
652 vlc_memstream_puts( &stream
, p_sys
->url
.psz_path
);
653 if( p_sys
->url
.psz_option
!= NULL
)
654 vlc_memstream_printf( &stream
, "?%s", p_sys
->url
.psz_option
);
655 vlc_memstream_puts( &stream
, " HTTP/1.0\r\n" );
657 vlc_memstream_printf( &stream
, "Host: %s", p_sys
->url
.psz_host
);
658 if( p_sys
->url
.i_port
!= 80 )
659 vlc_memstream_printf( &stream
, ":%d", p_sys
->url
.i_port
);
660 vlc_memstream_puts( &stream
, "\r\n" );
663 vlc_memstream_printf( &stream
, "User-Agent: %s\r\n",
664 p_sys
->psz_user_agent
);
666 if (p_sys
->psz_referrer
)
667 vlc_memstream_printf( &stream
, "Referer: %s\r\n",
668 p_sys
->psz_referrer
);
671 if( p_sys
->url
.psz_username
!= NULL
&& p_sys
->url
.psz_password
!= NULL
)
675 auth
= vlc_http_auth_FormatAuthorizationHeader( VLC_OBJECT(p_access
),
676 &p_sys
->auth
, "GET", p_sys
->url
.psz_path
,
677 p_sys
->url
.psz_username
, p_sys
->url
.psz_password
);
679 vlc_memstream_printf( &stream
, "Authorization: %s\r\n", auth
);
683 /* Proxy Authentication */
684 if( p_sys
->b_proxy
&& p_sys
->proxy
.psz_username
!= NULL
685 && p_sys
->proxy
.psz_password
!= NULL
)
689 auth
= vlc_http_auth_FormatAuthorizationHeader( VLC_OBJECT(p_access
),
690 &p_sys
->proxy_auth
, "GET", p_sys
->url
.psz_path
,
691 p_sys
->proxy
.psz_username
, p_sys
->proxy
.psz_password
);
693 vlc_memstream_printf( &stream
, "Proxy-Authorization: %s\r\n",
698 /* ICY meta data request */
699 vlc_memstream_puts( &stream
, "Icy-MetaData: 1\r\n" );
701 vlc_memstream_puts( &stream
, "\r\n" );
703 if( vlc_memstream_close( &stream
) )
706 /* Open connection */
707 assert(p_sys
->stream
== NULL
); /* No open sockets (leaking fds is BAD) */
708 p_sys
->stream
= vlc_tls_SocketOpenTCP(VLC_OBJECT(p_access
),
709 srv
.psz_host
, srv
.i_port
);
710 if (p_sys
->stream
== NULL
)
712 msg_Err( p_access
, "cannot connect to %s:%d", srv
.psz_host
, srv
.i_port
);
717 msg_Dbg( p_access
, "sending request:\n%s", stream
.ptr
);
718 val
= vlc_tls_Write(p_sys
->stream
, stream
.ptr
, stream
.length
);
721 if( val
< (ssize_t
)stream
.length
)
723 msg_Err( p_access
, "failed to send request" );
724 Disconnect( p_access
);
729 char *psz
= vlc_tls_GetLine(p_sys
->stream
);
732 msg_Err( p_access
, "failed to read answer" );
735 if( !strncmp( psz
, "HTTP/1.", 7 ) )
737 p_sys
->i_code
= atoi( &psz
[9] );
738 msg_Dbg( p_access
, "HTTP answer code %d", p_sys
->i_code
);
740 else if( !strncmp( psz
, "ICY", 3 ) )
742 p_sys
->i_code
= atoi( &psz
[4] );
743 msg_Dbg( p_access
, "ICY answer code %d", p_sys
->i_code
);
744 p_sys
->b_icecast
= true;
745 p_sys
->b_reconnect
= true;
749 msg_Err( p_access
, "invalid HTTP reply '%s'", psz
);
753 /* Authentication error - We'll have to display the dialog */
754 if( p_sys
->i_code
== 401 )
758 /* Other fatal error */
759 else if( p_sys
->i_code
>= 400 )
761 msg_Err( p_access
, "error: %s", psz
);
769 char *p
, *p_trailing
;
771 psz
= vlc_tls_GetLine(p_sys
->stream
);
774 msg_Err( p_access
, "failed to read answer" );
778 /* msg_Dbg( p_input, "Line=%s", psz ); */
785 if( ( p
= strchr( psz
, ':' ) ) == NULL
)
787 msg_Err( p_access
, "malformed header line: %s", psz
);
792 p
+= strspn( p
, " \t" );
794 /* trim trailing white space */
795 p_trailing
= p
+ strlen( p
);
799 while( ( *p_trailing
== ' ' || *p_trailing
== '\t' ) && p_trailing
> p
)
806 if( !strcasecmp( psz
, "Content-Length" ) )
808 uint64_t i_size
= (uint64_t)atoll( p
);
809 if(i_size
> p_sys
->size
) {
810 p_sys
->b_has_size
= true;
811 p_sys
->size
= i_size
;
814 else if( !strcasecmp( psz
, "Location" ) )
818 /* This does not follow RFC 2068, but yet if the url is not absolute,
819 * handle it as everyone does. */
822 if( p_sys
->url
.i_port
== 80 )
824 if( asprintf(&psz_new_loc
, "http://%s%s",
825 p_sys
->url
.psz_host
, p
) < 0 )
830 if( asprintf(&psz_new_loc
, "http://%s:%d%s",
831 p_sys
->url
.psz_host
, p_sys
->url
.i_port
, p
) < 0 )
837 psz_new_loc
= strdup( p
);
840 free( p_sys
->psz_location
);
841 p_sys
->psz_location
= psz_new_loc
;
843 else if( !strcasecmp( psz
, "Content-Type" ) )
845 free( p_sys
->psz_mime
);
846 p_sys
->psz_mime
= strdup( p
);
847 msg_Dbg( p_access
, "Content-Type: %s", p_sys
->psz_mime
);
849 else if( !strcasecmp( psz
, "Content-Encoding" ) )
851 msg_Dbg( p_access
, "Content-Encoding: %s", p
);
853 else if( !strcasecmp( psz
, "Server" ) )
855 msg_Dbg( p_access
, "Server: %s", p
);
856 if( !strncasecmp( p
, "Icecast", 7 ) ||
857 !strncasecmp( p
, "Nanocaster", 10 ) )
859 /* Remember if this is Icecast
860 * we need to force demux in this case without breaking
863 /* Let live 365 streams (nanocaster) piggyback on the icecast
864 * routine. They look very similar */
866 p_sys
->b_reconnect
= true;
867 p_sys
->b_icecast
= true;
870 else if( !strcasecmp( psz
, "Icy-MetaInt" ) )
872 msg_Dbg( p_access
, "Icy-MetaInt: %s", p
);
873 p_sys
->i_icy_meta
= atoi( p
);
874 if( p_sys
->i_icy_meta
< 0 )
875 p_sys
->i_icy_meta
= 0;
876 if( p_sys
->i_icy_meta
> 1 )
878 p_sys
->i_icy_offset
= p_sys
->i_icy_meta
;
879 p_sys
->b_icecast
= true;
882 msg_Warn( p_access
, "ICY metaint=%d", p_sys
->i_icy_meta
);
884 else if( !strcasecmp( psz
, "Icy-Name" ) )
886 free( p_sys
->psz_icy_name
);
887 char *psz_tmp
= strdup( p
);
888 p_sys
->psz_icy_name
= EnsureUTF8( psz_tmp
);
889 if( !p_sys
->psz_icy_name
)
892 vlc_xml_decode( p_sys
->psz_icy_name
);
893 msg_Dbg( p_access
, "Icy-Name: %s", p_sys
->psz_icy_name
);
894 if ( p_access
->p_input_item
)
895 input_item_SetMeta( p_access
->p_input_item
, vlc_meta_Title
,
896 p_sys
->psz_icy_name
);
898 p_sys
->b_icecast
= true; /* be on the safeside. set it here as well. */
899 p_sys
->b_reconnect
= true;
901 else if( !strcasecmp( psz
, "Icy-Genre" ) )
903 free( p_sys
->psz_icy_genre
);
904 char *psz_tmp
= strdup( p
);
905 p_sys
->psz_icy_genre
= EnsureUTF8( psz_tmp
);
906 if( !p_sys
->psz_icy_genre
)
909 vlc_xml_decode( p_sys
->psz_icy_genre
);
910 msg_Dbg( p_access
, "Icy-Genre: %s", p_sys
->psz_icy_genre
);
911 if( p_access
->p_input_item
)
912 input_item_SetMeta( p_access
->p_input_item
, vlc_meta_Genre
,
913 p_sys
->psz_icy_genre
);
915 else if( !strncasecmp( psz
, "Icy-Notice", 10 ) )
917 msg_Dbg( p_access
, "Icy-Notice: %s", p
);
919 else if( !strncasecmp( psz
, "icy-", 4 ) ||
920 !strncasecmp( psz
, "ice-", 4 ) ||
921 !strncasecmp( psz
, "x-audiocast", 11 ) )
923 msg_Dbg( p_access
, "Meta-Info: %s: %s", psz
, p
);
925 else if( !strcasecmp( psz
, "www-authenticate" ) )
927 msg_Dbg( p_access
, "Authentication header: %s", p
);
928 vlc_http_auth_ParseWwwAuthenticateHeader( VLC_OBJECT(p_access
),
931 else if( !strcasecmp( psz
, "proxy-authenticate" ) )
933 msg_Dbg( p_access
, "Proxy authentication header: %s", p
);
934 vlc_http_auth_ParseWwwAuthenticateHeader( VLC_OBJECT(p_access
),
935 &p_sys
->proxy_auth
, p
);
937 else if( !strcasecmp( psz
, "authentication-info" ) )
939 msg_Dbg( p_access
, "Authentication Info header: %s", p
);
940 if( AuthCheckReply( p_access
, p
, &p_sys
->url
, &p_sys
->auth
) )
943 else if( !strcasecmp( psz
, "proxy-authentication-info" ) )
945 msg_Dbg( p_access
, "Proxy Authentication Info header: %s", p
);
946 if( AuthCheckReply( p_access
, p
, &p_sys
->proxy
, &p_sys
->proxy_auth
) )
955 Disconnect( p_access
);
959 /*****************************************************************************
961 *****************************************************************************/
962 static void Disconnect( stream_t
*p_access
)
964 access_sys_t
*p_sys
= p_access
->p_sys
;
966 if (p_sys
->stream
!= NULL
)
967 vlc_tls_Close(p_sys
->stream
);
968 p_sys
->stream
= NULL
;
970 vlc_http_auth_Deinit( &p_sys
->auth
);
971 vlc_http_auth_Deinit( &p_sys
->proxy_auth
);
974 /*****************************************************************************
975 * HTTP authentication
976 *****************************************************************************/
978 static int AuthCheckReply( stream_t
*p_access
, const char *psz_header
,
979 vlc_url_t
*p_url
, vlc_http_auth_t
*p_auth
)
982 vlc_http_auth_ParseAuthenticationInfoHeader( VLC_OBJECT(p_access
),
987 p_url
->psz_password
);