📄 httpd.c
字号:
/***************************************************************************** * High Level Funtions: httpd_file_t *****************************************************************************/struct httpd_file_t{ httpd_url_t *url; char *psz_url; char *psz_mime; httpd_file_callback_t pf_fill; httpd_file_sys_t *p_sys;};static int httpd_FileCallBack( httpd_callback_sys_t *p_sys, httpd_client_t *cl, httpd_message_t *answer, httpd_message_t *query ){ httpd_file_t *file = (httpd_file_t*)p_sys; if( answer == NULL || query == NULL ) { return VLC_SUCCESS; } answer->i_proto = HTTPD_PROTO_HTTP; answer->i_version= query->i_version; answer->i_type = HTTPD_MSG_ANSWER; answer->i_status = 200; answer->psz_status = strdup( "OK" ); httpd_MsgAdd( answer, "Content-type", "%s", file->psz_mime ); httpd_MsgAdd( answer, "Cache-Control", "%s", "no-cache" ); if( query->i_type != HTTPD_MSG_HEAD ) { char *psz_args = query->psz_args; if( query->i_type == HTTPD_MSG_POST ) { /* Check that */ psz_args = query->p_body; } file->pf_fill( file->p_sys, file, psz_args, &answer->p_body, &answer->i_body ); } /* We respect client request */ if( strcmp( httpd_MsgGet( &cl->query, "Connection" ), "" ) ) { httpd_MsgAdd( answer, "Connection", httpd_MsgGet( &cl->query, "Connection" ) ); } httpd_MsgAdd( answer, "Content-Length", "%d", answer->i_body ); return VLC_SUCCESS;}httpd_file_t *httpd_FileNew( httpd_host_t *host, char *psz_url, char *psz_mime, char *psz_user, char *psz_password, httpd_file_callback_t pf_fill, httpd_file_sys_t *p_sys ){ httpd_file_t *file = malloc( sizeof( httpd_file_t ) ); if( ( file->url = httpd_UrlNewUnique( host, psz_url, psz_user, psz_password ) ) == NULL ) { free( file ); return NULL; } file->psz_url = strdup( psz_url ); if( psz_mime && *psz_mime ) { file->psz_mime = strdup( psz_mime ); } else { file->psz_mime = strdup( httpd_MimeFromUrl( psz_url ) ); } file->pf_fill = pf_fill; file->p_sys = p_sys; httpd_UrlCatch( file->url, HTTPD_MSG_HEAD, httpd_FileCallBack, (httpd_callback_sys_t*)file ); httpd_UrlCatch( file->url, HTTPD_MSG_GET, httpd_FileCallBack, (httpd_callback_sys_t*)file ); httpd_UrlCatch( file->url, HTTPD_MSG_POST, httpd_FileCallBack, (httpd_callback_sys_t*)file ); return file;}void httpd_FileDelete( httpd_file_t *file ){ httpd_UrlDelete( file->url ); free( file->psz_url ); free( file->psz_mime ); free( file );}/***************************************************************************** * High Level Funtions: httpd_redirect_t *****************************************************************************/struct httpd_redirect_t{ httpd_url_t *url; char *psz_dst;};static int httpd_RedirectCallBack( httpd_callback_sys_t *p_sys, httpd_client_t *cl, httpd_message_t *answer, httpd_message_t *query ){ httpd_redirect_t *rdir = (httpd_redirect_t*)p_sys; uint8_t *p; if( answer == NULL || query == NULL ) { return VLC_SUCCESS; } answer->i_proto = query->i_proto; answer->i_version= query->i_version; answer->i_type = HTTPD_MSG_ANSWER; answer->i_status = 301; answer->psz_status = strdup( "Moved Permanently" ); p = answer->p_body = malloc( 1000 + strlen( rdir->psz_dst ) ); p += sprintf( p, "<html>\n" ); p += sprintf( p, "<head>\n" ); p += sprintf( p, "<title>Redirection</title>\n" ); p += sprintf( p, "</head>\n" ); p += sprintf( p, "<body>\n" ); p += sprintf( p, "<h1><center>You should be <a href=\"%s\">redirected</a></center></h1>\n", rdir->psz_dst ); p += sprintf( p, "<hr />\n" ); p += sprintf( p, "<a href=\"http://www.videolan.org\">VideoLAN</a>\n" ); p += sprintf( p, "</body>\n" ); p += sprintf( p, "</html>\n" ); answer->i_body = p - answer->p_body; /* XXX check if it's ok or we need to set an absolute url */ httpd_MsgAdd( answer, "Location", "%s", rdir->psz_dst ); httpd_MsgAdd( answer, "Content-Length", "%d", answer->i_body ); return VLC_SUCCESS;}httpd_redirect_t *httpd_RedirectNew( httpd_host_t *host, char *psz_url_dst, char *psz_url_src ){ httpd_redirect_t *rdir = malloc( sizeof( httpd_redirect_t ) ); if( !( rdir->url = httpd_UrlNewUnique( host, psz_url_src, NULL, NULL ) ) ) { free( rdir ); return NULL; } rdir->psz_dst = strdup( psz_url_dst ); /* Redirect apply for all HTTP request and RTSP DESCRIBE resquest */ httpd_UrlCatch( rdir->url, HTTPD_MSG_HEAD, httpd_RedirectCallBack, (httpd_callback_sys_t*)rdir ); httpd_UrlCatch( rdir->url, HTTPD_MSG_GET, httpd_RedirectCallBack, (httpd_callback_sys_t*)rdir ); httpd_UrlCatch( rdir->url, HTTPD_MSG_POST, httpd_RedirectCallBack, (httpd_callback_sys_t*)rdir ); httpd_UrlCatch( rdir->url, HTTPD_MSG_DESCRIBE, httpd_RedirectCallBack, (httpd_callback_sys_t*)rdir ); return rdir;}void httpd_RedirectDelete( httpd_redirect_t *rdir ){ httpd_UrlDelete( rdir->url ); free( rdir->psz_dst ); free( rdir );}/***************************************************************************** * High Level Funtions: httpd_stream_t *****************************************************************************/struct httpd_stream_t{ vlc_mutex_t lock; httpd_url_t *url; char *psz_mime; /* Header to send as first packet */ uint8_t *p_header; int i_header; /* circular buffer */ int i_buffer_size; /* buffer size, can't be reallocated smaller */ uint8_t *p_buffer; /* buffer */ int64_t i_buffer_pos; /* absolute position from begining */ int64_t i_buffer_last_pos; /* a new connection will start with that */};static int httpd_StreamCallBack( httpd_callback_sys_t *p_sys, httpd_client_t *cl, httpd_message_t *answer, httpd_message_t *query ){ httpd_stream_t *stream = (httpd_stream_t*)p_sys; if( answer == NULL || query == NULL || cl == NULL ) { return VLC_SUCCESS; } if( answer->i_body_offset > 0 ) { int64_t i_write; int i_pos;#if 0 fprintf( stderr, "httpd_StreamCallBack i_body_offset=%lld\n", answer->i_body_offset );#endif if( answer->i_body_offset >= stream->i_buffer_pos ) { /* fprintf( stderr, "httpd_StreamCallBack: no data\n" ); */ return VLC_EGENERIC; /* wait, no data available */ } if( answer->i_body_offset + stream->i_buffer_size < stream->i_buffer_pos ) { /* this client isn't fast enough */ fprintf( stderr, "fixing i_body_offset (old=%lld new=%lld)\n", answer->i_body_offset, stream->i_buffer_last_pos ); answer->i_body_offset = stream->i_buffer_last_pos; } i_pos = answer->i_body_offset % stream->i_buffer_size; i_write = stream->i_buffer_pos - answer->i_body_offset; if( i_write > 10000 ) { i_write = 10000; } else if( i_write <= 0 ) { return VLC_EGENERIC; /* wait, no data available */ } /* Don't go past the end of the circular buffer */ i_write = __MIN( i_write, stream->i_buffer_size - i_pos ); /* using HTTPD_MSG_ANSWER -> data available */ answer->i_proto = HTTPD_PROTO_HTTP; answer->i_version= 0; answer->i_type = HTTPD_MSG_ANSWER; answer->i_body = i_write; answer->p_body = malloc( i_write ); memcpy( answer->p_body, &stream->p_buffer[i_pos], i_write ); answer->i_body_offset += i_write; return VLC_SUCCESS; } else { answer->i_proto = HTTPD_PROTO_HTTP; answer->i_version= 0; answer->i_type = HTTPD_MSG_ANSWER; answer->i_status = 200; answer->psz_status = strdup( "OK" ); if( query->i_type != HTTPD_MSG_HEAD ) { httpd_ClientModeStream( cl ); vlc_mutex_lock( &stream->lock ); /* Send the header */ if( stream->i_header > 0 ) { answer->i_body = stream->i_header; answer->p_body = malloc( stream->i_header ); memcpy( answer->p_body, stream->p_header, stream->i_header ); } answer->i_body_offset = stream->i_buffer_last_pos; vlc_mutex_unlock( &stream->lock ); } else { httpd_MsgAdd( answer, "Content-Length", "%d", 0 ); answer->i_body_offset = 0; } if( !strcmp( stream->psz_mime, "video/x-ms-asf-stream" ) ) { vlc_bool_t b_xplaystream = VLC_FALSE; int i; httpd_MsgAdd( answer, "Content-type", "%s", "application/octet-stream" ); httpd_MsgAdd( answer, "Server", "Cougar 4.1.0.3921" ); httpd_MsgAdd( answer, "Pragma", "no-cache" ); httpd_MsgAdd( answer, "Pragma", "client-id=%d", rand()&0x7fff ); httpd_MsgAdd( answer, "Pragma", "features=\"broadcast\"" ); /* Check if there is a xPlayStrm=1 */ for( i = 0; i < query->i_name; i++ ) { if( !strcasecmp( query->name[i], "Pragma" ) && strstr( query->value[i], "xPlayStrm=1" ) ) { b_xplaystream = VLC_TRUE; } } if( !b_xplaystream ) { answer->i_body_offset = 0; } } else { httpd_MsgAdd( answer, "Content-type", "%s", stream->psz_mime ); } httpd_MsgAdd( answer, "Cache-Control", "%s", "no-cache" ); return VLC_SUCCESS; }}httpd_stream_t *httpd_StreamNew( httpd_host_t *host, char *psz_url, char *psz_mime, char *psz_user, char *psz_password ){ httpd_stream_t *stream = malloc( sizeof( httpd_stream_t ) ); if( ( stream->url = httpd_UrlNewUnique( host, psz_url, psz_user, psz_password ) ) == NULL ) { free( stream ); return NULL; } vlc_mutex_init( host, &stream->lock ); if( psz_mime && *psz_mime ) { stream->psz_mime = strdup( psz_mime ); } else { stream->psz_mime = strdup( httpd_MimeFromUrl( psz_url ) ); } stream->i_header = 0; stream->p_header = NULL; stream->i_buffer_size = 5000000; /* 5 Mo per stream */ stream->p_buffer = malloc( stream->i_buffer_size ); /* We set to 1 to make life simpler * (this way i_body_offset can never be 0) */ stream->i_buffer_pos = 1; stream->i_buffer_last_pos = 1; httpd_UrlCatch( stream->url, HTTPD_MSG_HEAD, httpd_StreamCallBack, (httpd_callback_sys_t*)stream ); httpd_UrlCatch( stream->url, HTTPD_MSG_GET, httpd_StreamCallBack, (httpd_callback_sys_t*)stream ); httpd_UrlCatch( stream->url, HTTPD_MSG_POST, httpd_StreamCallBack, (httpd_callback_sys_t*)stream ); return stream;}int httpd_StreamHeader( httpd_stream_t *stream, uint8_t *p_data, int i_data ){ vlc_mutex_lock( &stream->lock ); if( stream->p_header ) { free( stream->p_header ); stream->p_header = NULL; } stream->i_header = i_data; if( i_data > 0 ) { stream->p_header = malloc( i_data ); memcpy( stream->p_header, p_data, i_data ); } vlc_mutex_unlock( &stream->lock ); return VLC_SUCCESS;}int httpd_StreamSend( httpd_stream_t *stream, uint8_t *p_data, int i_data ){ int i_count; int i_pos; if( i_data < 0 || p_data == NULL ) { return VLC_SUCCESS; } vlc_mutex_lock( &stream->lock ); /* save this pointer (to be used by new connection) */ stream->i_buffer_last_pos = stream->i_buffer_pos; i_pos = stream->i_buffer_pos % stream->i_buffer_size; i_count = i_data; while( i_count > 0) { int i_copy; i_copy = __MIN( i_count, stream->i_buffer_size - i_pos ); /* Ok, we can't go past the end of our buffer */ memcpy( &stream->p_buffer[i_pos], p_data, i_copy ); i_pos = ( i_pos + i_copy ) % stream->i_buffer_size; i_count -= i_copy; p_data += i_copy; } stream->i_buffer_pos += i_data; vlc_mutex_unlock( &stream->lock ); return VLC_SUCCESS;}void httpd_StreamDelete( httpd_stream_t *stream ){ httpd_UrlDelete( stream->url ); vlc_mutex_destroy( &stream->lock ); if( stream->psz_mime ) free( stream->psz_mime ); if( stream->p_header ) free( stream->p_header ); if( stream->p_buffer ) free( stream->p_buffer ); free( stream );}/***************************************************************************** * Low level
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -