summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMorten Sorvig <msorvig@trolltech.com>2009-08-07 20:33:17 +0200
committerMorten Sorvig <msorvig@trolltech.com>2009-08-07 20:33:17 +0200
commita3ec9a9c0e2d1f38b57616a649bb0f953344d713 (patch)
tree5afa70b4a1579e8d91d44993a9f3c8f391f1e5d2 /src
parentdc8d69e7939546390a890902edae2ffe7682d920 (diff)
Implement eTag support for static content
Diffstat (limited to 'src')
-rw-r--r--src/webclientserver.cpp72
-rw-r--r--src/webclientserver.h9
2 files changed, 69 insertions, 12 deletions
diff --git a/src/webclientserver.cpp b/src/webclientserver.cpp
index 664e04e..a8bee77 100644
--- a/src/webclientserver.cpp
+++ b/src/webclientserver.cpp
@@ -2,6 +2,8 @@
#include "webclientserver.h"
#include <time.h>
+const QByteArray &eTagVersion = "v1-";
+
HttpRequest::HttpRequest()
{
}
@@ -63,12 +65,14 @@ void HttpRequest::parseText()
QByteArray hostline = line.split(' ').at(1); // ###
hostline.chop(2); // remove newline
m_hostName = hostline;
+ } else if (line.startsWith("If-None-Match:")){
+ m_ifNoneMatch = line.mid(18).simplified(); // remove "If-None-Match: vX-", where X is the integer version number
}
}
}
HttpResponse::HttpResponse()
-: contentType("text/html") { }
+: contentType("text/html"), response304(false) { }
void HttpResponse::setBody(const QByteArray &body)
{
@@ -85,21 +89,49 @@ void HttpResponse::setContentType(const QByteArray &contentType)
this->contentType = contentType;
}
+void HttpResponse::seteTag(const QByteArray &eTag)
+{
+ this->eTag = eTagVersion + eTag;
+}
+
+void HttpResponse::set304Response()
+{
+ response304 = true;
+}
+
+bool HttpResponse::isHandled() const
+{
+ return response304 || body.isEmpty() == false;
+}
+
QByteArray HttpResponse::toText()
{
time_t currentTime = time(0);
- QByteArray text =
- QByteArray("HTTP/1.1 200 OK \r\n")
- + QByteArray("Date: ") + QByteArray(asctime(gmtime(&currentTime))) + QByteArray("")
+ QByteArray text;
+
+ if (response304) {
+ text += QByteArray("HTTP/1.1 304 Not Modified\r\n");
+ text+= QByteArray("\r\n");
+ return text;
+ }
+
+ text += QByteArray("HTTP/1.1 200 OK \r\n");
+ text += QByteArray("Date: ") + QByteArray(asctime(gmtime(&currentTime))) + QByteArray("")
+ QByteArray("Content-Type: " + contentType + " \r\n")
- + QByteArray("Content-Length: " + QByteArray::number(body.length()) + "\r\n")
- + QByteArray("Cace-control: no-cache \r\n");
+ + QByteArray("Content-Length: " + QByteArray::number(body.length()) + "\r\n");
if (cookie.isEmpty() == false) {
text+= "Set-Cookie: " + cookie + "\r\n";
}
+ if (eTag.isEmpty() == false) {
+ text += "eTag: " + eTag + "\r\n";
+ } else {
+ text += QByteArray("Cace-control: no-cache \r\n");
+ text += QByteArray("max-age: 0 \r\n");
+ }
+
text+= QByteArray("\r\n")
+ body;
return text;
@@ -257,7 +289,7 @@ void Server::dataOnSocket()
}
*/
session->emitRequestContent(&request, &response);
- if (response.body.isEmpty() == false) {
+ if (response.isHandled()) {
QByteArray responseText = response.toText();
dynamicBytesWritten += responseText.count();
socket->write(responseText);
@@ -271,7 +303,7 @@ void Server::dataOnSocket()
// if (path == "/idle")
// DEBUG << response.body;
- if (path.startsWith("/idle") && response.body == QByteArray()) {
+ if (path.startsWith("/idle") && response.isHandled() == false) {
// Keep one socket for each connection, the html spec allows
// only two connections between a web browser and a server.
if (session->m_idleSocket == 0) {
@@ -284,7 +316,7 @@ void Server::dataOnSocket()
return;
} else if (path.startsWith("/statistics")) {
response.setBody(createStatiticsPage());
- } else if (response.body == QByteArray()) {
+ } else if (response.isHandled() == false) {
fileServer.handleRequest(&request, &response);
QByteArray responseText = response.toText();
staticBytesWritten += responseText.count();
@@ -327,7 +359,7 @@ FileServer::FileServer()
void FileServer::handleRequest(HttpRequest *request, HttpResponse *response)
{
- if (response->body != QByteArray())
+ if (response->isHandled())
return;
const QByteArray path = request->path();
@@ -335,7 +367,7 @@ void FileServer::handleRequest(HttpRequest *request, HttpResponse *response)
DEBUG << "file server handle request" << path << filePath;
- if (filePath == "")
+ if (filePath == "" || filePath == "index.html")
filePath = ":index.html";
if (allowedFileNames.contains(filePath) == false)
@@ -347,6 +379,17 @@ void FileServer::handleRequest(HttpRequest *request, HttpResponse *response)
return;
}
+ // Check if the client sends an If-None-Match, return
+ // 304 Not Modified if it matches the server's eTag
+ // for the file path.
+ if (request->m_ifNoneMatch.isEmpty() == false) {
+ if (request->m_ifNoneMatch == eTags.value(filePath)) {
+ response->set304Response();
+ response->seteTag(request->m_ifNoneMatch);
+ return;
+ }
+ }
+
file.open(QIODevice::ReadOnly);
QByteArray fileContents = file.readAll();
fileContents.replace("INSERT_HOSTNAME", request->hostName());
@@ -356,5 +399,12 @@ void FileServer::handleRequest(HttpRequest *request, HttpResponse *response)
if (fileContents.contains("INSERT_PAGE_ID"))
fileContents.replace("INSERT_PAGE_ID", QByteArray::number(++pageId));
*/
+ QByteArray eTag = eTags[filePath];
+ if (eTag.isEmpty()) {
+ eTag = QByteArray::number(qHash(fileContents));
+ eTags[filePath] = eTag;
+ }
+
+ response->seteTag(eTag);
response->setBody(fileContents);
}
diff --git a/src/webclientserver.h b/src/webclientserver.h
index 6a29f1e..1f231c9 100644
--- a/src/webclientserver.h
+++ b/src/webclientserver.h
@@ -24,6 +24,7 @@ public:
QByteArray m_hostName;
QList<QByteArray> m_text;
QTcpSocket *m_socket;
+ QByteArray m_ifNoneMatch;
};
class HttpResponse
@@ -33,12 +34,17 @@ public:
void setBody(const QByteArray &body);
void setCookie(const QByteArray &name, const QByteArray &value);
void setContentType(const QByteArray &contentType);
-// void setLastModified(QDateTime lastModified, QDateTime expires);
+ void seteTag(const QByteArray &eTag);
+ void set304Response();
+
+ bool isHandled() const;
QByteArray toText();
QByteArray body;
QByteArray cookie;
QByteArray contentType;
+ QByteArray eTag;
+ bool response304;
};
class Server;
@@ -75,6 +81,7 @@ public slots:
virtual void handleRequest(HttpRequest *request, HttpResponse *response);
private:
QSet<QString> allowedFileNames;
+ QHash<QString, QByteArray> eTags;
};
class Server : public QTcpServer