1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtNetwork module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40//#define QNETWORKACCESSCACHEBACKEND_DEBUG
41
42#include "qnetworkaccesscachebackend_p.h"
43#include "qabstractnetworkcache.h"
44#include "qfileinfo.h"
45#include "qdir.h"
46#include "qcoreapplication.h"
47
48QT_BEGIN_NAMESPACE
49
50QNetworkAccessCacheBackend::QNetworkAccessCacheBackend()
51 : QNetworkAccessBackend(QNetworkAccessBackend::TargetType::Local)
52{
53}
54
55QNetworkAccessCacheBackend::~QNetworkAccessCacheBackend()
56{
57}
58
59void QNetworkAccessCacheBackend::open()
60{
61 if (operation() != QNetworkAccessManager::GetOperation || !sendCacheContents()) {
62 QString msg = QCoreApplication::translate("QNetworkAccessCacheBackend", "Error opening %1")
63 .arg(this->url().toString());
64 error(QNetworkReply::ContentNotFoundError, msg);
65 } else {
66 setAttribute(QNetworkRequest::SourceIsFromCacheAttribute, true);
67 }
68 finished();
69}
70
71bool QNetworkAccessCacheBackend::sendCacheContents()
72{
73 setCachingEnabled(false);
74 QAbstractNetworkCache *nc = networkCache();
75 if (!nc)
76 return false;
77
78 QNetworkCacheMetaData item = nc->metaData(url());
79 if (!item.isValid())
80 return false;
81
82 QNetworkCacheMetaData::AttributesMap attributes = item.attributes();
83 setAttribute(QNetworkRequest::HttpStatusCodeAttribute, attributes.value(QNetworkRequest::HttpStatusCodeAttribute));
84 setAttribute(QNetworkRequest::HttpReasonPhraseAttribute, attributes.value(QNetworkRequest::HttpReasonPhraseAttribute));
85
86 // set the raw headers
87 const QNetworkCacheMetaData::RawHeaderList rawHeaders = item.rawHeaders();
88 for (const auto &header : rawHeaders) {
89 if (header.first.toLower() == "cache-control") {
90 const QByteArray cacheControlValue = header.second.toLower();
91 if (cacheControlValue.contains("must-revalidate")
92 || cacheControlValue.contains("no-cache")) {
93 return false;
94 }
95 }
96 setRawHeader(header.first, header.second);
97 }
98
99 // handle a possible redirect
100 QVariant redirectionTarget = attributes.value(QNetworkRequest::RedirectionTargetAttribute);
101 if (redirectionTarget.isValid()) {
102 setAttribute(QNetworkRequest::RedirectionTargetAttribute, redirectionTarget);
103 redirectionRequested(redirectionTarget.toUrl());
104 }
105
106 // signal we're open
107 metaDataChanged();
108
109 if (operation() == QNetworkAccessManager::GetOperation) {
110 device = nc->data(url());
111 if (!device)
112 return false;
113 device->setParent(this);
114 readyRead();
115 }
116
117#if defined(QNETWORKACCESSCACHEBACKEND_DEBUG)
118 qDebug() << "Successfully sent cache:" << url();
119#endif
120 return true;
121}
122
123bool QNetworkAccessCacheBackend::start()
124{
125 open();
126 return true;
127}
128
129void QNetworkAccessCacheBackend::close() { }
130
131qint64 QNetworkAccessCacheBackend::bytesAvailable() const
132{
133 return device ? device->bytesAvailable() : qint64(0);
134}
135
136qint64 QNetworkAccessCacheBackend::read(char *data, qint64 maxlen)
137{
138 return device ? device->read(data, maxlen) : qint64(0);
139}
140
141QT_END_NAMESPACE
142
143