📄 warsvrprotocolhttp.cpp
字号:
#include "StdAfx.h"#if WAR_RFC2068#include "WarSvrProtocolHttp.h" // class implemented#ifndef WAR_LOG_H# include "WarLog.h"#endif#ifndef WAR_AUTO_LOCK_H# include "WarAutoLock.h"#endif#ifndef WAR_SVR_ENGINE_H# include "WarSvrEngine.h"#endif#ifndef WAR_TIMER_H# include "WarTimer.h"#endif#ifndef WAR_PERFMON_DEF_H# include "WarPerfmonDef.h"#endif#ifndef WAR_USER_AUTH_IMPERSONATE_H# include "WarUserAuthImpersonate.h"#endif#ifndef WAR_ATOI_H# include "WarAtoi.h"#endif#ifndef WAR_FSYS_H# include "WarFsys.h"#endif#ifndef WAR_AP_BASE64_H# include "ap_base64.h"#endif#define AUTO_LOCK WarAutoLock MyLock(mSvrLock);using namespace std;/////////////////////////////// PUBLIC /////////////////////////////////////////============================= LIFECYCLE ====================================WarSvrProtocolHttp::WarSvrProtocolHttp( war_socket_io_ptr_t& companionPtr, WarSvrDefinition& svrDefinion) :WarSvrProtocol(companionPtr, svrDefinion){ mProtocolType = PROT_HTTP; mReply.mpProtocol = this; Reset(); AddLogIdentifierTag("HTTPD");}//============================= OPERATORS ====================================//============================= OPERATIONS ===================================void WarSvrProtocolHttp::Abort(const WarError& reason) throw(WarException){ CloseConnection(reason);}void WarSvrProtocolHttp::CloseConnection(const WarError& reason) throw(WarException){ if (IsOpen()) { Close(); } Logout(); GetEngine().UnregisterSession(*this); WarThrow(reason, NULL);}void WarSvrProtocolHttp::Reset(){ AUTO_LOCK; Logout(); mReply.Reset(); mHaveEndOfHeader = false; if (!mInputBuffer.IsEmpty()) mInputBuffer.Reset(); mExpectedContentBytes = 0; mReceivedContentBytes = 0; mRelayInput = false; WarTransferSocket::Reset(); // See if we have pending input if (!mQueuedInput.IsEmpty() || !mInputBuffer.IsEmpty()) { WarLog net_log(WARLOG_NETWORK, "WarSvrProtocolHttp::Reset()", this); if (net_log) { size_t bytes = mInputBuffer.GetLength(); if (mQueuedInput) bytes += mQueuedInput->GetBytesUsed(); net_log << "I found some queued input. (" << bytes << " bytes). " "I will call PreprocessInput() with this data, just as " "if it came fresh from the net." << war_endl; } war_transfer_buffer_ptr_t tmp_ptr = mQueuedInput; mQueuedInput = NULL; PreprocessInput(tmp_ptr); }}//============================= CALLBACK ===================================void WarSvrProtocolHttp::OnClientConnect(){ AUTO_LOCK // Update internal variables // and start receiving commands from the user try { WarSvrProtocol::OnClientConnect(); } catch(WarException& ex) { switch(ex.LocalError()) { case WAR_ERR_IP_IS_DENIED: mReply << HSM_BAD_IP << HTTPR_FORBIDDEN; break; case WAR_ERR_ACCESS_DENIED: mReply << HSM_ACCESS_DENIED << HTTPR_FORBIDDEN; break; default: mReply << HSM_GENERIC_FAIL << HTTPR_INTERNAL_SERVER_ERROR; break; } CloseConnection(ex); // Throws } WarUrl my_url; my_url.Create("http://", NULL, NULL, GetLocalAddress().GetPort(), NULL, "/"); mRequestHeader.Reset(); mRequestHeader.SetDefaultUrl(my_url);}void WarSvrProtocolHttp::OnReceived(const WarError& status, war_transfer_buffer_ptr_t& buffer){ WarSvrProtocol::OnReceived(status, buffer); if (status) { try { if (WAR_NETERR_HARD_CLOSE == status.LocalError()) { WarLog http_log(WARLOG_DEBUG_HTTP, "WarSvrProtocolHttp::OnReceived()", this); http_log << "Connection closed by the remote host." << status << war_endl; } else { // Error! WarLog warn_log(WARLOG_WARNINGS, "WarSvrProtocolHttp::OnReceived()", this); warn_log << "Error while receiving data. Closing connection." << status << war_endl; } } catch(WarException) { } CloseConnection(status); // throws } if (mRelayInput) { mQueuedInput = buffer; } else { PreprocessInput(buffer); }}void WarSvrProtocolHttp::PreprocessInput(war_transfer_buffer_ptr_t& buffer){ if (buffer.IsEmpty()) { try { // Connection closed! WarLog http_log(WARLOG_DEBUG_HTTP, "WarSvrProtocolHttp::PreprocessInput()", this); if (http_log) { http_log << "Connection closed by remote client" << war_endl; return; } } catch(WarException ex) { } CloseConnection(WarError()); // throws return; } try { ProcessInput(buffer); if (IsOpen() && mIoInBufferPtr) { mIoInBufferPtr->Reset(); RecvWithCallback(mIoInBufferPtr); } } catch(WarException& ex) { // Exception during input. This will normally indicate // an error-situation where we should give a short // explanation and close the connection. // Exceptions are when we negotiate authentication // credentials. switch(ex.LocalError()) { case WAR_HTERR_HEADER_TOO_LONG: GetReply() << HSM_HEADER_TOO_LONG << HTTPR_INTERNAL_SERVER_ERROR; CloseConnection(ex); return; case WAR_ERR_NOT_IMPLEMENTED: GetReply() << HSM_NOT_IMPLEMENTED << HTTPR_NOT_IMPLEMENTED; CloseConnection(ex); return; default: GetReply() << ex.Explain() << HTTPR_INTERNAL_SERVER_ERROR; CloseConnection(ex); } }}void WarSvrProtocolHttp::OnSent(const WarError& status, war_transfer_buffer_ptr_t& buffer){}void WarSvrProtocolHttp::OnValidateHeaderLength(size_t currLen)throw(WarException){ size_t max_len; if (currLen > (max_len = (size_t)GetIntOption("http_MAXHDRLEN"))) { WarLog security_log(WARLOG_SECURITY, "WarSvrProtocolHttp::OnValidateHeaderLength()", this); security_log << "HTTP header length exeeds the limit of " << max_len << "bytes defined by http_MAXHDRLEN option. " "This may indicate a breakin attempt from a hostile host." << war_endl; WarThrow(WarError(WAR_HTERR_HEADER_TOO_LONG), NULL); }}//============================= ACCESS ===================================//============================= INQUIRY ===================================/////////////////////////////// PROTECTED ///////////////////////////////////WarSvrProtocolHttp::~WarSvrProtocolHttp(void){}void WarSvrProtocolHttp::ProcessInput(war_transfer_buffer_ptr_t& buffer){ AUTO_LOCK; if (!buffer.IsEmpty()) mInputBuffer.PushData(buffer->GetBuffer(), buffer->GetBytesUsed());again: if (!mHaveEndOfHeader) { // Scan for end of header marker war_ccstr_t p = mInputBuffer.GetStartOfBuffer(); war_ccstr_t pp = mInputBuffer.GetEndOfBuffer() -3; while(p < pp) { if ((p[0] == '\r') && (p[1] == '\n') && (p[2] == '\r') && (p[3] == '\n')) { mHaveEndOfHeader = true; size_t header_len = (p - mInputBuffer.GetStartOfBuffer()) + 4; // Check if the header-length is too large OnValidateHeaderLength(header_len); // Process header mRequestHeader << mInputBuffer.PopData(header_len); mReply.GetHeader().SetHttpVersion(mRequestHeader.GetHttpVersion()); WarLog http_log(WARLOG_DEBUG_HTTP, "WarSvrProtocolHttp::ProcessInput()", this); if (http_log) { WarCollector<char> headers; mRequestHeader.GetNativeHeaders(headers); http_log << "Request headers: " << headers << war_endl; } // Load properties for the virtual host, if present LoadVirtual(mRequestHeader.GetUrl()); // Verify IP Access VerifyRemoteIpAddress(); // Attempt to log on VerfiyHttpAuth(); // Set CWD to / SetCwd("/"); // Check if method is allowed VerifyHttpRequest(); // Process headers try { mExpectedContentBytes = WarAtoi<contentlen_t>( mRequestHeader.GetHeaderValue("Content-Length").c_str()); } catch(WarException) { } goto process_content; } else ++p; } // Check if the header-length is too large OnValidateHeaderLength(mInputBuffer.GetLength()); if (!mHaveEndOfHeader) return; // Need more input }process_content: mReceivedContentBytes += mInputBuffer.GetLength(); if (mExpectedContentBytes >= mReceivedContentBytes) { // The request is complete WarError caught_err; war_ccstr_t data = NULL; size_t num_bytes_in_request_header = mInputBuffer.GetLength(); if (0 != num_bytes_in_request_header) data = mInputBuffer.PopData(mExpectedContentBytes); prot_cmd_prp_t prepare_cmd(this); // Allocates and deallocates resources try { switch(mRequestHeader.GetMethod()) { case HM_GET: OnGetRequest(data, mExpectedContentBytes); break; case HM_OPTIONS: OnOptionsRequest(data, mExpectedContentBytes); break; case HM_HEAD: OnHeadRequest(data, mExpectedContentBytes); break; case HM_POST: OnPostRequest(data, mExpectedContentBytes); break; case HM_PUT: OnPutRequest(data, mExpectedContentBytes); break; case HM_DELETE: OnDeleteRequest(data, mExpectedContentBytes); break; case HM_TRACE: OnTraceRequest(data, mExpectedContentBytes); break; default: OnInvalidRequest(data, mExpectedContentBytes); } } catch(WarException &ex) { switch(ex.LocalError()) { case WAR_BYPASS_DEFAULT_PRC: // Async IO operation in progress. We will be // called again when it completes. { WarLog net_log(WARLOG_NETWORK, "WarSvrProtocolHttp::ProcessInput()", this); if (net_log) { net_log << "Caught WAR_BYPASS_DEFAULT_PRC. " "I will not continue to process input " "until I'm called again. " << war_endl; } // Send reply GetReply() << HSM_NOT_IMPLEMENTED << HTTPR_NOT_IMPLEMENTED; } return; case WAR_ERR_NOT_IMPLEMENTED:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -