⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 httpsrvr.cxx

📁 sloedgy open sip stack source code
💻 CXX
📖 第 1 页 / 共 4 页
字号:
                                 const PString & password_)
  : realm(realm_), username(username_), password(password_)
{
  PAssert(!realm, "Must have a realm!");
}


PObject * PHTTPSimpleAuth::Clone() const
{
  return new PHTTPSimpleAuth(realm, username, password);
}


BOOL PHTTPSimpleAuth::IsActive() const
{
  return !username || !password;
}


PString PHTTPSimpleAuth::GetRealm(const PHTTPRequest &) const
{
  return realm;
}


BOOL PHTTPSimpleAuth::Validate(const PHTTPRequest &,
                               const PString & authInfo) const
{
  PString user, pass;
  DecodeBasicAuthority(authInfo, user, pass);
  return username == user && password == pass;
}


//////////////////////////////////////////////////////////////////////////////
// PHTTPMultiSimpAuth

PHTTPMultiSimpAuth::PHTTPMultiSimpAuth(const PString & realm_)
  : realm(realm_)
{
  PAssert(!realm, "Must have a realm!");
}


PHTTPMultiSimpAuth::PHTTPMultiSimpAuth(const PString & realm_,
                                       const PStringToString & users_)
  : realm(realm_), users(users_)
{
  PAssert(!realm, "Must have a realm!");
}


PObject * PHTTPMultiSimpAuth::Clone() const
{
  return new PHTTPMultiSimpAuth(realm, users);
}


BOOL PHTTPMultiSimpAuth::IsActive() const
{
  return !users.IsEmpty();
}


PString PHTTPMultiSimpAuth::GetRealm(const PHTTPRequest &) const
{
  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 & _url,
                      const PMIMEInfo & _mime,
        const PMultipartFormInfoArray & _multipartFormInfo,
                          PHTTPServer & _server)
  : server(_server),
    url(_url),
    inMIME(_mime),
    multipartFormInfo(_multipartFormInfo),
    origin(0),
    localAddr(0),
    localPort(0)
{
  code        = PHTTP::RequestOK;
  contentSize = P_MAX_INDEX;

  PIPSocket * socket = server.GetSocket();
  if (socket != NULL) {
    socket->GetPeerAddress(origin);
    socket->GetLocalAddress(localAddr, localPort);
  }
}


//////////////////////////////////////////////////////////////////////////////
// PHTTPConnectionInfo

PHTTPConnectionInfo::PHTTPConnectionInfo()
  : persistenceTimeout(0, DEFAULT_PERSIST_TIMEOUT) // maximum lifetime (in seconds) of persistant connections
{
  // maximum lifetime (in transactions) of persistant connections
  persistenceMaximum = DEFAULT_PERSIST_TRANSATIONS;

  commandCode       = PHTTP::NumCommands;

  majorVersion      = 0;
  minorVersion      = 9;

  isPersistant      = FALSE;
  wasPersistant     = FALSE;
  isProxyConnection = FALSE;

  entityBodyLength  = -1;

  multipartFormInfoArray.AllowDeleteObjects();
}


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;

  wasPersistant = isPersistant;
  isPersistant = FALSE;

  PString str;

  // check for Proxy-Connection and Connection strings
  isProxyConnection = mimeInfo.Contains(PHTTP::ProxyConnectionTag);
  if (isProxyConnection)
    str = mimeInfo[PHTTP::ProxyConnectionTag];
  else if (mimeInfo.Contains(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);
  }

  // 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) {
      PTRACE(5, "HTTPServer\tPersistant connection has no content length");
      entityBodyLength = 0;
      mimeInfo.SetAt(PHTTP::ContentLengthTag, "0");
    }
  }

  return TRUE;
}


void PHTTPConnectionInfo::SetMIME(const PString & tag, const PString & value)
{
  mimeInfo.MakeUnique();
  mimeInfo.SetAt(tag, value);
}


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)
{
  // Nede to split songle if into 2 so the Tornado compiler won't end with
  // 'internal compiler error'
  if (isGET && info.Contains(PHTTP::IfModifiedSinceTag))
    if (!IsModifiedSince(PTime(info[PHTTP::IfModifiedSinceTag])))
      return server.OnError(PHTTP::NotModified, url.AsString(), connectInfo);

  PHTTPRequest * request = CreateRequest(url,
                                         info,
                                         connectInfo.GetMultipartFormInfo(),
                                         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)
{
  SendData(request);
  return request.outMIME.Contains(PHTTP::ContentLengthTag) ||
         request.outMIME.Contains(PHTTP::TransferEncodingTag);
}


BOOL PHTTPResource::OnPOST(PHTTPServer & server,
                            const PURL & url,
                       const PMIMEInfo & info,
                 const PStringToString & data,
             const PHTTPConnectionInfo & connectInfo)
{
  PHTTPRequest * request = CreateRequest(url,
                                         info,
                                         connectInfo.GetMultipartFormInfo(),
                                         server);

  request->entityBody = connectInfo.GetEntityBody();

  BOOL persist = TRUE;
  if (CheckAuthority(server, *request, connectInfo)) {
    server.SetDefaultMIMEInfo(request->outMIME, connectInfo);
    persist = OnPOSTData(*request, data);
    if (request->code != PHTTP::RequestOK)
      persist = server.OnError(request->code, "", connectInfo) && persist;
  }

  delete request;
  return persist;
}


BOOL PHTTPResource::OnPOSTData(PHTTPRequest & request,
                               const PStringToString & data)
{
  PHTML msg;
  BOOL persist = Post(request, data, msg);

  if (msg.Is(PHTML::InBody))
    msg << PHTML::Body();

  if (request.code != PHTTP::RequestOK)
    return persist;

  if (msg.IsEmpty())
    msg << PHTML::Title()    << (unsigned)PHTTP::RequestOK << " OK" << PHTML::Body()
        << PHTML::Heading(1) << (unsigned)PHTTP::RequestOK << " OK" << PHTML::Heading(1)
        << PHTML::Body();

  request.outMIME.SetAt(PHTTP::ContentTypeTag, "text/html");

  PINDEX len = msg.GetLength();
  request.server.StartResponse(request.code, request.outMIME, len);
  return request.server.Write((const char *)msg, len) && 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;
}


PHTTPRequest * PHTTPResource::CreateRequest(const PURL & url,
                                            const PMIMEInfo & inMIME,
                                            const PMultipartFormInfoArray & multipartFormInfo,
                                            PHTTPServer & socket)
{
  return new PHTTPRequest(url, inMIME, multipartFormInfo, socket);
}


static void WriteChunkedDataToServer(PHTTPServer & server, PCharArray & data)
{
  if (data.GetSize() == 0)
    return;

  server << data.GetSize() << "\r\n";
  server.Write(data, data.GetSize());
  server << "\r\n";
  data.SetSize(0);
}


void PHTTPResource::SendData(PHTTPRequest & request)
{
  if (!request.outMIME.Contains(PHTTP::ContentTypeTag) && !contentType)
    request.outMIME.SetAt(PHTTP::ContentTypeTag, contentType);

  PCharArray data;
  if (LoadData(request, data)) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -