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 *****************************************************************************/
34 #include <vlc_common.h>
35 #include <vlc_plugin.h>
38 #include <vlc_access.h>
40 #include <vlc_dialog.h>
42 #include <vlc_network.h>
45 #include <vlc_strings.h>
46 #include <vlc_charset.h>
47 #include <vlc_input.h>
58 /*****************************************************************************
60 *****************************************************************************/
61 static int Open ( vlc_object_t
* );
62 static void Close( vlc_object_t
* );
64 #define PROXY_TEXT N_("HTTP proxy")
65 #define PROXY_LONGTEXT N_( \
66 "HTTP proxy to be used It must be of the form " \
67 "http://[user@]myproxy.mydomain:myport/ ; " \
68 "if empty, the http_proxy environment variable will be tried." )
70 #define PROXY_PASS_TEXT N_("HTTP proxy password")
71 #define PROXY_PASS_LONGTEXT N_( \
72 "If your HTTP proxy requires a password, set it here." )
74 #define RECONNECT_TEXT N_("Auto re-connect")
75 #define RECONNECT_LONGTEXT N_( \
76 "Automatically try to reconnect to the stream in case of a sudden " \
79 #define CONTINUOUS_TEXT N_("Continuous stream")
80 #define CONTINUOUS_LONGTEXT N_("Read a file that is " \
81 "being constantly updated (for example, a JPG file on a server). " \
82 "You should not globally enable this option as it will break all other " \
83 "types of HTTP streams." )
85 #define FORWARD_COOKIES_TEXT N_("Forward Cookies")
86 #define FORWARD_COOKIES_LONGTEXT N_("Forward Cookies across http redirections.")
88 #define REFERER_TEXT N_("HTTP referer value")
89 #define REFERER_LONGTEXT N_("Customize the HTTP referer, simulating a previous document")
91 #define UA_TEXT N_("User Agent")
92 #define UA_LONGTEXT N_("The name and version of the program will be " \
93 "provided to the HTTP server. They must be separated by a forward " \
94 "slash, e.g. FooBar/1.2.3. This option can only be specified per input " \
95 "item, not globally.")
98 set_description( N_("HTTP input") )
99 set_capability( "access", 0 )
100 set_shortname( N_( "HTTP(S)" ) )
101 set_category( CAT_INPUT
)
102 set_subcategory( SUBCAT_INPUT_ACCESS
)
104 add_string( "http-proxy", NULL
, PROXY_TEXT
, PROXY_LONGTEXT
,
106 add_password( "http-proxy-pwd", NULL
,
107 PROXY_PASS_TEXT
, PROXY_PASS_LONGTEXT
, false )
108 add_obsolete_bool( "http-use-IE-proxy" )
109 add_string( "http-referrer", NULL
, REFERER_TEXT
, REFERER_LONGTEXT
, false )
111 add_string( "http-user-agent", NULL
, UA_TEXT
, UA_LONGTEXT
, false )
114 add_bool( "http-reconnect", false, RECONNECT_TEXT
,
115 RECONNECT_LONGTEXT
, true )
116 add_bool( "http-continuous", false, CONTINUOUS_TEXT
,
117 CONTINUOUS_LONGTEXT
, true )
119 add_bool( "http-forward-cookies", true, FORWARD_COOKIES_TEXT
,
120 FORWARD_COOKIES_LONGTEXT
, true )
121 /* 'itpc' = iTunes Podcast */
122 add_shortcut( "http", "https", "unsv", "itpc", "icyx" )
123 set_callbacks( Open
, Close
)
126 /*****************************************************************************
128 *****************************************************************************/
134 vlc_tls_creds_t
*p_creds
;
140 char *psz_user_agent
;
147 http_auth_t proxy_auth
;
148 char *psz_proxy_passbuf
;
152 const char *psz_protocol
;
173 uint64_t i_icy_offset
;
178 uint64_t i_remaining
;
181 /* cookie jar borrowed from playlist, do not free */
182 vlc_http_cookie_jar_t
* cookies
;
193 static int OpenRedirected( vlc_object_t
*p_this
, const char *psz_access
,
194 unsigned i_redirect
);
197 static ssize_t
Read( access_t
*, uint8_t *, size_t );
198 static ssize_t
ReadCompressed( access_t
*, uint8_t *, size_t );
199 static int Seek( access_t
*, uint64_t );
200 static int Control( access_t
*, int, va_list );
203 static int Connect( access_t
*, uint64_t );
204 static int Request( access_t
*p_access
, uint64_t i_tell
);
205 static void Disconnect( access_t
* );
208 static void AuthReply( access_t
*p_acces
, const char *psz_prefix
,
209 vlc_url_t
*p_url
, http_auth_t
*p_auth
);
210 static int AuthCheckReply( access_t
*p_access
, const char *psz_header
,
211 vlc_url_t
*p_url
, http_auth_t
*p_auth
);
212 static vlc_http_cookie_jar_t
*GetCookieJar( vlc_object_t
*p_this
);
214 /*****************************************************************************
216 *****************************************************************************/
217 static int Open( vlc_object_t
*p_this
)
219 access_t
*p_access
= (access_t
*)p_this
;
220 return OpenRedirected( p_this
, p_access
->psz_access
, 5 );
224 * Open the given url with limited redirects
225 * @param p_this: the vlc object
226 * @psz_access: the acces to use (http, https, ...) (this value must be used
227 * instead of p_access->psz_access)
228 * @i_redirect: number of redirections remaining
229 * @return vlc error codes
231 static int OpenRedirected( vlc_object_t
*p_this
, const char *psz_access
,
232 unsigned i_redirect
)
234 access_t
*p_access
= (access_t
*)p_this
;
238 /* Set up p_access */
239 STANDARD_READ_ACCESS_INIT
;
241 p_access
->pf_read
= ReadCompressed
;
244 p_sys
->b_proxy
= false;
245 p_sys
->psz_proxy_passbuf
= NULL
;
246 p_sys
->i_version
= 1;
247 p_sys
->b_seekable
= true;
248 p_sys
->psz_mime
= NULL
;
249 p_sys
->psz_pragma
= NULL
;
250 p_sys
->b_mms
= false;
251 p_sys
->b_icecast
= false;
252 p_sys
->psz_location
= NULL
;
253 p_sys
->psz_user_agent
= NULL
;
254 p_sys
->psz_referrer
= NULL
;
255 p_sys
->b_pace_control
= true;
257 p_sys
->b_compressed
= false;
258 /* 15 is the max windowBits, +32 to enable optional gzip decoding */
259 if( inflateInit2( &p_sys
->inflate
.stream
, 32+15 ) != Z_OK
)
260 msg_Warn( p_access
, "Error during zlib initialisation: %s",
261 p_sys
->inflate
.stream
.msg
);
262 if( zlibCompileFlags() & (1<<17) )
263 msg_Warn( p_access
, "Your zlib was compiled without gzip support." );
264 p_sys
->inflate
.p_buffer
= NULL
;
268 p_sys
->i_icy_meta
= 0;
269 p_sys
->i_icy_offset
= 0;
270 p_sys
->psz_icy_name
= NULL
;
271 p_sys
->psz_icy_genre
= NULL
;
272 p_sys
->psz_icy_title
= NULL
;
273 p_sys
->i_remaining
= 0;
274 p_sys
->b_persist
= false;
275 p_sys
->b_has_size
= false;
277 p_access
->info
.i_pos
= 0;
278 p_access
->info
.b_eof
= false;
280 /* Only forward an store cookies if the corresponding option is activated */
281 if( var_CreateGetBool( p_access
, "http-forward-cookies" ) )
282 p_sys
->cookies
= GetCookieJar( p_this
);
284 p_sys
->cookies
= NULL
;
286 http_auth_Init( &p_sys
->auth
);
287 http_auth_Init( &p_sys
->proxy_auth
);
289 /* Parse URI - remove spaces */
290 p
= psz
= strdup( p_access
->psz_location
);
291 while( (p
= strchr( p
, ' ' )) != NULL
)
293 vlc_UrlParse( &p_sys
->url
, psz
, 0 );
296 if( p_sys
->url
.psz_host
== NULL
|| *p_sys
->url
.psz_host
== '\0' )
298 msg_Warn( p_access
, "invalid host" );
301 if( !strncmp( psz_access
, "https", 5 ) )
304 p_sys
->p_creds
= vlc_tls_ClientCreate( p_this
);
305 if( p_sys
->p_creds
== NULL
)
307 if( p_sys
->url
.i_port
<= 0 )
308 p_sys
->url
.i_port
= 443;
312 if( p_sys
->url
.i_port
<= 0 )
313 p_sys
->url
.i_port
= 80;
316 /* Determine the HTTP user agent */
317 /* See RFC2616 §2.2 token and comment definition, and §3.8 and
318 * §14.43 user-agent header */
319 p_sys
->psz_user_agent
= var_InheritString( p_access
, "http-user-agent" );
320 if (p_sys
->psz_user_agent
)
322 unsigned comment_level
= 0;
323 for( char *p
= p_sys
->psz_user_agent
; *p
; p
++ )
326 if (comment_level
== 0)
328 if( c
< 32 || strchr( ")<>@,;:\\\"[]?={}", c
) )
329 *p
= '_'; /* remove potentially harmful characters */
335 else if( c
< 32 && strchr( "\t\r\n", c
) == NULL
)
336 *p
= '_'; /* remove potentially harmful characters */
340 if (comment_level
== UINT_MAX
)
345 /* truncate evil unclosed comments */
346 if (comment_level
> 0)
348 char *p
= strchr(p_sys
->psz_user_agent
, '(');
354 p_sys
->psz_referrer
= var_InheritString( p_access
, "http-referrer" );
357 psz
= var_InheritString( p_access
, "http-proxy" );
362 if (likely(asprintf(&url
, "%s://%s", psz_access
,
363 p_access
->psz_location
) != -1))
365 msg_Dbg(p_access
, "querying proxy for %s", url
);
366 psz
= vlc_getProxyUrl(url
);
371 msg_Dbg(p_access
, "proxy: %s", psz
);
373 msg_Dbg(p_access
, "no proxy");
377 p_sys
->b_proxy
= true;
378 vlc_UrlParse( &p_sys
->proxy
, psz
, 0 );
381 psz
= var_InheritString( p_access
, "http-proxy-pwd" );
383 p_sys
->proxy
.psz_password
= p_sys
->psz_proxy_passbuf
= psz
;
385 if( p_sys
->proxy
.psz_host
== NULL
|| *p_sys
->proxy
.psz_host
== '\0' )
387 msg_Warn( p_access
, "invalid proxy host" );
390 if( p_sys
->proxy
.i_port
<= 0 )
392 p_sys
->proxy
.i_port
= 80;
396 msg_Dbg( p_access
, "http: server='%s' port=%d file='%s'",
397 p_sys
->url
.psz_host
, p_sys
->url
.i_port
,
398 p_sys
->url
.psz_path
!= NULL
? p_sys
->url
.psz_path
: "" );
401 msg_Dbg( p_access
, " proxy %s:%d", p_sys
->proxy
.psz_host
,
402 p_sys
->proxy
.i_port
);
404 if( p_sys
->url
.psz_username
&& *p_sys
->url
.psz_username
)
406 msg_Dbg( p_access
, " user='%s'", p_sys
->url
.psz_username
);
409 p_sys
->b_reconnect
= var_InheritBool( p_access
, "http-reconnect" );
410 p_sys
->b_continuous
= var_InheritBool( p_access
, "http-continuous" );
414 switch( Connect( p_access
, 0 ) )
420 /* Retry with http 1.0 */
421 msg_Dbg( p_access
, "switching to HTTP version 1.0" );
422 p_sys
->i_version
= 0;
423 p_sys
->b_seekable
= false;
425 if( !vlc_object_alive (p_access
) || Connect( p_access
, 0 ) )
435 if( p_sys
->i_code
== 401 )
437 if( p_sys
->auth
.psz_realm
== NULL
)
439 msg_Err( p_access
, "authentication failed without realm" );
442 char *psz_login
, *psz_password
;
444 if( p_sys
->url
.psz_username
&& p_sys
->url
.psz_password
&&
445 p_sys
->auth
.psz_nonce
&& p_sys
->auth
.i_nonce
== 0 )
447 Disconnect( p_access
);
450 msg_Dbg( p_access
, "authentication failed for realm %s",
451 p_sys
->auth
.psz_realm
);
452 dialog_Login( p_access
, &psz_login
, &psz_password
,
453 _("HTTP authentication"),
454 _("Please enter a valid login name and a password for realm %s."),
455 p_sys
->auth
.psz_realm
);
456 if( psz_login
!= NULL
&& psz_password
!= NULL
)
458 msg_Dbg( p_access
, "retrying with user=%s", psz_login
);
459 p_sys
->url
.psz_username
= psz_login
;
460 p_sys
->url
.psz_password
= psz_password
;
461 Disconnect( p_access
);
467 free( psz_password
);
472 if( ( p_sys
->i_code
== 301 || p_sys
->i_code
== 302 ||
473 p_sys
->i_code
== 303 || p_sys
->i_code
== 307 ) &&
474 p_sys
->psz_location
&& *p_sys
->psz_location
)
476 msg_Dbg( p_access
, "redirection to %s", p_sys
->psz_location
);
478 /* Check the number of redirection already done */
479 if( i_redirect
== 0 )
481 msg_Err( p_access
, "Too many redirection: break potential infinite"
486 const char *psz_protocol
;
487 if( !strncmp( p_sys
->psz_location
, "http://", 7 ) )
488 psz_protocol
= "http";
489 else if( !strncmp( p_sys
->psz_location
, "https://", 8 ) )
490 psz_protocol
= "https";
492 { /* Do not accept redirection outside of HTTP */
493 msg_Err( p_access
, "unsupported redirection ignored" );
496 free( p_access
->psz_location
);
497 p_access
->psz_location
= strdup( p_sys
->psz_location
498 + strlen( psz_protocol
) + 3 );
499 /* Clean up current Open() run */
500 vlc_UrlClean( &p_sys
->url
);
501 http_auth_Reset( &p_sys
->auth
);
502 vlc_UrlClean( &p_sys
->proxy
);
503 free( p_sys
->psz_proxy_passbuf
);
504 http_auth_Reset( &p_sys
->proxy_auth
);
505 free( p_sys
->psz_mime
);
506 free( p_sys
->psz_pragma
);
507 free( p_sys
->psz_location
);
508 free( p_sys
->psz_user_agent
);
509 free( p_sys
->psz_referrer
);
511 Disconnect( p_access
);
512 vlc_tls_Delete( p_sys
->p_creds
);
514 inflateEnd( &p_sys
->inflate
.stream
);
518 /* Do new Open() run with new data */
519 return OpenRedirected( p_this
, psz_protocol
, i_redirect
- 1 );
524 msg_Dbg( p_access
, "this is actually a live mms server, BAIL" );
528 if( !strcmp( p_sys
->psz_protocol
, "ICY" ) || p_sys
->b_icecast
)
530 if( p_sys
->psz_mime
&& strcasecmp( p_sys
->psz_mime
, "application/ogg" ) )
532 if( !strcasecmp( p_sys
->psz_mime
, "video/nsv" ) ||
533 !strcasecmp( p_sys
->psz_mime
, "video/nsa" ) )
535 free( p_access
->psz_demux
);
536 p_access
->psz_demux
= strdup( "nsv" );
538 else if( !strcasecmp( p_sys
->psz_mime
, "audio/aac" ) ||
539 !strcasecmp( p_sys
->psz_mime
, "audio/aacp" ) )
541 free( p_access
->psz_demux
);
542 p_access
->psz_demux
= strdup( "m4a" );
544 else if( !strcasecmp( p_sys
->psz_mime
, "audio/mpeg" ) )
546 free( p_access
->psz_demux
);
547 p_access
->psz_demux
= strdup( "mp3" );
550 msg_Info( p_access
, "Raw-audio server found, %s demuxer selected",
551 p_access
->psz_demux
);
553 #if 0 /* Doesn't work really well because of the pre-buffering in
554 * shoutcast servers (the buffer content will be sent as fast as
556 p_sys
->b_pace_control
= false;
559 else if( !p_sys
->psz_mime
)
561 free( p_access
->psz_demux
);
563 p_access
->psz_demux
= strdup( "mp3" );
565 /* else probably Ogg Vorbis */
567 else if( !strcasecmp( psz_access
, "unsv" ) &&
569 !strcasecmp( p_sys
->psz_mime
, "misc/ultravox" ) )
571 free( p_access
->psz_demux
);
572 /* Grrrr! detect ultravox server and force NSV demuxer */
573 p_access
->psz_demux
= strdup( "nsv" );
575 else if( !strcmp( psz_access
, "itpc" ) )
577 free( p_access
->psz_demux
);
578 p_access
->psz_demux
= strdup( "podcast" );
581 if( p_sys
->b_reconnect
) msg_Dbg( p_access
, "auto re-connect enabled" );
586 vlc_UrlClean( &p_sys
->url
);
587 vlc_UrlClean( &p_sys
->proxy
);
588 free( p_sys
->psz_proxy_passbuf
);
589 free( p_sys
->psz_mime
);
590 free( p_sys
->psz_pragma
);
591 free( p_sys
->psz_location
);
592 free( p_sys
->psz_user_agent
);
593 free( p_sys
->psz_referrer
);
595 Disconnect( p_access
);
596 vlc_tls_Delete( p_sys
->p_creds
);
599 inflateEnd( &p_sys
->inflate
.stream
);
605 /*****************************************************************************
607 *****************************************************************************/
608 static void Close( vlc_object_t
*p_this
)
610 access_t
*p_access
= (access_t
*)p_this
;
611 access_sys_t
*p_sys
= p_access
->p_sys
;
613 vlc_UrlClean( &p_sys
->url
);
614 http_auth_Reset( &p_sys
->auth
);
615 vlc_UrlClean( &p_sys
->proxy
);
616 http_auth_Reset( &p_sys
->proxy_auth
);
618 free( p_sys
->psz_mime
);
619 free( p_sys
->psz_pragma
);
620 free( p_sys
->psz_location
);
622 free( p_sys
->psz_icy_name
);
623 free( p_sys
->psz_icy_genre
);
624 free( p_sys
->psz_icy_title
);
626 free( p_sys
->psz_user_agent
);
627 free( p_sys
->psz_referrer
);
629 Disconnect( p_access
);
630 vlc_tls_Delete( p_sys
->p_creds
);
633 inflateEnd( &p_sys
->inflate
.stream
);
634 free( p_sys
->inflate
.p_buffer
);
640 /* Read data from the socket taking care of chunked transfer if needed */
641 static int ReadData( access_t
*p_access
, int *pi_read
,
642 uint8_t *p_buffer
, size_t i_len
)
644 access_sys_t
*p_sys
= p_access
->p_sys
;
645 if( p_sys
->b_chunked
)
647 if( p_sys
->i_chunk
< 0 )
650 if( p_sys
->i_chunk
<= 0 )
652 char *psz
= net_Gets( p_access
, p_sys
->fd
, p_sys
->p_vs
);
653 /* read the chunk header */
656 /* fatal error - end of file */
657 msg_Dbg( p_access
, "failed reading chunk-header line" );
660 p_sys
->i_chunk
= strtoll( psz
, NULL
, 16 );
663 if( p_sys
->i_chunk
<= 0 ) /* eof */
670 if( i_len
> p_sys
->i_chunk
)
671 i_len
= p_sys
->i_chunk
;
673 *pi_read
= net_Read( p_access
, p_sys
->fd
, p_sys
->p_vs
, p_buffer
, i_len
, false );
677 if( p_sys
->b_chunked
)
679 p_sys
->i_chunk
-= *pi_read
;
680 if( p_sys
->i_chunk
<= 0 )
682 /* read the empty line */
683 char *psz
= net_Gets( p_access
, p_sys
->fd
, p_sys
->p_vs
);
690 /*****************************************************************************
691 * Read: Read up to i_len bytes from the http connection and place in
692 * p_buffer. Return the actual number of bytes read
693 *****************************************************************************/
694 static int ReadICYMeta( access_t
*p_access
);
695 static ssize_t
Read( access_t
*p_access
, uint8_t *p_buffer
, size_t i_len
)
697 access_sys_t
*p_sys
= p_access
->p_sys
;
700 if( p_sys
->fd
== -1 )
703 if( p_sys
->b_has_size
)
705 /* Remaining bytes in the file */
706 uint64_t remainder
= p_sys
->size
- p_access
->info
.i_pos
;
707 if( remainder
< i_len
)
710 /* Remaining bytes in the response */
711 if( p_sys
->i_remaining
< i_len
)
712 i_len
= p_sys
->i_remaining
;
717 if( p_sys
->i_icy_meta
> 0 && p_access
->info
.i_pos
- p_sys
->i_icy_offset
> 0 )
719 int64_t i_next
= p_sys
->i_icy_meta
-
720 (p_access
->info
.i_pos
- p_sys
->i_icy_offset
) % p_sys
->i_icy_meta
;
722 if( i_next
== p_sys
->i_icy_meta
)
724 if( ReadICYMeta( p_access
) )
731 if( ReadData( p_access
, &i_read
, p_buffer
, i_len
) )
737 * I very much doubt that this will work.
738 * If i_read == 0, the connection *IS* dead, so the only
739 * sensible thing to do is Disconnect() and then retry.
740 * Otherwise, I got recv() completely wrong. -- Courmisch
742 if( p_sys
->b_continuous
)
744 Request( p_access
, 0 );
745 p_sys
->b_continuous
= false;
746 i_read
= Read( p_access
, p_buffer
, i_len
);
747 p_sys
->b_continuous
= true;
749 Disconnect( p_access
);
750 if( p_sys
->b_reconnect
&& vlc_object_alive( p_access
) )
752 msg_Dbg( p_access
, "got disconnected, trying to reconnect" );
753 if( Connect( p_access
, p_access
->info
.i_pos
) )
755 msg_Dbg( p_access
, "reconnection failed" );
759 p_sys
->b_reconnect
= false;
760 i_read
= Read( p_access
, p_buffer
, i_len
);
761 p_sys
->b_reconnect
= true;
770 p_sys
->b_error
= true;
775 assert( i_read
>= 0 );
776 p_access
->info
.i_pos
+= i_read
;
777 if( p_sys
->b_has_size
)
779 assert( p_access
->info
.i_pos
<= p_sys
->size
);
780 assert( (unsigned)i_read
<= p_sys
->i_remaining
);
781 p_sys
->i_remaining
-= i_read
;
787 p_access
->info
.b_eof
= true;
791 static int ReadICYMeta( access_t
*p_access
)
793 access_sys_t
*p_sys
= p_access
->p_sys
;
799 /* Read meta data length */
800 if( ReadData( p_access
, &i_read
, &buffer
, 1 ) )
804 const int i_size
= buffer
<< 4;
805 /* msg_Dbg( p_access, "ICY meta size=%u", i_size); */
807 psz_meta
= malloc( i_size
+ 1 );
808 for( i_read
= 0; i_read
< i_size
; )
811 if( ReadData( p_access
, &i_tmp
, (uint8_t *)&psz_meta
[i_read
], i_size
- i_read
) || i_tmp
<= 0 )
818 psz_meta
[i_read
] = '\0'; /* Just in case */
820 /* msg_Dbg( p_access, "icy-meta=%s", psz_meta ); */
822 /* Now parse the meta */
823 /* Look for StreamTitle= */
824 p
= strcasestr( (char *)psz_meta
, "StreamTitle=" );
827 p
+= strlen( "StreamTitle=" );
828 if( *p
== '\'' || *p
== '"' )
830 char closing
[] = { p
[0], ';', '\0' };
831 char *psz
= strstr( &p
[1], closing
);
833 psz
= strchr( &p
[1], ';' );
835 if( psz
) *psz
= '\0';
839 char *psz
= strchr( &p
[1], ';' );
840 if( psz
) *psz
= '\0';
843 if( !p_sys
->psz_icy_title
||
844 strcmp( p_sys
->psz_icy_title
, &p
[1] ) )
846 free( p_sys
->psz_icy_title
);
847 char *psz_tmp
= strdup( &p
[1] );
848 p_sys
->psz_icy_title
= EnsureUTF8( psz_tmp
);
849 if( !p_sys
->psz_icy_title
)
852 msg_Dbg( p_access
, "New Icy-Title=%s", p_sys
->psz_icy_title
);
853 input_thread_t
*p_input
= access_GetParentInput( p_access
);
856 input_item_t
*p_input_item
= input_GetItem( p_access
->p_input
);
858 input_item_SetMeta( p_input_item
, vlc_meta_NowPlaying
, p_sys
->psz_icy_title
);
859 vlc_object_release( p_input
);
869 static ssize_t
ReadCompressed( access_t
*p_access
, uint8_t *p_buffer
,
872 access_sys_t
*p_sys
= p_access
->p_sys
;
874 if( p_sys
->b_compressed
)
878 if( !p_sys
->inflate
.p_buffer
)
879 p_sys
->inflate
.p_buffer
= malloc( 256 * 1024 );
881 if( p_sys
->inflate
.stream
.avail_in
== 0 )
883 ssize_t i_read
= Read( p_access
, p_sys
->inflate
.p_buffer
, 256 * 1024 );
884 if( i_read
<= 0 ) return i_read
;
885 p_sys
->inflate
.stream
.next_in
= p_sys
->inflate
.p_buffer
;
886 p_sys
->inflate
.stream
.avail_in
= i_read
;
889 p_sys
->inflate
.stream
.avail_out
= i_len
;
890 p_sys
->inflate
.stream
.next_out
= p_buffer
;
892 i_ret
= inflate( &p_sys
->inflate
.stream
, Z_SYNC_FLUSH
);
893 if ( i_ret
!= Z_OK
&& i_ret
!= Z_STREAM_END
)
894 msg_Warn( p_access
, "inflate return value: %d, %s", i_ret
, p_sys
->inflate
.stream
.msg
);
896 return i_len
- p_sys
->inflate
.stream
.avail_out
;
900 return Read( p_access
, p_buffer
, i_len
);
905 /*****************************************************************************
906 * Seek: close and re-open a connection at the right place
907 *****************************************************************************/
908 static int Seek( access_t
*p_access
, uint64_t i_pos
)
910 access_sys_t
*p_sys
= p_access
->p_sys
;
912 msg_Dbg( p_access
, "trying to seek to %"PRId64
, i_pos
);
913 Disconnect( p_access
);
915 if( p_sys
->size
&& i_pos
>= p_sys
->size
)
917 msg_Err( p_access
, "seek too far" );
918 int retval
= Seek( p_access
, p_sys
->size
- 1 );
919 if( retval
== VLC_SUCCESS
) {
921 Read( p_access
, p_buffer
, 1);
922 p_access
->info
.b_eof
= false;
926 if( Connect( p_access
, i_pos
) )
928 msg_Err( p_access
, "seek failed" );
929 p_access
->info
.b_eof
= true;
935 /*****************************************************************************
937 *****************************************************************************/
938 static int Control( access_t
*p_access
, int i_query
, va_list args
)
940 access_sys_t
*p_sys
= p_access
->p_sys
;
947 case ACCESS_CAN_SEEK
:
948 pb_bool
= (bool*)va_arg( args
, bool* );
949 *pb_bool
= p_sys
->b_seekable
;
951 case ACCESS_CAN_FASTSEEK
:
952 pb_bool
= (bool*)va_arg( args
, bool* );
955 case ACCESS_CAN_PAUSE
:
956 case ACCESS_CAN_CONTROL_PACE
:
957 pb_bool
= (bool*)va_arg( args
, bool* );
959 #if 0 /* Disable for now until we have a clock synchro algo
960 * which works with something else than MPEG over UDP */
961 *pb_bool
= p_sys
->b_pace_control
;
967 case ACCESS_GET_PTS_DELAY
:
968 pi_64
= (int64_t*)va_arg( args
, int64_t * );
969 *pi_64
= INT64_C(1000)
970 * var_InheritInteger( p_access
, "network-caching" );
973 case ACCESS_GET_SIZE
:
974 pi_64
= (int64_t*)va_arg( args
, int64_t * );
975 *pi_64
= p_sys
->size
;
979 case ACCESS_SET_PAUSE_STATE
:
982 case ACCESS_GET_CONTENT_TYPE
:
983 *va_arg( args
, char ** ) =
984 p_sys
->psz_mime
? strdup( p_sys
->psz_mime
) : NULL
;
994 /*****************************************************************************
996 *****************************************************************************/
997 static int Connect( access_t
*p_access
, uint64_t i_tell
)
999 access_sys_t
*p_sys
= p_access
->p_sys
;
1000 vlc_url_t srv
= p_sys
->b_proxy
? p_sys
->proxy
: p_sys
->url
;
1003 free( p_sys
->psz_location
);
1004 free( p_sys
->psz_mime
);
1005 free( p_sys
->psz_pragma
);
1007 free( p_sys
->psz_icy_genre
);
1008 free( p_sys
->psz_icy_name
);
1009 free( p_sys
->psz_icy_title
);
1012 p_sys
->psz_location
= NULL
;
1013 p_sys
->psz_mime
= NULL
;
1014 p_sys
->psz_pragma
= NULL
;
1015 p_sys
->b_mms
= false;
1016 p_sys
->b_chunked
= false;
1018 p_sys
->i_icy_meta
= 0;
1019 p_sys
->i_icy_offset
= i_tell
;
1020 p_sys
->psz_icy_name
= NULL
;
1021 p_sys
->psz_icy_genre
= NULL
;
1022 p_sys
->psz_icy_title
= NULL
;
1023 p_sys
->i_remaining
= 0;
1024 p_sys
->b_persist
= false;
1025 p_sys
->b_has_size
= false;
1027 p_access
->info
.i_pos
= i_tell
;
1028 p_access
->info
.b_eof
= false;
1030 /* Open connection */
1031 assert( p_sys
->fd
== -1 ); /* No open sockets (leaking fds is BAD) */
1032 p_sys
->fd
= net_ConnectTCP( p_access
, srv
.psz_host
, srv
.i_port
);
1033 if( p_sys
->fd
== -1 )
1035 msg_Err( p_access
, "cannot connect to %s:%d", srv
.psz_host
, srv
.i_port
);
1038 setsockopt (p_sys
->fd
, SOL_SOCKET
, SO_KEEPALIVE
, &(int){ 1 }, sizeof (int));
1040 /* Initialize TLS/SSL session */
1041 if( p_sys
->p_creds
!= NULL
)
1043 /* CONNECT to establish TLS tunnel through HTTP proxy */
1044 if( p_sys
->b_proxy
)
1047 unsigned i_status
= 0;
1049 if( p_sys
->i_version
== 0 )
1051 /* CONNECT is not in HTTP/1.0 */
1052 Disconnect( p_access
);
1056 net_Printf( p_access
, p_sys
->fd
, NULL
,
1057 "CONNECT %s:%d HTTP/1.%d\r\nHost: %s:%d\r\n\r\n",
1058 p_sys
->url
.psz_host
, p_sys
->url
.i_port
,
1060 p_sys
->url
.psz_host
, p_sys
->url
.i_port
);
1062 psz
= net_Gets( p_access
, p_sys
->fd
, NULL
);
1065 msg_Err( p_access
, "cannot establish HTTP/TLS tunnel" );
1066 Disconnect( p_access
);
1070 sscanf( psz
, "HTTP/%*u.%*u %3u", &i_status
);
1073 if( ( i_status
/ 100 ) != 2 )
1075 msg_Err( p_access
, "HTTP/TLS tunnel through proxy denied" );
1076 Disconnect( p_access
);
1082 psz
= net_Gets( p_access
, p_sys
->fd
, NULL
);
1085 msg_Err( p_access
, "HTTP proxy connection failed" );
1086 Disconnect( p_access
);
1095 if( !vlc_object_alive (p_access
) || p_sys
->b_error
)
1097 Disconnect( p_access
);
1104 /* TLS/SSL handshake */
1105 const char *alpn
[] = { "http/1.1", NULL
};
1107 p_sys
->p_tls
= vlc_tls_ClientSessionCreate( p_sys
->p_creds
, p_sys
->fd
,
1108 p_sys
->url
.psz_host
, "https",
1109 p_sys
->i_version
? alpn
: NULL
, NULL
);
1110 if( p_sys
->p_tls
== NULL
)
1112 msg_Err( p_access
, "cannot establish HTTP/TLS session" );
1113 Disconnect( p_access
);
1116 p_sys
->p_vs
= &p_sys
->p_tls
->sock
;
1119 return Request( p_access
, i_tell
) ? -2 : 0;
1123 static int Request( access_t
*p_access
, uint64_t i_tell
)
1125 access_sys_t
*p_sys
= p_access
->p_sys
;
1127 v_socket_t
*pvs
= p_sys
->p_vs
;
1128 p_sys
->b_persist
= false;
1130 p_sys
->i_remaining
= 0;
1132 const char *psz_path
= p_sys
->url
.psz_path
;
1133 if( !psz_path
|| !*psz_path
)
1135 if( p_sys
->b_proxy
&& pvs
== NULL
)
1136 net_Printf( p_access
, p_sys
->fd
, NULL
,
1137 "GET http://%s:%d%s HTTP/1.%d\r\n",
1138 p_sys
->url
.psz_host
, p_sys
->url
.i_port
,
1139 psz_path
, p_sys
->i_version
);
1141 net_Printf( p_access
, p_sys
->fd
, pvs
, "GET %s HTTP/1.%d\r\n",
1142 psz_path
, p_sys
->i_version
);
1143 if( p_sys
->url
.i_port
!= (pvs
? 443 : 80) )
1144 net_Printf( p_access
, p_sys
->fd
, pvs
, "Host: %s:%d\r\n",
1145 p_sys
->url
.psz_host
, p_sys
->url
.i_port
);
1147 net_Printf( p_access
, p_sys
->fd
, pvs
, "Host: %s\r\n",
1148 p_sys
->url
.psz_host
);
1150 net_Printf( p_access
, p_sys
->fd
, pvs
, "User-Agent: %s\r\n",
1151 p_sys
->psz_user_agent
);
1153 if (p_sys
->psz_referrer
)
1155 net_Printf( p_access
, p_sys
->fd
, pvs
, "Referer: %s\r\n",
1156 p_sys
->psz_referrer
);
1159 if( p_sys
->i_version
== 1 && ! p_sys
->b_continuous
)
1161 p_sys
->b_persist
= true;
1162 net_Printf( p_access
, p_sys
->fd
, pvs
,
1163 "Range: bytes=%"PRIu64
"-\r\n", i_tell
);
1164 net_Printf( p_access
, p_sys
->fd
, pvs
, "Connection: close\r\n" );
1168 if( p_sys
->cookies
)
1170 char * psz_cookiestring
= vlc_http_cookies_for_url( p_sys
->cookies
, &p_sys
->url
);
1171 if ( psz_cookiestring
)
1173 msg_Dbg( p_access
, "Sending Cookie %s", psz_cookiestring
);
1174 if( net_Printf( p_access
, p_sys
->fd
, pvs
, "Cookie: %s\r\n", psz_cookiestring
) < 0 )
1175 msg_Err( p_access
, "failed to send Cookie" );
1176 free( psz_cookiestring
);
1180 /* Authentication */
1181 if( p_sys
->url
.psz_username
&& p_sys
->url
.psz_password
)
1182 AuthReply( p_access
, "", &p_sys
->url
, &p_sys
->auth
);
1184 /* Proxy Authentication */
1185 if( p_sys
->proxy
.psz_username
&& p_sys
->proxy
.psz_password
)
1186 AuthReply( p_access
, "Proxy-", &p_sys
->proxy
, &p_sys
->proxy_auth
);
1188 /* ICY meta data request */
1189 net_Printf( p_access
, p_sys
->fd
, pvs
, "Icy-MetaData: 1\r\n" );
1192 if( net_Printf( p_access
, p_sys
->fd
, pvs
, "\r\n" ) < 0 )
1194 msg_Err( p_access
, "failed to send request" );
1195 Disconnect( p_access
);
1196 return VLC_EGENERIC
;
1200 if( ( psz
= net_Gets( p_access
, p_sys
->fd
, pvs
) ) == NULL
)
1202 msg_Err( p_access
, "failed to read answer" );
1205 if( !strncmp( psz
, "HTTP/1.", 7 ) )
1207 p_sys
->psz_protocol
= "HTTP";
1208 p_sys
->i_code
= atoi( &psz
[9] );
1210 else if( !strncmp( psz
, "ICY", 3 ) )
1212 p_sys
->psz_protocol
= "ICY";
1213 p_sys
->i_code
= atoi( &psz
[4] );
1214 p_sys
->b_reconnect
= true;
1218 msg_Err( p_access
, "invalid HTTP reply '%s'", psz
);
1222 msg_Dbg( p_access
, "protocol '%s' answer code %d",
1223 p_sys
->psz_protocol
, p_sys
->i_code
);
1224 if( !strcmp( p_sys
->psz_protocol
, "ICY" ) )
1226 p_sys
->b_seekable
= false;
1228 if( p_sys
->i_code
!= 206 && p_sys
->i_code
!= 401 )
1230 p_sys
->b_seekable
= false;
1232 /* Authentication error - We'll have to display the dialog */
1233 if( p_sys
->i_code
== 401 )
1237 /* Other fatal error */
1238 else if( p_sys
->i_code
>= 400 )
1240 msg_Err( p_access
, "error: %s", psz
);
1248 char *psz
= net_Gets( p_access
, p_sys
->fd
, pvs
);
1254 msg_Err( p_access
, "failed to read answer" );
1258 if( !vlc_object_alive (p_access
) || p_sys
->b_error
)
1264 /* msg_Dbg( p_input, "Line=%s", psz ); */
1271 if( ( p
= strchr( psz
, ':' ) ) == NULL
)
1273 msg_Err( p_access
, "malformed header line: %s", psz
);
1278 p
+= strspn( p
, " \t" );
1280 /* trim trailing white space */
1281 p_trailing
= p
+ strlen( p
);
1282 if( p_trailing
> p
)
1285 while( ( *p_trailing
== ' ' || *p_trailing
== '\t' ) && p_trailing
> p
)
1292 if( !strcasecmp( psz
, "Content-Length" ) )
1294 uint64_t i_size
= i_tell
+ (p_sys
->i_remaining
= (uint64_t)atoll( p
));
1295 if(i_size
> p_sys
->size
) {
1296 p_sys
->b_has_size
= true;
1297 p_sys
->size
= i_size
;
1299 msg_Dbg( p_access
, "this frame size=%"PRIu64
, p_sys
->i_remaining
);
1301 else if( !strcasecmp( psz
, "Content-Range" ) ) {
1302 uint64_t i_ntell
= i_tell
;
1303 uint64_t i_nend
= (p_sys
->size
> 0) ? (p_sys
->size
- 1) : i_tell
;
1304 uint64_t i_nsize
= p_sys
->size
;
1305 sscanf(p
,"bytes %"SCNu64
"-%"SCNu64
"/%"SCNu64
,&i_ntell
,&i_nend
,&i_nsize
);
1306 if(i_nend
> i_ntell
) {
1307 p_access
->info
.i_pos
= i_ntell
;
1308 p_sys
->i_icy_offset
= i_ntell
;
1309 p_sys
->i_remaining
= i_nend
+1-i_ntell
;
1310 uint64_t i_size
= (i_nsize
> i_nend
) ? i_nsize
: (i_nend
+ 1);
1311 if(i_size
> p_sys
->size
) {
1312 p_sys
->b_has_size
= true;
1313 p_sys
->size
= i_size
;
1315 msg_Dbg( p_access
, "stream size=%"PRIu64
",pos=%"PRIu64
",remaining=%"PRIu64
,
1316 i_nsize
, i_ntell
, p_sys
->i_remaining
);
1319 else if( !strcasecmp( psz
, "Connection" ) ) {
1320 msg_Dbg( p_access
, "Connection: %s",p
);
1322 sscanf(p
, "close%n",&i
);
1324 p_sys
->b_persist
= false;
1327 else if( !strcasecmp( psz
, "Location" ) )
1331 /* This does not follow RFC 2068, but yet if the url is not absolute,
1332 * handle it as everyone does. */
1335 const char *psz_http_ext
= p_sys
->p_tls
? "s" : "" ;
1337 if( p_sys
->url
.i_port
== ( p_sys
->p_tls
? 443 : 80 ) )
1339 if( asprintf(&psz_new_loc
, "http%s://%s%s", psz_http_ext
,
1340 p_sys
->url
.psz_host
, p
) < 0 )
1345 if( asprintf(&psz_new_loc
, "http%s://%s:%d%s", psz_http_ext
,
1346 p_sys
->url
.psz_host
, p_sys
->url
.i_port
, p
) < 0 )
1352 psz_new_loc
= strdup( p
);
1355 free( p_sys
->psz_location
);
1356 p_sys
->psz_location
= psz_new_loc
;
1358 else if( !strcasecmp( psz
, "Content-Type" ) )
1360 free( p_sys
->psz_mime
);
1361 p_sys
->psz_mime
= strdup( p
);
1362 msg_Dbg( p_access
, "Content-Type: %s", p_sys
->psz_mime
);
1364 else if( !strcasecmp( psz
, "Content-Encoding" ) )
1366 msg_Dbg( p_access
, "Content-Encoding: %s", p
);
1367 if( !strcasecmp( p
, "identity" ) )
1370 else if( !strcasecmp( p
, "gzip" ) || !strcasecmp( p
, "deflate" ) )
1371 p_sys
->b_compressed
= true;
1374 msg_Warn( p_access
, "Unknown content coding: %s", p
);
1376 else if( !strcasecmp( psz
, "Pragma" ) )
1378 if( !strcasecmp( psz
, "Pragma: features" ) )
1379 p_sys
->b_mms
= true;
1380 free( p_sys
->psz_pragma
);
1381 p_sys
->psz_pragma
= strdup( p
);
1382 msg_Dbg( p_access
, "Pragma: %s", p_sys
->psz_pragma
);
1384 else if( !strcasecmp( psz
, "Server" ) )
1386 msg_Dbg( p_access
, "Server: %s", p
);
1387 if( !strncasecmp( p
, "Icecast", 7 ) ||
1388 !strncasecmp( p
, "Nanocaster", 10 ) )
1390 /* Remember if this is Icecast
1391 * we need to force demux in this case without breaking
1394 /* Let live 365 streams (nanocaster) piggyback on the icecast
1395 * routine. They look very similar */
1397 p_sys
->b_reconnect
= true;
1398 p_sys
->b_pace_control
= false;
1399 p_sys
->b_icecast
= true;
1402 else if( !strcasecmp( psz
, "Transfer-Encoding" ) )
1404 msg_Dbg( p_access
, "Transfer-Encoding: %s", p
);
1405 if( !strncasecmp( p
, "chunked", 7 ) )
1407 p_sys
->b_chunked
= true;
1410 else if( !strcasecmp( psz
, "Icy-MetaInt" ) )
1412 msg_Dbg( p_access
, "Icy-MetaInt: %s", p
);
1413 p_sys
->i_icy_meta
= atoi( p
);
1414 if( p_sys
->i_icy_meta
< 0 )
1415 p_sys
->i_icy_meta
= 0;
1416 if( p_sys
->i_icy_meta
> 0 )
1417 p_sys
->b_icecast
= true;
1419 msg_Warn( p_access
, "ICY metaint=%d", p_sys
->i_icy_meta
);
1421 else if( !strcasecmp( psz
, "Icy-Name" ) )
1423 free( p_sys
->psz_icy_name
);
1424 char *psz_tmp
= strdup( p
);
1425 p_sys
->psz_icy_name
= EnsureUTF8( psz_tmp
);
1426 if( !p_sys
->psz_icy_name
)
1428 msg_Dbg( p_access
, "Icy-Name: %s", p_sys
->psz_icy_name
);
1429 input_thread_t
*p_input
= access_GetParentInput( p_access
);
1432 input_item_t
*p_input_item
= input_GetItem( p_access
->p_input
);
1434 input_item_SetMeta( p_input_item
, vlc_meta_Title
, p_sys
->psz_icy_name
);
1435 vlc_object_release( p_input
);
1438 p_sys
->b_icecast
= true; /* be on the safeside. set it here as well. */
1439 p_sys
->b_reconnect
= true;
1440 p_sys
->b_pace_control
= false;
1442 else if( !strcasecmp( psz
, "Icy-Genre" ) )
1444 free( p_sys
->psz_icy_genre
);
1445 char *psz_tmp
= strdup( p
);
1446 p_sys
->psz_icy_genre
= EnsureUTF8( psz_tmp
);
1447 if( !p_sys
->psz_icy_genre
)
1449 msg_Dbg( p_access
, "Icy-Genre: %s", p_sys
->psz_icy_genre
);
1450 input_thread_t
*p_input
= access_GetParentInput( p_access
);
1453 input_item_t
*p_input_item
= input_GetItem( p_access
->p_input
);
1455 input_item_SetMeta( p_input_item
, vlc_meta_Genre
, p_sys
->psz_icy_genre
);
1456 vlc_object_release( p_input
);
1459 else if( !strncasecmp( psz
, "Icy-Notice", 10 ) )
1461 msg_Dbg( p_access
, "Icy-Notice: %s", p
);
1463 else if( !strncasecmp( psz
, "icy-", 4 ) ||
1464 !strncasecmp( psz
, "ice-", 4 ) ||
1465 !strncasecmp( psz
, "x-audiocast", 11 ) )
1467 msg_Dbg( p_access
, "Meta-Info: %s: %s", psz
, p
);
1469 else if( !strcasecmp( psz
, "Set-Cookie" ) )
1471 if( p_sys
->cookies
)
1473 if ( vlc_http_cookies_append( p_sys
->cookies
, p
, &p_sys
->url
) )
1474 msg_Dbg( p_access
, "Accepting Cookie: %s", p
);
1476 msg_Dbg( p_access
, "Rejected Cookie: %s", p
);
1479 msg_Dbg( p_access
, "We have a Cookie we won't remember: %s", p
);
1481 else if( !strcasecmp( psz
, "www-authenticate" ) )
1483 msg_Dbg( p_access
, "Authentication header: %s", p
);
1484 http_auth_ParseWwwAuthenticateHeader( VLC_OBJECT(p_access
),
1487 else if( !strcasecmp( psz
, "proxy-authenticate" ) )
1489 msg_Dbg( p_access
, "Proxy authentication header: %s", p
);
1490 http_auth_ParseWwwAuthenticateHeader( VLC_OBJECT(p_access
),
1491 &p_sys
->proxy_auth
, p
);
1493 else if( !strcasecmp( psz
, "authentication-info" ) )
1495 msg_Dbg( p_access
, "Authentication Info header: %s", p
);
1496 if( AuthCheckReply( p_access
, p
, &p_sys
->url
, &p_sys
->auth
) )
1499 else if( !strcasecmp( psz
, "proxy-authentication-info" ) )
1501 msg_Dbg( p_access
, "Proxy Authentication Info header: %s", p
);
1502 if( AuthCheckReply( p_access
, p
, &p_sys
->proxy
, &p_sys
->proxy_auth
) )
1505 else if( !strcasecmp( psz
, "Accept-Ranges" ) )
1507 if( !strcasecmp( p
, "bytes" ) )
1508 p_sys
->b_seekable
= true;
1513 /* We close the stream for zero length data, unless of course the
1514 * server has already promised to do this for us.
1516 if( p_sys
->b_has_size
&& p_sys
->i_remaining
== 0 && p_sys
->b_persist
) {
1517 Disconnect( p_access
);
1522 Disconnect( p_access
);
1523 return VLC_EGENERIC
;
1526 /*****************************************************************************
1528 *****************************************************************************/
1529 static void Disconnect( access_t
*p_access
)
1531 access_sys_t
*p_sys
= p_access
->p_sys
;
1533 if( p_sys
->p_tls
!= NULL
)
1535 vlc_tls_SessionDelete( p_sys
->p_tls
);
1536 p_sys
->p_tls
= NULL
;
1539 if( p_sys
->fd
!= -1)
1541 net_Close(p_sys
->fd
);
1547 /*****************************************************************************
1548 * HTTP authentication
1549 *****************************************************************************/
1551 static void AuthReply( access_t
*p_access
, const char *psz_prefix
,
1552 vlc_url_t
*p_url
, http_auth_t
*p_auth
)
1554 access_sys_t
*p_sys
= p_access
->p_sys
;
1558 http_auth_FormatAuthorizationHeader( VLC_OBJECT(p_access
), p_auth
,
1559 "GET", p_url
->psz_path
,
1560 p_url
->psz_username
,
1561 p_url
->psz_password
);
1562 if ( psz_value
== NULL
)
1565 net_Printf( p_access
, p_sys
->fd
, p_sys
->p_vs
,
1566 "%sAuthorization: %s\r\n", psz_prefix
, psz_value
);
1570 static int AuthCheckReply( access_t
*p_access
, const char *psz_header
,
1571 vlc_url_t
*p_url
, http_auth_t
*p_auth
)
1574 http_auth_ParseAuthenticationInfoHeader( VLC_OBJECT(p_access
), p_auth
,
1577 p_url
->psz_username
,
1578 p_url
->psz_password
);
1581 /*****************************************************************************
1583 *****************************************************************************/
1586 * Inherit the cookie jar from the playlist
1588 * @param p_this: http access object
1589 * @return A borrowed reference to a vlc_http_cookie_jar_t, do not free
1591 static vlc_http_cookie_jar_t
*GetCookieJar( vlc_object_t
*p_this
)
1595 if ( var_Inherit( p_this
, "http-cookies", VLC_VAR_ADDRESS
, &val
) == VLC_SUCCESS
)
1596 return val
.p_address
;