File indexing completed on 2025-01-05 03:58:12

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2011-03-22
0007  * Description : a MediaWiki C++ interface
0008  *
0009  * SPDX-FileCopyrightText: 2011-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0010  * SPDX-FileCopyrightText: 2011      by Alexandre Mendes <alex dot mendes1988 at gmail dot com>
0011  * SPDX-FileCopyrightText: 2011      by Hormiere Guillaume <hormiere dot guillaume at gmail dot com>
0012  * SPDX-FileCopyrightText: 2011      by Manuel Campomanes <campomanes dot manuel at gmail dot com>
0013  *
0014  * SPDX-License-Identifier: GPL-2.0-or-later
0015  *
0016  * ============================================================ */
0017 
0018 #include "fakeserver.h"
0019 
0020 // C++ includes
0021 
0022 #include <iostream>
0023 
0024 // Qt includes
0025 
0026 #include <QFile>
0027 #include <QRegularExpression>
0028 
0029 FakeServer::FakeServer(QObject* const parent)
0030     :  QThread       (parent),
0031        m_tcpServer   (nullptr),
0032        m_clientSocket(nullptr)
0033 {
0034     moveToThread(this);
0035 }
0036 
0037 FakeServer::~FakeServer()
0038 {
0039     quit();
0040     wait();
0041 }
0042 
0043 void FakeServer::startAndWait()
0044 {
0045     start();
0046 
0047     // this will block until the event queue starts
0048 
0049     QMetaObject::invokeMethod(this, "started", Qt::BlockingQueuedConnection);
0050 }
0051 
0052 void FakeServer::newConnection()
0053 {
0054     QMutexLocker locker(&m_mutex);
0055     m_clientSocket = m_tcpServer->nextPendingConnection();
0056 
0057     connect(m_clientSocket, SIGNAL(readyRead()),
0058             this, SLOT(dataAvailable()));
0059 }
0060 
0061 void FakeServer::dataAvailable()
0062 {
0063     QMutexLocker locker(&m_mutex);
0064 
0065     if (m_clientSocket->canReadLine())
0066     {
0067         QStringList token = QString::fromUtf8(m_clientSocket->readAll()).split(QRegularExpression(QStringLiteral("[ \r\n][ \r\n]*")));
0068 
0069         if (token.size() > 2)
0070         {
0071             FakeServer::Request request;
0072             request.type  = token[0];
0073             request.value = token[1];
0074 
0075             int index     = token.indexOf(QLatin1String("User-Agent:"));
0076 
0077             if ((index > 0) && ((index + 1) < token.size()))
0078             {
0079                 request.agent = token[index + 1];
0080             }
0081 
0082             // It might happen that the same request cames through more than once, so you need to check that you are
0083             // counting each different request only once.
0084             //
0085             // For more information, see: qt-project.org/forums/viewthread/25521
0086 
0087             if (!m_request.contains(request))
0088             {
0089                 m_request << request;
0090 
0091                 QString retour   = m_scenarios.isEmpty() ? QStringLiteral("empty") : m_scenarios.takeFirst();
0092                 QString cookie   = m_cookie.isEmpty()    ? QStringLiteral("empty") : m_cookie.takeFirst();
0093                 QString scenario = QStringLiteral("HTTP/1.0 200 Ok\r\nContent-Type: text/html; charset=\"utf-8\"\r\nSet-Cookie:") + cookie + QStringLiteral("\r\n\r\n") + retour;
0094                 m_clientSocket->write(scenario.toLocal8Bit());
0095             }
0096         }
0097     }
0098 
0099     m_clientSocket->close();
0100 }
0101 
0102 void FakeServer::run()
0103 {
0104     m_tcpServer = new QTcpServer();
0105 
0106     if (!m_tcpServer->listen(QHostAddress(QHostAddress::LocalHost), 12566))
0107     {
0108         // TODO
0109     }
0110 
0111     connect(m_tcpServer, SIGNAL(newConnection()),
0112             this, SLOT(newConnection()));
0113 
0114     exec();
0115 
0116     delete m_clientSocket;
0117     delete m_tcpServer;
0118 }
0119 
0120 void FakeServer::started()
0121 {
0122     // do nothing: this is a dummy slot used by startAndWait()
0123 }
0124 
0125 void FakeServer::setScenario(const QString& scenario, const QString& cookie)
0126 {
0127     QMutexLocker locker(&m_mutex);
0128 
0129     m_scenarios.clear();
0130     m_scenarios << scenario;
0131     m_cookie.clear();
0132     m_cookie    << cookie;
0133     m_request.clear();
0134 }
0135 
0136 void FakeServer::addScenario(const QString& scenario, const QString& cookie )
0137 {
0138     QMutexLocker locker(&m_mutex);
0139 
0140     m_scenarios << scenario;
0141     m_cookie    << cookie;
0142 }
0143 
0144 void FakeServer::addScenarioFromFile(const QString& fileName, const QString& cookie )
0145 {
0146     QFile file(fileName);
0147 
0148     if (!file.open(QFile::ReadOnly))
0149     {
0150         return;
0151     }
0152 
0153     QTextStream in(&file);
0154     QString scenario;
0155 
0156     // When loading from files we never have the authentication phase
0157     // force jumping directly to authenticated state.
0158 
0159     while (!in.atEnd())
0160     {
0161         scenario.append(in.readLine());
0162     }
0163 
0164     file.close();
0165 
0166     addScenario(scenario, cookie);
0167 }
0168 
0169 bool FakeServer::isScenarioDone( int scenarioNumber ) const
0170 {
0171     QMutexLocker locker(&m_mutex);
0172 
0173     if (scenarioNumber < m_scenarios.size())
0174     {
0175         return m_scenarios[scenarioNumber].isEmpty();
0176     }
0177     else
0178     {
0179         return true; // Non existent hence empty, right?
0180     }
0181 }
0182 
0183 bool FakeServer::isAllScenarioDone() const
0184 {
0185     QMutexLocker locker(&m_mutex);
0186 
0187     Q_FOREACH (const QString& scenario, m_scenarios)
0188     {
0189         if (!scenario.isEmpty())
0190         {   // cppcheck-suppress useStlAlgorithm
0191             return false;
0192         }
0193     }
0194 
0195     return true;
0196 }
0197 
0198 const QList<FakeServer::Request>& FakeServer::getRequest()
0199 {
0200     return m_request;
0201 }
0202 
0203 FakeServer::Request FakeServer::takeLastRequest()
0204 {
0205     return m_request.takeLast();
0206 }
0207 
0208 FakeServer::Request FakeServer::takeFirstRequest()
0209 {
0210     return m_request.takeFirst();
0211 }
0212 
0213 void FakeServer::clearRequest()
0214 {
0215     m_request.clear();
0216 }
0217 
0218 #include "moc_fakeserver.cpp"