Make httpsock (and thus webadmin) support client side caching of static files

If such a file is served (e.g. webadmin images) an ETag header is now generated.
When the browser needs the file again it sends the ETag back to us in an
If-None-Match header and the file isn't transfered again if the ETag still
matches. This should greatly reduce webadmin's traffic usage.

This also updates HTTPSock to sometimes generate a HTTP/1.1 reply
(ETag was added in HTTP/1.1).

This was successfully tested with Firefox 2 & 3 and IE7.
Konqueror failed badly (No If-None-Match header generated).

Thanks to flakes for having the idea, writing the patch and testing it.


git-svn-id: https://znc.svn.sourceforge.net/svnroot/znc/trunk@1248 726aef4b-f618-498e-8847-2d620e286838
This commit is contained in:
psychon
2008-10-12 15:49:03 +00:00
parent 2db68c519b
commit 90ecce7880
2 changed files with 47 additions and 16 deletions
+43 -16
View File
@@ -12,22 +12,20 @@
#include "znc.h"
CHTTPSock::CHTTPSock(CModule *pMod) : CSocket(pMod) {
m_bSentHeader = false;
m_bGotHeader = false;
m_bLoggedIn = false;
m_bPost = false;
m_bDone = false;
m_uPostLen = 0;
EnableReadLine();
SetMaxBufferThreshold(10240);
Init();
}
CHTTPSock::CHTTPSock(CModule *pMod, const CString& sHostname, unsigned short uPort, int iTimeout) : CSocket(pMod, sHostname, uPort, iTimeout) {
Init();
}
void CHTTPSock::Init() {
m_bSentHeader = false;
m_bGotHeader = false;
m_bLoggedIn = false;
m_bPost = false;
m_bDone = false;
m_bHTTP10Client = false;
m_uPostLen = 0;
EnableReadLine();
SetMaxBufferThreshold(10240);
@@ -68,6 +66,7 @@ void CHTTPSock::ReadLine(const CString& sData) {
if (sName.Equals("GET")) {
m_bPost = false;
m_sURI = sLine.Token(1);
m_bHTTP10Client = sLine.Token(2).Equals("HTTP/1.0");
ParseURI();
} else if (sName.Equals("POST")) {
m_bPost = true;
@@ -81,6 +80,9 @@ void CHTTPSock::ReadLine(const CString& sData) {
m_bLoggedIn = OnLogin(m_sUser, m_sPass);
} else if (sName.Equals("Content-Length:")) {
m_uPostLen = sLine.Token(1).ToULong();
} else if (sName.Equals("If-None-Match:")) {
// this is for proper client cache support (HTTP 304) on static files:
m_sIfNoneMatch = sLine.Token(1, true);
} else if (sLine.empty()) {
m_bGotHeader = true;
DisableReadLine();
@@ -157,15 +159,37 @@ bool CHTTPSock::PrintFile(const CString& sFileName, CString sContentType) {
}
}
PrintHeader(File.GetSize(), sContentType);
const time_t iMTime = File.GetMTime();
bool bNotModified = false;
CString sETag;
char szBuf[4096];
int iLen = 0;
if (iMTime > 0 && !m_bHTTP10Client) {
sETag = "-" + CString(iMTime); // lighttpd style ETag
while ((iLen = File.Read(szBuf, 4096)) > 0) {
Write(szBuf, iLen);
AddHeader("ETag", "\"" + sETag + "\"");
AddHeader("Cache-Control", "private");
if (!m_sIfNoneMatch.empty()) {
m_sIfNoneMatch.Trim("\\\"'");
bNotModified = (m_sIfNoneMatch.Equals(sETag, true));
}
}
if (bNotModified) {
PrintHeader(0, sContentType, 304, "Not Modified");
} else {
char szBuf[4096];
int iLen = 0;
PrintHeader(File.GetSize(), sContentType);
while ((iLen = File.Read(szBuf, 4096)) > 0) {
Write(szBuf, iLen);
}
}
DEBUG_ONLY(cout << "ETag: [" << sETag << "] / If-None-Match [" << m_sIfNoneMatch << "]" << endl);
Close(Csock::CLT_AFTERWRITE);
return true;
@@ -333,17 +357,20 @@ bool CHTTPSock::PrintHeader(unsigned long uContentLength, const CString& sConten
DEBUG_ONLY(cout << "- " << uStatusId << " (" << sStatusMsg << ") [" << m_sContentType << "]" << endl);
Write("HTTP/1.0 " + CString(uStatusId) + " " + sStatusMsg + "\r\n");
Write("HTTP/" + CString(m_bHTTP10Client ? "1.0 " : "1.1 ") + CString(uStatusId) + " " + sStatusMsg + "\r\n");
//Write("Date: Tue, 28 Jun 2005 20:45:36 GMT\r\n");
Write("Server: " + CZNC::GetTag() + "\r\n");
Write("Content-Length: " + CString(uContentLength) + "\r\n");
Write("Connection: Close\r\n");
if (uContentLength > 0) {
Write("Content-Length: " + CString(uContentLength) + "\r\n");
}
Write("Content-Type: " + m_sContentType + "\r\n");
for (MCString::iterator it = m_msHeaders.begin(); it != m_msHeaders.end(); it++) {
Write(it->first + ": " + it->second + "\r\n");
}
Write("Connection: Close\r\n");
Write("\r\n");
m_bSentHeader = true;
+4
View File
@@ -71,6 +71,8 @@ public:
// !Getters
private:
protected:
void Init();
bool m_bSentHeader;
bool m_bGotHeader;
bool m_bLoggedIn;
@@ -85,6 +87,8 @@ protected:
CString m_sDocRoot;
map<CString, VCString> m_msvsParams;
MCString m_msHeaders;
bool m_bHTTP10Client;
CString m_sIfNoneMatch;
};
#endif // !_HTTPSOCK_H