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

📄 httpsrvr.cxx

📁 pwlib源码库
💻 CXX
📖 第 1 页 / 共 4 页
字号:
    info = new PMultipartFormInfo;    // read MIME information    info->mime.ReadFrom(data);    // get the content type    PString type = info->mime(PHTTP::ContentTypeTag);    // check the encoding    PString encoding = info->mime("Content-Transfer-Encoding");    // accumulate text until another seperator or end of data    PString & buf = info->body;    PINDEX len = 0;    buf.SetSize(len+1);    buf[0] = '\0';    PINDEX sepLen = sep.GetLength();    const char * sepPtr = (const char *)sep;    while (data.good()) {      buf.SetSize(len);      data >> buf[len++];      if ((len >= sepLen) && (memcmp(((const char *)buf) + len - sepLen, sepPtr, sepLen) == 0)) {        char ch;        data >> ch;        if (ch != 0x0d)          data.putback(ch);         else {          data >> ch;          if (ch != 0x0a)            data.putback(ch);         }        len -= sepLen;        break;      }    }    buf.SetSize(len+1);    buf[len] = '\0';    /*    while (data.good()) {      data >> line;      if (line.Find(sep) == 0)        break;      info->body += line + "\n";    }     */    multipartFormInfoArray.Append(info);    info = NULL;  }#endif}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 = connectInfo.GetPersistenceTimeout();  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;    // make sure the form info is reset for each new operation  connectInfo.ResetMultipartFormInfo();  // 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 {    connectInfo.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 :        {          // check for multi-part form POSTs          PString postType = (connectInfo.GetMIME())(ContentTypeTag);          if (postType.Find("multipart/form-data") == 0)            connectInfo.DecodeMultipartFormInfo(postType, connectInfo.entityBody);          else  // if (postType *= "x-www-form-urlencoded)            PURL::SplitQueryVars(connectInfo.entityBody, postData);        }        persist = OnPOST(url, connectInfo.GetMIME(), postData, connectInfo);        break;      case P_MAX_INDEX:      default:        persist = OnUnknown(args, connectInfo);    }  }  flush();  // if the function just indicated that the connection is to persist,  // and so did the client, then return TRUE. Note that all of the OnXXXX  // routines above must make sure that their return value is FALSE if  // if there was no ContentLength field in the response. This ensures that  // we always close the socket so the client will get the correct end of file  if (persist && connectInfo.IsPersistant()) {    unsigned max = connectInfo.GetPersistenceMaximumTransations();    if (max == 0 || transactionCount < max)      return TRUE;  }  PTRACE(5, "HTTPServer\tConnection end: " << connectInfo.IsPersistant());  // close the output stream now and return FALSE  Shutdown(ShutdownWrite);  return FALSE;}PString PHTTPServer::ReadEntityBody(){  if (connectInfo.GetMajorVersion() < 1)    return PString();  PString entityBody;  long contentLength = connectInfo.GetEntityBodyLength();  // a content length of > 0 means read explicit length  // a content length of < 0 means read until EOF  // a content length of 0 means read nothing  int count = 0;  if (contentLength > 0) {    entityBody = ReadString((PINDEX)contentLength);  } else if (contentLength == -2) {    ReadLine(entityBody, FALSE);  } else if (contentLength < 0) {    while (Read(entityBody.GetPointer(count+1000)+count, 1000))      count += GetLastReadCount();    entityBody.SetSize(count+1);  }  // close the connection, if not persistant  if (!connectInfo.IsPersistant()) {    PIPSocket * socket = GetSocket();    if (socket != NULL)      socket->Shutdown(PIPSocket::ShutdownRead);  }  return entityBody;}PString PHTTPServer::GetServerName() const{  return "PWLib-HTTP-Server/1.0 PWLib/1.0";}void PHTTPServer::SetURLSpace(const PHTTPSpace & space){  urlSpace = space;}BOOL PHTTPServer::OnGET(const PURL & url,                   const PMIMEInfo & info,         const PHTTPConnectionInfo & connectInfo){  urlSpace.StartRead();  PHTTPResource * resource = urlSpace.FindResource(url);  if (resource == NULL) {    urlSpace.EndRead();    return OnError(NotFound, url.AsString(), connectInfo);  }  BOOL retval = resource->OnGET(*this, url, info, connectInfo);  urlSpace.EndRead();  return retval;}BOOL PHTTPServer::OnHEAD(const PURL & url,                    const PMIMEInfo & info,          const PHTTPConnectionInfo & connectInfo){  urlSpace.StartRead();  PHTTPResource * resource = urlSpace.FindResource(url);  if (resource == NULL) {    urlSpace.EndRead();    return OnError(NotFound, url.AsString(), connectInfo);  }  BOOL retval = resource->OnHEAD(*this, url, info, connectInfo);  urlSpace.EndRead();  return retval;}BOOL PHTTPServer::OnPOST(const PURL & url,                    const PMIMEInfo & info,              const PStringToString & data,          const PHTTPConnectionInfo & connectInfo){  urlSpace.StartRead();  PHTTPResource * resource = urlSpace.FindResource(url);  if (resource == NULL) {    urlSpace.EndRead();    return OnError(NotFound, url.AsString(), connectInfo);  }  BOOL retval = resource->OnPOST(*this, url, info, data, connectInfo);  urlSpace.EndRead();  return retval;}BOOL PHTTPServer::OnProxy(const PHTTPConnectionInfo & connectInfo){  return OnError(BadGateway, "Proxy not implemented.", connectInfo) &&         connectInfo.GetCommandCode() != CONNECT;}struct httpStatusCodeStruct {  const char * text;  int  code;  BOOL allowedBody;  int  majorVersion;  int  minorVersion;};static const httpStatusCodeStruct * GetStatusCodeStruct(int code){  static const httpStatusCodeStruct httpStatusDefn[] = {    // First entry MUST be InternalServerError    { "Internal Server Error",         PHTTP::InternalServerError, 1 },    { "OK",                            PHTTP::RequestOK, 1 },    { "Unauthorised",                  PHTTP::UnAuthorised, 1 },    { "Forbidden",                     PHTTP::Forbidden, 1 },    { "Not Found",                     PHTTP::NotFound, 1 },    { "Not Modified",                  PHTTP::NotModified },    { "No Content",                    PHTTP::NoContent },    { "Bad Gateway",                   PHTTP::BadGateway, 1 },    { "Bad Request",                   PHTTP::BadRequest, 1 },    { "Continue",                      PHTTP::Continue, 1, 1, 1 },    { "Switching Protocols",           PHTTP::SwitchingProtocols, 1, 1, 1 },    { "Created",                       PHTTP::Created, 1 },    { "Accepted",                      PHTTP::Accepted, 1 },    { "Non-Authoritative Information", PHTTP::NonAuthoritativeInformation, 1, 1, 1 },    { "Reset Content",                 PHTTP::ResetContent, 0, 1, 1 },    { "Partial Content",               PHTTP::PartialContent, 1, 1, 1 },    { "Multiple Choices",              PHTTP::MultipleChoices, 1, 1, 1 },    { "Moved Permanently",             PHTTP::MovedPermanently, 1 },    { "Moved Temporarily",             PHTTP::MovedTemporarily, 1 },    { "See Other",                     PHTTP::SeeOther, 1, 1, 1 },    { "Use Proxy",                     PHTTP::UseProxy, 1, 1, 1 },    { "Payment Required",              PHTTP::PaymentRequired, 1, 1, 1 },    { "Method Not Allowed",            PHTTP::MethodNotAllowed, 1, 1, 1 },    { "None Acceptable",               PHTTP::NoneAcceptable, 1, 1, 1 },    { "Proxy Authetication Required",  PHTTP::ProxyAuthenticationRequired, 1, 1, 1 },    { "Request Timeout",               PHTTP::RequestTimeout, 1, 1, 1 },    { "Conflict",                      PHTTP::Conflict, 1, 1, 1 },    { "Gone",                          PHTTP::Gone, 1, 1, 1 },    { "Length Required",               PHTTP::LengthRequired, 1, 1, 1 },    { "Unless True",                   PHTTP::UnlessTrue, 1, 1, 1 },    { "Not Implemented",               PHTTP::NotImplemented, 1 },    { "Service Unavailable",           PHTTP::ServiceUnavailable, 1, 1, 1 },    { "Gateway Timeout",               PHTTP::GatewayTimeout, 1, 1, 1 }  };  // make sure the error code is valid  for (PINDEX i = 0; i < PARRAYSIZE(httpStatusDefn); i++)    if (code == httpStatusDefn[i].code)      return &httpStatusDefn[i];  return httpStatusDefn;}BOOL PHTTPServer::StartResponse(StatusCode code,                                PMIMEInfo & headers,                                long bodySize){  if (connectInfo.majorVersion < 1)     return FALSE;  httpStatusCodeStruct dummyInfo;  const httpStatusCodeStruct * statusInfo;  if (connectInfo.commandCode < NumCommands)    statusInfo = GetStatusCodeStruct(code);  else {    dummyInfo.text = "";    dummyInfo.code = code;    dummyInfo.allowedBody = TRUE;    dummyInfo.majorVersion = connectInfo.majorVersion;    dummyInfo.minorVersion = connectInfo.minorVersion;    statusInfo = &dummyInfo;  }  // output the command line  *this << "HTTP/" << connectInfo.majorVersion << '.' << connectInfo.minorVersion        << ' ' << statusInfo->code << ' ' << statusInfo->text << "\r\n";  BOOL chunked = FALSE;  // If do not have user set content length, decide if we should add one  if (!headers.Contains(ContentLengthTag)) {    if (connectInfo.minorVersion < 1) {      // v1.0 client, don't put in ContentLength if the bodySize is zero because      // that can be confused by some browsers as meaning there is no body length.      if (bodySize > 0)        headers.SetAt(ContentLengthTag, bodySize);    }    else {      // v1.1 or later, see if will use chunked output      chunked = bodySize == P_MAX_INDEX;      if (chunked)        headers.SetAt(TransferEncodingTag, ChunkedTag);      else if (bodySize >= 0 && bodySize < P_MAX_INDEX)        headers.SetAt(ContentLengthTag, bodySize);    }  }  *this << setfill('\r') << headers;#ifdef STRANGE_NETSCAPE_BUG  // The following is a work around for a strange bug in Netscape where it  // locks up when a persistent connection is made and data less than 1k  // (including MIME headers) is sent. Go figure....  if (bodySize < 1024 && connectInfo.GetMIME()(UserAgentTag).Find("Mozilla/2.0") != P_MAX_INDEX)    nextTimeout.SetInterval(STRANGE_NETSCAPE_BUG*1000);#endif  return chunked;}void PHTTPServer::SetDefaultMIMEInfo(PMIMEInfo & info,                     const PHTTPConnectionInfo & connectInfo){  PTime now;  if (!info.Contains(DateTag))    info.SetAt(DateTag, now.AsString(PTime::RFC1123, PTime::GMT));  if (!info.Contains(MIMEVersionTag))    info.SetAt(MIMEVersionTag, "1.0");  if (!info.Contains(ServerTag))    info.SetAt(ServerTag, GetServerName());  if (connectInfo.IsPersistant()) {    if (connectInfo.IsProxyConnection()) {      PTRACE(5, "HTTPServer\tSetting proxy persistant response");      info.SetAt(ProxyConnectionTag, KeepAliveTag);    }    else {      PTRACE(5, "HTTPServer\tSetting direct persistant response");      info.SetAt(ConnectionTag, KeepAliveTag);    }  }}BOOL PHTTPServer::OnUnknown(const PCaselessString & cmd,                         const PHTTPConnectionInfo & connectInfo){  return OnError(NotImplemented, cmd, connectInfo);}BOOL PHTTPServer::OnError(StatusCode code,             const PCaselessString & extra,         const PHTTPConnectionInfo & connectInfo){  const httpStatusCodeStruct * statusInfo = GetStatusCodeStruct(code);  if (!connectInfo.IsCompatible(statusInfo->majorVersion, statusInfo->minorVersion))    statusInfo = GetStatusCodeStruct((code/100)*100);  PMIMEInfo headers;  SetDefaultMIMEInfo(headers, connectInfo);  if (!statusInfo->allowedBody) {    StartResponse(code, headers, 0);    return statusInfo->code == RequestOK;  }  PString reply;  if (extra.Find("<body") != P_MAX_INDEX)    reply = extra;  else {    PHTML html;    html << PHTML::Title()         << statusInfo->code         << ' '         << statusInfo->text         << PHTML::Body()         << PHTML::Heading(1)         << statusInfo->code         << ' '         << statusInfo->text         << PHTML::Heading(1)         << extra         << PHTML::Body();    reply = html;  }  headers.SetAt(ContentTypeTag, "text/html");  StartResponse(code, headers, reply.GetLength());  WriteString(reply);  return statusInfo->code == RequestOK;}//////////////////////////////////////////////////////////////////////////////// PHTTPSimpleAuthvoid PHTTPAuthority::DecodeBasicAuthority(const PString & authInfo,                                          PString & username,                                          PString & password){  PString decoded;  if (authInfo(0, 5) *= "Basic ")    decoded = PBase64::Decode(authInfo(6, P_MAX_INDEX));  else    decoded = PBase64::Decode(authInfo);  PINDEX colonPos = decoded.Find(':');  if (colonPos == P_MAX_INDEX) {    username = decoded;    password = PString();  }  else {    username = decoded.Left(colonPos).Trim();    password = decoded.Mid(colonPos+1).Trim();  }}BOOL PHTTPAuthority::IsActive() const{  return TRUE;}//////////////////////////////////////////////////////////////////////////////// PHTTPSimpleAuthPHTTPSimpleAuth::PHTTPSimpleAuth(const PString & realm_,                                 const PString & username_,                                 const PString & password_)  : realm(realm_), username(username_), password(password_){  PAssert(!realm, "Must have a realm!");

⌨️ 快捷键说明

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