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
;
412 if( p_sys
->fd
== -1 )
417 if( p_sys
->i_icy_meta
> 0 )
419 if( UINT64_MAX
- i_chunk
< p_sys
->offset
)
420 i_chunk
= UINT64_MAX
- p_sys
->offset
;
422 if( p_sys
->offset
+ i_chunk
> p_sys
->i_icy_offset
)
423 i_chunk
= p_sys
->i_icy_offset
- p_sys
->offset
;
427 if( ReadData( p_access
, &i_read
, (uint8_t*)p_buffer
, i_chunk
) )
431 return -1; /* EINTR / EAGAIN */
435 Disconnect( p_access
);
436 if( p_sys
->b_reconnect
)
438 msg_Dbg( p_access
, "got disconnected, trying to reconnect" );
439 if( Connect( p_access
) )
440 msg_Dbg( p_access
, "reconnection failed" );
447 assert( i_read
>= 0 );
448 p_sys
->offset
+= i_read
;
450 if( p_sys
->i_icy_meta
> 0 &&
451 p_sys
->offset
== p_sys
->i_icy_offset
)
453 if( ReadICYMeta( p_access
) )
455 p_sys
->i_icy_offset
= p_sys
->offset
+ p_sys
->i_icy_meta
;
461 static int ReadICYMeta( stream_t
*p_access
)
463 access_sys_t
*p_sys
= p_access
->p_sys
;
469 /* Read meta data length */
470 if( ReadData( p_access
, &i_read
, &buffer
, 1 ) )
474 const int i_size
= buffer
<< 4;
475 /* msg_Dbg( p_access, "ICY meta size=%u", i_size); */
477 psz_meta
= malloc( i_size
+ 1 );
478 for( i_read
= 0; i_read
< i_size
; )
481 if( ReadData( p_access
, &i_tmp
, (uint8_t *)&psz_meta
[i_read
], i_size
- i_read
) || i_tmp
<= 0 )
488 psz_meta
[i_read
] = '\0'; /* Just in case */
490 /* msg_Dbg( p_access, "icy-meta=%s", psz_meta ); */
492 /* Now parse the meta */
493 /* Look for StreamTitle= */
494 p
= strcasestr( (char *)psz_meta
, "StreamTitle=" );
497 p
+= strlen( "StreamTitle=" );
498 if( *p
== '\'' || *p
== '"' )
500 char closing
[] = { p
[0], ';', '\0' };
501 char *psz
= strstr( &p
[1], closing
);
503 psz
= strchr( &p
[1], ';' );
505 if( psz
) *psz
= '\0';
510 char *psz
= strchr( p
, ';' );
511 if( psz
) *psz
= '\0';
514 if( !p_sys
->psz_icy_title
||
515 strcmp( p_sys
->psz_icy_title
, p
) )
517 free( p_sys
->psz_icy_title
);
518 char *psz_tmp
= strdup( p
);
519 p_sys
->psz_icy_title
= EnsureUTF8( psz_tmp
);
520 if( !p_sys
->psz_icy_title
)
523 msg_Dbg( p_access
, "New Icy-Title=%s", p_sys
->psz_icy_title
);
524 input_thread_t
*p_input
= p_access
->p_input
;
527 input_item_t
*p_input_item
= input_GetItem( p_access
->p_input
);
529 input_item_SetMeta( p_input_item
, vlc_meta_NowPlaying
, p_sys
->psz_icy_title
);
538 /*****************************************************************************
539 * Seek: close and re-open a connection at the right place
540 *****************************************************************************/
541 static int Seek( stream_t
*p_access
, uint64_t i_pos
)
543 (void) p_access
; (void) i_pos
;
547 /*****************************************************************************
549 *****************************************************************************/
550 static int Control( stream_t
*p_access
, int i_query
, va_list args
)
552 access_sys_t
*p_sys
= p_access
->p_sys
;
559 case STREAM_CAN_SEEK
:
560 case STREAM_CAN_FASTSEEK
:
561 pb_bool
= va_arg( args
, bool* );
564 case STREAM_CAN_PAUSE
:
565 case STREAM_CAN_CONTROL_PACE
:
566 pb_bool
= va_arg( args
, bool* );
571 case STREAM_GET_PTS_DELAY
:
572 pi_64
= va_arg( args
, int64_t * );
573 *pi_64
= INT64_C(1000)
574 * var_InheritInteger( p_access
, "network-caching" );
577 case STREAM_GET_SIZE
:
578 if( !p_sys
->b_has_size
)
580 *va_arg( args
, uint64_t*) = p_sys
->size
;
584 case STREAM_SET_PAUSE_STATE
:
587 case STREAM_GET_CONTENT_TYPE
:
589 char **type
= va_arg( args
, char ** );
591 if( p_sys
->b_icecast
&& p_sys
->psz_mime
== NULL
)
592 *type
= strdup( "audio/mpeg" );
593 else if( !strcasecmp( p_access
->psz_name
, "itpc" ) )
594 *type
= strdup( "application/rss+xml" );
595 else if( !strcasecmp( p_access
->psz_name
, "unsv" ) &&
596 p_sys
->psz_mime
!= NULL
&&
597 !strcasecmp( p_sys
->psz_mime
, "misc/ultravox" ) )
598 /* Grrrr! detect ultravox server and force NSV demuxer */
599 *type
= strdup( "video/nsa" );
600 else if( p_sys
->psz_mime
)
601 *type
= strdup( p_sys
->psz_mime
);
614 /*****************************************************************************
616 *****************************************************************************/
617 static int Connect( stream_t
*p_access
)
619 access_sys_t
*p_sys
= p_access
->p_sys
;
620 vlc_url_t srv
= p_sys
->b_proxy
? p_sys
->proxy
: p_sys
->url
;
624 free( p_sys
->psz_location
);
625 free( p_sys
->psz_mime
);
627 free( p_sys
->psz_icy_genre
);
628 free( p_sys
->psz_icy_name
);
629 free( p_sys
->psz_icy_title
);
631 vlc_http_auth_Init( &p_sys
->auth
);
632 vlc_http_auth_Init( &p_sys
->proxy_auth
);
633 p_sys
->psz_location
= NULL
;
634 p_sys
->psz_mime
= NULL
;
635 p_sys
->i_icy_meta
= 0;
636 p_sys
->i_icy_offset
= 0;
637 p_sys
->psz_icy_name
= NULL
;
638 p_sys
->psz_icy_genre
= NULL
;
639 p_sys
->psz_icy_title
= NULL
;
640 p_sys
->b_has_size
= false;
644 struct vlc_memstream stream
;
646 vlc_memstream_open(&stream
);
648 vlc_memstream_puts(&stream
, "GET ");
650 vlc_memstream_printf( &stream
, "http://%s:%d",
651 p_sys
->url
.psz_host
, p_sys
->url
.i_port
);
652 if( p_sys
->url
.psz_path
== NULL
|| p_sys
->url
.psz_path
[0] == '\0' )
653 vlc_memstream_putc( &stream
, '/' );
655 vlc_memstream_puts( &stream
, p_sys
->url
.psz_path
);
656 if( p_sys
->url
.psz_option
!= NULL
)
657 vlc_memstream_printf( &stream
, "?%s", p_sys
->url
.psz_option
);
658 vlc_memstream_puts( &stream
, " HTTP/1.0\r\n" );
660 vlc_memstream_printf( &stream
, "Host: %s", p_sys
->url
.psz_host
);
661 if( p_sys
->url
.i_port
!= 80 )
662 vlc_memstream_printf( &stream
, ":%d", p_sys
->url
.i_port
);
663 vlc_memstream_puts( &stream
, "\r\n" );
666 vlc_memstream_printf( &stream
, "User-Agent: %s\r\n",
667 p_sys
->psz_user_agent
);
669 if (p_sys
->psz_referrer
)
670 vlc_memstream_printf( &stream
, "Referer: %s\r\n",
671 p_sys
->psz_referrer
);
674 if( p_sys
->url
.psz_username
!= NULL
&& p_sys
->url
.psz_password
!= NULL
)
678 auth
= vlc_http_auth_FormatAuthorizationHeader( VLC_OBJECT(p_access
),
679 &p_sys
->auth
, "GET", p_sys
->url
.psz_path
,
680 p_sys
->url
.psz_username
, p_sys
->url
.psz_password
);
682 vlc_memstream_printf( &stream
, "Authorization: %s\r\n", auth
);
686 /* Proxy Authentication */
687 if( p_sys
->b_proxy
&& p_sys
->proxy
.psz_username
!= NULL
688 && p_sys
->proxy
.psz_password
!= NULL
)
692 auth
= vlc_http_auth_FormatAuthorizationHeader( VLC_OBJECT(p_access
),
693 &p_sys
->proxy_auth
, "GET", p_sys
->url
.psz_path
,
694 p_sys
->proxy
.psz_username
, p_sys
->proxy
.psz_password
);
696 vlc_memstream_printf( &stream
, "Proxy-Authorization: %s\r\n",
701 /* ICY meta data request */
702 vlc_memstream_puts( &stream
, "Icy-MetaData: 1\r\n" );
704 vlc_memstream_puts( &stream
, "\r\n" );
706 if( vlc_memstream_close( &stream
) )
709 /* Open connection */
710 assert( p_sys
->fd
== -1 ); /* No open sockets (leaking fds is BAD) */
711 p_sys
->fd
= net_ConnectTCP( p_access
, srv
.psz_host
, srv
.i_port
);
712 if( p_sys
->fd
== -1 )
714 msg_Err( p_access
, "cannot connect to %s:%d", srv
.psz_host
, srv
.i_port
);
718 setsockopt (p_sys
->fd
, SOL_SOCKET
, SO_KEEPALIVE
, &(int){ 1 }, sizeof (int));
720 msg_Dbg( p_access
, "sending request:\n%s", stream
.ptr
);
721 val
= net_Write( p_access
, p_sys
->fd
, stream
.ptr
, stream
.length
);
724 if( val
< (ssize_t
)stream
.length
)
726 msg_Err( p_access
, "failed to send request" );
727 Disconnect( p_access
);
732 char *psz
= net_Gets( p_access
, p_sys
->fd
);
735 msg_Err( p_access
, "failed to read answer" );
738 if( !strncmp( psz
, "HTTP/1.", 7 ) )
740 p_sys
->i_code
= atoi( &psz
[9] );
741 msg_Dbg( p_access
, "HTTP answer code %d", p_sys
->i_code
);
743 else if( !strncmp( psz
, "ICY", 3 ) )
745 p_sys
->i_code
= atoi( &psz
[4] );
746 msg_Dbg( p_access
, "ICY answer code %d", p_sys
->i_code
);
747 p_sys
->b_icecast
= true;
748 p_sys
->b_reconnect
= true;
752 msg_Err( p_access
, "invalid HTTP reply '%s'", psz
);
756 /* Authentication error - We'll have to display the dialog */
757 if( p_sys
->i_code
== 401 )
761 /* Other fatal error */
762 else if( p_sys
->i_code
>= 400 )
764 msg_Err( p_access
, "error: %s", psz
);
772 char *p
, *p_trailing
;
774 psz
= net_Gets( p_access
, p_sys
->fd
);
777 msg_Err( p_access
, "failed to read answer" );
781 /* msg_Dbg( p_input, "Line=%s", psz ); */
788 if( ( p
= strchr( psz
, ':' ) ) == NULL
)
790 msg_Err( p_access
, "malformed header line: %s", psz
);
795 p
+= strspn( p
, " \t" );
797 /* trim trailing white space */
798 p_trailing
= p
+ strlen( p
);
802 while( ( *p_trailing
== ' ' || *p_trailing
== '\t' ) && p_trailing
> p
)
809 if( !strcasecmp( psz
, "Content-Length" ) )
811 uint64_t i_size
= (uint64_t)atoll( p
);
812 if(i_size
> p_sys
->size
) {
813 p_sys
->b_has_size
= true;
814 p_sys
->size
= i_size
;
817 else if( !strcasecmp( psz
, "Location" ) )
821 /* This does not follow RFC 2068, but yet if the url is not absolute,
822 * handle it as everyone does. */
825 if( p_sys
->url
.i_port
== 80 )
827 if( asprintf(&psz_new_loc
, "http://%s%s",
828 p_sys
->url
.psz_host
, p
) < 0 )
833 if( asprintf(&psz_new_loc
, "http://%s:%d%s",
834 p_sys
->url
.psz_host
, p_sys
->url
.i_port
, p
) < 0 )
840 psz_new_loc
= strdup( p
);
843 free( p_sys
->psz_location
);
844 p_sys
->psz_location
= psz_new_loc
;
846 else if( !strcasecmp( psz
, "Content-Type" ) )
848 free( p_sys
->psz_mime
);
849 p_sys
->psz_mime
= strdup( p
);
850 msg_Dbg( p_access
, "Content-Type: %s", p_sys
->psz_mime
);
852 else if( !strcasecmp( psz
, "Content-Encoding" ) )
854 msg_Dbg( p_access
, "Content-Encoding: %s", p
);
856 else if( !strcasecmp( psz
, "Server" ) )
858 msg_Dbg( p_access
, "Server: %s", p
);
859 if( !strncasecmp( p
, "Icecast", 7 ) ||
860 !strncasecmp( p
, "Nanocaster", 10 ) )
862 /* Remember if this is Icecast
863 * we need to force demux in this case without breaking
866 /* Let live 365 streams (nanocaster) piggyback on the icecast
867 * routine. They look very similar */
869 p_sys
->b_reconnect
= true;
870 p_sys
->b_icecast
= true;
873 else if( !strcasecmp( psz
, "Icy-MetaInt" ) )
875 msg_Dbg( p_access
, "Icy-MetaInt: %s", p
);
876 p_sys
->i_icy_meta
= atoi( p
);
877 if( p_sys
->i_icy_meta
< 0 )
878 p_sys
->i_icy_meta
= 0;
879 if( p_sys
->i_icy_meta
> 1 )
881 p_sys
->i_icy_offset
= p_sys
->i_icy_meta
;
882 p_sys
->b_icecast
= true;
885 msg_Warn( p_access
, "ICY metaint=%d", p_sys
->i_icy_meta
);
887 else if( !strcasecmp( psz
, "Icy-Name" ) )
889 free( p_sys
->psz_icy_name
);
890 char *psz_tmp
= strdup( p
);
891 p_sys
->psz_icy_name
= EnsureUTF8( psz_tmp
);
892 if( !p_sys
->psz_icy_name
)
895 vlc_xml_decode( p_sys
->psz_icy_name
);
896 msg_Dbg( p_access
, "Icy-Name: %s", p_sys
->psz_icy_name
);
897 input_thread_t
*p_input
= p_access
->p_input
;
900 input_item_t
*p_input_item
= input_GetItem( p_access
->p_input
);
902 input_item_SetMeta( p_input_item
, vlc_meta_Title
, p_sys
->psz_icy_name
);
905 p_sys
->b_icecast
= true; /* be on the safeside. set it here as well. */
906 p_sys
->b_reconnect
= true;
908 else if( !strcasecmp( psz
, "Icy-Genre" ) )
910 free( p_sys
->psz_icy_genre
);
911 char *psz_tmp
= strdup( p
);
912 p_sys
->psz_icy_genre
= EnsureUTF8( psz_tmp
);
913 if( !p_sys
->psz_icy_genre
)
916 vlc_xml_decode( p_sys
->psz_icy_genre
);
917 msg_Dbg( p_access
, "Icy-Genre: %s", p_sys
->psz_icy_genre
);
918 input_thread_t
*p_input
= p_access
->p_input
;
921 input_item_t
*p_input_item
= input_GetItem( p_access
->p_input
);
923 input_item_SetMeta( p_input_item
, vlc_meta_Genre
, p_sys
->psz_icy_genre
);
926 else if( !strncasecmp( psz
, "Icy-Notice", 10 ) )
928 msg_Dbg( p_access
, "Icy-Notice: %s", p
);
930 else if( !strncasecmp( psz
, "icy-", 4 ) ||
931 !strncasecmp( psz
, "ice-", 4 ) ||
932 !strncasecmp( psz
, "x-audiocast", 11 ) )
934 msg_Dbg( p_access
, "Meta-Info: %s: %s", psz
, p
);
936 else if( !strcasecmp( psz
, "www-authenticate" ) )
938 msg_Dbg( p_access
, "Authentication header: %s", p
);
939 vlc_http_auth_ParseWwwAuthenticateHeader( VLC_OBJECT(p_access
),
942 else if( !strcasecmp( psz
, "proxy-authenticate" ) )
944 msg_Dbg( p_access
, "Proxy authentication header: %s", p
);
945 vlc_http_auth_ParseWwwAuthenticateHeader( VLC_OBJECT(p_access
),
946 &p_sys
->proxy_auth
, p
);
948 else if( !strcasecmp( psz
, "authentication-info" ) )
950 msg_Dbg( p_access
, "Authentication Info header: %s", p
);
951 if( AuthCheckReply( p_access
, p
, &p_sys
->url
, &p_sys
->auth
) )
954 else if( !strcasecmp( psz
, "proxy-authentication-info" ) )
956 msg_Dbg( p_access
, "Proxy Authentication Info header: %s", p
);
957 if( AuthCheckReply( p_access
, p
, &p_sys
->proxy
, &p_sys
->proxy_auth
) )
966 Disconnect( p_access
);
970 /*****************************************************************************
972 *****************************************************************************/
973 static void Disconnect( stream_t
*p_access
)
975 access_sys_t
*p_sys
= p_access
->p_sys
;
978 net_Close(p_sys
->fd
);
981 vlc_http_auth_Deinit( &p_sys
->auth
);
982 vlc_http_auth_Deinit( &p_sys
->proxy_auth
);
985 /*****************************************************************************
986 * HTTP authentication
987 *****************************************************************************/
989 static int AuthCheckReply( stream_t
*p_access
, const char *psz_header
,
990 vlc_url_t
*p_url
, vlc_http_auth_t
*p_auth
)
993 vlc_http_auth_ParseAuthenticationInfoHeader( VLC_OBJECT(p_access
),
998 p_url
->psz_password
);