📄 webserver.c
字号:
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2000-2003 Intel Corporation
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither name of Intel Corporation nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
///////////////////////////////////////////////////////////////////////////
/************************************************************************
* Purpose: This file defines the Web Server and has functions to carry out
* operations of the Web Server.
************************************************************************/
#include <assert.h>
#include "util.h"
#include "strintmap.h"
#include "membuffer.h"
#include "httpparser.h"
#include "httpreadwrite.h"
#include "statcodes.h"
#include "webserver.h"
#include "upnp.h"
#include "config.h"
#include "upnpapi.h"
#ifndef _WIN32
#include <unistd.h>
#endif
#include <sys/stat.h>
#include "ithread.h"
#include "unixutil.h"
/*
Response Types
*/
enum resp_type { RESP_FILEDOC, RESP_XMLDOC, RESP_HEADERS, RESP_WEBDOC,
RESP_POST };
// mapping of file extension to content-type of document
struct document_type_t {
const char *file_ext;
const char *content_type;
const char *content_subtype;
};
struct xml_alias_t {
membuffer name; // name of DOC from root; e.g.: /foo/bar/mydesc.xml
membuffer doc; // the XML document contents
time_t last_modified;
int *ct;
};
static const char *gMediaTypes[] = {
NULL, // 0
"audio", // 1
"video", // 2
"image", // 3
"application", // 4
"text" // 5
};
/*
Defines
*/
// index into 'gMediaTypes'
#define AUDIO_STR "\1"
#define VIDEO_STR "\2"
#define IMAGE_STR "\3"
#define APPLICATION_STR "\4"
#define TEXT_STR "\5"
// int index
#define APPLICATION_INDEX 4
#define TEXT_INDEX 5
// general
#define NUM_MEDIA_TYPES 69
#define NUM_HTTP_HEADER_NAMES 33
// sorted by file extension; must have 'NUM_MEDIA_TYPES' extensions
static const char *gEncodedMediaTypes =
"aif\0" AUDIO_STR "aiff\0"
"aifc\0" AUDIO_STR "aiff\0"
"aiff\0" AUDIO_STR "aiff\0"
"asf\0" VIDEO_STR "x-ms-asf\0"
"asx\0" VIDEO_STR "x-ms-asf\0"
"au\0" AUDIO_STR "basic\0"
"avi\0" VIDEO_STR "msvideo\0"
"bmp\0" IMAGE_STR "bmp\0"
"dcr\0" APPLICATION_STR "x-director\0"
"dib\0" IMAGE_STR "bmp\0"
"dir\0" APPLICATION_STR "x-director\0"
"dxr\0" APPLICATION_STR "x-director\0"
"gif\0" IMAGE_STR "gif\0"
"hta\0" TEXT_STR "hta\0"
"htm\0" TEXT_STR "html\0"
"html\0" TEXT_STR "html\0"
"jar\0" APPLICATION_STR "java-archive\0"
"jfif\0" IMAGE_STR "pjpeg\0"
"jpe\0" IMAGE_STR "jpeg\0"
"jpeg\0" IMAGE_STR "jpeg\0"
"jpg\0" IMAGE_STR "jpeg\0"
"js\0" APPLICATION_STR "x-javascript\0"
"kar\0" AUDIO_STR "midi\0"
"m3u\0" AUDIO_STR "mpegurl\0"
"mid\0" AUDIO_STR "midi\0"
"midi\0" AUDIO_STR "midi\0"
"mov\0" VIDEO_STR "quicktime\0"
"mp2v\0" VIDEO_STR "x-mpeg2\0"
"mp3\0" AUDIO_STR "mpeg\0"
"mpe\0" VIDEO_STR "mpeg\0"
"mpeg\0" VIDEO_STR "mpeg\0"
"mpg\0" VIDEO_STR "mpeg\0"
"mpv\0" VIDEO_STR "mpeg\0"
"mpv2\0" VIDEO_STR "x-mpeg2\0"
"pdf\0" APPLICATION_STR "pdf\0"
"pjp\0" IMAGE_STR "jpeg\0"
"pjpeg\0" IMAGE_STR "jpeg\0"
"plg\0" TEXT_STR "html\0"
"pls\0" AUDIO_STR "scpls\0"
"png\0" IMAGE_STR "png\0"
"qt\0" VIDEO_STR "quicktime\0"
"ram\0" AUDIO_STR "x-pn-realaudio\0"
"rmi\0" AUDIO_STR "mid\0"
"rmm\0" AUDIO_STR "x-pn-realaudio\0"
"rtf\0" APPLICATION_STR "rtf\0"
"shtml\0" TEXT_STR "html\0"
"smf\0" AUDIO_STR "midi\0"
"snd\0" AUDIO_STR "basic\0"
"spl\0" APPLICATION_STR "futuresplash\0"
"ssm\0" APPLICATION_STR "streamingmedia\0"
"swf\0" APPLICATION_STR "x-shockwave-flash\0"
"tar\0" APPLICATION_STR "tar\0"
"tcl\0" APPLICATION_STR "x-tcl\0"
"text\0" TEXT_STR "plain\0"
"tif\0" IMAGE_STR "tiff\0"
"tiff\0" IMAGE_STR "tiff\0"
"txt\0" TEXT_STR "plain\0"
"ulw\0" AUDIO_STR "basic\0"
"wav\0" AUDIO_STR "wav\0"
"wax\0" AUDIO_STR "x-ms-wax\0"
"wm\0" VIDEO_STR "x-ms-wm\0"
"wma\0" AUDIO_STR "x-ms-wma\0"
"wmv\0" VIDEO_STR "x-ms-wmv\0"
"wvx\0" VIDEO_STR "x-ms-wvx\0"
"xbm\0" IMAGE_STR "x-xbitmap\0"
"xml\0" TEXT_STR "xml\0"
"xsl\0" TEXT_STR "xml\0"
"z\0" APPLICATION_STR "x-compress\0"
"zip\0" APPLICATION_STR "zip\0" "\0";
// *** end ***
/***********************************************************************/
/*
module variables - Globals, static and externs
*/
/***********************************************************************/
static struct document_type_t gMediaTypeList[NUM_MEDIA_TYPES];
membuffer gDocumentRootDir; // a local dir which serves as webserver root
#ifdef _ALIASDOC
static struct xml_alias_t gAliasDoc; // XML document
#else _ALIASDOC
// need a dictionary of these things
#define NUM_ALIASES 10
static struct xml_alias_t gAliasDict[NUM_ALIASES];
static int numAliasDictEntries = 0;
#endif
static ithread_mutex_t gWebMutex;
extern str_int_entry Http_Header_Names[NUM_HTTP_HEADER_NAMES];
/************************************************************************
* Function: has_xml_content_type
*
* Parameters:
* none
*
* Description: decodes list and stores it in gMediaTypeList
*
* Returns:
* void
************************************************************************/
static XINLINE void
media_list_init( void )
{
int i;
const char *s = gEncodedMediaTypes;
struct document_type_t *doc_type;
for( i = 0; *s != '\0'; i++ ) {
doc_type = &gMediaTypeList[i];
doc_type->file_ext = s;
s += strlen( s ) + 1; // point to type
doc_type->content_type = gMediaTypes[( int )*s]; // set cont-type
s++; // point to subtype
doc_type->content_subtype = s;
s += strlen( s ) + 1; // next entry
}
assert( i == NUM_MEDIA_TYPES );
}
/************************************************************************
* Function: has_xml_content_type
*
* Parameters:
* IN const char* extension ;
* OUT const char** con_type,
* OUT const char** con_subtype
*
* Description: Based on the extension, returns the content type and
* content subtype
*
* Returns:
* 0 on success;
* -1 on error
************************************************************************/
static XINLINE int
search_extension( IN const char *extension,
OUT const char **con_type,
OUT const char **con_subtype )
{
int top,
mid,
bot;
int cmp;
top = 0;
bot = NUM_MEDIA_TYPES - 1;
while( top <= bot ) {
mid = ( top + bot ) / 2;
#ifndef _WIN32
cmp = strcasecmp( extension, gMediaTypeList[mid].file_ext );
#else
cmp = _stricmp( extension, gMediaTypeList[mid].file_ext );
#endif
if( cmp > 0 ) {
top = mid + 1; // look below mid
} else if( cmp < 0 ) {
bot = mid - 1; // look above mid
} else // cmp == 0
{
*con_type = gMediaTypeList[mid].content_type;
*con_subtype = gMediaTypeList[mid].content_subtype;
return 0;
}
}
return -1;
}
/************************************************************************
* Function: get_content_type
*
* Parameters:
* IN const char* filename,
* OUT DOMString* content_type
*
* Description: Based on the extension, clones an XML string based on
* type and content subtype. If content type and sub type are not
* found, unknown types are used
*
* Returns:
* 0 - On Sucess
* UPNP_E_OUTOF_MEMORY - on memory allocation failures
************************************************************************/
XINLINE int
get_content_type( IN const char *filename,
OUT DOMString * content_type )
{
const char *extension;
const char *type,
*subtype;
xboolean ctype_found = FALSE;
char *temp = NULL;
int length = 0;
( *content_type ) = NULL;
// get ext
extension = strrchr( filename, '.' );
if( extension != NULL ) {
if( search_extension( extension + 1, &type, &subtype ) == 0 ) {
ctype_found = TRUE;
}
}
if( !ctype_found ) {
// unknown content type
type = gMediaTypes[APPLICATION_INDEX];
subtype = "octet-stream";
}
length = strlen( type ) + strlen( "/" ) + strlen( subtype ) + 1;
temp = ( char * )malloc( length );
if( !temp ) {
return UPNP_E_OUTOF_MEMORY;
}
sprintf( temp, "%s/%s", type, subtype );
( *content_type ) = ixmlCloneDOMString( temp );
free( temp );
if( !content_type ) {
return UPNP_E_OUTOF_MEMORY;
}
return 0;
}
/************************************************************************
* Function: glob_alias_init
*
* Parameters:
* none
*
* Description: Initialize the global XML document. Allocate buffers
* for the XML document
*
* Returns:
* void
************************************************************************/
static XINLINE void
glob_alias_init( void )
{
#ifndef _ALIASDOC
int i;
struct xml_alias_t *alias = 0;
#else
struct xml_alias_t *alias = &gAliasDoc;
#endif
#ifndef _ALIASDOC
for (i = 0; i < NUM_ALIASES; i++ ) {
alias = &(gAliasDict[i]);
#endif
membuffer_init( &alias->doc );
membuffer_init( &alias->name );
alias->ct = NULL;
alias->last_modified = 0;
#ifndef _ALIASDOC
}
#endif
}
/************************************************************************
* Function: is_valid_alias
*
* Parameters:
* IN const struct xml_alias_t* alias ; XML alias object
*
* Description: Check for the validity of the XML object buffer
*
* Returns:
* BOOLEAN
************************************************************************/
static XINLINE xboolean
is_valid_alias( IN const struct xml_alias_t *alias )
{
return alias->doc.buf != NULL;
}
#ifdef _ALIASDOC
/************************************************************************
* Function: alias_grab
*
* Parameters:
* OUT struct xml_alias_t* alias ; XML alias object
*
* Description: Copy the contents of the global XML document into the
* local OUT parameter
*
* Returns:
* void
************************************************************************/
static void
alias_grab( OUT struct xml_alias_t *alias )
{
ithread_mutex_lock( &gWebMutex );
assert( is_valid_alias( &gAliasDoc ) );
memcpy( alias, &gAliasDoc, sizeof( struct xml_alias_t ) );
*alias->ct = *alias->ct + 1;
ithread_mutex_unlock( &gWebMutex );
}
#endif
/************************************************************************
* Function: alias_release
*
* Parameters:
* IN struct xml_alias_t* alias ; XML alias object
*
* Description: Release the XML document referred to by the IN parameter
* Free the allocated buffers associated with this object
*
* Returns:
* void
************************************************************************/
static void
alias_release( IN struct xml_alias_t *alias )
{
ithread_mutex_lock( &gWebMutex );
// ignore invalid alias
if( !is_valid_alias( alias ) ) {
ithread_mutex_unlock( &gWebMutex );
return;
}
assert( alias->ct > 0 );
*alias->ct = *alias->ct - 1;
if( *alias->ct <= 0 ) {
membuffer_destroy( &alias->doc );
membuffer_destroy( &alias->name );
free( alias->ct );
}
ithread_mutex_unlock( &gWebMutex );
}
/************************************************************************
* Function: web_server_set_alias
*
* Parameters:
* alias_name: webserver name of alias; created by caller and freed by
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -