1 /*****************************************************************************
2 * http.c: HTTP input module
3 *****************************************************************************
4 * Copyright (C) 2001-2008 VLC authors and VideoLAN
6 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
7 * Christophe Massiot <massiot@via.ecp.fr>
9 * Antoine Cellerier <dionoea at videolan dot org>
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation; either version 2.1 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public License
22 * along with this program; if not, write to the Free Software Foundation,
23 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24 *****************************************************************************/
26 /*****************************************************************************
28 *****************************************************************************/
34 #define MODULE_STRING "oldhttp"
38 #include <vlc_common.h>
39 #include <vlc_plugin.h>
40 #include <vlc_access.h>
44 #include <vlc_strings.h>
45 #include <vlc_charset.h>
46 #include <vlc_input_item.h>
48 #include <vlc_interrupt.h>
49 #include <vlc_keystore.h>
50 #include <vlc_memstream.h>
55 /*****************************************************************************
57 *****************************************************************************/
58 static int Open ( vlc_object_t
* );
59 static void Close( vlc_object_t
* );
61 #define RECONNECT_TEXT N_("Auto re-connect")
62 #define RECONNECT_LONGTEXT N_( \
63 "Automatically try to reconnect to the stream in case of a sudden " \
67 set_description( N_("HTTP input") )
68 set_capability( "access", 0 )
69 set_shortname( N_( "HTTP(S)" ) )
70 set_category( CAT_INPUT
)
71 set_subcategory( SUBCAT_INPUT_ACCESS
)
73 add_bool( "http-reconnect", false, RECONNECT_TEXT
,
74 RECONNECT_LONGTEXT
, true )
75 /* 'itpc' = iTunes Podcast */
76 add_shortcut( "http", "unsv", "itpc", "icyx" )
77 set_callbacks( Open
, Close
)
80 /*****************************************************************************
82 *****************************************************************************/
99 vlc_http_auth_t proxy_auth
;
100 char *psz_proxy_passbuf
;
110 uint64_t i_icy_offset
;
123 static ssize_t
Read( stream_t
*, void *, size_t );
124 static int Seek( stream_t
*, uint64_t );
125 static int Control( stream_t
*, int, va_list );
128 static int Connect( stream_t
* );
129 static void Disconnect( stream_t
* );
132 static int AuthCheckReply( stream_t
*p_access
, const char *psz_header
,
133 vlc_url_t
*p_url
, vlc_http_auth_t
*p_auth
);
135 /*****************************************************************************
137 *****************************************************************************/
138 static int Open( vlc_object_t
*p_this
)
140 stream_t
*p_access
= (stream_t
*)p_this
;
141 const char *psz_url
= p_access
->psz_url
;
143 int ret
= VLC_EGENERIC
;
144 vlc_credential credential
;
146 access_sys_t
*p_sys
= vlc_obj_malloc( p_this
, sizeof(*p_sys
) );
147 if( unlikely(p_sys
== NULL
) )
150 p_sys
->stream
= NULL
;
151 p_sys
->b_proxy
= false;
152 p_sys
->psz_proxy_passbuf
= NULL
;
153 p_sys
->psz_mime
= NULL
;
154 p_sys
->b_icecast
= false;
155 p_sys
->psz_location
= NULL
;
156 p_sys
->psz_user_agent
= NULL
;
157 p_sys
->psz_referrer
= NULL
;
158 p_sys
->psz_username
= NULL
;
159 p_sys
->psz_password
= NULL
;
160 p_sys
->i_icy_meta
= 0;
161 p_sys
->i_icy_offset
= 0;
162 p_sys
->psz_icy_name
= NULL
;
163 p_sys
->psz_icy_genre
= NULL
;
164 p_sys
->psz_icy_title
= NULL
;
165 p_sys
->b_has_size
= false;
168 p_access
->p_sys
= p_sys
;
170 if( vlc_UrlParse( &p_sys
->url
, psz_url
) || p_sys
->url
.psz_host
== NULL
)
172 msg_Err( p_access
, "invalid URL" );
173 vlc_UrlClean( &p_sys
->url
);
176 if( p_sys
->url
.i_port
<= 0 )
177 p_sys
->url
.i_port
= 80;
179 vlc_credential_init( &credential
, &p_sys
->url
);
181 /* Determine the HTTP user agent */
182 /* See RFC2616 §2.2 token and comment definition, and §3.8 and
183 * §14.43 user-agent header */
184 p_sys
->psz_user_agent
= var_InheritString( p_access
, "http-user-agent" );
185 if (p_sys
->psz_user_agent
)
187 unsigned comment_level
= 0;
188 for( char *p
= p_sys
->psz_user_agent
; *p
; p
++ )
191 if (comment_level
== 0)
193 if( c
< 32 || strchr( ")<>@,;:\\\"[]?={}", c
) )
194 *p
= '_'; /* remove potentially harmful characters */
200 else if( c
< 32 && strchr( "\t\r\n", c
) == NULL
)
201 *p
= '_'; /* remove potentially harmful characters */
205 if (comment_level
== UINT_MAX
)
210 /* truncate evil unclosed comments */
211 if (comment_level
> 0)
213 char *p
= strchr(p_sys
->psz_user_agent
, '(');
219 p_sys
->psz_referrer
= var_InheritString( p_access
, "http-referrer" );
222 psz
= var_InheritString( p_access
, "http-proxy" );
225 msg_Dbg(p_access
, "querying proxy for %s", psz_url
);
226 psz
= vlc_getProxyUrl(psz_url
);
229 msg_Dbg(p_access
, "proxy: %s", psz
);
231 msg_Dbg(p_access
, "no proxy");
235 p_sys
->b_proxy
= true;
236 vlc_UrlParse( &p_sys
->proxy
, psz
);
239 psz
= var_InheritString( p_access
, "http-proxy-pwd" );
241 p_sys
->proxy
.psz_password
= p_sys
->psz_proxy_passbuf
= psz
;
243 if( p_sys
->proxy
.psz_host
== NULL
|| *p_sys
->proxy
.psz_host
== '\0' )
245 msg_Warn( p_access
, "invalid proxy host" );
248 if( p_sys
->proxy
.i_port
<= 0 )
250 p_sys
->proxy
.i_port
= 80;
254 msg_Dbg( p_access
, "http: server='%s' port=%d file='%s'",
255 p_sys
->url
.psz_host
, p_sys
->url
.i_port
,
256 p_sys
->url
.psz_path
!= NULL
? p_sys
->url
.psz_path
: "" );
259 msg_Dbg( p_access
, " proxy %s:%d", p_sys
->proxy
.psz_host
,
260 p_sys
->proxy
.i_port
);
262 if( p_sys
->url
.psz_username
&& *p_sys
->url
.psz_username
)
264 msg_Dbg( p_access
, " user='%s'", p_sys
->url
.psz_username
);
267 p_sys
->b_reconnect
= var_InheritBool( p_access
, "http-reconnect" );
269 if( vlc_credential_get( &credential
, p_access
, NULL
, NULL
, NULL
, NULL
) )
271 p_sys
->url
.psz_username
= (char *) credential
.psz_username
;
272 p_sys
->url
.psz_password
= (char *) credential
.psz_password
;
277 if( Connect( p_access
) )
280 if( p_sys
->i_code
== 401 )
282 if( p_sys
->auth
.psz_realm
== NULL
)
284 msg_Err( p_access
, "authentication failed without realm" );
288 if( p_sys
->url
.psz_username
&& p_sys
->url
.psz_password
&&
289 p_sys
->auth
.psz_nonce
&& p_sys
->auth
.i_nonce
== 0 )
291 Disconnect( p_access
);
294 free( p_sys
->psz_username
);
295 free( p_sys
->psz_password
);
296 p_sys
->psz_username
= p_sys
->psz_password
= NULL
;
298 msg_Dbg( p_access
, "authentication failed for realm %s",
299 p_sys
->auth
.psz_realm
);
301 credential
.psz_realm
= p_sys
->auth
.psz_realm
;
302 credential
.psz_authtype
= p_sys
->auth
.psz_nonce
? "Digest" : "Basic";
304 if( vlc_credential_get( &credential
, p_access
, NULL
, NULL
,
305 _("HTTP authentication"),
306 _("Please enter a valid login name and a "
307 "password for realm %s."), p_sys
->auth
.psz_realm
) )
309 p_sys
->psz_username
= strdup(credential
.psz_username
);
310 p_sys
->psz_password
= strdup(credential
.psz_password
);
311 if (!p_sys
->psz_username
|| !p_sys
->psz_password
)
313 msg_Err( p_access
, "retrying with user=%s", p_sys
->psz_username
);
314 p_sys
->url
.psz_username
= p_sys
->psz_username
;
315 p_sys
->url
.psz_password
= p_sys
->psz_password
;
316 Disconnect( p_access
);
323 vlc_credential_store( &credential
, p_access
);
325 if( ( p_sys
->i_code
== 301 || p_sys
->i_code
== 302 ||
326 p_sys
->i_code
== 303 || p_sys
->i_code
== 307 ) &&
327 p_sys
->psz_location
!= NULL
)
329 p_access
->psz_url
= p_sys
->psz_location
;
330 p_sys
->psz_location
= NULL
;
331 ret
= VLC_ACCESS_REDIRECT
;
335 if( p_sys
->b_reconnect
) msg_Dbg( p_access
, "auto re-connect enabled" );
337 /* Set up p_access */
338 p_access
->pf_read
= Read
;
339 p_access
->pf_control
= Control
;
340 p_access
->pf_seek
= Seek
;
342 vlc_credential_clean( &credential
);
347 Disconnect( p_access
);
350 vlc_credential_clean( &credential
);
351 vlc_UrlClean( &p_sys
->url
);
353 vlc_UrlClean( &p_sys
->proxy
);
354 free( p_sys
->psz_proxy_passbuf
);
355 free( p_sys
->psz_mime
);
356 free( p_sys
->psz_location
);
357 free( p_sys
->psz_user_agent
);
358 free( p_sys
->psz_referrer
);
359 free( p_sys
->psz_username
);
360 free( p_sys
->psz_password
);
365 /*****************************************************************************
367 *****************************************************************************/
368 static void Close( vlc_object_t
*p_this
)
370 stream_t
*p_access
= (stream_t
*)p_this
;
371 access_sys_t
*p_sys
= p_access
->p_sys
;
373 vlc_UrlClean( &p_sys
->url
);
375 vlc_UrlClean( &p_sys
->proxy
);
377 free( p_sys
->psz_mime
);
378 free( p_sys
->psz_location
);
380 free( p_sys
->psz_icy_name
);
381 free( p_sys
->psz_icy_genre
);
382 free( p_sys
->psz_icy_title
);
384 free( p_sys
->psz_user_agent
);
385 free( p_sys
->psz_referrer
);
386 free( p_sys
->psz_username
);
387 free( p_sys
->psz_password
);
389 Disconnect( p_access
);
392 /* Read data from the socket */
393 static int ReadData( stream_t
*p_access
, int *pi_read
,
394 void *p_buffer
, size_t i_len
)
396 access_sys_t
*p_sys
= p_access
->p_sys
;
398 *pi_read
= vlc_tls_Read(p_sys
->stream
, p_buffer
, i_len
, false);
399 if( *pi_read
< 0 && errno
!= EINTR
&& errno
!= EAGAIN
)
404 /*****************************************************************************
405 * Read: Read up to i_len bytes from the http connection and place in
406 * p_buffer. Return the actual number of bytes read
407 *****************************************************************************/
408 static int ReadICYMeta( stream_t
*p_access
);
410 static ssize_t
Read( stream_t
*p_access
, void *p_buffer
, size_t i_len
)
412 access_sys_t
*p_sys
= p_access
->p_sys
;
414 if (p_sys
->stream
== NULL
)
419 if( p_sys
->i_icy_meta
> 0 )
421 if( UINT64_MAX
- i_chunk
< p_sys
->offset
)
422 i_chunk
= UINT64_MAX
- p_sys
->offset
;
424 if( p_sys
->offset
+ i_chunk
> p_sys
->i_icy_offset
)
425 i_chunk
= p_sys
->i_icy_offset
- p_sys
->offset
;
429 if( ReadData( p_access
, &i_read
, (uint8_t*)p_buffer
, i_chunk
) )
433 return -1; /* EINTR / EAGAIN */
437 Disconnect( p_access
);
438 if( p_sys
->b_reconnect
)
440 msg_Dbg( p_access
, "got disconnected, trying to reconnect" );
441 if( Connect( p_access
) )
442 msg_Dbg( p_access
, "reconnection failed" );
449 assert( i_read
>= 0 );
450 p_sys
->offset
+= i_read
;
452 if( p_sys
->i_icy_meta
> 0 &&
453 p_sys
->offset
== p_sys
->i_icy_offset
)
455 if( ReadICYMeta( p_access
) )
457 p_sys
->i_icy_offset
= p_sys
->offset
+ p_sys
->i_icy_meta
;
463 static int ReadICYMeta( stream_t
*p_access
)
465 access_sys_t
*p_sys
= p_access
->p_sys
;
471 /* Read meta data length */
472 if( ReadData( p_access
, &i_read
, &buffer
, 1 ) )
476 const int i_size
= buffer
<< 4;
477 /* msg_Dbg( p_access, "ICY meta size=%u", i_size); */
479 psz_meta
= malloc( i_size
+ 1 );
480 for( i_read
= 0; i_read
< i_size
; )
483 if( ReadData( p_access
, &i_tmp
, (uint8_t *)&psz_meta
[i_read
], i_size
- i_read
) || i_tmp
<= 0 )
490 psz_meta
[i_read
] = '\0'; /* Just in case */
492 /* msg_Dbg( p_access, "icy-meta=%s", psz_meta ); */
494 /* Now parse the meta */
495 /* Look for StreamTitle= */
496 p
= strcasestr( (char *)psz_meta
, "StreamTitle=" );
499 p
+= strlen( "StreamTitle=" );
500 if( *p
== '\'' || *p
== '"' )
502 char closing
[] = { p
[0], ';', '\0' };
503 char *psz
= strstr( &p
[1], closing
);
505 psz
= strchr( &p
[1], ';' );
507 if( psz
) *psz
= '\0';
512 char *psz
= strchr( p
, ';' );
513 if( psz
) *psz
= '\0';
516 if( !p_sys
->psz_icy_title
||
517 strcmp( p_sys
->psz_icy_title
, p
) )
519 free( p_sys
->psz_icy_title
);
520 char *psz_tmp
= strdup( p
);
521 p_sys
->psz_icy_title
= EnsureUTF8( psz_tmp
);
522 if( !p_sys
->psz_icy_title
)
525 msg_Dbg( p_access
, "New Icy-Title=%s", p_sys
->psz_icy_title
);
526 if( p_access
->p_input_item
)
527 input_item_SetMeta( p_access
->p_input_item
, vlc_meta_NowPlaying
,
528 p_sys
->psz_icy_title
);
536 /*****************************************************************************
537 * Seek: close and re-open a connection at the right place
538 *****************************************************************************/
539 static int Seek( stream_t
*p_access
, uint64_t i_pos
)
541 (void) p_access
; (void) i_pos
;
545 /*****************************************************************************
547 *****************************************************************************/
548 static int Control( stream_t
*p_access
, int i_query
, va_list args
)
550 access_sys_t
*p_sys
= p_access
->p_sys
;
556 case STREAM_CAN_SEEK
:
557 case STREAM_CAN_FASTSEEK
:
558 pb_bool
= va_arg( args
, bool* );
561 case STREAM_CAN_PAUSE
:
562 case STREAM_CAN_CONTROL_PACE
:
563 pb_bool
= va_arg( args
, bool* );
568 case STREAM_GET_PTS_DELAY
:
569 *va_arg( args
, vlc_tick_t
* ) =
570 VLC_TICK_FROM_MS(var_InheritInteger( p_access
, "network-caching" ));
573 case STREAM_GET_SIZE
:
574 if( !p_sys
->b_has_size
)
576 *va_arg( args
, uint64_t*) = p_sys
->size
;
580 case STREAM_SET_PAUSE_STATE
:
583 case STREAM_GET_CONTENT_TYPE
:
585 char **type
= va_arg( args
, char ** );
587 if( p_sys
->b_icecast
&& p_sys
->psz_mime
== NULL
)
588 *type
= strdup( "audio/mpeg" );
589 else if( !strcasecmp( p_access
->psz_name
, "itpc" ) )
590 *type
= strdup( "application/rss+xml" );
591 else if( !strcasecmp( p_access
->psz_name
, "unsv" ) &&
592 p_sys
->psz_mime
!= NULL
&&
593 !strcasecmp( p_sys
->psz_mime
, "misc/ultravox" ) )
594 /* Grrrr! detect ultravox server and force NSV demuxer */
595 *type
= strdup( "video/nsa" );
596 else if( p_sys
->psz_mime
)
597 *type
= strdup( p_sys
->psz_mime
);
610 /*****************************************************************************
612 *****************************************************************************/
613 static int Connect( stream_t
*p_access
)
615 access_sys_t
*p_sys
= p_access
->p_sys
;
616 vlc_url_t srv
= p_sys
->b_proxy
? p_sys
->proxy
: p_sys
->url
;
620 free( p_sys
->psz_location
);
621 free( p_sys
->psz_mime
);
623 free( p_sys
->psz_icy_genre
);
624 free( p_sys
->psz_icy_name
);
625 free( p_sys
->psz_icy_title
);
627 vlc_http_auth_Init( &p_sys
->auth
);
628 vlc_http_auth_Init( &p_sys
->proxy_auth
);
629 p_sys
->psz_location
= NULL
;
630 p_sys
->psz_mime
= NULL
;
631 p_sys
->i_icy_meta
= 0;
632 p_sys
->i_icy_offset
= 0;
633 p_sys
->psz_icy_name
= NULL
;
634 p_sys
->psz_icy_genre
= NULL
;
635 p_sys
->psz_icy_title
= NULL
;
636 p_sys
->b_has_size
= false;
640 struct vlc_memstream stream
;
642 vlc_memstream_open(&stream
);
644 vlc_memstream_puts(&stream
, "GET ");
646 vlc_memstream_printf( &stream
, "http://%s:%d",
647 p_sys
->url
.psz_host
, p_sys
->url
.i_port
);
648 if( p_sys
->url
.psz_path
== NULL
|| p_sys
->url
.psz_path
[0] == '\0' )
649 vlc_memstream_putc( &stream
, '/' );
651 vlc_memstream_puts( &stream
, p_sys
->url
.psz_path
);
652 if( p_sys
->url
.psz_option
!= NULL
)
653 vlc_memstream_printf( &stream
, "?%s", p_sys
->url
.psz_option
);
654 vlc_memstream_puts( &stream
, " HTTP/1.0\r\n" );
656 vlc_memstream_printf( &stream
, "Host: %s", p_sys
->url
.psz_host
);
657 if( p_sys
->url
.i_port
!= 80 )
658 vlc_memstream_printf( &stream
, ":%d", p_sys
->url
.i_port
);
659 vlc_memstream_puts( &stream
, "\r\n" );
662 vlc_memstream_printf( &stream
, "User-Agent: %s\r\n",
663 p_sys
->psz_user_agent
);
665 if (p_sys
->psz_referrer
)
666 vlc_memstream_printf( &stream
, "Referer: %s\r\n",
667 p_sys
->psz_referrer
);
670 if( p_sys
->url
.psz_username
!= NULL
&& p_sys
->url
.psz_password
!= NULL
)
674 auth
= vlc_http_auth_FormatAuthorizationHeader( VLC_OBJECT(p_access
),
675 &p_sys
->auth
, "GET", p_sys
->url
.psz_path
,
676 p_sys
->url
.psz_username
, p_sys
->url
.psz_password
);
678 vlc_memstream_printf( &stream
, "Authorization: %s\r\n", auth
);
682 /* Proxy Authentication */
683 if( p_sys
->b_proxy
&& p_sys
->proxy
.psz_username
!= NULL
684 && p_sys
->proxy
.psz_password
!= NULL
)
688 auth
= vlc_http_auth_FormatAuthorizationHeader( VLC_OBJECT(p_access
),
689 &p_sys
->proxy_auth
, "GET", p_sys
->url
.psz_path
,
690 p_sys
->proxy
.psz_username
, p_sys
->proxy
.psz_password
);
692 vlc_memstream_printf( &stream
, "Proxy-Authorization: %s\r\n",
697 /* ICY meta data request */
698 vlc_memstream_puts( &stream
, "Icy-MetaData: 1\r\n" );
700 vlc_memstream_puts( &stream
, "\r\n" );
702 if( vlc_memstream_close( &stream
) )
705 /* Open connection */
706 assert(p_sys
->stream
== NULL
); /* No open sockets (leaking fds is BAD) */
707 p_sys
->stream
= vlc_tls_SocketOpenTCP(VLC_OBJECT(p_access
),
708 srv
.psz_host
, srv
.i_port
);
709 if (p_sys
->stream
== NULL
)
711 msg_Err( p_access
, "cannot connect to %s:%d", srv
.psz_host
, srv
.i_port
);
716 msg_Dbg( p_access
, "sending request:\n%s", stream
.ptr
);
717 val
= vlc_tls_Write(p_sys
->stream
, stream
.ptr
, stream
.length
);
720 if( val
< (ssize_t
)stream
.length
)
722 msg_Err( p_access
, "failed to send request" );
723 Disconnect( p_access
);
728 char *psz
= vlc_tls_GetLine(p_sys
->stream
);
731 msg_Err( p_access
, "failed to read answer" );
734 if( !strncmp( psz
, "HTTP/1.", 7 ) )
736 p_sys
->i_code
= atoi( &psz
[9] );
737 msg_Dbg( p_access
, "HTTP answer code %d", p_sys
->i_code
);
739 else if( !strncmp( psz
, "ICY", 3 ) )
741 p_sys
->i_code
= atoi( &psz
[4] );
742 msg_Dbg( p_access
, "ICY answer code %d", p_sys
->i_code
);
743 p_sys
->b_icecast
= true;
744 p_sys
->b_reconnect
= true;
748 msg_Err( p_access
, "invalid HTTP reply '%s'", psz
);
752 /* Authentication error - We'll have to display the dialog */
753 if( p_sys
->i_code
== 401 )
757 /* Other fatal error */
758 else if( p_sys
->i_code
>= 400 )
760 msg_Err( p_access
, "error: %s", psz
);
768 char *p
, *p_trailing
;
770 psz
= vlc_tls_GetLine(p_sys
->stream
);
773 msg_Err( p_access
, "failed to read answer" );
777 /* msg_Dbg( p_input, "Line=%s", psz ); */
784 if( ( p
= strchr( psz
, ':' ) ) == NULL
)
786 msg_Err( p_access
, "malformed header line: %s", psz
);
791 p
+= strspn( p
, " \t" );
793 /* trim trailing white space */
794 p_trailing
= p
+ strlen( p
);
798 while( ( *p_trailing
== ' ' || *p_trailing
== '\t' ) && p_trailing
> p
)
805 if( !strcasecmp( psz
, "Content-Length" ) )
807 uint64_t i_size
= (uint64_t)atoll( p
);
808 if(i_size
> p_sys
->size
) {
809 p_sys
->b_has_size
= true;
810 p_sys
->size
= i_size
;
813 else if( !strcasecmp( psz
, "Location" ) )
817 /* This does not follow RFC 2068, but yet if the url is not absolute,
818 * handle it as everyone does. */
821 if( p_sys
->url
.i_port
== 80 )
823 if( asprintf(&psz_new_loc
, "http://%s%s",
824 p_sys
->url
.psz_host
, p
) < 0 )
829 if( asprintf(&psz_new_loc
, "http://%s:%d%s",
830 p_sys
->url
.psz_host
, p_sys
->url
.i_port
, p
) < 0 )
836 psz_new_loc
= strdup( p
);
839 free( p_sys
->psz_location
);
840 p_sys
->psz_location
= psz_new_loc
;
842 else if( !strcasecmp( psz
, "Content-Type" ) )
844 free( p_sys
->psz_mime
);
845 p_sys
->psz_mime
= strdup( p
);
846 msg_Dbg( p_access
, "Content-Type: %s", p_sys
->psz_mime
);
848 else if( !strcasecmp( psz
, "Content-Encoding" ) )
850 msg_Dbg( p_access
, "Content-Encoding: %s", p
);
852 else if( !strcasecmp( psz
, "Server" ) )
854 msg_Dbg( p_access
, "Server: %s", p
);
855 if( !strncasecmp( p
, "Icecast", 7 ) ||
856 !strncasecmp( p
, "Nanocaster", 10 ) )
858 /* Remember if this is Icecast
859 * we need to force demux in this case without breaking
862 /* Let live 365 streams (nanocaster) piggyback on the icecast
863 * routine. They look very similar */
865 p_sys
->b_reconnect
= true;
866 p_sys
->b_icecast
= true;
869 else if( !strcasecmp( psz
, "Icy-MetaInt" ) )
871 msg_Dbg( p_access
, "Icy-MetaInt: %s", p
);
872 p_sys
->i_icy_meta
= atoi( p
);
873 if( p_sys
->i_icy_meta
< 0 )
874 p_sys
->i_icy_meta
= 0;
875 if( p_sys
->i_icy_meta
> 1 )
877 p_sys
->i_icy_offset
= p_sys
->i_icy_meta
;
878 p_sys
->b_icecast
= true;
881 msg_Warn( p_access
, "ICY metaint=%d", p_sys
->i_icy_meta
);
883 else if( !strcasecmp( psz
, "Icy-Name" ) )
885 free( p_sys
->psz_icy_name
);
886 char *psz_tmp
= strdup( p
);
887 p_sys
->psz_icy_name
= EnsureUTF8( psz_tmp
);
888 if( !p_sys
->psz_icy_name
)
891 vlc_xml_decode( p_sys
->psz_icy_name
);
892 msg_Dbg( p_access
, "Icy-Name: %s", p_sys
->psz_icy_name
);
893 if ( p_access
->p_input_item
)
894 input_item_SetMeta( p_access
->p_input_item
, vlc_meta_Title
,
895 p_sys
->psz_icy_name
);
897 p_sys
->b_icecast
= true; /* be on the safeside. set it here as well. */
898 p_sys
->b_reconnect
= true;
900 else if( !strcasecmp( psz
, "Icy-Genre" ) )
902 free( p_sys
->psz_icy_genre
);
903 char *psz_tmp
= strdup( p
);
904 p_sys
->psz_icy_genre
= EnsureUTF8( psz_tmp
);
905 if( !p_sys
->psz_icy_genre
)
908 vlc_xml_decode( p_sys
->psz_icy_genre
);
909 msg_Dbg( p_access
, "Icy-Genre: %s", p_sys
->psz_icy_genre
);
910 if( p_access
->p_input_item
)
911 input_item_SetMeta( p_access
->p_input_item
, vlc_meta_Genre
,
912 p_sys
->psz_icy_genre
);
914 else if( !strncasecmp( psz
, "Icy-Notice", 10 ) )
916 msg_Dbg( p_access
, "Icy-Notice: %s", p
);
918 else if( !strncasecmp( psz
, "icy-", 4 ) ||
919 !strncasecmp( psz
, "ice-", 4 ) ||
920 !strncasecmp( psz
, "x-audiocast", 11 ) )
922 msg_Dbg( p_access
, "Meta-Info: %s: %s", psz
, p
);
924 else if( !strcasecmp( psz
, "www-authenticate" ) )
926 msg_Dbg( p_access
, "Authentication header: %s", p
);
927 vlc_http_auth_ParseWwwAuthenticateHeader( VLC_OBJECT(p_access
),
930 else if( !strcasecmp( psz
, "proxy-authenticate" ) )
932 msg_Dbg( p_access
, "Proxy authentication header: %s", p
);
933 vlc_http_auth_ParseWwwAuthenticateHeader( VLC_OBJECT(p_access
),
934 &p_sys
->proxy_auth
, p
);
936 else if( !strcasecmp( psz
, "authentication-info" ) )
938 msg_Dbg( p_access
, "Authentication Info header: %s", p
);
939 if( AuthCheckReply( p_access
, p
, &p_sys
->url
, &p_sys
->auth
) )
942 else if( !strcasecmp( psz
, "proxy-authentication-info" ) )
944 msg_Dbg( p_access
, "Proxy Authentication Info header: %s", p
);
945 if( AuthCheckReply( p_access
, p
, &p_sys
->proxy
, &p_sys
->proxy_auth
) )
954 Disconnect( p_access
);
958 /*****************************************************************************
960 *****************************************************************************/
961 static void Disconnect( stream_t
*p_access
)
963 access_sys_t
*p_sys
= p_access
->p_sys
;
965 if (p_sys
->stream
!= NULL
)
966 vlc_tls_Close(p_sys
->stream
);
967 p_sys
->stream
= NULL
;
969 vlc_http_auth_Deinit( &p_sys
->auth
);
970 vlc_http_auth_Deinit( &p_sys
->proxy_auth
);
973 /*****************************************************************************
974 * HTTP authentication
975 *****************************************************************************/
977 static int AuthCheckReply( stream_t
*p_access
, const char *psz_header
,
978 vlc_url_t
*p_url
, vlc_http_auth_t
*p_auth
)
981 vlc_http_auth_ParseAuthenticationInfoHeader( VLC_OBJECT(p_access
),
986 p_url
->psz_password
);