Line data Source code
1 : #include "FangNetworkAccessManager.h"
2 : #include "ResilientNetworkReply.h"
3 : #include "NetworkStateMonitor.h"
4 : #include "../utilities/FangLogging.h"
5 :
6 : #include <QNetworkDiskCache>
7 : #include <QStandardPaths>
8 :
9 212 : FangNetworkAccessManager::FangNetworkAccessManager(QObject *parent) :
10 212 : QNetworkAccessManager(parent)
11 : {
12 212 : QNetworkDiskCache* diskCache = new QNetworkDiskCache(this);
13 212 : QString cacheDir = QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
14 212 : diskCache->setCacheDirectory(cacheDir);
15 212 : if (!cacheDir.isEmpty())
16 212 : setCache(diskCache);
17 :
18 : // Set up our circuit breaker.
19 212 : NetworkStateMonitor& monitor = NetworkStateMonitor::instance();
20 212 : connect(&monitor, &NetworkStateMonitor::circuitOpened,
21 212 : this, &FangNetworkAccessManager::onCircuitOpened);
22 212 : connect(&monitor, &NetworkStateMonitor::circuitClosed,
23 212 : this, &FangNetworkAccessManager::onCircuitClosed);
24 :
25 : //qCDebug(logNetwork) << "FangNetworkAccessManager initialized with resilience features";
26 212 : }
27 :
28 30 : QNetworkReply* FangNetworkAccessManager::createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest& request, QIODevice* outgoingData)
29 : {
30 30 : QNetworkRequest& req = const_cast<QNetworkRequest&>(request);
31 :
32 : #ifdef QT_DEBUG
33 : // In debug mode, WebKit doesn't like Vine's headers.
34 : //
35 : // TODO: Revisit when WebKit is upgraded in Qt.
36 : //
37 : // https://github.com/MrEricSir/Fang/issues/77
38 : // https://bugs.webkit.org/show_bug.cgi?id=129081
39 30 : if (req.url().host() == "vine.co") {
40 0 : req.setUrl(QUrl("http://0.0.0.0"));
41 : }
42 : #endif // QT_DEBUG
43 :
44 : // This SHOULD be the default, but just in case.
45 30 : req.setAttribute(QNetworkRequest::CacheLoadControlAttribute,
46 : QNetworkRequest::PreferNetwork);
47 :
48 : // We have to pretend to be Firefox in order for some stupid servers to speak with us.
49 30 : req.setHeader(QNetworkRequest::UserAgentHeader,
50 : "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0");
51 :
52 : // Required for blogs.gnome.org.
53 30 : req.setRawHeader("Accept",
54 : "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
55 :
56 30 : return QNetworkAccessManager::createRequest(op, req, outgoingData);
57 : }
58 :
59 22 : ResilientNetworkReply* FangNetworkAccessManager::createResilientGet(
60 : const QNetworkRequest& request,
61 : const NetworkRetryPolicy& policy)
62 : {
63 : auto* resilientReply = new ResilientNetworkReply(
64 : this,
65 : request,
66 : QNetworkAccessManager::GetOperation,
67 : policy,
68 : this
69 22 : );
70 :
71 : // Monitor network state metrics.
72 22 : connect(resilientReply, &ResilientNetworkReply::finished, this, [=]() {
73 14 : NetworkStateMonitor::instance().recordSuccess();
74 28 : qCDebug(logNetwork) << "Resilient request succeeded: " << request.url();
75 14 : });
76 :
77 22 : connect(resilientReply, &ResilientNetworkReply::failed, this, [=](QNetworkReply::NetworkError error) {
78 8 : NetworkStateMonitor::instance().recordFailure();
79 24 : qCWarning(logNetwork) << "Resilient request failed: " << request.url()
80 16 : << "Error: " << error;
81 8 : });
82 :
83 22 : return resilientReply;
84 : }
85 :
86 0 : ResilientNetworkReply* FangNetworkAccessManager::createResilientHead(
87 : const QNetworkRequest& request,
88 : const NetworkRetryPolicy& policy)
89 : {
90 : auto* resilientReply = new ResilientNetworkReply(
91 : this,
92 : request,
93 : QNetworkAccessManager::HeadOperation,
94 : policy,
95 : this
96 0 : );
97 :
98 : // Monitor network state metrics.
99 0 : connect(resilientReply, &ResilientNetworkReply::finished, this, [=]() {
100 0 : NetworkStateMonitor::instance().recordSuccess();
101 0 : });
102 :
103 0 : connect(resilientReply, &ResilientNetworkReply::failed, this, [=](QNetworkReply::NetworkError) {
104 0 : NetworkStateMonitor::instance().recordFailure();
105 0 : });
106 :
107 0 : return resilientReply;
108 : }
109 :
110 3 : bool FangNetworkAccessManager::isCircuitOpen() const
111 : {
112 3 : return NetworkStateMonitor::instance().circuitState() == NetworkStateMonitor::Open;
113 : }
114 :
115 0 : float FangNetworkAccessManager::networkFailureRate() const
116 : {
117 0 : return NetworkStateMonitor::instance().failureRate();
118 : }
119 :
120 9 : void FangNetworkAccessManager::onCircuitOpened()
121 : {
122 18 : qCWarning(logNetwork) << "Circuit breaker OPENED - blocking new network requests";
123 9 : emit circuitBreakerOpened();
124 9 : }
125 :
126 9 : void FangNetworkAccessManager::onCircuitClosed()
127 : {
128 18 : qCInfo(logNetwork) << "Circuit breaker CLOSED - resuming network requests";
129 9 : emit circuitBreakerClosed();
130 9 : }
|