diff options
author | Jüri Valdmann <juri.valdmann@qt.io> | 2017-08-10 12:24:27 +0200 |
---|---|---|
committer | Jüri Valdmann <juri.valdmann@qt.io> | 2017-09-12 08:21:00 +0000 |
commit | 1c7a520edfb850cc34a29d96417c475a373ed355 (patch) | |
tree | 1cdcd47de7a0be4fa297768d88de3ae8632f90cb /tests/auto/shared | |
parent | e409cfca1765aad5f6cc09c0e0ebd019dd5b37e2 (diff) |
Add test for downloading a link via user action
Change-Id: Ide3294840ceb3d18da0c4da92d892ff467a9b739
Reviewed-by: Michal Klocek <michal.klocek@qt.io>
Diffstat (limited to 'tests/auto/shared')
-rw-r--r-- | tests/auto/shared/http.pri | 3 | ||||
-rw-r--r-- | tests/auto/shared/httpreqrep.cpp | 91 | ||||
-rw-r--r-- | tests/auto/shared/httpreqrep.h | 75 | ||||
-rw-r--r-- | tests/auto/shared/httpserver.cpp | 70 | ||||
-rw-r--r-- | tests/auto/shared/httpserver.h | 61 | ||||
-rw-r--r-- | tests/auto/shared/waitforsignal.h | 90 |
6 files changed, 390 insertions, 0 deletions
diff --git a/tests/auto/shared/http.pri b/tests/auto/shared/http.pri new file mode 100644 index 000000000..5236e9d26 --- /dev/null +++ b/tests/auto/shared/http.pri @@ -0,0 +1,3 @@ +HEADERS += $$PWD/httpserver.h $$PWD/httpreqrep.h +SOURCES += $$PWD/httpserver.cpp $$PWD/httpreqrep.cpp +INCLUDEPATH += $$PWD diff --git a/tests/auto/shared/httpreqrep.cpp b/tests/auto/shared/httpreqrep.cpp new file mode 100644 index 000000000..eb2db6890 --- /dev/null +++ b/tests/auto/shared/httpreqrep.cpp @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "httpreqrep.h" + +HttpReqRep::HttpReqRep(QTcpSocket *socket, QObject *parent) + : QObject(parent), m_socket(socket) +{ + m_socket->setParent(this); + connect(m_socket, &QIODevice::readyRead, this, &HttpReqRep::handleReadyRead); +} + +void HttpReqRep::sendResponse() +{ + m_socket->write("HTTP/1.1 "); + m_socket->write(QByteArray::number(m_responseStatusCode)); + m_socket->write(" OK?\r\n"); + for (const auto & kv : m_responseHeaders) { + m_socket->write(kv.first); + m_socket->write(": "); + m_socket->write(kv.second); + m_socket->write("\r\n"); + } + m_socket->write("\r\n"); + m_socket->write(m_responseBody); + m_socket->close(); +} + +QByteArray HttpReqRep::requestHeader(const QByteArray &key) const +{ + auto it = m_requestHeaders.find(key); + if (it != m_requestHeaders.end()) + return it->second; + return {}; +} + +void HttpReqRep::handleReadyRead() +{ + const auto requestLine = m_socket->readLine(); + const auto requestLineParts = requestLine.split(' '); + if (requestLineParts.size() != 3 || !requestLineParts[2].toUpper().startsWith("HTTP/")) { + qWarning("HttpReqRep: invalid request line"); + Q_EMIT readFinished(false); + return; + } + + decltype(m_requestHeaders) headers; + for (;;) { + const auto headerLine = m_socket->readLine(); + if (headerLine == QByteArrayLiteral("\r\n")) + break; + int colonIndex = headerLine.indexOf(':'); + if (colonIndex < 0) { + qWarning("HttpReqRep: invalid header line"); + Q_EMIT readFinished(false); + return; + } + auto headerKey = headerLine.left(colonIndex).trimmed().toLower(); + auto headerValue = headerLine.mid(colonIndex + 1).trimmed().toLower(); + headers.emplace(headerKey, headerValue); + } + + m_requestMethod = requestLineParts[0]; + m_requestPath = requestLineParts[1]; + m_requestHeaders = headers; + Q_EMIT readFinished(true); +} diff --git a/tests/auto/shared/httpreqrep.h b/tests/auto/shared/httpreqrep.h new file mode 100644 index 000000000..4e9f10dff --- /dev/null +++ b/tests/auto/shared/httpreqrep.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef HTTPREQREP_H +#define HTTPREQREP_H + +#include <QTcpSocket> + +#include <utility> + +// Represents an HTTP request-response exchange. +class HttpReqRep : public QObject +{ + Q_OBJECT +public: + HttpReqRep(QTcpSocket *socket, QObject *parent = nullptr); + void sendResponse(); + QByteArray requestMethod() const { return m_requestMethod; } + QByteArray requestPath() const { return m_requestPath; } + QByteArray requestHeader(const QByteArray &key) const; + void setResponseStatus(int statusCode) + { + m_responseStatusCode = statusCode; + } + void setResponseHeader(const QByteArray &key, QByteArray value) + { + m_responseHeaders[key.toLower()] = std::move(value); + } + void setResponseBody(QByteArray content) + { + m_responseHeaders["content-length"] = QByteArray::number(content.size()); + m_responseBody = std::move(content); + } + +Q_SIGNALS: + void readFinished(bool ok); + +private Q_SLOTS: + void handleReadyRead(); + +private: + QTcpSocket *m_socket = nullptr; + QByteArray m_requestMethod; + QByteArray m_requestPath; + std::map<QByteArray, QByteArray> m_requestHeaders; + int m_responseStatusCode = 200; + std::map<QByteArray, QByteArray> m_responseHeaders; + QByteArray m_responseBody; +}; + +#endif // !HTTPREQREP_H diff --git a/tests/auto/shared/httpserver.cpp b/tests/auto/shared/httpserver.cpp new file mode 100644 index 000000000..6012379f2 --- /dev/null +++ b/tests/auto/shared/httpserver.cpp @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "httpserver.h" + +#include "waitforsignal.h" + +HttpServer::HttpServer(QObject *parent) : QObject(parent) +{ + connect(&m_tcpServer, &QTcpServer::newConnection, this, &HttpServer::handleNewConnection); + if (!m_tcpServer.listen()) + qWarning("HttpServer: listen() failed"); + m_url = QStringLiteral("http://127.0.0.1:") + QString::number(m_tcpServer.serverPort()); +} + +QUrl HttpServer::url(const QString &path) const +{ + auto copy = m_url; + copy.setPath(path); + return copy; +} + +void HttpServer::handleNewConnection() +{ + auto reqRep = new HttpReqRep(m_tcpServer.nextPendingConnection(), this); + connect(reqRep, &HttpReqRep::readFinished, this, &HttpServer::handleReadFinished); +} + +void HttpServer::handleReadFinished(bool ok) +{ + auto reqRep = qobject_cast<HttpReqRep *>(sender()); + if (ok) + Q_EMIT newRequest(reqRep); + else + reqRep->deleteLater(); +} + +std::unique_ptr<HttpReqRep> waitForRequest(HttpServer *server) +{ + std::unique_ptr<HttpReqRep> result; + waitForSignal(server, &HttpServer::newRequest, [&](HttpReqRep *rr) { + rr->setParent(nullptr); + result.reset(rr); + }); + return result; +} diff --git a/tests/auto/shared/httpserver.h b/tests/auto/shared/httpserver.h new file mode 100644 index 000000000..e45743b7b --- /dev/null +++ b/tests/auto/shared/httpserver.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef HTTPSERVER_H +#define HTTPSERVER_H + +#include "httpreqrep.h" + +#include <QTcpServer> +#include <QUrl> + +#include <memory> + +// Listens on a TCP socket and creates HttpReqReps for each connection. +class HttpServer : public QObject +{ + Q_OBJECT + + QTcpServer m_tcpServer; + QUrl m_url; + +public: + HttpServer(QObject *parent = nullptr); + QUrl url(const QString &path = QStringLiteral("/")) const; + +Q_SIGNALS: + void newRequest(HttpReqRep *reqRep); + +private Q_SLOTS: + void handleNewConnection(); + void handleReadFinished(bool ok); +}; + +// Wait for an HTTP request to be received. +std::unique_ptr<HttpReqRep> waitForRequest(HttpServer *server); + +#endif // !HTTPSERVER_H diff --git a/tests/auto/shared/waitforsignal.h b/tests/auto/shared/waitforsignal.h new file mode 100644 index 000000000..9b2daf7af --- /dev/null +++ b/tests/auto/shared/waitforsignal.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef WAITFORSIGNAL_H +#define WAITFORSIGNAL_H + +#include <QObject> +#include <QTestEventLoop> + +#include <utility> + +// Implementation details of waitForSignal. +namespace { + // Wraps a functor to set a flag and exit from event loop if called. + template <class SignalHandler> + struct waitForSignal_SignalHandlerWrapper { + waitForSignal_SignalHandlerWrapper(SignalHandler &&sh) + : signalHandler(std::forward<SignalHandler>(sh)) {} + + template <class... Args> + void operator()(Args && ... args) { + signalHandler(std::forward<Args>(args)...); + hasBeenCalled = true; + loop.exitLoop(); + } + + SignalHandler &&signalHandler; + QTestEventLoop loop; + bool hasBeenCalled = false; + }; + + // No-op functor. + struct waitForSignal_DefaultSignalHandler { + template <class... Args> + void operator()(Args && ...) {} + }; +} // namespace + +// Wait for a signal to be emitted. +// +// The given functor is called with the signal arguments allowing the arguments +// to be modified before returning from the signal handler (unlike QSignalSpy). +template <class Sender, class Signal, class SignalHandler> +bool waitForSignal(Sender &&sender, Signal &&signal, SignalHandler &&signalHandler, int timeout = 15000) +{ + waitForSignal_SignalHandlerWrapper<SignalHandler> signalHandlerWrapper( + std::forward<SignalHandler>(signalHandler)); + auto connection = QObject::connect( + std::forward<Sender>(sender), + std::forward<Signal>(signal), + std::ref(signalHandlerWrapper)); + signalHandlerWrapper.loop.enterLoopMSecs(timeout); + QObject::disconnect(connection); + return signalHandlerWrapper.hasBeenCalled; +} + +template <class Sender, class Signal> +bool waitForSignal(Sender &&sender, Signal &&signal, int timeout = 15000) +{ + return waitForSignal(std::forward<Sender>(sender), + std::forward<Signal>(signal), + waitForSignal_DefaultSignalHandler(), + timeout); +} + +#endif // !WAITFORSIGNAL_H |