diff options
author | Morten Sorvig <msorvig@trolltech.com> | 2009-08-07 20:33:17 +0200 |
---|---|---|
committer | Morten Sorvig <msorvig@trolltech.com> | 2009-08-07 20:33:17 +0200 |
commit | a3ec9a9c0e2d1f38b57616a649bb0f953344d713 (patch) | |
tree | 5afa70b4a1579e8d91d44993a9f3c8f391f1e5d2 /src | |
parent | dc8d69e7939546390a890902edae2ffe7682d920 (diff) |
Implement eTag support for static content
Diffstat (limited to 'src')
-rw-r--r-- | src/webclientserver.cpp | 72 | ||||
-rw-r--r-- | src/webclientserver.h | 9 |
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(¤tTime))) + 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(¤tTime))) + 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 |