LCOV - code coverage report
Current view: top level - src/network - FangNetworkAccessManager.cpp (source / functions) Coverage Total Hit
Test: coverage.info.cleaned Lines: 77.8 % 54 42
Test Date: 2026-01-27 22:31:25 Functions: 66.7 % 12 8

            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 : }
        

Generated by: LCOV version 2.0-1