📄 httpd.c
字号:
/***************************************************************************** * httpd.c ***************************************************************************** * Copyright (C) 2004-2006 the VideoLAN team * Copyright © 2004-2007 Rémi Denis-Courmont * $Id: c98b51c22797faa21727b9ff2256a6661d1e7bde $ * * 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. *****************************************************************************/#ifdef HAVE_CONFIG_H# include "config.h"#endif#include <vlc_common.h>#include <vlc_httpd.h>#ifdef ENABLE_HTTPD#include <assert.h>#include <vlc_network.h>#include <vlc_tls.h>#include <vlc_acl.h>#include <vlc_strings.h>#include "../libvlc.h"#include <string.h>#include <errno.h>#ifdef HAVE_UNISTD_H# include <unistd.h>#endif#ifdef HAVE_FCNTL_H# include <fcntl.h>#endif#ifdef HAVE_POLL# include <poll.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_t{ VLC_COMMON_MEMBERS int i_host; httpd_host_t **host;};/* each host run in his own thread */struct httpd_host_t{ VLC_COMMON_MEMBERS httpd_t *httpd; /* ref count */ int i_ref; /* address/port and socket for listening at connections */ char *psz_hostname; int i_port; int *fds; unsigned nfd; vlc_mutex_t lock; /* all registered url (becarefull that 2 httpd_url_t could point at the same url) * This will slow down the url research but make my live easier * All url will have their cb trigger, but only the first one can answer * */ int i_url; httpd_url_t **url; int i_client; httpd_client_t **client; /* TLS data */ tls_server_t *p_tls;};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; 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 *****************************************************************************/static const struct{ const char psz_ext[8]; 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" }, /* same as modules/mux/mpjpeg.c here: */ { ".mpjpeg","multipart/x-mixed-replace; boundary=7b3cc56e5f51db803f790dad720ed50a" }, /* 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 */ { "", "" }};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[0] ; i++ ) { if( !strcasecmp( http_mime[i].psz_ext, psz_ext ) ) { return http_mime[i].psz_mime; } } } return "application/octet-stream";}typedef struct{ unsigned i_code; const char psz_reason[36];} 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" }, { 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, "Read-only parameter" },*/ { 459, "Aggregate operation not allowed" }, { 460, "Non-aggregate operation not 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" }, { 551, "Option not supported" }, { 999, "" }};static const char psz_fallback_reason[5][16] ={ "Continue", "OK", "Found", "Client error", "Server error" };static const char *httpd_ReasonFromCode( unsigned i_code ){ const http_status_info *p; assert( ( i_code >= 100 ) && ( i_code <= 599 ) ); for (p = http_reason; i_code > p->i_code; p++); if( p->i_code == i_code ) return p->psz_reason; return psz_fallback_reason[(i_code / 100) - 1];}static size_t httpd_HtmlError (char **body, int code, const char *url){ const char *errname = httpd_ReasonFromCode (code); assert (errname != NULL); int res = asprintf (body, "<?xml version=\"1.0\" encoding=\"ascii\" ?>\n" "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"" " \"http://www.w3.org/TR/xhtml10/DTD/xhtml10strict.dtd\">\n" "<html lang=\"en\">\n" "<head>\n" "<title>%s</title>\n" "</head>\n" "<body>\n" "<h1>%d %s%s%s%s</h1>\n" "<hr />\n" "<a href=\"http://www.videolan.org\">VideoLAN</a>\n" "</body>\n" "</html>\n", errname, code, errname, (url ? " (" : ""), (url ?: ""), (url ? ")" : "")); if (res == -1) { *body = NULL; return 0; } return (size_t)res;}/***************************************************************************** * 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 inthttpd_FileCallBack( httpd_callback_sys_t *p_sys, httpd_client_t *cl, httpd_message_t *answer, const httpd_message_t *query ){ httpd_file_t *file = (httpd_file_t*)p_sys; uint8_t **pp_body, *p_body; const char *psz_connection; int *pi_body, i_body; if( answer == NULL || query == NULL ) { return VLC_SUCCESS; } answer->i_proto = HTTPD_PROTO_HTTP; answer->i_version= 1; answer->i_type = HTTPD_MSG_ANSWER; answer->i_status = 200; 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 */ } uint8_t *psz_args = query->psz_args; 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 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -