@ -126,7 +126,7 @@ static const AVOption options[] = {
{ " location " , " The actual location of the data received " , OFFSET ( location ) , AV_OPT_TYPE_STRING , { 0 } , 0 , 0 , D | E } ,
{ " offset " , " initial byte offset " , OFFSET ( off ) , AV_OPT_TYPE_INT64 , { . i64 = 0 } , 0 , INT64_MAX , D } ,
{ " end_offset " , " try to limit the request to bytes preceding this offset " , OFFSET ( end_off ) , AV_OPT_TYPE_INT64 , { . i64 = 0 } , 0 , INT64_MAX , D } ,
{ " method " , " Override the HTTP method " , OFFSET ( method ) , AV_OPT_TYPE_STRING , { . str = NULL } , 0 , 0 , E } ,
{ " method " , " Override the HTTP method or set the expected HTTP method from a client " , OFFSET ( method ) , AV_OPT_TYPE_STRING , { . str = NULL } , 0 , 0 , D | E } ,
{ " reconnect " , " auto reconnect after disconnect before EOF " , OFFSET ( reconnect ) , AV_OPT_TYPE_INT , { . i64 = 0 } , 0 , 1 , D } ,
{ " listen " , " listen on HTTP " , OFFSET ( listen ) , AV_OPT_TYPE_INT , { . i64 = 0 } , 0 , 1 , D | E } ,
{ NULL }
@ -299,6 +299,23 @@ int ff_http_averror(int status_code, int default_averror)
return default_averror ;
}
static void handle_http_errors ( URLContext * h , int error )
{
static const char bad_request [ ] = " HTTP/1.1 400 Bad Request \r \n Content-Type: text/plain \r \n \r \n 400 Bad Request \r \n " ;
static const char internal_server_error [ ] = " HTTP/1.1 500 Internal server error \r \n Content-Type: text/plain \r \n \r \n 500 Internal server error \r \n " ;
HTTPContext * s = h - > priv_data ;
if ( h - > is_connected ) {
switch ( error ) {
case AVERROR_HTTP_BAD_REQUEST :
ffurl_write ( s - > hd , bad_request , strlen ( bad_request ) ) ;
break ;
default :
av_log ( h , AV_LOG_ERROR , " Unhandled HTTP error. \n " ) ;
ffurl_write ( s - > hd , internal_server_error , strlen ( internal_server_error ) ) ;
}
}
}
static int http_listen ( URLContext * h , const char * uri , int flags ,
AVDictionary * * options ) {
HTTPContext * s = h - > priv_data ;
@ -318,13 +335,14 @@ static int http_listen(URLContext *h, const char *uri, int flags,
if ( ( ret = ffurl_open ( & s - > hd , lower_url , AVIO_FLAG_READ_WRITE ,
& h - > interrupt_callback , options ) ) < 0 )
goto fail ;
if ( ( ret = ffurl_write ( s - > hd , header , strlen ( header ) ) ) < 0 )
goto fail ;
if ( ( ret = http_read_header ( h , & new_location ) ) < 0 )
goto fail ;
if ( ( ret = ffurl_write ( s - > hd , header , strlen ( header ) ) ) < 0 )
goto fail ;
return 0 ;
fail :
handle_http_errors ( h , ret ) ;
av_dict_free ( & s - > chained_options ) ;
return ret ;
}
@ -545,7 +563,8 @@ static int process_line(URLContext *h, char *line, int line_count,
int * new_location )
{
HTTPContext * s = h - > priv_data ;
char * tag , * p , * end ;
const char * auto_method = h - > flags & AVIO_FLAG_READ ? " POST " : " GET " ;
char * tag , * p , * end , * method , * resource , * version ;
int ret ;
/* end of header */
@ -556,16 +575,62 @@ static int process_line(URLContext *h, char *line, int line_count,
p = line ;
if ( line_count = = 0 ) {
while ( ! av_isspace ( * p ) & & * p ! = ' \0 ' )
p + + ;
while ( av_isspace ( * p ) )
p + + ;
s - > http_code = strtol ( p , & end , 10 ) ;
if ( s - > listen ) {
// HTTP method
method = p ;
while ( ! av_isspace ( * p ) )
p + + ;
* ( p + + ) = ' \0 ' ;
av_log ( h , AV_LOG_TRACE , " Received method: %s \n " , method ) ;
if ( s - > method ) {
if ( av_strcasecmp ( s - > method , method ) ) {
av_log ( h , AV_LOG_ERROR , " Received and expected HTTP method do not match. (%s expected, %s received) \n " ,
s - > method , method ) ;
return ff_http_averror ( 400 , AVERROR ( EIO ) ) ;
}
} else {
// use autodetected HTTP method to expect
av_log ( h , AV_LOG_TRACE , " Autodetected %s HTTP method \n " , auto_method ) ;
if ( av_strcasecmp ( auto_method , method ) ) {
av_log ( h , AV_LOG_ERROR , " Received and autodetected HTTP method did not match "
" (%s autodetected %s received) \n " , auto_method , method ) ;
return ff_http_averror ( 400 , AVERROR ( EIO ) ) ;
}
}
// HTTP resource
while ( av_isspace ( * p ) )
p + + ;
resource = p ;
while ( ! av_isspace ( * p ) )
p + + ;
* ( p + + ) = ' \0 ' ;
av_log ( h , AV_LOG_TRACE , " Requested resource: %s \n " , resource ) ;
// HTTP version
while ( av_isspace ( * p ) )
p + + ;
version = p ;
while ( ! av_isspace ( * p ) )
p + + ;
* p = ' \0 ' ;
if ( av_strncasecmp ( version , " HTTP/ " , 5 ) ) {
av_log ( h , AV_LOG_ERROR , " Malformed HTTP version string. \n " ) ;
return ff_http_averror ( 400 , AVERROR ( EIO ) ) ;
}
av_log ( h , AV_LOG_TRACE , " HTTP version string: %s \n " , version ) ;
} else {
while ( ! av_isspace ( * p ) & & * p ! = ' \0 ' )
p + + ;
while ( av_isspace ( * p ) )
p + + ;
s - > http_code = strtol ( p , & end , 10 ) ;
av_log ( h , AV_LOG_TRACE , " http_code=%d \n " , s - > http_code ) ;
av_log ( h , AV_LOG_TRACE , " http_code=%d \n " , s - > http_code ) ;
if ( ( ret = check_http_code ( h , s - > http_code , end ) ) < 0 )
return ret ;
if ( ( ret = check_http_code ( h , s - > http_code , end ) ) < 0 )
return ret ;
}
} else {
while ( * p ! = ' \0 ' & & * p ! = ' : ' )
p + + ;