1 #include "cachedhttp.h"
2 #include "localcache.h"
5 CachedHttpReply::CachedHttpReply(const QByteArray &body, const QUrl &url, bool autoSignals)
6 : bytes(body), requestUrl(url) {
7 if (autoSignals) QTimer::singleShot(0, this, SLOT(emitSignals()));
10 QByteArray CachedHttpReply::body() const {
14 void CachedHttpReply::emitSignals() {
20 WrappedHttpReply::WrappedHttpReply(CachedHttp &cachedHttp,
22 const QByteArray &key,
24 : HttpReply(httpReply), cachedHttp(cachedHttp), cache(cache), key(key), httpReply(httpReply) {
25 connect(httpReply, SIGNAL(finished(HttpReply)), SLOT(originFinished(HttpReply)));
28 void WrappedHttpReply::originFinished(const HttpReply &reply) {
29 qDebug() << reply.statusCode() << reply.url();
30 bool success = reply.isSuccessful();
32 // Fallback to stale cached data on HTTP error
33 const QByteArray value = cache->possiblyStaleValue(key);
34 if (!value.isNull()) {
35 qDebug() << "Using stale cache value" << reply.url();
37 auto replyFromCache = new CachedHttpReply(value, reply.url(), false);
38 emit finished(*replyFromCache);
39 replyFromCache->deleteLater();
44 bool doCache = success;
46 const auto &validators = cachedHttp.getValidators();
47 if (!validators.isEmpty()) {
48 const QByteArray &mime = reply.header("Content-Type");
49 auto i = validators.constFind(mime);
50 if (i != validators.constEnd()) {
51 auto validator = i.value();
52 doCache = validator(reply);
54 i = validators.constFind("*");
55 if (i != validators.constEnd()) {
56 auto validator = i.value();
57 doCache = validator(reply);
64 cache->insert(key, reply.body());
66 qDebug() << "Not caching" << reply.statusCode() << reply.url();
69 emit data(reply.body());
71 emit error(reply.reasonPhrase());
76 CachedHttp::CachedHttp(Http &http, const char *name)
77 : http(http), cache(LocalCache::instance(name)), cachePostRequests(false) {}
79 void CachedHttp::setMaxSeconds(uint seconds) {
80 cache->setMaxSeconds(seconds);
83 void CachedHttp::setMaxSize(uint maxSize) {
84 cache->setMaxSize(maxSize);
87 HttpReply *CachedHttp::request(const HttpRequest &req) {
88 bool cacheable = req.operation == QNetworkAccessManager::GetOperation ||
89 (cachePostRequests && req.operation == QNetworkAccessManager::PostOperation);
91 qDebug() << "Not cacheable" << req.url;
92 return http.request(req);
94 const QByteArray key = requestHash(req);
95 const QByteArray value = cache->value(key);
96 if (!value.isNull()) {
97 qDebug() << "HIT" << key << req.url;
98 return new CachedHttpReply(value, req.url);
100 qDebug() << "MISS" << key << req.url;
101 return new WrappedHttpReply(*this, cache, key, http.request(req));
104 QByteArray CachedHttp::requestHash(const HttpRequest &req) {
105 const char sep = '|';
108 if (ignoreHostname) {
109 s = (req.url.scheme() + sep + req.url.path() + sep + req.url.query()).toUtf8();
111 s = req.url.toEncoded();
113 s += sep + req.body + sep + QByteArray::number(req.offset);
114 if (req.operation == QNetworkAccessManager::PostOperation) {
118 return LocalCache::hash(s);