📄 httpsrvr.cxx
字号:
/*
* httpsrvr.cxx
*
* HTTP server classes.
*
* Portable Windows Library
*
* Copyright (c) 1993-2002 Equivalence Pty. Ltd.
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is Portable Windows Library.
*
* The Initial Developer of the Original Code is Equivalence Pty. Ltd.
*
* Contributor(s): ______________________________________.
*
* $Log: httpsrvr.cxx,v $
* Revision 1.1 2006/06/29 04:18:02 joegenbaclor
* *** empty log message ***
*
* Revision 1.49 2005/11/30 12:47:41 csoutheren
* Removed tabs, reformatted some code, and changed tags for Doxygen
*
* Revision 1.48 2005/01/15 07:53:55 csoutheren
* Fixed problem when disabling http
*
* Revision 1.47 2004/02/03 09:37:20 rjongbloed
* Added check to text files via the type extension, thanks David Parr
*
* Revision 1.46 2003/03/19 01:55:26 robertj
* Fixed bugs in deleteing HTTP resources from server, thanks Diego T醨tara
*
* Revision 1.45 2002/11/06 22:47:25 robertj
* Fixed header comment (copyright etc)
*
* Revision 1.44 2002/10/10 04:43:44 robertj
* VxWorks port, thanks Martijn Roest
*
* Revision 1.43 2002/10/02 08:54:01 craigs
* Added support for XMLRPC server
*
* Revision 1.42 2002/08/27 23:49:08 robertj
* Fixed security hole where possible to get any file on disk when using
* PHTTPDirectory HTTP resource.
*
* Revision 1.41 2002/07/17 08:43:52 robertj
* Fixed closing of html msg on generated post output.
*
* Revision 1.40 2002/05/08 05:38:54 robertj
* Added PHTTPTailFile resource to do a unix 'tail -f' of a file.
*
* Revision 1.39 2002/04/12 08:15:23 robertj
* Fixed warning on older GNU compilers, also guarantees numeric output.
*
* Revision 1.38 2001/10/31 01:37:13 robertj
* Fixed deleting of object added to http name space if add fails.
* Changes to support HTTP v1.1 chunked transfer encoding.
*
* Revision 1.37 2001/09/28 00:45:27 robertj
* Removed HasKey() as is confusing due to ancestor Contains().
*
* Revision 1.36 2001/06/01 07:28:23 craigs
* Added handling for binary data in multi-part MIME fields
*
* Revision 1.35 2001/03/14 01:49:54 craigs
* Added ability to handle multi-part form POST commands
*
* Revision 1.34 2001/01/15 06:17:56 robertj
* Set HTTP resource members to private to assure are not modified by
* dscendents in non-threadsafe manner.
*
* Revision 1.33 2000/09/04 03:57:58 robertj
* Added ability to change the persistent connection parameters (timeout etc).
*
* Revision 1.32 2000/05/02 07:55:22 craigs
* Changed static PString to static const char * to avoid "memory leak"
*
* Revision 1.31 1999/05/13 04:04:04 robertj
* Fixed problem of initialised commandName in ConnectionInfo.
*
* Revision 1.30 1999/05/12 01:40:47 robertj
* Fixed "unknown" response codes being passed on when used with an "unknown" command.
*
* Revision 1.29 1999/05/11 12:23:22 robertj
* Fixed search for persistent connection to accept kee-alive on multile MIME fields.
*
* Revision 1.28 1999/05/04 15:26:01 robertj
* Improved HTTP/1.1 compatibility (pass through user commands).
* Fixed problems with quicktime installer.
*
* Revision 1.27 1999/04/24 11:50:11 robertj
* Changed HTTP command parser so will work if some idiot puts spaces in a URL.
*
* Revision 1.26 1999/04/21 01:58:08 robertj
* Fixed problem with reading data for request using second form of PHTTPRequestInfo constructor.
*
* Revision 1.25 1998/11/30 04:51:59 robertj
* New directory structure
*
* Revision 1.24 1998/11/14 01:11:38 robertj
* PPC linux GNU compatibility.
*
* Revision 1.23 1998/10/31 12:49:23 robertj
* Added read/write mutex to the HTTP space variable to avoid thread crashes.
*
* Revision 1.22 1998/10/25 01:02:41 craigs
* Added ability to specify per-directory authorisation for PHTTPDirectory
*
* Revision 1.21 1998/10/13 14:06:23 robertj
* Complete rewrite of memory leak detection code.
*
* Revision 1.20 1998/09/23 06:22:13 robertj
* Added open source copyright license.
*
* Revision 1.19 1998/08/06 00:54:22 robertj
* Fixed bug in sending empty files, caused endless wait in Netscape.
*
* Revision 1.18 1998/06/16 03:32:14 robertj
* Propagated persistence and proxy flags in new connection info instances.
*
* Revision 1.17 1998/04/01 01:55:16 robertj
* Fixed bug when serving HTTPFile that has zero bytes in it.
*
* Revision 1.16 1998/02/03 06:24:10 robertj
* Added local address and port to PHTTPRequest.
* Fixed bug in default entity length. should be read to EOF.
* Fixed OnError() so can detec HTML bosy tag with parameters.
*
* Revision 1.14 1998/01/26 00:42:19 robertj
* Added more information to PHTTPConnectionInfo.
* Made SetDefaultMIMEFields in HTTP Server not set those fields if already set.
*
* Revision 1.13 1997/10/30 10:22:04 robertj
* Added multiple user basic authorisation scheme.
*
* Revision 1.12 1997/10/03 13:39:25 robertj
* Fixed race condition on socket close in Select() function.
*
* Revision 1.12 1997/10/03 13:31:12 craigs
* Added ability to access client socket from within HTTP resources
*
* Revision 1.11 1997/08/04 10:44:36 robertj
* Improved receiving of a POST on a non-persistant connection, do not wait for EOF if have CRLF.
*
* Revision 1.10 1997/07/14 11:47:13 robertj
* Added "const" to numerous variables.
*
* Revision 1.9 1997/07/08 13:10:26 robertj
* Fixed bug in HTTP server where standard error text is not sent to remote client.
*
* Revision 1.8 1997/04/15 14:32:19 robertj
* Fixed case problem for HTTP version string.
*
* Revision 1.7 1997/03/20 13:01:32 robertj
* Fixed bug in proxy POST having unexpexted reset of connection.
*
* Revision 1.6 1997/02/09 04:09:30 robertj
* Fixed GCC warning
*
* Revision 1.5 1997/01/12 04:15:23 robertj
* Globalised MIME tag strings.
*
* Revision 1.4 1996/12/12 09:24:16 robertj
* Persistent proxy connection support (work in progress).
*
* Revision 1.3 1996/11/10 21:09:33 robertj
* Removed redundent GetSocket() call.
* Added flush of stream after processing request, important on persistent connections.
*
* Revision 1.2 1996/10/26 03:31:05 robertj
* Changed OnError so can pass in full HTML page as parameter.
*
* Revision 1.1 1996/09/14 13:02:18 robertj
* Initial revision
*
*/
#include <ptlib.h>
#ifdef P_HTTP
#include <ptlib/sockets.h>
#include <ptclib/http.h>
#include <ctype.h>
#define new PNEW
// define to enable work-around for Netscape persistant connection bug
// set to lifetime of suspect sockets (in seconds)
#define STRANGE_NETSCAPE_BUG 3
// maximum delay between characters whilst reading a line of text
#define READLINE_TIMEOUT 30
#define DEFAULT_PERSIST_TIMEOUT 30
#define DEFAULT_PERSIST_TRANSATIONS 10
// filename to use for directory access directives
static const char * accessFilename = "_access";
//////////////////////////////////////////////////////////////////////////////
// PHTTPSpace
PHTTPSpace::PHTTPSpace()
{
mutex = new PReadWriteMutex;
root = new Node(PString(), NULL);
}
void PHTTPSpace::DestroyContents()
{
delete mutex;
delete root;
}
void PHTTPSpace::CloneContents(const PHTTPSpace * c)
{
mutex = new PReadWriteMutex;
root = new Node(*c->root);
}
void PHTTPSpace::CopyContents(const PHTTPSpace & c)
{
mutex = c.mutex;
root = c.root;
}
PHTTPSpace::Node::Node(const PString & nam, Node * parentNode)
: PString(nam)
{
parent = parentNode;
resource = NULL;
}
PHTTPSpace::Node::~Node()
{
delete resource;
}
BOOL PHTTPSpace::AddResource(PHTTPResource * res, AddOptions overwrite)
{
PAssert(res != NULL, PInvalidParameter);
const PStringArray & path = res->GetURL().GetPath();
Node * node = root;
for (PINDEX i = 0; i < path.GetSize(); i++) {
if (path[i].IsEmpty())
break;
if (node->resource != NULL) {
delete res;
return FALSE; // Already a resource in tree in partial path
}
PINDEX pos = node->children.GetValuesIndex(path[i]);
if (pos == P_MAX_INDEX)
pos = node->children.Append(new Node(path[i], node));
node = &node->children[pos];
}
if (!node->children.IsEmpty()) {
delete res;
return FALSE; // Already a resource in tree further down path.
}
if (overwrite == ErrorOnExist && node->resource != NULL) {
delete res;
return FALSE; // Already a resource in tree at leaf
}
delete node->resource;
node->resource = res;
return TRUE;
}
BOOL PHTTPSpace::DelResource(const PURL & url)
{
const PStringArray & path = url.GetPath();
Node * node = root;
for (PINDEX i = 0; i < path.GetSize(); i++) {
if (path[i].IsEmpty())
break;
PINDEX pos = node->children.GetValuesIndex(path[i]);
if (pos == P_MAX_INDEX)
return FALSE;
node = &node->children[pos];
// If have resource and not last node, then trying to remove something
// further down the tree than a leaf node.
if (node->resource != NULL && i < (path.GetSize()-1))
return FALSE;
}
if (!node->children.IsEmpty())
return FALSE; // Still a resource in tree further down path.
if (node->parent != NULL) {
do {
Node * par = node->parent;
par->children.Remove(node);
node = par;
} while (node != NULL && node->children.IsEmpty());
}
return TRUE;
}
static const char * const HTMLIndexFiles[] = {
"Welcome.html", "welcome.html", "index.html",
"Welcome.htm", "welcome.htm", "index.htm"
};
PHTTPResource * PHTTPSpace::FindResource(const PURL & url)
{
const PStringArray & path = url.GetPath();
Node * node = root;
PINDEX i;
for (i = 0; i < path.GetSize(); i++) {
if (path[i].IsEmpty())
break;
PINDEX pos = node->children.GetValuesIndex(path[i]);
if (pos == P_MAX_INDEX)
return NULL;
node = &node->children[pos];
if (node->resource != NULL)
return node->resource;
}
for (i = 0; i < PARRAYSIZE(HTMLIndexFiles); i++) {
PINDEX pos = node->children.GetValuesIndex(PString(HTMLIndexFiles[i]));
if (pos != P_MAX_INDEX)
return node->children[pos].resource;
}
return NULL;
}
//////////////////////////////////////////////////////////////////////////////
// PHTTPServer
PHTTPServer::PHTTPServer()
{
Construct();
}
PHTTPServer::PHTTPServer(const PHTTPSpace & space)
: urlSpace(space)
{
Construct();
}
void PHTTPServer::Construct()
{
transactionCount = 0;
SetReadLineTimeout(PTimeInterval(0, READLINE_TIMEOUT));
}
void PHTTPConnectionInfo::DecodeMultipartFormInfo(const PString & type, const PString & entityBody)
{
// remove trailing ","
PINDEX pos = type.Find(",");
if (pos == P_MAX_INDEX) {
pos = type.Find(";");
if (pos == P_MAX_INDEX)
return;
}
PString seperator = type.Mid(pos+1).Trim();
// remove "boundary"
pos = seperator.Find("boundary");
if (pos == P_MAX_INDEX)
return;
seperator = seperator.Mid(8).Trim();
// remove "="
pos = seperator.Find("=");
if (pos == P_MAX_INDEX)
return;
seperator = seperator.Mid(1).Trim();
// seperators have a "--" according to RFC 1521
seperator = PString("--") + seperator;
PINDEX sepLen = seperator.GetLength();
const char * sep = (const char *)seperator;
// split body into parts, assuming binary data
const char * body = (const char *)entityBody;
PINDEX entityOffs = 0;
PINDEX entityLen = entityBody.GetSize()-1;
BOOL ignore = TRUE;
BOOL last = FALSE;
PMultipartFormInfo * info = NULL;
while (!last && (entityOffs < entityLen)) {
// find end of part
PINDEX partStart = entityOffs;
PINDEX partLen;
BOOL foundSep = FALSE;
// collect length of part until seperator
for (partLen = 0; (partStart + partLen) < entityLen; partLen++) {
if ((partLen >= sepLen) && (memcmp(body + partStart + partLen - sepLen, sep, sepLen) == 0)) {
foundSep = TRUE;
break;
}
}
// move entity ptr to the end of the part
entityOffs = partStart + partLen;
// if no seperator found, then this is the last part
// otherwise, look for "--" trailer on seperator and remove CRLF
if (!foundSep)
last = TRUE;
else {
partLen -= sepLen;
// determine if this is the last block
if (((entityOffs + 2) <= entityLen) && (body[entityOffs] == '-') && (body[entityOffs+1] == '-')) {
last = TRUE;
entityOffs += 2;
}
// remove crlf
if (((entityOffs + 2) <= entityLen) && (body[entityOffs] == '\r') && (body[entityOffs+1] == '\n'))
entityOffs += 2;
}
// ignore everything up to the first seperator,
// then adjust seperator to include leading CRLF
if (ignore) {
ignore = FALSE;
seperator = PString("\r\n") + seperator;
sepLen = seperator.GetLength();
sep = (const char *)seperator;
continue;
}
// extract the MIME header, by looking for a double CRLF
PINDEX ptr;
PINDEX nlCount = 0;
for (ptr = partStart;(ptr < (partStart + partLen)) && (nlCount < 2); ptr++) {
if (body[ptr] == '\r') {
nlCount++;
if ((ptr < entityLen-1) && (body[ptr+1] == '\n'))
ptr++;
} else
nlCount = 0;
}
// create the new part info
info = new PMultipartFormInfo;
// read MIME information
PStringStream strm(PString(body + partStart, ptr - partStart));
info->mime.ReadFrom(strm);
// save the entity body, being careful of binary files
int savedLen = partStart + partLen - ptr;
char * saved = info->body.GetPointer(savedLen + 1);
memcpy(saved, body + ptr, savedLen);
saved[savedLen] = '\0';
// add the data to the array
multipartFormInfoArray.Append(info);
info = NULL;
}
#if 0
// ignore until first separator
do {
data >> line;
if (line.IsEmpty())
return;
} while (line.Find(sep) != 0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -