📄 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.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 directivesstatic const char * accessFilename = "_access";//////////////////////////////////////////////////////////////////////////////// PHTTPSpacePHTTPSpace::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;}//////////////////////////////////////////////////////////////////////////////// PHTTPServerPHTTPServer::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); PMultipartFormInfo * info = NULL; // read form parts while (data.good() && (line.Right(2) != "--")) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -