📄 httpsrvr.cxx
字号:
return realm;
}
BOOL PHTTPMultiSimpAuth::Validate(const PHTTPRequest &,
const PString & authInfo) const
{
PString user, pass;
DecodeBasicAuthority(authInfo, user, pass);
return users.Contains(user) && users[user] == pass;
}
void PHTTPMultiSimpAuth::AddUser(const PString & username, const PString & password)
{
users.SetAt(username, password);
}
//////////////////////////////////////////////////////////////////////////////
// PHTTPRequest
PHTTPRequest::PHTTPRequest(const PURL & u, const PMIMEInfo & iM, PHTTPServer & server)
: url(u), inMIME(iM), origin(0), localAddr(0), localPort(0)
{
code = PHTTP::OK;
contentSize = 0;
PIPSocket * socket = server.GetSocket();
if (socket != NULL) {
socket->GetPeerAddress(origin);
socket->GetLocalAddress(localAddr, localPort);
}
}
//////////////////////////////////////////////////////////////////////////////
// PHTTPConnectionInfo
PHTTPConnectionInfo::PHTTPConnectionInfo()
{
commandCode = PHTTP::NumCommands;
majorVersion = 0;
minorVersion = 9;
isPersistant = FALSE;
isProxyConnection = FALSE;
entityBodyLength = -1;
}
BOOL PHTTPConnectionInfo::Initialise(PHTTPServer & server, PString & args)
{
// if only one argument, then it must be a version 0.9 simple request
PINDEX lastSpacePos = args.FindLast(' ');
static const PCaselessString httpId = "HTTP/";
if (lastSpacePos == P_MAX_INDEX || httpId != args(lastSpacePos+1, lastSpacePos+5)) {
majorVersion = 0;
minorVersion = 9;
return TRUE;
}
// otherwise, attempt to extract a version number
PCaselessString verStr = args.Mid(lastSpacePos + 6);
PINDEX dotPos = verStr.Find('.');
if (dotPos == 0 || dotPos >= verStr.GetLength()) {
server.OnError(PHTTP::BadRequest, "Malformed version number: " + verStr, *this);
return FALSE;
}
// should actually check if the text contains only digits, but the
// chances of matching everything else and it not being a valid number
// are pretty small, so don't bother
majorVersion = (int)verStr.Left(dotPos).AsInteger();
minorVersion = (int)verStr.Mid(dotPos+1).AsInteger();
args.Delete(lastSpacePos, P_MAX_INDEX);
// build our connection info reading MIME info until an empty line is
// received, or EOF
if (!mimeInfo.Read(server))
return FALSE;
isPersistant = FALSE;
#ifndef HAS_PERSISTANCE
isProxyConnection = FALSE;
#else
PString str;
// check for Proxy-Connection and Connection strings
isProxyConnection = mimeInfo.HasKey(PHTTP::ProxyConnectionTag);
if (isProxyConnection)
str = mimeInfo[PHTTP::ProxyConnectionTag];
else if (mimeInfo.HasKey(PHTTP::ConnectionTag))
str = mimeInfo[PHTTP::ConnectionTag];
// get any connection options
if (!str) {
PStringArray tokens = str.Tokenise(", \r\n", FALSE);
for (PINDEX z = 0; !isPersistant && z < tokens.GetSize(); z++)
isPersistant = isPersistant || (tokens[z] *= PHTTP::KeepAliveTag);
}
#endif
// if (connectInfo.IsPersistant()) {
// if (connectInfo.IsProxyConnection())
// PError << "Server: Persistant proxy connection received" << endl;
// else
// PError << "Server: Persistant direct connection received" << endl;
// }
// If the protocol is version 1.0 or greater, there is MIME info, and the
// prescence of a an entity body is signalled by the inclusion of
// Content-Length header. If the protocol is less than version 1.0, then
// there is no entity body!
// if the client specified a persistant connection, then use the
// ContentLength field. If there is no content length field, then
// assume a ContentLength of zero and close the connection.
// The spec actually says to read until end of file in this case,
// but Netscape hangs if this is done.
// If the client didn't specify a persistant connection, then use the
// ContentLength if there is one or read until end of file if there isn't
if (!isPersistant)
entityBodyLength = mimeInfo.GetInteger(PHTTP::ContentLengthTag,
(commandCode == PHTTP::POST) ? -2 : 0);
else {
entityBodyLength = mimeInfo.GetInteger(PHTTP::ContentLengthTag, -1);
if (entityBodyLength < 0) {
// PError << "Server: persistant connection has no content length" << endl;
entityBodyLength = 0;
mimeInfo.SetAt(PHTTP::ContentLengthTag, "0");
}
}
return TRUE;
}
void PHTTPConnectionInfo::SetMIME(const PString & tag, const PString & value)
{
mimeInfo.MakeUnique();
mimeInfo.SetAt(tag, value);
}
void PHTTPConnectionInfo::SetPersistance(BOOL newPersist)
{
#ifdef HAS_PERSISTANCE
isPersistant = newPersist;
#else
isPersistant = FALSE;
#endif
}
BOOL PHTTPConnectionInfo::IsCompatible(int major, int minor) const
{
if (minor == 0 && major == 0)
return TRUE;
else
return (majorVersion > major) ||
((majorVersion == major) && (minorVersion >= minor));
}
//////////////////////////////////////////////////////////////////////////////
// PHTTPResource
PHTTPResource::PHTTPResource(const PURL & url)
: baseURL(url)
{
authority = NULL;
hitCount = 0;
}
PHTTPResource::PHTTPResource(const PURL & url, const PHTTPAuthority & auth)
: baseURL(url)
{
authority = (PHTTPAuthority *)auth.Clone();
hitCount = 0;
}
PHTTPResource::PHTTPResource(const PURL & url, const PString & type)
: baseURL(url), contentType(type)
{
authority = NULL;
hitCount = 0;
}
PHTTPResource::PHTTPResource(const PURL & url,
const PString & type,
const PHTTPAuthority & auth)
: baseURL(url), contentType(type)
{
authority = (PHTTPAuthority *)auth.Clone();
hitCount = 0;
}
PHTTPResource::~PHTTPResource()
{
delete authority;
}
BOOL PHTTPResource::OnGET(PHTTPServer & server,
const PURL & url,
const PMIMEInfo & info,
const PHTTPConnectionInfo & connectInfo)
{
return OnGETOrHEAD(server, url, info, connectInfo, TRUE);
}
BOOL PHTTPResource::OnHEAD(PHTTPServer & server,
const PURL & url,
const PMIMEInfo & info,
const PHTTPConnectionInfo & connectInfo)
{
return OnGETOrHEAD(server, url, info, connectInfo, FALSE);
}
BOOL PHTTPResource::OnGETOrHEAD(PHTTPServer & server,
const PURL & url,
const PMIMEInfo & info,
const PHTTPConnectionInfo & connectInfo,
BOOL isGET)
{
if (isGET && info.Contains(PHTTP::IfModifiedSinceTag) &&
!IsModifiedSince(PTime(info[PHTTP::IfModifiedSinceTag])))
return server.OnError(PHTTP::NotModified, url.AsString(), connectInfo);
PHTTPRequest * request = CreateRequest(url, info, server);
BOOL retVal = TRUE;
if (CheckAuthority(server, *request, connectInfo)) {
retVal = FALSE;
server.SetDefaultMIMEInfo(request->outMIME, connectInfo);
PTime expiryDate;
if (GetExpirationDate(expiryDate))
request->outMIME.SetAt(PHTTP::ExpiresTag,
expiryDate.AsString(PTime::RFC1123, PTime::GMT));
if (!LoadHeaders(*request))
retVal = server.OnError(request->code, url.AsString(), connectInfo);
else if (!isGET)
retVal = request->outMIME.Contains(PHTTP::ContentLengthTag);
else {
hitCount++;
retVal = OnGETData(server, url, connectInfo, *request);
}
}
delete request;
return retVal;
}
BOOL PHTTPResource::OnGETData(PHTTPServer & server,
const PURL & /*url*/,
const PHTTPConnectionInfo & /*connectInfo*/,
PHTTPRequest & request)
{
if (!request.outMIME.Contains(PHTTP::ContentTypeTag) && !contentType)
request.outMIME.SetAt(PHTTP::ContentTypeTag, contentType);
PCharArray data;
if (LoadData(request, data)) {
server.StartResponse(request.code, request.outMIME, request.contentSize);
do {
server.Write(data, data.GetSize());
data.SetSize(0);
} while (LoadData(request, data));
}
else
server.StartResponse(request.code, request.outMIME, data.GetSize());
server.Write(data, data.GetSize());
return request.outMIME.Contains(PHTTP::ContentLengthTag);
}
BOOL PHTTPResource::OnPOST(PHTTPServer & server,
const PURL & url,
const PMIMEInfo & info,
const PStringToString & data,
const PHTTPConnectionInfo & connectInfo)
{
PHTTPRequest * request = CreateRequest(url, info, server);
BOOL persist = TRUE;
if (CheckAuthority(server, *request, connectInfo)) {
PHTML msg;
persist = Post(*request, data, msg);
if (msg.IsEmpty())
persist = server.OnError(request->code, "", connectInfo) && persist;
else {
if (msg.Is(PHTML::InBody))
msg << PHTML::Body();
request->outMIME.SetAt(PHTTP::ContentTypeTag, "text/html");
PINDEX len = msg.GetLength();
server.StartResponse(request->code, request->outMIME, len);
persist = server.Write((const char *)msg, len) && persist;
}
}
delete request;
return persist;
}
BOOL PHTTPResource::CheckAuthority(PHTTPServer & server,
const PHTTPRequest & request,
const PHTTPConnectionInfo & connectInfo)
{
if (authority == NULL)
return TRUE;
return CheckAuthority(*authority, server, request, connectInfo);
}
BOOL PHTTPResource::CheckAuthority(PHTTPAuthority & authority,
PHTTPServer & server,
const PHTTPRequest & request,
const PHTTPConnectionInfo & connectInfo)
{
if (!authority.IsActive())
return TRUE;
// if this is an authorisation request...
if (request.inMIME.Contains(PHTTP::AuthorizationTag) &&
authority.Validate(request, request.inMIME[PHTTP::AuthorizationTag]))
return TRUE;
// it must be a request for authorisation
PMIMEInfo headers;
server.SetDefaultMIMEInfo(headers, connectInfo);
headers.SetAt(PHTTP::WWWAuthenticateTag,
"Basic realm=\"" + authority.GetRealm(request) + "\"");
headers.SetAt(PHTTP::ContentTypeTag, "text/html");
const httpStatusCodeStruct * statusInfo =
GetStatusCodeStruct(PHTTP::UnAuthorised);
PHTML reply;
reply << PHTML::Title()
<< statusInfo->code
<< ' '
<< statusInfo->text
<< PHTML::Body()
<< PHTML::Heading(1)
<< statusInfo->code
<< ' '
<< statusInfo->text
<< PHTML::Heading(1)
<< "Your request cannot be authorised because it requires authentication."
<< PHTML::Paragraph()
<< "This may be because you entered an incorrect username or password, "
<< "or because your browser is not performing Basic authentication."
<< PHTML::Body();
server.StartResponse(PHTTP::UnAuthorised, headers, reply.GetLength());
server.WriteString(reply);
return FALSE;
}
void PHTTPResource::SetAuthority(const PHTTPAuthority & auth)
{
delete authority;
authority = (PHTTPAuthority *)auth.Clone();
}
void PHTTPResource::ClearAuthority()
{
delete authority;
authority = NULL;
}
BOOL PHTTPResource::IsModifiedSince(const PTime &)
{
return TRUE;
}
BOOL PHTTPResource::GetExpirationDate(PTime &)
{
return FALSE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -