1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2001-2009 the VideoLAN team
7 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8 * Jon Lech Johansen <jon@nanocrew.net>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
36 #include <vlc_block.h>
39 #include <vlc_input.h>
40 #include <vlc_playlist.h>
41 #include <vlc_httpd.h>
43 /*****************************************************************************
45 *****************************************************************************/
46 static int Open ( vlc_object_t * );
47 static void Close( vlc_object_t * );
49 #define SOUT_CFG_PREFIX "sout-http-"
51 #define USER_TEXT N_("Username")
52 #define USER_LONGTEXT N_("User name that will be " \
53 "requested to access the stream." )
54 #define PASS_TEXT N_("Password")
55 #define PASS_LONGTEXT N_("Password that will be " \
56 "requested to access the stream." )
57 #define MIME_TEXT N_("Mime")
58 #define MIME_LONGTEXT N_("MIME returned by the server (autodetected " \
59 "if not specified)." )
63 set_description( N_("HTTP stream output") )
64 set_capability( "sout access", 0 )
65 set_shortname( "HTTP" )
66 add_shortcut( "http", "https", "mmsh" )
67 set_category( CAT_SOUT )
68 set_subcategory( SUBCAT_SOUT_ACO )
69 add_string( SOUT_CFG_PREFIX "user", "",
70 USER_TEXT, USER_LONGTEXT, true )
71 add_password( SOUT_CFG_PREFIX "pwd", "",
72 PASS_TEXT, PASS_LONGTEXT, true )
73 add_string( SOUT_CFG_PREFIX "mime", "",
74 MIME_TEXT, MIME_LONGTEXT, true )
75 set_callbacks( Open, Close )
79 /*****************************************************************************
81 *****************************************************************************/
82 static const char *const ppsz_sout_options[] = {
83 "user", "pwd", "mime", NULL
86 static ssize_t Write( sout_access_out_t *, block_t * );
87 static int Seek ( sout_access_out_t *, off_t );
88 static int Control( sout_access_out_t *, int, va_list );
90 struct sout_access_out_sys_t
93 httpd_host_t *p_httpd_host;
96 httpd_stream_t *p_httpd_stream;
98 /* gather header from stream */
99 int i_header_allocated;
102 bool b_header_complete;
105 /*****************************************************************************
106 * Open: open the file
107 *****************************************************************************/
108 static int Open( vlc_object_t *p_this )
110 sout_access_out_t *p_access = (sout_access_out_t*)p_this;
111 sout_access_out_sys_t *p_sys;
117 if( !( p_sys = p_access->p_sys =
118 malloc( sizeof( sout_access_out_sys_t ) ) ) )
121 config_ChainParse( p_access, SOUT_CFG_PREFIX, ppsz_sout_options, p_access->p_cfg );
123 const char *path = p_access->psz_path;
124 path += strcspn( path, "/" );
125 if( path > p_access->psz_path )
127 const char *port = strrchr( p_access->psz_path, ':' );
128 if( port != NULL && strchr( port, ']' ) != NULL )
129 port = NULL; /* IPv6 numeral */
130 if( port != p_access->psz_path )
132 int len = (port ? port : path) - p_access->psz_path;
133 msg_Warn( p_access, "\"%.*s\" HTTP host might be ignored in "
134 "multiple-host configurations, use at your own risks.",
135 len, p_access->psz_path );
136 msg_Info( p_access, "Consider passing --http-host=IP on the "
137 "command line instead." );
140 strncpy( host, p_access->psz_path, len );
143 var_Create( p_access, "http-host", VLC_VAR_STRING );
144 var_SetString( p_access, "http-host", host );
148 /* int len = path - ++port;
149 msg_Info( p_access, "Consider passing --%s-port=%.*s on the "
150 "command line instead.",
151 strcasecmp( p_access->psz_access, "https" )
152 ? "http" : "https", len, port ); */
155 int bind_port = atoi( port );
158 const char *var = strcasecmp( p_access->psz_access, "https" )
159 ? "http-port" : "https-port";
160 var_Create( p_access, var, VLC_VAR_INTEGER );
161 var_SetInteger( p_access, var, bind_port );
169 if( p_access->psz_access && !strcmp( p_access->psz_access, "https" ) )
170 p_sys->p_httpd_host = vlc_https_HostNew( VLC_OBJECT(p_access) );
172 p_sys->p_httpd_host = vlc_http_HostNew( VLC_OBJECT(p_access) );
174 if( p_sys->p_httpd_host == NULL )
176 msg_Err( p_access, "cannot start HTTP server" );
181 psz_user = var_GetNonEmptyString( p_access, SOUT_CFG_PREFIX "user" );
182 psz_pwd = var_GetNonEmptyString( p_access, SOUT_CFG_PREFIX "pwd" );
183 if( p_access->psz_access && !strcmp( p_access->psz_access, "mmsh" ) )
185 psz_mime = strdup( "video/x-ms-asf-stream" );
189 psz_mime = var_GetNonEmptyString( p_access, SOUT_CFG_PREFIX "mime" );
192 p_sys->p_httpd_stream =
193 httpd_StreamNew( p_sys->p_httpd_host, path, psz_mime,
199 if( p_sys->p_httpd_stream == NULL )
201 msg_Err( p_access, "cannot add stream %s", path );
202 httpd_HostDelete( p_sys->p_httpd_host );
208 p_sys->i_header_allocated = 1024;
209 p_sys->i_header_size = 0;
210 p_sys->p_header = xmalloc( p_sys->i_header_allocated );
211 p_sys->b_header_complete = false;
213 p_access->pf_write = Write;
214 p_access->pf_seek = Seek;
215 p_access->pf_control = Control;
220 /*****************************************************************************
221 * Close: close the target
222 *****************************************************************************/
223 static void Close( vlc_object_t * p_this )
225 sout_access_out_t *p_access = (sout_access_out_t*)p_this;
226 sout_access_out_sys_t *p_sys = p_access->p_sys;
228 httpd_StreamDelete( p_sys->p_httpd_stream );
229 httpd_HostDelete( p_sys->p_httpd_host );
231 free( p_sys->p_header );
233 msg_Dbg( p_access, "Close" );
238 static int Control( sout_access_out_t *p_access, int i_query, va_list args )
244 case ACCESS_OUT_CONTROLS_PACE:
245 *va_arg( args, bool * ) = false;
254 /*****************************************************************************
256 *****************************************************************************/
257 static ssize_t Write( sout_access_out_t *p_access, block_t *p_buffer )
259 sout_access_out_sys_t *p_sys = p_access->p_sys;
267 if( p_buffer->i_flags & BLOCK_FLAG_HEADER )
270 if( p_sys->b_header_complete )
272 /* free previously gathered header */
273 p_sys->i_header_size = 0;
274 p_sys->b_header_complete = false;
276 if( (int)(p_buffer->i_buffer + p_sys->i_header_size) >
277 p_sys->i_header_allocated )
279 p_sys->i_header_allocated =
280 p_buffer->i_buffer + p_sys->i_header_size + 1024;
281 p_sys->p_header = xrealloc( p_sys->p_header,
282 p_sys->i_header_allocated );
284 memcpy( &p_sys->p_header[p_sys->i_header_size],
286 p_buffer->i_buffer );
287 p_sys->i_header_size += p_buffer->i_buffer;
289 else if( !p_sys->b_header_complete )
291 p_sys->b_header_complete = true;
293 httpd_StreamHeader( p_sys->p_httpd_stream, p_sys->p_header,
294 p_sys->i_header_size );
297 i_len += p_buffer->i_buffer;
299 i_err = httpd_StreamSend( p_sys->p_httpd_stream, p_buffer->p_buffer,
300 p_buffer->i_buffer );
302 p_next = p_buffer->p_next;
303 block_Release( p_buffer );
314 block_ChainRelease( p_buffer );
317 return( i_err < 0 ? VLC_EGENERIC : i_len );
320 /*****************************************************************************
321 * Seek: seek to a specific location in a file
322 *****************************************************************************/
323 static int Seek( sout_access_out_t *p_access, off_t i_pos )
326 msg_Warn( p_access, "HTTP sout access cannot seek" );