From fcbd9c4ed5b5a087a8eee4c3dc0c52c1b750982e Mon Sep 17 00:00:00 2001 From: prozacx Date: Tue, 5 Jul 2005 09:24:21 +0000 Subject: [PATCH] HTTP Server git-svn-id: https://znc.svn.sourceforge.net/svnroot/znc/trunk@412 726aef4b-f618-498e-8847-2d620e286838 --- HTTPSock.cpp | 250 +++++++++++++++++++++++++++++++++++++++++++++++++++ HTTPSock.h | 67 ++++++++++++++ 2 files changed, 317 insertions(+) create mode 100644 HTTPSock.cpp create mode 100644 HTTPSock.h diff --git a/HTTPSock.cpp b/HTTPSock.cpp new file mode 100644 index 00000000..6ddcc30f --- /dev/null +++ b/HTTPSock.cpp @@ -0,0 +1,250 @@ +#include "HTTPSock.h" +#include "znc.h" + +CHTTPSock::CHTTPSock() : Csock() { + m_bSentHeader = false; + m_bGotHeader = false; + m_bPost = false; + m_bLoggedIn = false; + m_uPostLen = 0; + EnableReadLine(); +} + +CHTTPSock::CHTTPSock(const CString& sHostname, unsigned short uPort, int iTimeout) : Csock(sHostname, uPort, iTimeout) { + m_bSentHeader = false; + m_bGotHeader = false; + m_bLoggedIn = false; + m_bPost = false; + m_uPostLen = 0; + EnableReadLine(); +} + +CHTTPSock::~CHTTPSock() {} + +void CHTTPSock::ReadData(const char* data, int len) { + if (m_bGotHeader && m_bPost) { + const CString& sBuf = GetInternalBuffer(); + if (sBuf.size() >= m_uPostLen) { + ParseParams(sBuf); + GetPage(); + } + } +} + +void CHTTPSock::ReadLine(const CString& sData) { + CString sLine = sData; + sLine.TrimRight("\r\n"); + + if (m_bGotHeader) { + return; + } + + CString sName = sLine.Token(0); + + if (sName.CaseCmp("GET") == 0) { + m_bPost = false; + m_sURI = sLine.Token(1); + ParseURI(); + } else if (sName.CaseCmp("POST") == 0) { + m_bPost = true; + m_sURI = sLine.Token(1); + ParseURI(); + } else if (sName.CaseCmp("Authorization:") == 0) { + CString sUnhashed; + sLine.Token(2).Base64Decode(sUnhashed); + m_sUser = sUnhashed.Token(0, false, ":"); + m_sPass = sUnhashed.Token(1, true, ":"); + m_bLoggedIn = OnLogin(m_sUser, m_sPass); + } else if (sName.CaseCmp("Content-Length:") == 0) { + m_uPostLen = sLine.Token(1).ToULong(); + } else if (sLine.empty()) { + m_bGotHeader = true; + + if (!m_bPost) { + GetPage(); + } + } +} + +void CHTTPSock::GetPage() { + CString sPage; + + if (!OnPageRequest(m_sURI, sPage)) { + PrintNotFound(); + return; + } + + if (PrintHeader(sPage.length())) { + Write(sPage); + Close(); + } +} + +void CHTTPSock::ParseURI() { + ParseParams(m_sURI.Token(1, true, "?")); + m_sURI = m_sURI.Token(0, false, "?"); +} + +void CHTTPSock::ParseParams(const CString& sParams) { + m_msvsParams.clear(); + + VCString vsPairs; + sParams.Split("&", vsPairs, true); + + for (unsigned int a = 0; a < vsPairs.size(); a++) { + const CString& sPair = vsPairs[a]; + CString sName = sPair.Token(0, false, "=").Escape_n(CString::EURL, CString::EAscii); + CString sValue = sPair.Token(1, true, "=").Escape_n(CString::EURL, CString::EAscii); + + m_msvsParams[sName].push_back(sValue); + } +} + +const CString& CHTTPSock::GetUser() const { + return m_sUser; +} + +const CString& CHTTPSock::GetPass() const { + return m_sPass; +} + +CString CHTTPSock::GetParam(const CString& sName) const { + CString sRet; + + VCString vsParams; + if (GetParamValues(sName, vsParams)) { + sRet = vsParams[0]; + } + + return sRet; +} + +unsigned int CHTTPSock::GetParamValues(const CString& sName, VCString& vsRet) const { + vsRet.clear(); + + map::const_iterator it = m_msvsParams.find(sName); + + if (it != m_msvsParams.end()) { + vsRet = it->second; + } + + return vsRet.size(); +} + +const map& CHTTPSock::GetParams() const { + return m_msvsParams; +} + +bool CHTTPSock::OnPageRequest(const CString& sURI, CString& sPageRet) { + return false; +} + +CString CHTTPSock::GetErrorPage(unsigned int uStatusId, const CString& sStatusMsg, const CString& sMessage) { + return "\r\n" + "\r\n" + CString::ToString(uStatusId) + " " + sStatusMsg.Escape_n(CString::EHTML) + "\r\n" + "\r\n

" + sStatusMsg.Escape_n(CString::EHTML) + "

\r\n" + "

" + sMessage.Escape_n(CString::EHTML) + "

\r\n" + "
\r\n
" + CZNC::GetTag().Escape_n(CString::EHTML) + " at " + GetLocalIP().Escape_n(CString::EHTML) + " Port " + CString::ToString(GetLocalPort()) + "
\r\n" + "\r\n"; +} + +bool CHTTPSock::ForceLogin() { + if (m_bLoggedIn) { + return true; + } + + if (SentHeader()) { + return false; + } + + CString sPage = GetErrorPage(401, "Unauthorized", "You need to login to view this page."); + AddHeader("WWW-Authenticate", "Basic realm=\"" + CZNC::GetTag() + "\""); + PrintHeader(sPage.length(), "text/html", 401, "Unauthorized"); + Write(sPage); + Close(); + + return false; +} + +bool CHTTPSock::OnLogin(const CString& sUser, const CString& sPass) { + return false; +} + +bool CHTTPSock::PrintNotFound() { + if (SentHeader()) { + return false; + } + + CString sPage = GetErrorPage(404, "Not Found", "The requested URL was not found on this server."); + PrintHeader(sPage.length(), "text/html", 404, "Not Found"); + Write(sPage); + Close(); + + return true; +} + +bool CHTTPSock::SentHeader() const { + return m_bSentHeader; +} + +bool CHTTPSock::PrintHeader(unsigned long uContentLength, const CString& sContentType, unsigned int uStatusId, const CString& sStatusMsg) { + if (SentHeader()) { + return false; + } + + Write("HTTP/1.0 " + CString::ToString(uStatusId) + " " + sStatusMsg + "\r\n"); + //Write("Date: Tue, 28 Jun 2005 20:45:36 GMT\r\n"); + Write("Server: ZNC " + CZNC::GetTag() + "\r\n"); + Write("Content-Length: " + CString::ToString(uContentLength) + "\r\n"); + Write("Connection: Close\r\n"); + Write("Content-Type: " + sContentType + "\r\n"); + + for (MCString::iterator it = m_msHeaders.begin(); it != m_msHeaders.end(); it++) { + Write(it->first + ": " + it->second + "\r\n"); + } + + Write("\r\n"); + m_bSentHeader = true; + + return true; +} + +void CHTTPSock::AddHeader(const CString& sName, const CString& sValue) { + m_msHeaders[sName] = sValue; +} + +bool CHTTPSock::Redirect(const CString& sURL) { + if (SentHeader()) { + return false; + } + + DEBUG_ONLY(cout << "Redirect to [" << sURL << "]" << endl); + CString sPage = GetErrorPage(302, "Found", "The document has moved here."); + AddHeader("Location", sURL); + PrintHeader(sPage.length(), "text/html", 302, "Found"); + Write(sPage); + Close(); + + return true; +} + +void CHTTPSock::Timeout() { +} + +void CHTTPSock::SockError(int iErrno) { +} + +void CHTTPSock::Connected() { + SetTimeout(120); +} + +void CHTTPSock::Disconnected() { +} + +Csock* CHTTPSock::GetSockObj(const CString& sHost, unsigned short uPort) { + CHTTPSock* pSock = new CHTTPSock; + pSock->SetSockName("HTTP::CLIENT"); + pSock->SetTimeout(120); + + return pSock; +} diff --git a/HTTPSock.h b/HTTPSock.h new file mode 100644 index 00000000..aae0e1d0 --- /dev/null +++ b/HTTPSock.h @@ -0,0 +1,67 @@ +#ifndef _HTTPSOCK_H +#define _HTTPSOCK_H + +#include "main.h" +#include "Utils.h" +#include "FileUtils.h" +#include "User.h" + +class CHTTPSock : public Csock { +public: + CHTTPSock(); + CHTTPSock(const CString& sHostname, unsigned short uPort, int iTimeout = 60); + virtual ~CHTTPSock(); + + // Csocket derived members + virtual void ReadData(const char* data, int len); + virtual void ReadLine(const CString& sData); + virtual void SockError(int iErrno); + virtual void Timeout(); + virtual void Connected(); + virtual void Disconnected(); + virtual Csock* GetSockObj(const CString& sHost, unsigned short uPort); + // !Csocket derived members + + // Hooks + virtual bool OnPageRequest(const CString& sURI, CString& sPageRet); + virtual bool OnLogin(const CString& sUser, const CString& sPass); + // !Hooks + + bool SentHeader() const; + bool PrintHeader(unsigned long uContentLength, const CString& sContentType = "text/html", unsigned int uStatusId = 200, const CString& sStatusMsg = "OK"); + void AddHeader(const CString& sName, const CString& sValue); + + bool PrintNotFound(); + bool Redirect(const CString& sURL); + bool ForceLogin(); + CString GetErrorPage(unsigned int uStatusId, const CString& sStatusMsg, const CString& sMessage); + void ParseParams(const CString& sParams); + void ParseURI(); + void GetPage(); + + // Setters + // !Setters + + // Getters + CString GetParam(const CString& sName) const; + const CString& GetUser() const; + const CString& GetPass() const; + unsigned int GetParamValues(const CString& sName, VCString& vsRet) const; + const map& GetParams() const; + // !Getters +private: +protected: + bool m_bSentHeader; + bool m_bGotHeader; + bool m_bLoggedIn; + bool m_bPost; + unsigned long m_uPostLen; + CString m_sURI; + CString m_sUser; + CString m_sPass; + map m_msvsParams; + MCString m_msHeaders; +}; + +#endif // !_HTTPSOCK_H +