diff --git a/include/znc/HTTPSock.h b/include/znc/HTTPSock.h index 65da6fdb..2c3cc872 100644 --- a/include/znc/HTTPSock.h +++ b/include/znc/HTTPSock.h @@ -25,8 +25,8 @@ class CModule; class CHTTPSock : public CSocket { public: - CHTTPSock(CModule *pMod); - CHTTPSock(CModule *pMod, const CString& sHostname, unsigned short uPort, int iTimeout = 60); + CHTTPSock(CModule *pMod, const CString& sURIPrefix); + CHTTPSock(CModule *pMod, const CString& sURIPrefix, const CString& sHostname, unsigned short uPort, int iTimeout = 60); virtual ~CHTTPSock(); // Csocket derived members @@ -76,6 +76,7 @@ public: const CString& GetPass() const; const CString& GetParamString() const; const CString& GetContentType() const; + const CString& GetURIPrefix() const; bool IsPost() const; // !Getters @@ -121,6 +122,7 @@ protected: bool m_bAcceptGzip; MCString m_msRequestCookies; MCString m_msResponseCookies; + CString m_sURIPrefix; }; #endif // !_HTTPSOCK_H diff --git a/include/znc/Listener.h b/include/znc/Listener.h index 224cecb4..0f39887d 100644 --- a/include/znc/Listener.h +++ b/include/znc/Listener.h @@ -32,11 +32,12 @@ public: ACCEPT_ALL } EAcceptType; - CListener(unsigned short uPort, const CString& sBindHost, bool bSSL, EAddrType eAddr, EAcceptType eAccept) { + CListener(unsigned short uPort, const CString& sBindHost, const CString& sURIPrefix, bool bSSL, EAddrType eAddr, EAcceptType eAccept) { m_uPort = uPort; m_sBindHost = sBindHost; m_bSSL = bSSL; m_eAddr = eAddr; + m_sURIPrefix = sURIPrefix; m_pListener = NULL; m_eAcceptType = eAccept; } @@ -49,6 +50,7 @@ public: unsigned short GetPort() const { return m_uPort; } const CString& GetBindHost() const { return m_sBindHost; } CRealListener* GetRealListener() const { return m_pListener; } + const CString& GetURIPrefix() const { return m_sURIPrefix; } EAcceptType GetAcceptType() const { return m_eAcceptType; } // !Getters @@ -65,6 +67,7 @@ protected: EAddrType m_eAddr; unsigned short m_uPort; CString m_sBindHost; + CString m_sURIPrefix; CRealListener* m_pListener; EAcceptType m_eAcceptType; }; @@ -84,13 +87,14 @@ private: class CIncomingConnection : public CZNCSock { public: - CIncomingConnection(const CString& sHostname, unsigned short uPort, CListener::EAcceptType eAcceptType); + CIncomingConnection(const CString& sHostname, unsigned short uPort, CListener::EAcceptType eAcceptType, const CString& sURIPrefix); virtual ~CIncomingConnection() {} virtual void ReadLine(const CString& sData); virtual void ReachedMaxBuffer(); private: CListener::EAcceptType m_eAcceptType; + const CString m_sURIPrefix; }; #endif // !_LISTENER_H diff --git a/include/znc/WebModules.h b/include/znc/WebModules.h index 3c04ddfd..44e477e5 100644 --- a/include/znc/WebModules.h +++ b/include/znc/WebModules.h @@ -117,7 +117,7 @@ public: PAGE_DONE // all stuff has been done }; - CWebSock(); + CWebSock(const CString& sURIPrefix); virtual ~CWebSock(); virtual bool ForceLogin(); diff --git a/include/znc/znc.h b/include/znc/znc.h index 99c10cb2..2ec5e57a 100644 --- a/include/znc/znc.h +++ b/include/znc/znc.h @@ -152,7 +152,8 @@ public: // Listener yummy CListener* FindListener(u_short uPort, const CString& BindHost, EAddrType eAddr); bool AddListener(CListener*); - bool AddListener(unsigned short uPort, const CString& sBindHost, bool bSSL, + bool AddListener(unsigned short uPort, const CString& sBindHost, + const CString& sURIPrefix, bool bSSL, EAddrType eAddr, CListener::EAcceptType eAccept, CString& sError); bool DelListener(CListener*); diff --git a/modules/data/webadmin/tmpl/settings.tmpl b/modules/data/webadmin/tmpl/settings.tmpl index 9c958442..66879fe1 100644 --- a/modules/data/webadmin/tmpl/settings.tmpl +++ b/modules/data/webadmin/tmpl/settings.tmpl @@ -16,6 +16,7 @@ IPv6 IRC Web + URIPrefix @@ -38,6 +39,7 @@
checked="checked"/>
+
@@ -56,12 +58,13 @@ - +
+
diff --git a/modules/webadmin.cpp b/modules/webadmin.cpp index ec675080..5f72721e 100644 --- a/modules/webadmin.cpp +++ b/modules/webadmin.cpp @@ -101,6 +101,7 @@ public: CString sArgs(sArgStr); CString sPort; CString sListenHost; + CString sURIPrefix; while (sArgs.Left(1) == "-") { CString sOpt = sArgs.Token(0); @@ -150,7 +151,7 @@ public: } // Now turn that into a listener instance - CListener *pListener = new CListener(uPort, sListenHost, bSSL, + CListener *pListener = new CListener(uPort, sListenHost, sURIPrefix, bSSL, (!bIPv6 ? ADDR_IPV4ONLY : ADDR_ALL), CListener::ACCEPT_HTTP); if (!pListener->Listen()) { @@ -1420,6 +1421,7 @@ public: bool AddListener(CWebSock& WebSock, CTemplate& Tmpl) { unsigned short uPort = WebSock.GetParam("port").ToUShort(); CString sHost = WebSock.GetParam("host"); + CString sURIPrefix = WebSock.GetParam("uriprefix"); if (sHost == "*") sHost = ""; bool bSSL = WebSock.GetParam("ssl").ToBool(); bool bIPv4 = WebSock.GetParam("ipv4").ToBool(); @@ -1460,7 +1462,7 @@ public: } CString sMessage; - if (CZNC::Get().AddListener(uPort, sHost, bSSL, eAddr, eAccept, sMessage)) { + if (CZNC::Get().AddListener(uPort, sHost, sURIPrefix, bSSL, eAddr, eAccept, sMessage)) { if (!sMessage.empty()) { WebSock.GetSession()->AddSuccess(sMessage); } @@ -1545,6 +1547,8 @@ public: l["IsWeb"] = CString(pListener->GetAcceptType() != CListener::ACCEPT_IRC); l["IsIRC"] = CString(pListener->GetAcceptType() != CListener::ACCEPT_HTTP); + l["URIPrefix"] = pListener->GetURIPrefix() + "/"; + // simple protection for user from shooting his own foot // TODO check also for hosts/families // such check is only here, user still can forge HTTP request to delete web port diff --git a/src/ClientCommand.cpp b/src/ClientCommand.cpp index 1d42ec91..38b8a491 100644 --- a/src/ClientCommand.cpp +++ b/src/ClientCommand.cpp @@ -1430,6 +1430,7 @@ void CClient::UserPortCommand(CString& sLine) { Table.AddColumn("SSL"); Table.AddColumn("Proto"); Table.AddColumn("IRC/Web"); + Table.AddColumn("URIPrefix"); vector::const_iterator it; const vector& vpListeners = CZNC::Get().GetListeners(); @@ -1445,6 +1446,7 @@ void CClient::UserPortCommand(CString& sLine) { CListener::EAcceptType eAccept = (*it)->GetAcceptType(); Table.SetCell("IRC/Web", (eAccept == CListener::ACCEPT_ALL ? "All" : (eAccept == CListener::ACCEPT_IRC ? "IRC" : "Web"))); + Table.SetCell("URIPrefix", (*it)->GetURIPrefix() + "/"); } PutStatus(Table); @@ -1483,12 +1485,13 @@ void CClient::UserPortCommand(CString& sLine) { } if (sPort.empty() || sAddr.empty() || sAccept.empty()) { - PutStatus("Usage: AddPort <[+]port> [bindhost]"); + PutStatus("Usage: AddPort <[+]port> [bindhost [uriprefix]]"); } else { bool bSSL = (sPort.Left(1).Equals("+")); const CString sBindHost = sLine.Token(4); + const CString sURIPrefix = sLine.Token(5); - CListener* pListener = new CListener(uPort, sBindHost, bSSL, eAddr, eAccept); + CListener* pListener = new CListener(uPort, sBindHost, sURIPrefix, bSSL, eAddr, eAccept); if (!pListener->Listen()) { delete pListener; diff --git a/src/HTTPSock.cpp b/src/HTTPSock.cpp index 9ce157eb..d3da712e 100644 --- a/src/HTTPSock.cpp +++ b/src/HTTPSock.cpp @@ -28,11 +28,11 @@ using std::set; #define MAX_POST_SIZE 1024 * 1024 -CHTTPSock::CHTTPSock(CModule *pMod) : CSocket(pMod) { +CHTTPSock::CHTTPSock(CModule *pMod, const CString& sURIPrefix) : CSocket(pMod), m_sURIPrefix(sURIPrefix) { Init(); } -CHTTPSock::CHTTPSock(CModule *pMod, const CString& sHostname, unsigned short uPort, int iTimeout) : CSocket(pMod, sHostname, uPort, iTimeout) { +CHTTPSock::CHTTPSock(CModule *pMod, const CString& sURIPrefix, const CString& sHostname, unsigned short uPort, int iTimeout) : CSocket(pMod, sHostname, uPort, iTimeout), m_sURIPrefix(sURIPrefix) { Init(); } @@ -495,6 +495,10 @@ const CString& CHTTPSock::GetParamString() const { return m_sPostData; } +const CString& CHTTPSock::GetURIPrefix() const { + return m_sURIPrefix; +} + bool CHTTPSock::HasParam(const CString& sName, bool bPost) const { if (bPost) return (m_msvsPOSTParams.find(sName) != m_msvsPOSTParams.end()); diff --git a/src/Listener.cpp b/src/Listener.cpp index 9950cd2d..6e0e34eb 100644 --- a/src/Listener.cpp +++ b/src/Listener.cpp @@ -60,7 +60,9 @@ bool CRealListener::ConnectionFrom(const CString& sHost, unsigned short uPort) { } Csock* CRealListener::GetSockObj(const CString& sHost, unsigned short uPort) { - CIncomingConnection *pClient = new CIncomingConnection(sHost, uPort, m_Listener.GetAcceptType()); + CIncomingConnection *pClient = new CIncomingConnection(sHost, uPort, + m_Listener.GetAcceptType(), + m_Listener.GetURIPrefix()); if (CZNC::Get().AllowConnectionFrom(sHost)) { GLOBALMODULECALL(OnClientConnect(pClient, sHost, uPort), NOTHING); } else { @@ -83,7 +85,7 @@ void CRealListener::SockError(int iErrno, const CString& sDescription) { } } -CIncomingConnection::CIncomingConnection(const CString& sHostname, unsigned short uPort, CListener::EAcceptType eAcceptType) : CZNCSock(sHostname, uPort) { +CIncomingConnection::CIncomingConnection(const CString& sHostname, unsigned short uPort, CListener::EAcceptType eAcceptType, const CString& sURIPrefix) : CZNCSock(sHostname, uPort), m_sURIPrefix(sURIPrefix) { m_eAcceptType = eAcceptType; // The socket will time out in 120 secs, no matter what. // This has to be fixed up later, if desired. @@ -141,7 +143,7 @@ void CIncomingConnection::ReadLine(const CString& sLine) { return; } - pSock = new CWebSock(); + pSock = new CWebSock(m_sURIPrefix); CZNC::Get().GetManager().SwapSockByAddr(pSock, this); // And don't forget to give it some sane name / timeout diff --git a/src/WebModules.cpp b/src/WebModules.cpp index c8f1c655..e6e689d2 100644 --- a/src/WebModules.cpp +++ b/src/WebModules.cpp @@ -185,7 +185,7 @@ void CWebAuth::Invalidate() { m_pWebSock = NULL; } -CWebSock::CWebSock() : CHTTPSock(NULL) { +CWebSock::CWebSock(const CString& sURIPrefix) : CHTTPSock(NULL, sURIPrefix) { m_bPathsSet = false; m_Template.AddTagHandler(new CZNCTagHandler(*this)); diff --git a/src/znc.cpp b/src/znc.cpp index 9022fe68..fe799cf0 100644 --- a/src/znc.cpp +++ b/src/znc.cpp @@ -454,6 +454,7 @@ bool CZNC::WriteConfig() { CConfig listenerConfig; listenerConfig.AddKeyValuePair("Host", pListener->GetBindHost()); + listenerConfig.AddKeyValuePair("URIPrefix", pListener->GetURIPrefix() + "/"); listenerConfig.AddKeyValuePair("Port", CString(pListener->GetPort())); listenerConfig.AddKeyValuePair("IPv4", CString(pListener->GetAddrType() != ADDR_IPV6ONLY)); @@ -582,6 +583,7 @@ bool CZNC::WriteNewConfig(const CString& sConfigFile) { bool b6 = false; #endif CString sListenHost; + CString sURIPrefix; bool bListenSSL = false; unsigned int uListenPort = 0; bool bSuccess; @@ -610,7 +612,7 @@ bool CZNC::WriteNewConfig(const CString& sConfigFile) { CUtils::GetInput("Listen Host", sListenHost, sListenHost, "Blank for all ips"); CUtils::PrintAction("Verifying the listener"); - CListener* pListener = new CListener((unsigned short int)uListenPort, sListenHost, bListenSSL, + CListener* pListener = new CListener((unsigned short int)uListenPort, sListenHost, sURIPrefix, bListenSSL, b6 ? ADDR_ALL : ADDR_IPV4ONLY, CListener::ACCEPT_ALL); if (!pListener->Listen()) { CUtils::PrintStatus(false, FormatBindError()); @@ -1695,12 +1697,15 @@ bool CZNC::AddListener(const CString& sLine, CString& sError) { bSSL = true; } + // No support for URIPrefix for old-style configs. + CString sURIPrefix; unsigned short uPort = sPort.ToUShort(); - return AddListener(uPort, sBindHost, bSSL, eAddr, eAccept, sError); + return AddListener(uPort, sBindHost, sURIPrefix, bSSL, eAddr, eAccept, sError); } -bool CZNC::AddListener(unsigned short uPort, const CString& sBindHost, bool bSSL, - EAddrType eAddr, CListener::EAcceptType eAccept, CString& sError) { +bool CZNC::AddListener(unsigned short uPort, const CString& sBindHost, + const CString& sURIPrefixRaw, bool bSSL, + EAddrType eAddr, CListener::EAcceptType eAccept, CString& sError) { CString sHostComment; if (!sBindHost.empty()) { @@ -1761,7 +1766,18 @@ bool CZNC::AddListener(unsigned short uPort, const CString& sBindHost, bool bSSL return false; } - CListener* pListener = new CListener(uPort, sBindHost, bSSL, eAddr, eAccept); + // URIPrefix must start with a slash and end without one. + CString sURIPrefix = CString(sURIPrefixRaw); + if(!sURIPrefix.empty()) { + if (!sURIPrefix.StartsWith("/")) { + sURIPrefix = "/" + sURIPrefix; + } + if (sURIPrefix.EndsWith("/")) { + sURIPrefix.TrimRight("/"); + } + } + + CListener* pListener = new CListener(uPort, sBindHost, sURIPrefix, bSSL, eAddr, eAccept); if (!pListener->Listen()) { sError = FormatBindError(); @@ -1778,6 +1794,7 @@ bool CZNC::AddListener(unsigned short uPort, const CString& sBindHost, bool bSSL bool CZNC::AddListener(CConfig* pConfig, CString& sError) { CString sBindHost; + CString sURIPrefix; bool bSSL; bool b4; #ifdef HAVE_IPV6 @@ -1799,6 +1816,7 @@ bool CZNC::AddListener(CConfig* pConfig, CString& sError) { pConfig->FindBoolEntry("ipv6", b6, b6); pConfig->FindBoolEntry("allowirc", bIRC, true); pConfig->FindBoolEntry("allowweb", bWeb, true); + pConfig->FindStringEntry("uriprefix", sURIPrefix); EAddrType eAddr; if (b4 && b6) { @@ -1826,7 +1844,7 @@ bool CZNC::AddListener(CConfig* pConfig, CString& sError) { return false; } - return AddListener(uPort, sBindHost, bSSL, eAddr, eAccept, sError); + return AddListener(uPort, sBindHost, sURIPrefix, bSSL, eAddr, eAccept, sError); } bool CZNC::AddListener(CListener* pListener) {