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 *****************************************************************************/
36 #include <vlc_common.h>
37 #include <vlc_plugin.h>
38 #include <vlc_access.h>
40 #include <vlc_network.h>
42 #include <vlc_strings.h>
43 #include <vlc_charset.h>
44 #include <vlc_input.h>
46 #include <vlc_interrupt.h>
47 #include <vlc_keystore.h>
48 #include <vlc_memstream.h>
53 /*****************************************************************************
55 *****************************************************************************/
56 static int Open ( vlc_object_t
* );
57 static void Close( vlc_object_t
* );
59 #define RECONNECT_TEXT N_("Auto re-connect")
60 #define RECONNECT_LONGTEXT N_( \
61 "Automatically try to reconnect to the stream in case of a sudden " \
65 set_description( N_("HTTP input") )
66 set_capability( "access", 0 )
67 set_shortname( N_( "HTTP(S)" ) )
68 set_category( CAT_INPUT
)
69 set_subcategory( SUBCAT_INPUT_ACCESS
)
71 add_bool( "http-reconnect", false, RECONNECT_TEXT
,
72 RECONNECT_LONGTEXT
, true )
73 /* 'itpc' = iTunes Podcast */
74 add_shortcut( "http", "unsv", "itpc", "icyx" )
75 set_callbacks( Open
, Close
)
78 /*****************************************************************************
80 *****************************************************************************/
97 vlc_http_auth_t proxy_auth
;
98 char *psz_proxy_passbuf
;
108 uint64_t i_icy_offset
;
121 static ssize_t
Read( stream_t
*, void *, size_t );
122 static int Seek( stream_t
*, uint64_t );
123 static int Control( stream_t
*, int, va_list );
126 static int Connect( stream_t
* );
127 static void Disconnect( stream_t
* );
130 static int AuthCheckReply( stream_t
*p_access
, const char *psz_header
,
131 vlc_url_t
*p_url
, vlc_http_auth_t
*p_auth
);
133 /*****************************************************************************
135 *****************************************************************************/
136 static int Open( vlc_object_t
*p_this
)
138 stream_t
*p_access
= (stream_t
*)p_this
;
139 const char *psz_url
= p_access
->psz_url
;
141 int ret
= VLC_EGENERIC
;
142 vlc_credential credential
;
144 access_sys_t
*p_sys
= vlc_obj_malloc( p_this
, sizeof(*p_sys
) );
145 if( unlikely(p_sys
== NULL
) )
149 p_sys
->b_proxy
= false;
150 p_sys
->psz_proxy_passbuf
= NULL
;
151 p_sys
->psz_mime
= NULL
;
152 p_sys
->b_icecast
= false;
153 p_sys
->psz_location
= NULL
;
154 p_sys
->psz_user_agent
= NULL
;
155 p_sys
->psz_referrer
= NULL
;
156 p_sys
->psz_username
= NULL
;
157 p_sys
->psz_password
= NULL
;
158 p_sys
->i_icy_meta
= 0;
159 p_sys
->i_icy_offset
= 0;
160 p_sys
->psz_icy_name
= NULL
;
161 p_sys
->psz_icy_genre
= NULL
;
162 p_sys
->psz_icy_title
= NULL
;
163 p_sys
->b_has_size
= false;
166 p_access
->p_sys
= p_sys
;
168 if( vlc_UrlParse( &p_sys
->url
, psz_url
) || p_sys
->url
.psz_host
== NULL
)
170 msg_Err( p_access
, "invalid URL" );
171 vlc_UrlClean( &p_sys
->url
);
174 if( p_sys
->url
.i_port
<= 0 )
175 p_sys
->url
.i_port
= 80;
177 vlc_credential_init( &credential
, &p_sys
->url
);
179 /* Determine the HTTP user agent */
180 /* See RFC2616 §2.2 token and comment definition, and §3.8 and
181 * §14.43 user-agent header */
182 p_sys
->psz_user_agent
= var_InheritString( p_access
, "http-user-agent" );
183 if (p_sys
->psz_user_agent
)
185 unsigned comment_level
= 0;
186 for( char *p
= p_sys
->psz_user_agent
; *p
; p
++ )
189 if (comment_level
== 0)
191 if( c
< 32 || strchr( ")<>@,;:\\\"[]?={}", c
) )
192 *p
= '_'; /* remove potentially harmful characters */
198 else if( c
< 32 && strchr( "\t\r\n", c
) == NULL
)
199 *p
= '_'; /* remove potentially harmful characters */
203 if (comment_level
== UINT_MAX
)
208 /* truncate evil unclosed comments */
209 if (comment_level
> 0)
211 char *p
= strchr(p_sys
->psz_user_agent
, '(');
217 p_sys
->psz_referrer
= var_InheritString( p_access
, "http-referrer" );
220 psz
= var_InheritString( p_access
, "http-proxy" );
223 msg_Dbg(p_access
, "querying proxy for %s", psz_url
);
224 psz
= vlc_getProxyUrl(psz_url
);
227 msg_Dbg(p_access
, "proxy: %s", psz
);
229 msg_Dbg(p_access
, "no proxy");
233 p_sys
->b_proxy
= true;
234 vlc_UrlParse( &p_sys
->proxy
, psz
);
237 psz
= var_InheritString( p_access
, "http-proxy-pwd" );
239 p_sys
->proxy
.psz_password
= p_sys
->psz_proxy_passbuf
= psz
;
241 if( p_sys
->proxy
.psz_host
== NULL
|| *p_sys
->proxy
.psz_host
== '\0' )
243 msg_Warn( p_access
, "invalid proxy host" );
246 if( p_sys
->proxy
.i_port
<= 0 )
248 p_sys
->proxy
.i_port
= 80;
252 msg_Dbg( p_access
, "http: server='%s' port=%d file='%s'",
253 p_sys
->url
.psz_host
, p_sys
->url
.i_port
,
254 p_sys
->url
.psz_path
!= NULL
? p_sys
->url
.psz_path
: "" );
257 msg_Dbg( p_access
, " proxy %s:%d", p_sys
->proxy
.psz_host
,
258 p_sys
->proxy
.i_port
);
260 if( p_sys
->url
.psz_username
&& *p_sys
->url
.psz_username
)
262 msg_Dbg( p_access
, " user='%s'", p_sys
->url
.psz_username
);
265 p_sys
->b_reconnect
= var_InheritBool( p_access
, "http-reconnect" );
267 if( vlc_credential_get( &credential
, p_access
, NULL
, NULL
, NULL
, NULL
) )
269 p_sys
->url
.psz_username
= (char *) credential
.psz_username
;
270 p_sys
->url
.psz_password
= (char *) credential
.psz_password
;
275 if( Connect( p_access
) )
278 if( p_sys
->i_code
== 401 )
280 if( p_sys
->auth
.psz_realm
== NULL
)
282 msg_Err( p_access
, "authentication failed without realm" );
286 if( p_sys
->url
.psz_username
&& p_sys
->url
.psz_password
&&
287 p_sys
->auth
.psz_nonce
&& p_sys
->auth
.i_nonce
== 0 )
289 Disconnect( p_access
);
292 free( p_sys
->psz_username
);
293 free( p_sys
->psz_password
);
294 p_sys
->psz_username
= p_sys
->psz_password
= NULL
;
296 msg_Dbg( p_access
, "authentication failed for realm %s",
297 p_sys
->auth
.psz_realm
);
299 credential
.psz_realm
= p_sys
->auth
.psz_realm
;
300 credential
.psz_authtype
= p_sys
->auth
.psz_nonce
? "Digest" : "Basic";
302 if( vlc_credential_get( &credential
, p_access
, NULL
, NULL
,
303 _("HTTP authentication"),
304 _("Please enter a valid login name and a "
305 "password for realm %s."), p_sys
->auth
.psz_realm
) )
307 p_sys
->psz_username
= strdup(credential
.psz_username
);
308 p_sys
->psz_password
= strdup(credential
.psz_password
);
309 if (!p_sys
->psz_username
|| !p_sys
->psz_password
)
311 msg_Err( p_access
, "retrying with user=%s", p_sys
->psz_username
);
312 p_sys
->url
.psz_username
= p_sys
->psz_username
;
313 p_sys
->url
.psz_password
= p_sys
->psz_password
;
314 Disconnect( p_access
);
321 vlc_credential_store( &credential
, p_access
);
323 if( ( p_sys
->i_code
== 301 || p_sys
->i_code
== 302 ||
324 p_sys
->i_code
== 303 || p_sys
->i_code
== 307 ) &&
325 p_sys
->psz_location
!= NULL
)
327 p_access
->psz_url
= p_sys
->psz_location
;
328 p_sys
->psz_location
= NULL
;
329 ret
= VLC_ACCESS_REDIRECT
;
333 if( p_sys
->b_reconnect
) msg_Dbg( p_access
, "auto re-connect enabled" );
335 /* Set up p_access */
336 p_access
->pf_read
= Read
;
337 p_access
->pf_control
= Control
;
338 p_access
->pf_seek
= Seek
;
340 vlc_credential_clean( &credential
);
345 Disconnect( p_access
);
348 vlc_credential_clean( &credential
);
349 vlc_UrlClean( &p_sys
->url
);
351 vlc_UrlClean( &p_sys
->proxy
);
352 free( p_sys
->psz_proxy_passbuf
);
353 free( p_sys
->psz_mime
);
354 free( p_sys
->psz_location
);
355 free( p_sys
->psz_user_agent
);
356 free( p_sys
->psz_referrer
);
357 free( p_sys
->psz_username
);
358 free( p_sys
->psz_password
);
363 /*****************************************************************************
365 *****************************************************************************/
366 static void Close( vlc_object_t
*p_this
)
368 stream_t
*p_access
= (stream_t
*)p_this
;
369 access_sys_t
*p_sys
= p_access
->p_sys
;
371 vlc_UrlClean( &p_sys
->url
);
373 vlc_UrlClean( &p_sys
->proxy
);
375 free( p_sys
->psz_mime
);
376 free( p_sys
->psz_location
);
378 free( p_sys
->psz_icy_name
);
379 free( p_sys
->psz_icy_genre
);
380 free( p_sys
->psz_icy_title
);
382 free( p_sys
->psz_user_agent
);
383 free( p_sys
->psz_referrer
);
384 free( p_sys
->psz_username
);
385 free( p_sys
->psz_password
);
387 Disconnect( p_access
);
390 /* Read data from the socket */
391 static int ReadData( stream_t
*p_access
, int *pi_read
,
392 void *p_buffer
, size_t i_len
)
394 access_sys_t
*p_sys
= p_access
->p_sys
;
396 *pi_read
= vlc_recv_i11e( p_sys
->fd
, p_buffer
, i_len
, 0 );
397 if( *pi_read
< 0 && errno
!= EINTR
&& errno
!= EAGAIN
)
402 /*****************************************************************************
403 * Read: Read up to i_len bytes from the http connection and place in
404 * p_buffer. Return the actual number of bytes read
405 *****************************************************************************/
406 static int ReadICYMeta( stream_t
*p_access
);
408 static ssize_t
Read( stream_t
*p_access
, void *p_buffer
, size_t i_len
)
410 access_sys_t
*p_sys
= p_access
->p_sys
;
411 int i_total_read
= 0;
412 int i_remain_toread
= i_len
;
414 if( p_sys
->fd
== -1 )
417 while( i_remain_toread
> 0 )
419 int i_chunk
= i_remain_toread
;
421 if( p_sys
->i_icy_meta
> 0 )
423 if( UINT64_MAX
- i_chunk
< p_sys
->offset
)
424 i_chunk
= i_remain_toread
= UINT64_MAX
- p_sys
->offset
;
426 if( p_sys
->offset
+ i_chunk
> p_sys
->i_icy_offset
)
427 i_chunk
= p_sys
->i_icy_offset
- p_sys
->offset
;
431 if( ReadData( p_access
, &i_read
, &((uint8_t*)p_buffer
)[i_total_read
], i_chunk
) )
435 return -1; /* EINTR / EAGAIN */
439 Disconnect( p_access
);
440 if( p_sys
->b_reconnect
)
442 msg_Dbg( p_access
, "got disconnected, trying to reconnect" );
443 if( Connect( p_access
) )
444 msg_Dbg( p_access
, "reconnection failed" );
451 assert( i_read
>= 0 );
452 p_sys
->offset
+= i_read
;
453 i_total_read
+= i_read
;
454 i_remain_toread
-= i_read
;
456 if( p_sys
->i_icy_meta
> 0 &&
457 p_sys
->offset
== p_sys
->i_icy_offset
)
459 if( ReadICYMeta( p_access
) )
461 p_sys
->i_icy_offset
= p_sys
->offset
+ p_sys
->i_icy_meta
;
468 static int ReadICYMeta( stream_t
*p_access
)
470 access_sys_t
*p_sys
= p_access
->p_sys
;
476 /* Read meta data length */
477 if( ReadData( p_access
, &i_read
, &buffer
, 1 ) )
481 const int i_size
= buffer
<< 4;
482 /* msg_Dbg( p_access, "ICY meta size=%u", i_size); */
484 psz_meta
= malloc( i_size
+ 1 );
485 for( i_read
= 0; i_read
< i_size
; )
488 if( ReadData( p_access
, &i_tmp
, (uint8_t *)&psz_meta
[i_read
], i_size
- i_read
) || i_tmp
<= 0 )
495 psz_meta
[i_read
] = '\0'; /* Just in case */
497 /* msg_Dbg( p_access, "icy-meta=%s", psz_meta ); */
499 /* Now parse the meta */
500 /* Look for StreamTitle= */
501 p
= strcasestr( (char *)psz_meta
, "StreamTitle=" );
504 p
+= strlen( "StreamTitle=" );
505 if( *p
== '\'' || *p
== '"' )
507 char closing
[] = { p
[0], ';', '\0' };
508 char *psz
= strstr( &p
[1], closing
);
510 psz
= strchr( &p
[1], ';' );
512 if( psz
) *psz
= '\0';
517 char *psz
= strchr( p
, ';' );
518 if( psz
) *psz
= '\0';
521 if( !p_sys
->psz_icy_title
||
522 strcmp( p_sys
->psz_icy_title
, p
) )
524 free( p_sys
->psz_icy_title
);
525 char *psz_tmp
= strdup( p
);
526 p_sys
->psz_icy_title
= EnsureUTF8( psz_tmp
);
527 if( !p_sys
->psz_icy_title
)
530 msg_Dbg( p_access
, "New Icy-Title=%s", p_sys
->psz_icy_title
);
531 input_thread_t
*p_input
= p_access
->p_input
;
534 input_item_t
*p_input_item
= input_GetItem( p_access
->p_input
);
536 input_item_SetMeta( p_input_item
, vlc_meta_NowPlaying
, p_sys
->psz_icy_title
);
545 /*****************************************************************************
546 * Seek: close and re-open a connection at the right place
547 *****************************************************************************/
548 static int Seek( stream_t
*p_access
, uint64_t i_pos
)
550 (void) p_access
; (void) i_pos
;
554 /*****************************************************************************
556 *****************************************************************************/
557 static int Control( stream_t
*p_access
, int i_query
, va_list args
)
559 access_sys_t
*p_sys
= p_access
->p_sys
;
566 case STREAM_CAN_SEEK
:
567 case STREAM_CAN_FASTSEEK
:
568 pb_bool
= va_arg( args
, bool* );
571 case STREAM_CAN_PAUSE
:
572 case STREAM_CAN_CONTROL_PACE
:
573 pb_bool
= va_arg( args
, bool* );
578 case STREAM_GET_PTS_DELAY
:
579 pi_64
= va_arg( args
, int64_t * );
580 *pi_64
= INT64_C(1000)
581 * var_InheritInteger( p_access
, "network-caching" );
584 case STREAM_GET_SIZE
:
585 if( !p_sys
->b_has_size
)
587 *va_arg( args
, uint64_t*) = p_sys
->size
;
591 case STREAM_SET_PAUSE_STATE
:
594 case STREAM_GET_CONTENT_TYPE
:
596 char **type
= va_arg( args
, char ** );
598 if( p_sys
->b_icecast
&& p_sys
->psz_mime
== NULL
)
599 *type
= strdup( "audio/mpeg" );
600 else if( !strcasecmp( p_access
->psz_name
, "itpc" ) )
601 *type
= strdup( "application/rss+xml" );
602 else if( !strcasecmp( p_access
->psz_name
, "unsv" ) &&
603 p_sys
->psz_mime
!= NULL
&&
604 !strcasecmp( p_sys
->psz_mime
, "misc/ultravox" ) )
605 /* Grrrr! detect ultravox server and force NSV demuxer */
606 *type
= strdup( "video/nsa" );
607 else if( p_sys
->psz_mime
)
608 *type
= strdup( p_sys
->psz_mime
);
621 /*****************************************************************************
623 *****************************************************************************/
624 static int Connect( stream_t
*p_access
)
626 access_sys_t
*p_sys
= p_access
->p_sys
;
627 vlc_url_t srv
= p_sys
->b_proxy
? p_sys
->proxy
: p_sys
->url
;
631 free( p_sys
->psz_location
);
632 free( p_sys
->psz_mime
);
634 free( p_sys
->psz_icy_genre
);
635 free( p_sys
->psz_icy_name
);
636 free( p_sys
->psz_icy_title
);
638 vlc_http_auth_Init( &p_sys
->auth
);
639 vlc_http_auth_Init( &p_sys
->proxy_auth
);
640 p_sys
->psz_location
= NULL
;
641 p_sys
->psz_mime
= NULL
;
642 p_sys
->i_icy_meta
= 0;
643 p_sys
->i_icy_offset
= 0;
644 p_sys
->psz_icy_name
= NULL
;
645 p_sys
->psz_icy_genre
= NULL
;
646 p_sys
->psz_icy_title
= NULL
;
647 p_sys
->b_has_size
= false;
651 struct vlc_memstream stream
;
653 vlc_memstream_open(&stream
);
655 vlc_memstream_puts(&stream
, "GET ");
657 vlc_memstream_printf( &stream
, "http://%s:%d",
658 p_sys
->url
.psz_host
, p_sys
->url
.i_port
);
659 if( p_sys
->url
.psz_path
== NULL
|| p_sys
->url
.psz_path
[0] == '\0' )
660 vlc_memstream_putc( &stream
, '/' );
662 vlc_memstream_puts( &stream
, p_sys
->url
.psz_path
);
663 if( p_sys
->url
.psz_option
!= NULL
)
664 vlc_memstream_printf( &stream
, "?%s", p_sys
->url
.psz_option
);
665 vlc_memstream_puts( &stream
, " HTTP/1.0\r\n" );
667 vlc_memstream_printf( &stream
, "Host: %s", p_sys
->url
.psz_host
);
668 if( p_sys
->url
.i_port
!= 80 )
669 vlc_memstream_printf( &stream
, ":%d", p_sys
->url
.i_port
);
670 vlc_memstream_puts( &stream
, "\r\n" );
673 vlc_memstream_printf( &stream
, "User-Agent: %s\r\n",
674 p_sys
->psz_user_agent
);
676 if (p_sys
->psz_referrer
)
677 vlc_memstream_printf( &stream
, "Referer: %s\r\n",
678 p_sys
->psz_referrer
);
681 if( p_sys
->url
.psz_username
!= NULL
&& p_sys
->url
.psz_password
!= NULL
)
685 auth
= vlc_http_auth_FormatAuthorizationHeader( VLC_OBJECT(p_access
),
686 &p_sys
->auth
, "GET", p_sys
->url
.psz_path
,
687 p_sys
->url
.psz_username
, p_sys
->url
.psz_password
);
689 vlc_memstream_printf( &stream
, "Authorization: %s\r\n", auth
);
693 /* Proxy Authentication */
694 if( p_sys
->b_proxy
&& p_sys
->proxy
.psz_username
!= NULL
695 && p_sys
->proxy
.psz_password
!= NULL
)
699 auth
= vlc_http_auth_FormatAuthorizationHeader( VLC_OBJECT(p_access
),
700 &p_sys
->proxy_auth
, "GET", p_sys
->url
.psz_path
,
701 p_sys
->proxy
.psz_username
, p_sys
->proxy
.psz_password
);
703 vlc_memstream_printf( &stream
, "Proxy-Authorization: %s\r\n",
708 /* ICY meta data request */
709 vlc_memstream_puts( &stream
, "Icy-MetaData: 1\r\n" );
711 vlc_memstream_puts( &stream
, "\r\n" );
713 if( vlc_memstream_close( &stream
) )
716 /* Open connection */
717 assert( p_sys
->fd
== -1 ); /* No open sockets (leaking fds is BAD) */
718 p_sys
->fd
= net_ConnectTCP( p_access
, srv
.psz_host
, srv
.i_port
);
719 if( p_sys
->fd
== -1 )
721 msg_Err( p_access
, "cannot connect to %s:%d", srv
.psz_host
, srv
.i_port
);
725 setsockopt (p_sys
->fd
, SOL_SOCKET
, SO_KEEPALIVE
, &(int){ 1 }, sizeof (int));
727 msg_Dbg( p_access
, "sending request:\n%s", stream
.ptr
);
728 val
= net_Write( p_access
, p_sys
->fd
, stream
.ptr
, stream
.length
);
731 if( val
< (ssize_t
)stream
.length
)
733 msg_Err( p_access
, "failed to send request" );
734 Disconnect( p_access
);
739 char *psz
= net_Gets( p_access
, p_sys
->fd
);
742 msg_Err( p_access
, "failed to read answer" );
745 if( !strncmp( psz
, "HTTP/1.", 7 ) )
747 p_sys
->i_code
= atoi( &psz
[9] );
748 msg_Dbg( p_access
, "HTTP answer code %d", p_sys
->i_code
);
750 else if( !strncmp( psz
, "ICY", 3 ) )
752 p_sys
->i_code
= atoi( &psz
[4] );
753 msg_Dbg( p_access
, "ICY answer code %d", p_sys
->i_code
);
754 p_sys
->b_icecast
= true;
755 p_sys
->b_reconnect
= true;
759 msg_Err( p_access
, "invalid HTTP reply '%s'", psz
);
763 /* Authentication error - We'll have to display the dialog */
764 if( p_sys
->i_code
== 401 )
768 /* Other fatal error */
769 else if( p_sys
->i_code
>= 400 )
771 msg_Err( p_access
, "error: %s", psz
);
779 char *p
, *p_trailing
;
781 psz
= net_Gets( p_access
, p_sys
->fd
);
784 msg_Err( p_access
, "failed to read answer" );
788 /* msg_Dbg( p_input, "Line=%s", psz ); */
795 if( ( p
= strchr( psz
, ':' ) ) == NULL
)
797 msg_Err( p_access
, "malformed header line: %s", psz
);
802 p
+= strspn( p
, " \t" );
804 /* trim trailing white space */
805 p_trailing
= p
+ strlen( p
);
809 while( ( *p_trailing
== ' ' || *p_trailing
== '\t' ) && p_trailing
> p
)
816 if( !strcasecmp( psz
, "Content-Length" ) )
818 uint64_t i_size
= (uint64_t)atoll( p
);
819 if(i_size
> p_sys
->size
) {
820 p_sys
->b_has_size
= true;
821 p_sys
->size
= i_size
;
824 else if( !strcasecmp( psz
, "Location" ) )
828 /* This does not follow RFC 2068, but yet if the url is not absolute,
829 * handle it as everyone does. */
832 if( p_sys
->url
.i_port
== 80 )
834 if( asprintf(&psz_new_loc
, "http://%s%s",
835 p_sys
->url
.psz_host
, p
) < 0 )
840 if( asprintf(&psz_new_loc
, "http://%s:%d%s",
841 p_sys
->url
.psz_host
, p_sys
->url
.i_port
, p
) < 0 )
847 psz_new_loc
= strdup( p
);
850 free( p_sys
->psz_location
);
851 p_sys
->psz_location
= psz_new_loc
;
853 else if( !strcasecmp( psz
, "Content-Type" ) )
855 free( p_sys
->psz_mime
);
856 p_sys
->psz_mime
= strdup( p
);
857 msg_Dbg( p_access
, "Content-Type: %s", p_sys
->psz_mime
);
859 else if( !strcasecmp( psz
, "Content-Encoding" ) )
861 msg_Dbg( p_access
, "Content-Encoding: %s", p
);
863 else if( !strcasecmp( psz
, "Server" ) )
865 msg_Dbg( p_access
, "Server: %s", p
);
866 if( !strncasecmp( p
, "Icecast", 7 ) ||
867 !strncasecmp( p
, "Nanocaster", 10 ) )
869 /* Remember if this is Icecast
870 * we need to force demux in this case without breaking
873 /* Let live 365 streams (nanocaster) piggyback on the icecast
874 * routine. They look very similar */
876 p_sys
->b_reconnect
= true;
877 p_sys
->b_icecast
= true;
880 else if( !strcasecmp( psz
, "Icy-MetaInt" ) )
882 msg_Dbg( p_access
, "Icy-MetaInt: %s", p
);
883 p_sys
->i_icy_meta
= atoi( p
);
884 if( p_sys
->i_icy_meta
< 0 )
885 p_sys
->i_icy_meta
= 0;
886 if( p_sys
->i_icy_meta
> 1 )
888 p_sys
->i_icy_offset
= p_sys
->i_icy_meta
;
889 p_sys
->b_icecast
= true;
892 msg_Warn( p_access
, "ICY metaint=%d", p_sys
->i_icy_meta
);
894 else if( !strcasecmp( psz
, "Icy-Name" ) )
896 free( p_sys
->psz_icy_name
);
897 char *psz_tmp
= strdup( p
);
898 p_sys
->psz_icy_name
= EnsureUTF8( psz_tmp
);
899 if( !p_sys
->psz_icy_name
)
902 vlc_xml_decode( p_sys
->psz_icy_name
);
903 msg_Dbg( p_access
, "Icy-Name: %s", p_sys
->psz_icy_name
);
904 input_thread_t
*p_input
= p_access
->p_input
;
907 input_item_t
*p_input_item
= input_GetItem( p_access
->p_input
);
909 input_item_SetMeta( p_input_item
, vlc_meta_Title
, p_sys
->psz_icy_name
);
912 p_sys
->b_icecast
= true; /* be on the safeside. set it here as well. */
913 p_sys
->b_reconnect
= true;
915 else if( !strcasecmp( psz
, "Icy-Genre" ) )
917 free( p_sys
->psz_icy_genre
);
918 char *psz_tmp
= strdup( p
);
919 p_sys
->psz_icy_genre
= EnsureUTF8( psz_tmp
);
920 if( !p_sys
->psz_icy_genre
)
923 vlc_xml_decode( p_sys
->psz_icy_genre
);
924 msg_Dbg( p_access
, "Icy-Genre: %s", p_sys
->psz_icy_genre
);
925 input_thread_t
*p_input
= p_access
->p_input
;
928 input_item_t
*p_input_item
= input_GetItem( p_access
->p_input
);
930 input_item_SetMeta( p_input_item
, vlc_meta_Genre
, p_sys
->psz_icy_genre
);
933 else if( !strncasecmp( psz
, "Icy-Notice", 10 ) )
935 msg_Dbg( p_access
, "Icy-Notice: %s", p
);
937 else if( !strncasecmp( psz
, "icy-", 4 ) ||
938 !strncasecmp( psz
, "ice-", 4 ) ||
939 !strncasecmp( psz
, "x-audiocast", 11 ) )
941 msg_Dbg( p_access
, "Meta-Info: %s: %s", psz
, p
);
943 else if( !strcasecmp( psz
, "www-authenticate" ) )
945 msg_Dbg( p_access
, "Authentication header: %s", p
);
946 vlc_http_auth_ParseWwwAuthenticateHeader( VLC_OBJECT(p_access
),
949 else if( !strcasecmp( psz
, "proxy-authenticate" ) )
951 msg_Dbg( p_access
, "Proxy authentication header: %s", p
);
952 vlc_http_auth_ParseWwwAuthenticateHeader( VLC_OBJECT(p_access
),
953 &p_sys
->proxy_auth
, p
);
955 else if( !strcasecmp( psz
, "authentication-info" ) )
957 msg_Dbg( p_access
, "Authentication Info header: %s", p
);
958 if( AuthCheckReply( p_access
, p
, &p_sys
->url
, &p_sys
->auth
) )
961 else if( !strcasecmp( psz
, "proxy-authentication-info" ) )
963 msg_Dbg( p_access
, "Proxy Authentication Info header: %s", p
);
964 if( AuthCheckReply( p_access
, p
, &p_sys
->proxy
, &p_sys
->proxy_auth
) )
973 Disconnect( p_access
);
977 /*****************************************************************************
979 *****************************************************************************/
980 static void Disconnect( stream_t
*p_access
)
982 access_sys_t
*p_sys
= p_access
->p_sys
;
985 net_Close(p_sys
->fd
);
988 vlc_http_auth_Deinit( &p_sys
->auth
);
989 vlc_http_auth_Deinit( &p_sys
->proxy_auth
);
992 /*****************************************************************************
993 * HTTP authentication
994 *****************************************************************************/
996 static int AuthCheckReply( stream_t
*p_access
, const char *psz_header
,
997 vlc_url_t
*p_url
, vlc_http_auth_t
*p_auth
)
1000 vlc_http_auth_ParseAuthenticationInfoHeader( VLC_OBJECT(p_access
),
1004 p_url
->psz_username
,
1005 p_url
->psz_password
);