📄 httpd.c
字号:
/***************************************************************************** * httpd.c ***************************************************************************** * Copyright (C) 2004-2006 the VideoLAN team * $Id: httpd.c 16774 2006-09-21 19:29:10Z hartman $ * * Authors: Laurent Aimar <fenrir@via.ecp.fr> * Rémi Denis-Courmont <rem # videolan.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/#include <stdlib.h>#include <vlc/vlc.h>#ifdef ENABLE_HTTPD#include <assert.h>#include "vlc_httpd.h"#include "network.h"#include "vlc_tls.h"#include "vlc_acl.h"#include <string.h>#include <errno.h>#ifdef HAVE_UNISTD_H# include <unistd.h>#endif#ifdef HAVE_FCNTL_H# include <fcntl.h>#endif#if defined( UNDER_CE )# include <winsock.h>#elif defined( WIN32 )# include <winsock2.h>#else# include <sys/socket.h>#endif#if defined( WIN32 )/* We need HUGE buffer otherwise TCP throughput is very limited */#define HTTPD_CL_BUFSIZE 1000000#else#define HTTPD_CL_BUFSIZE 10000#endifstatic void httpd_ClientClean( httpd_client_t *cl );struct httpd_url_t{ httpd_host_t *host; vlc_mutex_t lock; char *psz_url; char *psz_user; char *psz_password; vlc_acl_t *p_acl; struct { httpd_callback_t cb; httpd_callback_sys_t *p_sys; } catch[HTTPD_MSG_MAX];};/* status */enum{ HTTPD_CLIENT_RECEIVING, HTTPD_CLIENT_RECEIVE_DONE, HTTPD_CLIENT_SENDING, HTTPD_CLIENT_SEND_DONE, HTTPD_CLIENT_WAITING, HTTPD_CLIENT_DEAD, HTTPD_CLIENT_TLS_HS_IN, HTTPD_CLIENT_TLS_HS_OUT};/* mode */enum{ HTTPD_CLIENT_FILE, /* default */ HTTPD_CLIENT_STREAM, /* regulary get data from cb */ HTTPD_CLIENT_BIDIR, /* check for reading and get data from cb */};struct httpd_client_t{ httpd_url_t *url; int i_ref; struct sockaddr_storage sock; int i_sock_size; int fd; int i_mode; int i_state; int b_read_waiting; /* stop as soon as possible sending */ mtime_t i_activity_date; mtime_t i_activity_timeout; /* buffer for reading header */ int i_buffer_size; int i_buffer; uint8_t *p_buffer; /* */ httpd_message_t query; /* client -> httpd */ httpd_message_t answer; /* httpd -> client */ /* TLS data */ tls_session_t *p_tls;};/***************************************************************************** * Various functions *****************************************************************************//*char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";*/static void b64_decode( char *dest, char *src ){ int i_level; int last = 0; int b64[256] = { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 00-0F */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 10-1F */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63, /* 20-2F */ 52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1, /* 30-3F */ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, /* 40-4F */ 15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1, /* 50-5F */ -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, /* 60-6F */ 41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1, /* 70-7F */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 80-8F */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 90-9F */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* A0-AF */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* B0-BF */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* C0-CF */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* D0-DF */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* E0-EF */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 /* F0-FF */ }; for( i_level = 0; *src != '\0'; src++ ) { int c; c = b64[(unsigned int)*src]; if( c == -1 ) { continue; } switch( i_level ) { case 0: i_level++; break; case 1: *dest++ = ( last << 2 ) | ( ( c >> 4)&0x03 ); i_level++; break; case 2: *dest++ = ( ( last << 4 )&0xf0 ) | ( ( c >> 2 )&0x0f ); i_level++; break; case 3: *dest++ = ( ( last &0x03 ) << 6 ) | c; i_level = 0; } last = c; } *dest = '\0';}static struct{ const char *psz_ext; const char *psz_mime;} http_mime[] ={ { ".htm", "text/html" }, { ".html", "text/html" }, { ".txt", "text/plain" }, { ".xml", "text/xml" }, { ".dtd", "text/dtd" }, { ".css", "text/css" }, /* image mime */ { ".gif", "image/gif" }, { ".jpe", "image/jpeg" }, { ".jpg", "image/jpeg" }, { ".jpeg", "image/jpeg" }, { ".png", "image/png" }, { ".mpjpeg","multipart/x-mixed-replace; boundary=This Random String" }, /* media mime */ { ".avi", "video/avi" }, { ".asf", "video/x-ms-asf" }, { ".m1a", "audio/mpeg" }, { ".m2a", "audio/mpeg" }, { ".m1v", "video/mpeg" }, { ".m2v", "video/mpeg" }, { ".mp2", "audio/mpeg" }, { ".mp3", "audio/mpeg" }, { ".mpa", "audio/mpeg" }, { ".mpg", "video/mpeg" }, { ".mpeg", "video/mpeg" }, { ".mpe", "video/mpeg" }, { ".mov", "video/quicktime" }, { ".moov", "video/quicktime" }, { ".ogg", "application/ogg" }, { ".ogm", "application/ogg" }, { ".wav", "audio/wav" }, { ".wma", "audio/x-ms-wma" }, { ".wmv", "video/x-ms-wmv" }, /* end */ { NULL, NULL }};static const char *httpd_MimeFromUrl( const char *psz_url ){ char *psz_ext; psz_ext = strrchr( psz_url, '.' ); if( psz_ext ) { int i; for( i = 0; http_mime[i].psz_ext != NULL ; i++ ) { if( !strcasecmp( http_mime[i].psz_ext, psz_ext ) ) { return http_mime[i].psz_mime; } } } return "application/octet-stream";}#if 0typedef struct{ int i_code; const char *psz_reason;} http_status_info;static const http_status_info http_reason[] ={ /*{ 100, "Continue" }, { 101, "Switching Protocols" },*/ { 200, "OK" }/*, { 201, "Created" }, { 202, "Accepted" }, { 203, "Non-Authoritative Information" }, { 204, "No Content" }, { 205, "Reset Content" }, { 206, "Partial Content" }, { 250, "Low on Storage Space" }, { 300, "Multiple Choices" }*/, { 301, "Moved Permanently" }/*, { 302, "Moved Temporarily" }, - aka "Found" { 303, "See Other" }, { 304, "Not Modified" }, { 305, "Use Proxy" }, { 307, "Temporary Redirect" }, { 400, "Bad Request" }*/, { 401, "Unauthorized" }/*, { 402, "Payment Required" }*/, { 403, "Forbidden" }, { 404, "Not Found" }/*, { 405, "Method Not Allowed" }, { 406, "Not Acceptable" }, { 407, "Proxy Authentication Required" }, { 408, "Request Time-out" }, { 409, "Conflict" }, { 410, "Gone" }, { 411, "Length Required" }, { 412, "Precondition Failed" }, { 413, "Request Entity Too Large" }, { 414, "Request-URI Too Large" }, { 415, "Unsupported Media Type" }, { 416, "Requested range not satisfiable" }, { 417, "Expectation Failed" }, { 451, "Parameter Not Understood" }, { 452, "Conference Not Found" }, { 453, "Not Enough Bandwidth" }*/, { 454, "Session Not Found" }/*, { 455, "Method Not Valid in This State" }, { 456, "Header Field Not Valid for Resource" }, { 457, "Invalid Range" }, { 458, "Parameter Is Read-Only" }, { 459, "Aggregate operation not allowed" }, { 460, "Only aggregate operation allowed" }*/, { 461, "Unsupported transport" }/*, { 462, "Destination unreachable" }*/, { 500, "Internal Server Error" }, { 501, "Not Implemented" }/*, { 502, "Bad Gateway" }*/, { 503, "Service Unavailable" }/*, { 504, "Gateway Time-out" }, { 505, "Protocol version not supported" }*/, { 0, NULL }};static const char *psz_fallback_reason[] ={ "Continue", "OK", "Found", "Client Error", "Server Error" };static const char *httpd_ReasonFromCode( int i_code ){ const http_status_info *p; for (p = http_reason; p->i_code < i_code; p++); if( p->i_code == i_code ) return p->psz_reason; assert( ( i_code >= 100 ) && ( i_code <= 599 ) ); return psz_fallback_reason[(i_code / 100) - 1];}#endif/***************************************************************************** * High Level Functions: 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; uint8_t *psz_args = query->psz_args; uint8_t **pp_body, *p_body; char *psz_connection = NULL; int *pi_body, i_body; 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 ) { pp_body = &answer->p_body; pi_body = &answer->i_body; } else { /* The file still needs to be executed. */ p_body = NULL; i_body = 0; pp_body = &p_body; pi_body = &i_body; } if( query->i_type == HTTPD_MSG_POST ) { /* msg_Warn not supported */ } file->pf_fill( file->p_sys, file, psz_args, pp_body, pi_body ); if( query->i_type == HTTPD_MSG_HEAD && p_body != NULL ) { free( p_body ); } /* We respect client request */ psz_connection = httpd_MsgGet( &cl->query, "Connection" ); if( psz_connection != NULL ) { httpd_MsgAdd( answer, "Connection", psz_connection ); } httpd_MsgAdd( answer, "Content-Length", "%d", answer->i_body ); return VLC_SUCCESS;}httpd_file_t *httpd_FileNew( httpd_host_t *host, const char *psz_url, const char *psz_mime, const char *psz_user, const char *psz_password, const vlc_acl_t *p_acl, httpd_file_callback_t pf_fill, httpd_file_sys_t *p_sys )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -