]> git.sur5r.net Git - minitube/blob - lib/http/src/cachedhttp.cpp
New upstream version 3.6
[minitube] / lib / http / src / cachedhttp.cpp
1 #include "cachedhttp.h"
2 #include "localcache.h"
3 #include <QtNetwork>
4
5 CachedHttpReply::CachedHttpReply(const QByteArray &body, const HttpRequest &req)
6     : bytes(body), req(req) {
7     QTimer::singleShot(0, this, SLOT(emitSignals()));
8 }
9
10 QByteArray CachedHttpReply::body() const {
11     return bytes;
12 }
13
14 void CachedHttpReply::emitSignals() {
15     emit data(body());
16     emit finished(*this);
17     deleteLater();
18 }
19
20 WrappedHttpReply::WrappedHttpReply(CachedHttp &cachedHttp,
21                                    LocalCache *cache,
22                                    const QByteArray &key,
23                                    HttpReply *httpReply)
24     : HttpReply(httpReply), cachedHttp(cachedHttp), cache(cache), key(key), httpReply(httpReply) {
25     connect(httpReply, SIGNAL(data(QByteArray)), SIGNAL(data(QByteArray)));
26     connect(httpReply, SIGNAL(error(QString)), SIGNAL(error(QString)));
27     connect(httpReply, SIGNAL(finished(HttpReply)), SLOT(originFinished(HttpReply)));
28 }
29
30 void WrappedHttpReply::originFinished(const HttpReply &reply) {
31     qDebug() << reply.statusCode() << reply.url();
32     bool doCache = reply.isSuccessful();
33
34     if (doCache) {
35         const auto &validators = cachedHttp.getValidators();
36         if (!validators.isEmpty()) {
37             const QByteArray &mime = reply.header("Content-Type");
38             auto i = validators.constFind(mime);
39             if (i != validators.constEnd()) {
40                 auto validator = i.value();
41                 doCache = validator(reply);
42             } else {
43                 i = validators.constFind("*");
44                 if (i != validators.constEnd()) {
45                     auto validator = i.value();
46                     doCache = validator(reply);
47                 }
48             }
49         }
50     }
51
52     if (doCache)
53         cache->insert(key, reply.body());
54     else
55         qDebug() << "Not caching" << reply.statusCode() << reply.url();
56
57     emit finished(reply);
58 }
59
60 CachedHttp::CachedHttp(Http &http, const char *name)
61     : http(http), cache(LocalCache::instance(name)), cachePostRequests(false) {}
62
63 void CachedHttp::setMaxSeconds(uint seconds) {
64     cache->setMaxSeconds(seconds);
65 }
66
67 void CachedHttp::setMaxSize(uint maxSize) {
68     cache->setMaxSize(maxSize);
69 }
70
71 HttpReply *CachedHttp::request(const HttpRequest &req) {
72     bool cacheable = req.operation == QNetworkAccessManager::GetOperation ||
73                      (cachePostRequests && req.operation == QNetworkAccessManager::PostOperation);
74     if (!cacheable) {
75         qDebug() << "Not cacheable" << req.url;
76         return http.request(req);
77     }
78     const QByteArray key = requestHash(req);
79     const QByteArray value = cache->value(key);
80     if (!value.isNull()) {
81         qDebug() << "HIT" << key << req.url;
82         return new CachedHttpReply(value, req);
83     }
84     qDebug() << "MISS" << key << req.url;
85     return new WrappedHttpReply(*this, cache, key, http.request(req));
86 }
87
88 QByteArray CachedHttp::requestHash(const HttpRequest &req) {
89     const char sep = '|';
90
91     QByteArray s;
92     if (ignoreHostname) {
93         s = (req.url.scheme() + sep + req.url.path() + sep + req.url.query()).toUtf8();
94     } else {
95         s = req.url.toEncoded();
96     }
97     s += sep + req.body + sep + QByteArray::number(req.offset);
98     if (req.operation == QNetworkAccessManager::PostOperation) {
99         s.append(sep);
100         s.append("POST");
101     }
102     return LocalCache::hash(s);
103 }