📄 httpsrvr.cxx
字号:
/*
* httpsrvr.cxx
*
* HTTP server classes.
*
* Portable Windows Library
*
* Copyright (c) 1993-1998 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.
*
* Portions are Copyright (C) 1993 Free Software Foundation, Inc.
* All Rights Reserved.
*
* Contributor(s): ______________________________________.
*
* $Log: httpsrvr.cxx,v $
* 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>
#include <ptlib/sockets.h>
#include <ptclib/http.h>
#include <ctype.h>
#define new PNEW
// undefine to remove support for persistant connections
#define HAS_PERSISTANCE
// define to enable work-around for Netscape persistant connection bug
// set to lifetime of suspect sockets (in seconds)
#define STRANGE_NETSCAPE_BUG 3
// maximum lifetime (in seconds) of persistant connections
#define MAX_LIFETIME 30
// maximum lifetime (in transactions) of persistant connections
#define MAX_TRANSACTIONS 10
// maximum delay between characters whilst reading a line of text
#define READLINE_TIMEOUT 30
// filename to use for directory access directives
static const PString 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)
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())
return FALSE; // Already a resource in tree further down path.
if (overwrite == ErrorOnExist && node->resource != NULL)
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 (node->resource != NULL)
return FALSE;
}
if (!node->children.IsEmpty())
return FALSE; // Still a resource in tree further down path.
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));
}
BOOL PHTTPServer::ProcessCommand()
{
PString args;
PINDEX cmd;
// if this is not the first command received by this socket, then set
// the read timeout appropriately.
if (transactionCount > 0)
SetReadTimeout(nextTimeout);
// this will only return false upon timeout or completely invalid command
if (!ReadCommand(cmd, args))
return FALSE;
connectInfo.commandCode = (Commands)cmd;
if (cmd < NumCommands)
connectInfo.commandName = commandNames[cmd];
else {
PINDEX spacePos = args.Find(' ');
connectInfo.commandName = args.Left(spacePos);
args = args.Mid(spacePos);
}
// if no tokens, error
if (args.IsEmpty()) {
OnError(BadRequest, args, connectInfo);
return FALSE;
}
if (!connectInfo.Initialise(*this, args))
return FALSE;
// now that we've decided we did receive a HTTP request, increment the
// count of transactions
transactionCount++;
nextTimeout.SetInterval(MAX_LIFETIME*1000);
PIPSocket * socket = GetSocket();
WORD myPort = (WORD)(socket != NULL ? socket->GetPort() : 80);
// the URL that comes with Connect requests is not quite kosher, so
// mangle it into a proper URL and do NOT close the connection.
// for all other commands, close the read connection if not persistant
if (cmd == CONNECT)
connectInfo.url = "https://" + args;
else {
connectInfo.url = args;
if (connectInfo.url.GetPort() == 0)
connectInfo.url.SetPort(myPort);
}
BOOL persist;
// If the incoming URL is of a proxy type then call OnProxy() which will
// probably just go OnError(). Even if a full URL is provided in the
// command we should check to see if it is a local server request and process
// it anyway even though we are not a proxy. The usage of GetHostName()
// below are to catch every way of specifying the host (name, alias, any of
// several IP numbers etc).
const PURL & url = connectInfo.GetURL();
if (url.GetScheme() != "http" ||
(url.GetPort() != 0 && url.GetPort() != myPort) ||
(!url.GetHostName() && !PIPSocket::IsLocalHost(url.GetHostName())))
persist = OnProxy(connectInfo);
else {
PString entityBody = ReadEntityBody();
// Handle the local request
PStringToString postData;
switch (cmd) {
case GET :
persist = OnGET(url, connectInfo.GetMIME(), connectInfo);
break;
case HEAD :
persist = OnHEAD(url, connectInfo.GetMIME(), connectInfo);
break;
case POST :
PURL::SplitQueryVars(entityBody, postData);
persist = OnPOST(url, connectInfo.GetMIME(), postData, connectInfo);
break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -