Commit 1ffcc4e5 authored by Denis Charmet's avatar Denis Charmet

Allow custom HTTP headers for httpd_Stream

This will end up useful for cubemap implementation and may allow to put mms stuff out of the core
parent 956a6bc8
...@@ -71,6 +71,12 @@ VLC_API httpd_host_t *vlc_rtsp_HostNew( vlc_object_t * ) VLC_USED; ...@@ -71,6 +71,12 @@ VLC_API httpd_host_t *vlc_rtsp_HostNew( vlc_object_t * ) VLC_USED;
/* delete a host */ /* delete a host */
VLC_API void httpd_HostDelete( httpd_host_t * ); VLC_API void httpd_HostDelete( httpd_host_t * );
typedef struct
{
char * name;
char * value;
} httpd_header;
typedef struct httpd_message_t typedef struct httpd_message_t
{ {
httpd_client_t *cl; /* NULL if not throught a connection e vlc internal */ httpd_client_t *cl; /* NULL if not throught a connection e vlc internal */
...@@ -89,10 +95,8 @@ typedef struct httpd_message_t ...@@ -89,10 +95,8 @@ typedef struct httpd_message_t
uint8_t *psz_args; uint8_t *psz_args;
/* options */ /* options */
int i_name; size_t i_headers;
char **name; httpd_header *p_headers;
int i_value;
char **value;
/* body */ /* body */
int64_t i_body_offset; int64_t i_body_offset;
...@@ -139,7 +143,7 @@ VLC_API httpd_stream_t * httpd_StreamNew( httpd_host_t *, const char *psz_url, c ...@@ -139,7 +143,7 @@ VLC_API httpd_stream_t * httpd_StreamNew( httpd_host_t *, const char *psz_url, c
VLC_API void httpd_StreamDelete( httpd_stream_t * ); VLC_API void httpd_StreamDelete( httpd_stream_t * );
VLC_API int httpd_StreamHeader( httpd_stream_t *, uint8_t *p_data, int i_data ); VLC_API int httpd_StreamHeader( httpd_stream_t *, uint8_t *p_data, int i_data );
VLC_API int httpd_StreamSend( httpd_stream_t *, const block_t *p_block ); VLC_API int httpd_StreamSend( httpd_stream_t *, const block_t *p_block );
VLC_API int httpd_StreamSetHTTPHeaders(httpd_stream_t *, httpd_header *, size_t);
/* Msg functions facilities */ /* Msg functions facilities */
VLC_API void httpd_MsgAdd( httpd_message_t *, const char *psz_name, const char *psz_value, ... ) VLC_FORMAT( 3, 4 ); VLC_API void httpd_MsgAdd( httpd_message_t *, const char *psz_name, const char *psz_value, ... ) VLC_FORMAT( 3, 4 );
......
...@@ -162,6 +162,7 @@ httpd_StreamDelete ...@@ -162,6 +162,7 @@ httpd_StreamDelete
httpd_StreamHeader httpd_StreamHeader
httpd_StreamNew httpd_StreamNew
httpd_StreamSend httpd_StreamSend
httpd_StreamSetHTTPHeaders
httpd_UrlCatch httpd_UrlCatch
httpd_UrlDelete httpd_UrlDelete
httpd_UrlNew httpd_UrlNew
......
...@@ -645,6 +645,10 @@ struct httpd_stream_t ...@@ -645,6 +645,10 @@ struct httpd_stream_t
uint8_t *p_buffer; /* buffer */ uint8_t *p_buffer; /* buffer */
int64_t i_buffer_pos; /* absolute position from begining */ int64_t i_buffer_pos; /* absolute position from begining */
int64_t i_buffer_last_pos; /* a new connection will start with that */ int64_t i_buffer_last_pos; /* a new connection will start with that */
/* custom headers */
size_t i_http_headers;
httpd_header * p_http_headers;
}; };
static int httpd_StreamCallBack( httpd_callback_sys_t *p_sys, static int httpd_StreamCallBack( httpd_callback_sys_t *p_sys,
...@@ -729,6 +733,25 @@ static int httpd_StreamCallBack( httpd_callback_sys_t *p_sys, ...@@ -729,6 +733,25 @@ static int httpd_StreamCallBack( httpd_callback_sys_t *p_sys,
answer->i_status = 200; answer->i_status = 200;
bool b_has_content_type = false;
bool b_has_cache_control = false;
vlc_mutex_lock( &stream->lock );
for( size_t i = 0; i < stream->i_http_headers; i++ )
{
if( strncasecmp( stream->p_http_headers[i].name, "Content-Length", 14 ) )
{
httpd_MsgAdd( answer, stream->p_http_headers[i].name,
stream->p_http_headers[i].value );
if( !strncasecmp( stream->p_http_headers[i].name, "Content-Type", 12 ) )
b_has_content_type = true;
else if( !strncasecmp( stream->p_http_headers[i].name, "Cache-Control", 13 ) )
b_has_cache_control = true;
}
}
vlc_mutex_unlock( &stream->lock );
if( query->i_type != HTTPD_MSG_HEAD ) if( query->i_type != HTTPD_MSG_HEAD )
{ {
cl->b_stream_mode = true; cl->b_stream_mode = true;
...@@ -749,17 +772,17 @@ static int httpd_StreamCallBack( httpd_callback_sys_t *p_sys, ...@@ -749,17 +772,17 @@ static int httpd_StreamCallBack( httpd_callback_sys_t *p_sys,
} }
else else
{ {
httpd_MsgAdd( answer, "Content-Length", "%d", 0 ); httpd_MsgAdd( answer, "Content-Length", "0" );
answer->i_body_offset = 0; answer->i_body_offset = 0;
} }
/* FIXME: move to http access_output */
if( !strcmp( stream->psz_mime, "video/x-ms-asf-stream" ) ) if( !strcmp( stream->psz_mime, "video/x-ms-asf-stream" ) )
{ {
bool b_xplaystream = false; bool b_xplaystream = false;
int i; int i;
httpd_MsgAdd( answer, "Content-type", "%s", httpd_MsgAdd( answer, "Content-type", "application/octet-stream" );
"application/octet-stream" );
httpd_MsgAdd( answer, "Server", "Cougar 4.1.0.3921" ); httpd_MsgAdd( answer, "Server", "Cougar 4.1.0.3921" );
httpd_MsgAdd( answer, "Pragma", "no-cache" ); httpd_MsgAdd( answer, "Pragma", "no-cache" );
httpd_MsgAdd( answer, "Pragma", "client-id=%lu", httpd_MsgAdd( answer, "Pragma", "client-id=%lu",
...@@ -767,10 +790,10 @@ static int httpd_StreamCallBack( httpd_callback_sys_t *p_sys, ...@@ -767,10 +790,10 @@ static int httpd_StreamCallBack( httpd_callback_sys_t *p_sys,
httpd_MsgAdd( answer, "Pragma", "features=\"broadcast\"" ); httpd_MsgAdd( answer, "Pragma", "features=\"broadcast\"" );
/* Check if there is a xPlayStrm=1 */ /* Check if there is a xPlayStrm=1 */
for( i = 0; i < query->i_name; i++ ) for( i = 0; i < query->i_headers; i++ )
{ {
if( !strcasecmp( query->name[i], "Pragma" ) && if( !strcasecmp( query->p_headers[i].name, "Pragma" ) &&
strstr( query->value[i], "xPlayStrm=1" ) ) strstr( query->p_headers[i].value, "xPlayStrm=1" ) )
{ {
b_xplaystream = true; b_xplaystream = true;
} }
...@@ -781,11 +804,12 @@ static int httpd_StreamCallBack( httpd_callback_sys_t *p_sys, ...@@ -781,11 +804,12 @@ static int httpd_StreamCallBack( httpd_callback_sys_t *p_sys,
answer->i_body_offset = 0; answer->i_body_offset = 0;
} }
} }
else else if( !b_has_content_type )
{ {
httpd_MsgAdd( answer, "Content-type", "%s", stream->psz_mime ); httpd_MsgAdd( answer, "Content-type", stream->psz_mime );
} }
httpd_MsgAdd( answer, "Cache-Control", "%s", "no-cache" ); if( !b_has_cache_control )
httpd_MsgAdd( answer, "Cache-Control", "no-cache" );
return VLC_SUCCESS; return VLC_SUCCESS;
} }
} }
...@@ -821,6 +845,8 @@ httpd_stream_t *httpd_StreamNew( httpd_host_t *host, ...@@ -821,6 +845,8 @@ httpd_stream_t *httpd_StreamNew( httpd_host_t *host,
stream->i_buffer_last_pos = 1; stream->i_buffer_last_pos = 1;
stream->b_has_keyframes = false; stream->b_has_keyframes = false;
stream->i_last_keyframe_seen_pos = 0; stream->i_last_keyframe_seen_pos = 0;
stream->i_http_headers = 0;
stream->p_http_headers = NULL;
httpd_UrlCatch( stream->url, HTTPD_MSG_HEAD, httpd_StreamCallBack, httpd_UrlCatch( stream->url, HTTPD_MSG_HEAD, httpd_StreamCallBack,
(httpd_callback_sys_t*)stream ); (httpd_callback_sys_t*)stream );
...@@ -896,6 +922,12 @@ int httpd_StreamSend( httpd_stream_t *stream, const block_t *p_block ) ...@@ -896,6 +922,12 @@ int httpd_StreamSend( httpd_stream_t *stream, const block_t *p_block )
void httpd_StreamDelete( httpd_stream_t *stream ) void httpd_StreamDelete( httpd_stream_t *stream )
{ {
httpd_UrlDelete( stream->url ); httpd_UrlDelete( stream->url );
for( size_t i = 0; i < stream->i_http_headers; i++ )
{
free( stream->p_http_headers[i].name );
free( stream->p_http_headers[i].value );
}
free( stream->p_http_headers );
vlc_mutex_destroy( &stream->lock ); vlc_mutex_destroy( &stream->lock );
free( stream->psz_mime ); free( stream->psz_mime );
free( stream->p_header ); free( stream->p_header );
...@@ -1238,10 +1270,8 @@ static void httpd_MsgInit( httpd_message_t *msg ) ...@@ -1238,10 +1270,8 @@ static void httpd_MsgInit( httpd_message_t *msg )
msg->psz_url = NULL; msg->psz_url = NULL;
msg->psz_args = NULL; msg->psz_args = NULL;
msg->i_name = 0; msg->i_headers = 0;
msg->name = NULL; msg->p_headers = NULL;
msg->i_value = 0;
msg->value = NULL;
msg->i_body_offset = 0; msg->i_body_offset = 0;
msg->i_body = 0; msg->i_body = 0;
...@@ -1252,22 +1282,25 @@ static void httpd_MsgClean( httpd_message_t *msg ) ...@@ -1252,22 +1282,25 @@ static void httpd_MsgClean( httpd_message_t *msg )
{ {
free( msg->psz_url ); free( msg->psz_url );
free( msg->psz_args ); free( msg->psz_args );
for (int i = 0; i < msg->i_name; i++) { for( size_t i = 0; i < msg->i_headers; i++ )
free( msg->name[i] ); {
free( msg->value[i] ); free( msg->p_headers[i].name );
free( msg->p_headers[i].value );
} }
free( msg->name ); free( msg->p_headers );
free( msg->value );
free( msg->p_body ); free( msg->p_body );
httpd_MsgInit( msg ); httpd_MsgInit( msg );
} }
const char *httpd_MsgGet( const httpd_message_t *msg, const char *name ) const char *httpd_MsgGet( const httpd_message_t *msg, const char *name )
{ {
for (int i = 0; i < msg->i_name; i++ ) for( size_t i = 0; i < msg->i_headers; i++ )
if( !strcasecmp( msg->name[i], name )) {
return msg->value[i]; if( !strcasecmp( msg->p_headers[i].name, name ))
{
return msg->p_headers[i].value;
}
}
return NULL; return NULL;
} }
...@@ -1290,9 +1323,19 @@ void httpd_MsgAdd( httpd_message_t *msg, const char *name, const char *psz_value ...@@ -1290,9 +1323,19 @@ void httpd_MsgAdd( httpd_message_t *msg, const char *name, const char *psz_value
free( value ); free( value );
return; return;
} }
httpd_header * p_tmp = realloc( msg->p_headers, sizeof(httpd_header) * (msg->i_headers + 1));
TAB_APPEND( msg->i_name, msg->name, (char*)name ); if(p_tmp)
TAB_APPEND( msg->i_value, msg->value, value ); {
msg->p_headers = p_tmp;
msg->p_headers[msg->i_headers].name = name;
msg->p_headers[msg->i_headers].value = value;
msg->i_headers++;
}
else
{
free(name);
free(value);
}
} }
static void httpd_ClientInit( httpd_client_t *cl, mtime_t now ) static void httpd_ClientInit( httpd_client_t *cl, mtime_t now )
...@@ -1687,23 +1730,16 @@ static void httpd_ClientRecv( httpd_client_t *cl ) ...@@ -1687,23 +1730,16 @@ static void httpd_ClientRecv( httpd_client_t *cl )
if( ( colon = strchr( line, ':' ) ) ) if( ( colon = strchr( line, ':' ) ) )
{ {
char *name;
char *value;
*colon++ = '\0'; *colon++ = '\0';
while( *colon == ' ' ) while( *colon == ' ' )
{ {
colon++; colon++;
} }
name = strdup( line ); httpd_MsgAdd( &cl->query, line, colon );
value = strdup( colon );
TAB_APPEND( cl->query.i_name, cl->query.name, name );
TAB_APPEND( cl->query.i_value,cl->query.value,value);
if( !strcasecmp( name, "Content-Length" ) ) if( !strcasecmp( line, "Content-Length" ) )
{ {
cl->query.i_body = atol( value ); cl->query.i_body = atol( colon );
} }
} }
...@@ -1820,10 +1856,10 @@ static void httpd_ClientSend( httpd_client_t *cl ) ...@@ -1820,10 +1856,10 @@ static void httpd_ClientSend( httpd_client_t *cl )
const char *psz_status = httpd_ReasonFromCode( cl->answer.i_status ); const char *psz_status = httpd_ReasonFromCode( cl->answer.i_status );
i_size = strlen( "HTTP/1.") + 10 + 10 + strlen( psz_status ) + 5; i_size = strlen( "HTTP/1.") + 10 + 10 + strlen( psz_status ) + 5;
for( i = 0; i < cl->answer.i_name; i++ ) for( i = 0; i < cl->answer.i_headers; i++ )
{ {
i_size += strlen( cl->answer.name[i] ) + 2 + i_size += strlen( cl->answer.p_headers[i].name ) + 2 +
strlen( cl->answer.value[i] ) + 2; strlen( cl->answer.p_headers[i].value ) + 2;
} }
if( cl->i_buffer_size < i_size ) if( cl->i_buffer_size < i_size )
...@@ -1838,10 +1874,10 @@ static void httpd_ClientSend( httpd_client_t *cl ) ...@@ -1838,10 +1874,10 @@ static void httpd_ClientSend( httpd_client_t *cl )
cl->answer.i_proto == HTTPD_PROTO_HTTP ? "HTTP/1" : "RTSP/1", cl->answer.i_proto == HTTPD_PROTO_HTTP ? "HTTP/1" : "RTSP/1",
cl->answer.i_version, cl->answer.i_version,
cl->answer.i_status, psz_status ); cl->answer.i_status, psz_status );
for( i = 0; i < cl->answer.i_name; i++ ) for( i = 0; i < cl->answer.i_headers; i++ )
{ {
p += sprintf( p, "%s: %s\r\n", cl->answer.name[i], p += sprintf( p, "%s: %s\r\n", cl->answer.p_headers[i].name,
cl->answer.value[i] ); cl->answer.p_headers[i].value );
} }
p += sprintf( p, "\r\n" ); p += sprintf( p, "\r\n" );
...@@ -2324,3 +2360,57 @@ static void* httpd_HostThread( void *data ) ...@@ -2324,3 +2360,57 @@ static void* httpd_HostThread( void *data )
vlc_mutex_unlock( &host->lock ); vlc_mutex_unlock( &host->lock );
return NULL; return NULL;
} }
int httpd_StreamSetHTTPHeaders(httpd_stream_t * p_stream, httpd_header * p_headers, size_t i_headers )
{
if( !p_stream )
return VLC_EGENERIC;
vlc_mutex_lock( &p_stream->lock );
if( p_stream->p_http_headers )
{
for( size_t i = 0; i < p_stream->i_http_headers; i++)
{
free( p_stream->p_http_headers[i].name );
free( p_stream->p_http_headers[i].value );
}
free( p_stream->p_http_headers );
p_stream->p_http_headers = NULL;
p_stream->i_http_headers = 0;
}
if( !p_headers || !i_headers )
{
vlc_mutex_unlock( &p_stream->lock );
return VLC_SUCCESS;
}
p_stream->p_http_headers = malloc(sizeof(httpd_header) * i_headers );
if( !p_stream->p_http_headers )
{
vlc_mutex_unlock( &p_stream->lock );
return VLC_ENOMEM;
}
size_t j = 0;
for( size_t i = 0; i < i_headers; i++ )
{
if( unlikely( !p_headers[i].name || !p_headers[i].value ) )
continue;
p_stream->p_http_headers[j].name = strdup( p_headers[i].name );
p_stream->p_http_headers[j].value = strdup( p_headers[i].value );
if( unlikely( !p_stream->p_http_headers[j].name ||
!p_stream->p_http_headers[j].value ) )
{
free( p_stream->p_http_headers[j].name );
free( p_stream->p_http_headers[j].value );
break;
}
j++;
}
p_stream->i_http_headers = j;
vlc_mutex_unlock( &p_stream->lock );
return VLC_SUCCESS;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment