diff --git a/CMakeLists.txt b/CMakeLists.txt index f255a8b..aadafb0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 2.8.11) +cmake_minimum_required(VERSION 3.2.0) project(QHttpEngine) if(NOT (CMAKE_MAJOR_VERSION VERSION_LESS 3)) @@ -28,7 +28,7 @@ set(CMAKECONFIG_INSTALL_DIR "${LIB_INSTALL_DIR}/cmake/${PROJECT_NAME}" CACHE STR set(DOC_INSTALL_DIR share/doc/${PROJECT_NAME} CACHE STRING "Documentation installation directory relative to the install prefix") set(EXAMPLES_INSTALL_DIR "${LIB_INSTALL_DIR}/${PROJECT_NAME}/examples" CACHE STRING "Examples installation directory relative to the install prefix") -find_package(Qt5Network 5.1 REQUIRED) +find_package(Qt5Network 5.4 REQUIRED) set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_AUTOMOC ON) diff --git a/examples/chatserver/apihandler.cpp b/examples/chatserver/apihandler.cpp index 2f352d6..efc62dc 100644 --- a/examples/chatserver/apihandler.cpp +++ b/examples/chatserver/apihandler.cpp @@ -25,7 +25,7 @@ QVariantMap ApiHandler::get_messages(const QVariantMap &query) { // Ensure an index was supplied - if(!query.contains("index")) { + if (!query.contains("index")) { return QVariantMap(); } @@ -34,8 +34,8 @@ QVariantMap ApiHandler::get_messages(const QVariantMap &query) // Construct a list of all messages with an index higher than the one // that was provided as a parameter - if(index >= -1 && index < mMessages.count()) { - for(QStringList::const_iterator i = mMessages.constBegin() + index + 1; + if (index >= -1 && index < mMessages.count()) { + for (QStringList::const_iterator i = mMessages.constBegin() + index + 1; i != mMessages.constEnd(); ++i) { QVariantMap data; data.insert("index", i - mMessages.constBegin()); @@ -54,7 +54,7 @@ QVariantMap ApiHandler::get_messages(const QVariantMap &query) QVariantMap ApiHandler::post_newMessage(const QVariantMap &query, const QVariantMap ¶ms) { // Ensure that a valid message was supplied - if(!params.contains("message")) { + if (!params.contains("message")) { return QVariantMap(); } diff --git a/examples/chatserver/apihandler.h b/examples/chatserver/apihandler.h index d179c5a..43ddce5 100644 --- a/examples/chatserver/apihandler.h +++ b/examples/chatserver/apihandler.h @@ -24,6 +24,7 @@ #define CHAT_APIHANDLER_H #include +#include #include diff --git a/examples/chatserver/main.cpp b/examples/chatserver/main.cpp index d8a26da..e3f10eb 100644 --- a/examples/chatserver/main.cpp +++ b/examples/chatserver/main.cpp @@ -72,7 +72,7 @@ int main(int argc, char * argv[]) QHttpServer server(&handler); // Attempt to listen on the specified port - if(!server.listen(address, port)) { + if (!server.listen(address, port)) { qCritical("Unable to listen on the specified port."); return 1; } diff --git a/examples/fileserver/main.cpp b/examples/fileserver/main.cpp index f6cb8bb..b04fcb8 100644 --- a/examples/fileserver/main.cpp +++ b/examples/fileserver/main.cpp @@ -72,7 +72,7 @@ int main(int argc, char * argv[]) QHttpServer server(&handler); // Attempt to listen on the specified port - if(!server.listen(address, port)) { + if (!server.listen(address, port)) { qCritical("Unable to listen on the specified port."); return 1; } diff --git a/src/QHttpEngine/QFilesystemHandler b/include/QHttpEngine/QFilesystemHandler similarity index 100% rename from src/QHttpEngine/QFilesystemHandler rename to include/QHttpEngine/QFilesystemHandler diff --git a/src/QHttpEngine/QHttpHandler b/include/QHttpEngine/QHttpHandler similarity index 100% rename from src/QHttpEngine/QHttpHandler rename to include/QHttpEngine/QHttpHandler diff --git a/src/QHttpEngine/QHttpParser b/include/QHttpEngine/QHttpParser similarity index 100% rename from src/QHttpEngine/QHttpParser rename to include/QHttpEngine/QHttpParser diff --git a/src/QHttpEngine/QHttpServer b/include/QHttpEngine/QHttpServer similarity index 100% rename from src/QHttpEngine/QHttpServer rename to include/QHttpEngine/QHttpServer diff --git a/src/QHttpEngine/QHttpSocket b/include/QHttpEngine/QHttpSocket similarity index 100% rename from src/QHttpEngine/QHttpSocket rename to include/QHttpEngine/QHttpSocket diff --git a/src/QHttpEngine/QIByteArray b/include/QHttpEngine/QIByteArray similarity index 100% rename from src/QHttpEngine/QIByteArray rename to include/QHttpEngine/QIByteArray diff --git a/src/QHttpEngine/QIODeviceCopier b/include/QHttpEngine/QIODeviceCopier similarity index 100% rename from src/QHttpEngine/QIODeviceCopier rename to include/QHttpEngine/QIODeviceCopier diff --git a/src/QHttpEngine/QLocalFile b/include/QHttpEngine/QLocalFile similarity index 100% rename from src/QHttpEngine/QLocalFile rename to include/QHttpEngine/QLocalFile diff --git a/src/QHttpEngine/QObjectHandler b/include/QHttpEngine/QObjectHandler similarity index 100% rename from src/QHttpEngine/QObjectHandler rename to include/QHttpEngine/QObjectHandler diff --git a/src/QHttpEngine/qfilesystemhandler.h b/include/QHttpEngine/qfilesystemhandler.h similarity index 97% rename from src/QHttpEngine/qfilesystemhandler.h rename to include/QHttpEngine/qfilesystemhandler.h index 3023a12..71eede8 100644 --- a/src/QHttpEngine/qfilesystemhandler.h +++ b/include/QHttpEngine/qfilesystemhandler.h @@ -23,8 +23,9 @@ #ifndef QHTTPENGINE_QFILESYSTEMHANDLER_H #define QHTTPENGINE_QFILESYSTEMHANDLER_H -#include "qhttpengine.h" -#include "qhttphandler.h" +#include + +#include "qhttpengine_global.h" class QHTTPENGINE_EXPORT QFilesystemHandlerPrivate; diff --git a/src/QHttpEngine/qhttphandler.h b/include/QHttpEngine/qhttphandler.h similarity index 98% rename from src/QHttpEngine/qhttphandler.h rename to include/QHttpEngine/qhttphandler.h index 6fd2c04..280d2e3 100644 --- a/src/QHttpEngine/qhttphandler.h +++ b/include/QHttpEngine/qhttphandler.h @@ -24,11 +24,11 @@ #define QHTTPENGINE_QHTTPHANDLER_H #include -#include -#include "qhttpengine.h" -#include "qhttpsocket.h" +#include "qhttpengine_global.h" +class QRegExp; +class QHttpSocket; class QHTTPENGINE_EXPORT QHttpHandlerPrivate; /** diff --git a/src/QHttpEngine/qhttpparser.h b/include/QHttpEngine/qhttpparser.h similarity index 81% rename from src/QHttpEngine/qhttpparser.h rename to include/QHttpEngine/qhttpparser.h index 10b738a..0b87cba 100644 --- a/src/QHttpEngine/qhttpparser.h +++ b/include/QHttpEngine/qhttpparser.h @@ -24,23 +24,10 @@ #define QHTTPENGINE_QHTTPPARSER_H #include -#include -#include "qhttpengine.h" -#include "qibytearray.h" +#include -/** - * @brief Map consisting of query string values - */ -typedef QMultiMap QQueryStringMap; - -/** - * @brief Map consisting of HTTP headers - * - * The key used for the map is the QIByteArray class, which allows for - * case-insensitive comparison. - */ -typedef QMultiMap QHttpHeaderMap; +#include "qhttpengine_global.h" /** * @brief Utility methods for parsing HTTP requests and responses @@ -70,7 +57,7 @@ public: /** * @brief Parse and remove the query string from a path */ - static bool parsePath(const QByteArray &rawPath, QString &path, QQueryStringMap &queryString); + static bool parsePath(const QByteArray &rawPath, QString &path, QHttpSocket::QQueryStringMap &queryString); /** * @brief Parse a list of lines containing HTTP headers @@ -78,7 +65,7 @@ public: * Each line is expected to be in the format "name: value". Parsing is * immediately aborted if an invalid line is encountered. */ - static bool parseHeaderList(const QList &lines, QHttpHeaderMap &headers); + static bool parseHeaderList(const QList &lines, QHttpSocket::QHttpHeaderMap &headers); /** * @brief Parse HTTP headers @@ -87,17 +74,17 @@ public: * into a status line and HTTP headers. The parts list will contain the * parts from the status line. */ - static bool parseHeaders(const QByteArray &data, QList &parts, QHttpHeaderMap &headers); + static bool parseHeaders(const QByteArray &data, QList &parts, QHttpSocket::QHttpHeaderMap &headers); /** * @brief Parse HTTP request headers */ - static bool parseRequestHeaders(const QByteArray &data, QByteArray &method, QByteArray &path, QHttpHeaderMap &headers); + static bool parseRequestHeaders(const QByteArray &data, QHttpSocket::Method &method, QByteArray &path, QHttpSocket::QHttpHeaderMap &headers); /** * @brief Parse HTTP response headers */ - static bool parseResponseHeaders(const QByteArray &data, int &statusCode, QByteArray &statusReason, QHttpHeaderMap &headers); + static bool parseResponseHeaders(const QByteArray &data, int &statusCode, QByteArray &statusReason, QHttpSocket::QHttpHeaderMap &headers); }; #endif // QHTTPENGINE_QHTTPPARSER_H diff --git a/src/QHttpEngine/qhttpserver.h b/include/QHttpEngine/qhttpserver.h similarity index 97% rename from src/QHttpEngine/qhttpserver.h rename to include/QHttpEngine/qhttpserver.h index e4055f7..0eae18f 100644 --- a/src/QHttpEngine/qhttpserver.h +++ b/include/QHttpEngine/qhttpserver.h @@ -27,9 +27,9 @@ #include #include -#include "qhttpengine.h" -#include "qhttphandler.h" +#include "qhttpengine_global.h" +class QHttpHandler; class QHTTPENGINE_EXPORT QHttpServerPrivate; /** @@ -48,7 +48,7 @@ class QHTTPENGINE_EXPORT QHttpServerPrivate; * * @code * QHttpServer server; - * if(!server.listen()) { + * if (!server.listen()) { * // error handling * } * @endcode diff --git a/src/QHttpEngine/qhttpsocket.h b/include/QHttpEngine/qhttpsocket.h similarity index 86% rename from src/QHttpEngine/qhttpsocket.h rename to include/QHttpEngine/qhttpsocket.h index 2183c1b..8bc214b 100644 --- a/src/QHttpEngine/qhttpsocket.h +++ b/include/QHttpEngine/qhttpsocket.h @@ -23,11 +23,14 @@ #ifndef QHTTPENGINE_QHTTPSOCKET_H #define QHTTPENGINE_QHTTPSOCKET_H -#include +#include +#include -#include "qhttpengine.h" -#include "qhttpparser.h" +#include +#include "qhttpengine_global.h" + +class QTcpSocket; class QHTTPENGINE_EXPORT QHttpSocketPrivate; /** @@ -91,6 +94,44 @@ class QHTTPENGINE_EXPORT QHttpSocket : public QIODevice public: + /** + * @brief Map consisting of query string values + */ + typedef QMultiMap QQueryStringMap; + + /** + * @brief Map consisting of HTTP headers + * + * The key used for the map is the QIByteArray class, which allows for + * case-insensitive comparison. + */ + typedef QMultiMap QHttpHeaderMap; + + /** + * HTTP methods + * + * An integer constant is provided for each of the methods described in + * RFC 2616 (HTTP/1.1). + */ + enum Method { + /// Request for communications options + OPTIONS = 1, + /// Request resource + GET = 1 << 1, + /// Request resource without body + HEAD = 1 << 2, + /// Store subordinate resource + POST = 1 << 3, + /// Store resource + PUT = 1 << 4, + /// Delete resource + DELETE = 1 << 5, + /// Diagnostic trace + TRACE = 1 << 6, + /// Proxy connection + CONNECT = 1 << 7 + }; + /** * Predefined constants for HTTP status codes */ @@ -144,13 +185,18 @@ public: */ virtual void close(); + /** + * @brief Determine if the request headers have been parsed yet + */ + bool isHeadersParsed() const; + /** * @brief Retrieve the request method * * This method may only be called after the request headers have been * parsed. */ - QByteArray method() const; + Method method() const; /** * @brief Retrieve the raw request path @@ -176,11 +222,6 @@ public: */ QQueryStringMap queryString() const; - /** - * @brief Determine if the request headers have been parsed yet - */ - bool isHeadersParsed() const; - /** * @brief Retrieve a map of request headers * @@ -213,10 +254,10 @@ public: * @brief Set a response header to a specific value * * This method may only be called before the response headers are written. - * If the specified header already has a value set, it will be - * overwritten. + * Duplicate values will be either appended to the header or used to + * replace the original value, depending on the third parameter. */ - void setHeader(const QByteArray &name, const QByteArray &value); + void setHeader(const QByteArray &name, const QByteArray &value, bool replace = true); /** * @brief Set the response headers diff --git a/src/QHttpEngine/qibytearray.h b/include/QHttpEngine/qibytearray.h similarity index 98% rename from src/QHttpEngine/qibytearray.h rename to include/QHttpEngine/qibytearray.h index 4f5fcc4..d65036f 100644 --- a/src/QHttpEngine/qibytearray.h +++ b/include/QHttpEngine/qibytearray.h @@ -25,7 +25,7 @@ #include -#include "qhttpengine.h" +#include "qhttpengine_global.h" /** * @brief Case-insensitive subclass of QByteArray diff --git a/src/QHttpEngine/qiodevicecopier.h b/include/QHttpEngine/qiodevicecopier.h similarity index 98% rename from src/QHttpEngine/qiodevicecopier.h rename to include/QHttpEngine/qiodevicecopier.h index 442be55..ad8128c 100644 --- a/src/QHttpEngine/qiodevicecopier.h +++ b/include/QHttpEngine/qiodevicecopier.h @@ -23,11 +23,11 @@ #ifndef QHTTPENGINE_QIODEVICECOPIER_H #define QHTTPENGINE_QIODEVICECOPIER_H -#include #include -#include "qhttpengine.h" +#include "qhttpengine_global.h" +class QIODevice; class QHTTPENGINE_EXPORT QIODeviceCopierPrivate; /** diff --git a/src/QHttpEngine/qlocalfile.h b/include/QHttpEngine/qlocalfile.h similarity index 97% rename from src/QHttpEngine/qlocalfile.h rename to include/QHttpEngine/qlocalfile.h index 5dd90f1..d2a994a 100644 --- a/src/QHttpEngine/qlocalfile.h +++ b/include/QHttpEngine/qlocalfile.h @@ -25,7 +25,7 @@ #include -#include "qhttpengine.h" +#include "qhttpengine_global.h" class QHTTPENGINE_EXPORT QLocalFilePrivate; @@ -39,7 +39,7 @@ class QHTTPENGINE_EXPORT QLocalFilePrivate; * * @code * QLocalFile file; - * if(file.open()) { + * if (file.open()) { * file.write("private data"); * file.close(); * } diff --git a/src/QHttpEngine/qobjecthandler.h b/include/QHttpEngine/qobjecthandler.h similarity index 97% rename from src/QHttpEngine/qobjecthandler.h rename to include/QHttpEngine/qobjecthandler.h index 215f62f..066ae38 100644 --- a/src/QHttpEngine/qobjecthandler.h +++ b/include/QHttpEngine/qobjecthandler.h @@ -23,9 +23,11 @@ #ifndef QHTTPENGINE_QOBJECTHANDLER_H #define QHTTPENGINE_QOBJECTHANDLER_H -#include "qhttpengine.h" -#include "qhttphandler.h" +#include +#include "qhttpengine_global.h" + +class QHttpSocket; class QHTTPENGINE_EXPORT QObjectHandlerPrivate; /** diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index dac6505..f3b9dc6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,7 +1,7 @@ -file(GLOB HEADERS "${PROJECT_NAME}/*") +configure_file(qhttpengine_global.h.in "${CMAKE_CURRENT_BINARY_DIR}/qhttpengine_global.h") -configure_file(qhttpengine.h.in "${CMAKE_CURRENT_BINARY_DIR}/qhttpengine.h") -set(HEADERS "${HEADERS}" "${CMAKE_CURRENT_BINARY_DIR}/qhttpengine.h") +file(GLOB HEADERS "${CMAKE_SOURCE_DIR}/include/${PROJECT_NAME}/*") +set(HEADERS "${HEADERS}" "${CMAKE_CURRENT_BINARY_DIR}/qhttpengine_global.h") set(SRC qfilesystemhandler.cpp @@ -37,7 +37,7 @@ set_target_properties(QHttpEngine PROPERTIES ) target_include_directories(QHttpEngine PUBLIC - "$" + "$/include" "$" "$" ) diff --git a/src/qfilesystemhandler.cpp b/src/qfilesystemhandler.cpp index 2f8e172..b221c9b 100644 --- a/src/qfilesystemhandler.cpp +++ b/src/qfilesystemhandler.cpp @@ -25,8 +25,9 @@ #include #include -#include "QHttpEngine/qfilesystemhandler.h" -#include "QHttpEngine/qiodevicecopier.h" +#include +#include + #include "qfilesystemhandler_p.h" // Template for listing directory contents @@ -72,7 +73,7 @@ void QFilesystemHandlerPrivate::processFile(QHttpSocket *socket, const QString & { // Attempt to open the file for reading QFile *file = new QFile(absolutePath); - if(!file->open(QIODevice::ReadOnly)) { + if (!file->open(QIODevice::ReadOnly)) { delete file; socket->writeError(QHttpSocket::Forbidden); @@ -81,8 +82,8 @@ void QFilesystemHandlerPrivate::processFile(QHttpSocket *socket, const QString & // Create a QIODeviceCopier to copy the file contents to the socket QIODeviceCopier *copier = new QIODeviceCopier(file, socket); - connect(copier, SIGNAL(finished()), copier, SLOT(deleteLater())); - connect(copier, SIGNAL(finished()), file, SLOT(deleteLater())); + connect(copier, &QIODeviceCopier::finished, copier, &QIODeviceCopier::deleteLater); + connect(copier, &QIODeviceCopier::finished, file, &QFile::deleteLater); // Set the mimetype and content length socket->setHeader("Content-Type", mimeType(absolutePath)); @@ -97,7 +98,7 @@ void QFilesystemHandlerPrivate::processDirectory(QHttpSocket *socket, const QStr { // Add entries for each of the files QString listing; - foreach(QFileInfo info, QDir(absolutePath).entryInfoList()) { + foreach (QFileInfo info, QDir(absolutePath).entryInfoList()) { listing.append(QString("
  • %1%2
  • ") .arg(info.fileName().toHtmlEscaped()) .arg(info.isDir() ? "/" : "")); @@ -138,7 +139,7 @@ void QFilesystemHandler::setDocumentRoot(const QString &documentRoot) void QFilesystemHandler::process(QHttpSocket *socket, const QString &path) { // If a document root is not set, an error has occurred - if(d->documentRoot.path().isNull()) { + if (d->documentRoot.path().isNull()) { socket->writeError(QHttpSocket::InternalServerError); return; } @@ -148,12 +149,12 @@ void QFilesystemHandler::process(QHttpSocket *socket, const QString &path) // Attempt to retrieve the absolute path QString absolutePath; - if(!d->absolutePath(decodedPath, absolutePath)) { + if (!d->absolutePath(decodedPath, absolutePath)) { socket->writeError(QHttpSocket::NotFound); return; } - if(QFileInfo(absolutePath).isDir()) { + if (QFileInfo(absolutePath).isDir()) { d->processDirectory(socket, decodedPath, absolutePath); } else { d->processFile(socket, absolutePath); diff --git a/src/qfilesystemhandler_p.h b/src/qfilesystemhandler_p.h index 82630d4..7cda03c 100644 --- a/src/qfilesystemhandler_p.h +++ b/src/qfilesystemhandler_p.h @@ -27,8 +27,8 @@ #include #include -#include "QHttpEngine/qfilesystemhandler.h" -#include "QHttpEngine/qhttpsocket.h" +#include +#include class QFilesystemHandlerPrivate : public QObject { diff --git a/src/qhttpengine.h.in b/src/qhttpengine_global.h.in similarity index 100% rename from src/qhttpengine.h.in rename to src/qhttpengine_global.h.in diff --git a/src/qhttphandler.cpp b/src/qhttphandler.cpp index c5e933f..0f3305a 100644 --- a/src/qhttphandler.cpp +++ b/src/qhttphandler.cpp @@ -21,6 +21,7 @@ */ #include +#include #include "qhttphandler_p.h" @@ -49,10 +50,10 @@ void QHttpHandler::addSubHandler(const QRegExp &pattern, QHttpHandler *handler) void QHttpHandler::route(QHttpSocket *socket, const QString &path) { // Check each of the redirects for a match - foreach(Redirect redirect, d->redirects) { - if(redirect.first.indexIn(path) != -1) { + foreach (Redirect redirect, d->redirects) { + if (redirect.first.indexIn(path) != -1) { QString newPath = redirect.second; - foreach(QString replacement, redirect.first.capturedTexts().mid(1)) { + foreach (QString replacement, redirect.first.capturedTexts().mid(1)) { newPath = newPath.arg(replacement); } socket->writeRedirect(newPath.toUtf8()); @@ -61,8 +62,8 @@ void QHttpHandler::route(QHttpSocket *socket, const QString &path) } // Check each of the sub-handlers for a match - foreach(SubHandler subHandler, d->subHandlers) { - if(subHandler.first.indexIn(path) != -1) { + foreach (SubHandler subHandler, d->subHandlers) { + if (subHandler.first.indexIn(path) != -1) { subHandler.second->route(socket, path.mid(subHandler.first.matchedLength())); return; } diff --git a/src/qhttpparser.cpp b/src/qhttpparser.cpp index 768dccf..435a5b7 100644 --- a/src/qhttpparser.cpp +++ b/src/qhttpparser.cpp @@ -20,21 +20,20 @@ * IN THE SOFTWARE. */ -#include #include #include #include -#include "QHttpEngine/qhttpparser.h" +#include void QHttpParser::split(const QByteArray &data, const QByteArray &delim, int maxSplit, QList &parts) { int index = 0; - for(int i = 0; !maxSplit || i < maxSplit; ++i) { + for (int i = 0; !maxSplit || i < maxSplit; ++i) { int nextIndex = data.indexOf(delim, index); - if(nextIndex == -1) { + if (nextIndex == -1) { break; } @@ -46,7 +45,7 @@ void QHttpParser::split(const QByteArray &data, const QByteArray &delim, int max parts.append(data.mid(index)); } -bool QHttpParser::parsePath(const QByteArray &rawPath, QString &path, QQueryStringMap &queryString) +bool QHttpParser::parsePath(const QByteArray &rawPath, QString &path, QHttpSocket::QQueryStringMap &queryString) { QUrl url(rawPath); if (!url.isValid()) { @@ -62,15 +61,15 @@ bool QHttpParser::parsePath(const QByteArray &rawPath, QString &path, QQueryStri return true; } -bool QHttpParser::parseHeaderList(const QList &lines, QHttpHeaderMap &headers) +bool QHttpParser::parseHeaderList(const QList &lines, QHttpSocket::QHttpHeaderMap &headers) { - foreach(const QByteArray &line, lines) { + foreach (const QByteArray &line, lines) { QList parts; split(line, ":", 1, parts); // Ensure that the delimiter (":") was encountered at least once - if(parts.count() != 2) { + if (parts.count() != 2) { return false; } @@ -81,7 +80,7 @@ bool QHttpParser::parseHeaderList(const QList &lines, QHttpHeaderMap return true; } -bool QHttpParser::parseHeaders(const QByteArray &data, QList &parts, QHttpHeaderMap &headers) +bool QHttpParser::parseHeaders(const QByteArray &data, QList &parts, QHttpSocket::QHttpHeaderMap &headers) { // Split the data into individual lines QList lines; @@ -89,35 +88,54 @@ bool QHttpParser::parseHeaders(const QByteArray &data, QList &parts, // Split the first line into a maximum of three parts split(lines.takeFirst(), " ", 2, parts); - if(parts.count() != 3) { + if (parts.count() != 3) { return false; } return parseHeaderList(lines, headers); } -bool QHttpParser::parseRequestHeaders(const QByteArray &data, QByteArray &method, QByteArray &path, QHttpHeaderMap &headers) +bool QHttpParser::parseRequestHeaders(const QByteArray &data, QHttpSocket::Method &method, QByteArray &path, QHttpSocket::QHttpHeaderMap &headers) { QList parts; - if(!parseHeaders(data, parts, headers)) { + if (!parseHeaders(data, parts, headers)) { return false; } // Only HTTP/1.x versions are supported for now - if(parts[2] != "HTTP/1.0" && parts[2] != "HTTP/1.1") { + if (parts[2] != "HTTP/1.0" && parts[2] != "HTTP/1.1") { + return false; + } + + if (parts[0] == "OPTIONS") { + method = QHttpSocket::OPTIONS; + } else if (parts[0] == "GET") { + method = QHttpSocket::GET; + } else if (parts[0] == "HEAD") { + method = QHttpSocket::HEAD; + } else if (parts[0] == "POST") { + method = QHttpSocket::POST; + } else if (parts[0] == "PUT") { + method = QHttpSocket::PUT; + } else if (parts[0] == "DELETE") { + method = QHttpSocket::DELETE; + } else if (parts[0] == "TRACE") { + method = QHttpSocket::TRACE; + } else if (parts[0] == "CONNECT") { + method = QHttpSocket::CONNECT; + } else { return false; } - method = parts[0]; path = parts[1]; return true; } -bool QHttpParser::parseResponseHeaders(const QByteArray &data, int &statusCode, QByteArray &statusReason, QHttpHeaderMap &headers) +bool QHttpParser::parseResponseHeaders(const QByteArray &data, int &statusCode, QByteArray &statusReason, QHttpSocket::QHttpHeaderMap &headers) { QList parts; - if(!parseHeaders(data, parts, headers)) { + if (!parseHeaders(data, parts, headers)) { return false; } diff --git a/src/qhttpserver.cpp b/src/qhttpserver.cpp index cfdcb6a..f17ba8c 100644 --- a/src/qhttpserver.cpp +++ b/src/qhttpserver.cpp @@ -22,8 +22,9 @@ #include -#include "QHttpEngine/qhttpserver.h" -#include "QHttpEngine/qhttpsocket.h" +#include +#include + #include "qhttpserver_p.h" QHttpServerPrivate::QHttpServerPrivate(QHttpServer *httpServer) @@ -31,7 +32,7 @@ QHttpServerPrivate::QHttpServerPrivate(QHttpServer *httpServer) q(httpServer), handler(0) { - connect(q, SIGNAL(newConnection()), this, SLOT(onIncomingConnection())); + connect(q, &QHttpServer::incomingConnection, this, &QHttpServerPrivate::onIncomingConnection); } void QHttpServerPrivate::onIncomingConnection() @@ -41,28 +42,16 @@ void QHttpServerPrivate::onIncomingConnection() QHttpSocket *httpSocket = new QHttpSocket(tcpSocket, this); // Wait until the socket finishes reading the HTTP headers before routing - connect(httpSocket, SIGNAL(headersParsed()), this, SLOT(onHeadersParsed())); + connect(httpSocket, &QHttpSocket::headersParsed, [this, httpSocket]() { + if (handler) { + handler->route(httpSocket, QString(httpSocket->path().mid(1))); + } else { + httpSocket->writeError(QHttpSocket::InternalServerError); + } + }); // Destroy the socket once the client is disconnected - connect(tcpSocket, SIGNAL(disconnected()), httpSocket, SLOT(deleteLater())); -} - -void QHttpServerPrivate::onHeadersParsed() -{ - // Obtain the socket that corresponds with the sender of the signal - QHttpSocket *socket = qobject_cast(sender()); - - // Ensure that a handler has been set - if(handler) { - - // Obtain the path, strip the initial "/", and pass it along to the handler - handler->route(socket, QString(socket->path().mid(1))); - - } else { - - // Return an HTTP 500 error to the client - socket->writeError(QHttpSocket::InternalServerError); - } + connect(tcpSocket, &QTcpSocket::disconnected, httpSocket, &QHttpSocket::deleteLater); } QHttpServer::QHttpServer(QObject *parent) diff --git a/src/qhttpserver_p.h b/src/qhttpserver_p.h index ff1e185..ce598c0 100644 --- a/src/qhttpserver_p.h +++ b/src/qhttpserver_p.h @@ -24,10 +24,10 @@ #define QHTTPENGINE_QHTTPSERVERPRIVATE_H #include -#include -#include "QHttpEngine/qhttphandler.h" -#include "QHttpEngine/qhttpserver.h" +#include + +class QHttpHandler; class QHttpServerPrivate : public QObject { @@ -35,14 +35,13 @@ class QHttpServerPrivate : public QObject public: - QHttpServerPrivate(QHttpServer *httpServer); + explicit QHttpServerPrivate(QHttpServer *httpServer); QHttpHandler *handler; private Q_SLOTS: void onIncomingConnection(); - void onHeadersParsed(); private: diff --git a/src/qhttpsocket.cpp b/src/qhttpsocket.cpp index 3cb9461..374bce8 100644 --- a/src/qhttpsocket.cpp +++ b/src/qhttpsocket.cpp @@ -22,18 +22,32 @@ #include -#include "QHttpEngine/qhttpsocket.h" +#include + +#include + #include "qhttpsocket_p.h" // Predefined error response requires a simple HTML template to be returned to // the client describing the error condition const QString ErrorTemplate = - "" - "" - "%1 %2

    %1 %2

    " - "An error has occurred while trying to display the requested resource. " - "Please contact the website owner if this error persists." - "


    QHttpEngine %3

    "; + "" + "" + "" + "" + "" + "%1 %2" + "" + "" + "

    %1 %2

    " + "

    " + "An error has occurred while trying to display the requested resource. " + "Please contact the website owner if this error persists." + "

    " + "
    " + "

    QHttpEngine %3

    " + "" + ""; QHttpSocketPrivate::QHttpSocketPrivate(QHttpSocket *httpSocket, QTcpSocket *tcpSocket) : QObject(httpSocket), @@ -48,8 +62,8 @@ QHttpSocketPrivate::QHttpSocketPrivate(QHttpSocket *httpSocket, QTcpSocket *tcpS { socket->setParent(this); - connect(socket, SIGNAL(readyRead()), this, SLOT(onReadyRead())); - connect(socket, SIGNAL(bytesWritten(qint64)), this, SLOT(onBytesWritten(qint64))); + connect(socket, &QTcpSocket::readyRead, this, &QHttpSocketPrivate::onReadyRead); + connect(socket, &QTcpSocket::bytesWritten, this, &QHttpSocketPrivate::onBytesWritten); // Process anything already received by the socket onReadyRead(); @@ -57,7 +71,7 @@ QHttpSocketPrivate::QHttpSocketPrivate(QHttpSocket *httpSocket, QTcpSocket *tcpS QByteArray QHttpSocketPrivate::statusReason(int statusCode) const { - switch(statusCode) { + switch (statusCode) { case QHttpSocket::OK: return "OK"; case QHttpSocket::MovedPermanently: return "MOVED PERMANENTLY"; case QHttpSocket::Found: return "FOUND"; @@ -66,7 +80,7 @@ QByteArray QHttpSocketPrivate::statusReason(int statusCode) const case QHttpSocket::NotFound: return "NOT FOUND"; case QHttpSocket::MethodNotAllowed: return "METHOD NOT ALLOWED"; case QHttpSocket::InternalServerError: return "INTERNAL SERVER ERROR"; - default: return "UNKNOWN"; + default: return "UNKNOWN ERROR"; } } @@ -76,26 +90,26 @@ void QHttpSocketPrivate::onReadyRead() readBuffer.append(socket->readAll()); // If reading headers, return if they could not be read (yet) - if(readState == ReadHeaders) { - if(!readHeaders()) { - return; - } + if (readState == ReadHeaders && !readHeaders()) { + return; } - if(readState == ReadData) { + // Read data if in that state, otherwise discard + switch (readState) { + case ReadData: readData(); - } else if(readState == ReadFinished) { - - // Any data received here is unexpected and should be ignored + break; + case ReadFinished: readBuffer.clear(); + break; } } void QHttpSocketPrivate::onBytesWritten(qint64 bytes) { // Check to see if all of the response header was written - if(writeState == WriteHeaders) { - if(responseHeaderRemaining - bytes > 0) { + if (writeState == WriteHeaders) { + if (responseHeaderRemaining - bytes > 0) { responseHeaderRemaining -= bytes; } else { writeState = WriteData; @@ -103,7 +117,8 @@ void QHttpSocketPrivate::onBytesWritten(qint64 bytes) } } - if(writeState == WriteData) { + // Only emit bytesWritten() for data after the headers + if (writeState == WriteData) { Q_EMIT q->bytesWritten(bytes); } } @@ -113,13 +128,13 @@ bool QHttpSocketPrivate::readHeaders() // Check for the double CRLF that signals the end of the headers and // if it is not found, wait until the next time readyRead is emitted int index = readBuffer.indexOf("\r\n\r\n"); - if(index == -1) { + if (index == -1) { return false; } // Attempt to parse the headers and if a problem is encountered, abort // the connection (so that no more data is read or written) and return - if(!QHttpParser::parseRequestHeaders(readBuffer.left(index), requestMethod, requestRawPath, requestHeaders) || + if (!QHttpParser::parseRequestHeaders(readBuffer.left(index), requestMethod, requestRawPath, requestHeaders) || !QHttpParser::parsePath(requestRawPath, requestPath, requestQueryString)) { q->writeError(QHttpSocket::BadRequest); return false; @@ -131,7 +146,7 @@ bool QHttpSocketPrivate::readHeaders() // Check for the content-length header - if it is present, then // prepare to read the specified amount of data, otherwise, no data // should be read from the socket and the read channel is finished - if(requestHeaders.contains("Content-Length")) { + if (requestHeaders.contains("Content-Length")) { readState = ReadData; requestDataTotal = requestHeaders.value("Content-Length").toLongLong(); } else { @@ -142,7 +157,7 @@ bool QHttpSocketPrivate::readHeaders() Q_EMIT q->headersParsed(); // If the new readState is ReadFinished, then indicate so - if(readState == ReadFinished) { + if (readState == ReadFinished) { Q_EMIT q->readChannelFinished(); } @@ -152,13 +167,13 @@ bool QHttpSocketPrivate::readHeaders() void QHttpSocketPrivate::readData() { // Emit the readyRead() signal if any data is available in the buffer - if(readBuffer.size()) { + if (readBuffer.size()) { Q_EMIT q->readyRead(); } // Check to see if the specified amount of data has been read from the // socket, if so, emit the readChannelFinished() signal - if(requestDataRead + readBuffer.size() >= requestDataTotal) { + if (requestDataRead + readBuffer.size() >= requestDataTotal) { readState = ReadFinished; Q_EMIT q->readChannelFinished(); } @@ -174,7 +189,7 @@ QHttpSocket::QHttpSocket(QTcpSocket *socket, QObject *parent) qint64 QHttpSocket::bytesAvailable() const { - if(d->readState > QHttpSocketPrivate::ReadHeaders) { + if (d->readState > QHttpSocketPrivate::ReadHeaders) { return d->readBuffer.size() + QIODevice::bytesAvailable(); } else { return 0; @@ -197,7 +212,12 @@ void QHttpSocket::close() d->socket->close(); } -QByteArray QHttpSocket::method() const +bool QHttpSocket::isHeadersParsed() const +{ + return d->readState > QHttpSocketPrivate::ReadHeaders; +} + +QHttpSocket::Method QHttpSocket::method() const { return d->requestMethod; } @@ -212,17 +232,12 @@ QString QHttpSocket::path() const return d->requestPath; } -QQueryStringMap QHttpSocket::queryString() const +QHttpSocket::QQueryStringMap QHttpSocket::queryString() const { return d->requestQueryString; } -bool QHttpSocket::isHeadersParsed() const -{ - return d->readState > QHttpSocketPrivate::ReadHeaders; -} - -QHttpHeaderMap QHttpSocket::headers() const +QHttpSocket::QHttpHeaderMap QHttpSocket::headers() const { return d->requestHeaders; } @@ -238,9 +253,13 @@ void QHttpSocket::setStatusCode(int statusCode, const QByteArray &statusReason) d->responseStatusReason = statusReason.isNull() ? d->statusReason(statusCode) : statusReason; } -void QHttpSocket::setHeader(const QByteArray &name, const QByteArray &value) +void QHttpSocket::setHeader(const QByteArray &name, const QByteArray &value, bool replace) { - d->responseHeaders.insert(name, value); + if (replace || d->responseHeaders.count(name)) { + d->responseHeaders.replace(name, value); + } else { + d->responseHeaders.replace(name, d->responseHeaders.value(name) + ", " + value); + } } void QHttpSocket::setHeaders(const QHttpHeaderMap &headers) @@ -260,10 +279,10 @@ void QHttpSocket::writeHeaders() header.append("\r\n"); // Append each of the headers followed by a CRLF - for(QHttpHeaderMap::const_iterator i = d->responseHeaders.constBegin(); i != d->responseHeaders.constEnd(); ++i) { + for (auto i = d->responseHeaders.constBegin(); i != d->responseHeaders.constEnd(); ++i) { header.append(i.key()); header.append(": "); - header.append(i.value()); + header.append(d->responseHeaders.values(i.key()).join(", ")); header.append("\r\n"); } @@ -307,7 +326,7 @@ void QHttpSocket::writeError(int statusCode, const QByteArray &statusReason) qint64 QHttpSocket::readData(char *data, qint64 maxlen) { // Ensure the connection is in the correct state for reading data - if(d->readState == QHttpSocketPrivate::ReadHeaders) { + if (d->readState == QHttpSocketPrivate::ReadHeaders) { return 0; } @@ -326,7 +345,7 @@ qint64 QHttpSocket::writeData(const char *data, qint64 len) { // If the response headers have not yet been written, they must // immediately be written before the data can be - if(d->writeState == QHttpSocketPrivate::WriteNone) { + if (d->writeState == QHttpSocketPrivate::WriteNone) { writeHeaders(); } diff --git a/src/qhttpsocket_p.h b/src/qhttpsocket_p.h index c51e98d..4f8ce6e 100644 --- a/src/qhttpsocket_p.h +++ b/src/qhttpsocket_p.h @@ -23,11 +23,9 @@ #ifndef QHTTPENGINE_QHTTPSOCKETPRIVATE_H #define QHTTPENGINE_QHTTPSOCKETPRIVATE_H -#include -#include +#include -#include "QHttpEngine/qhttpparser.h" -#include "QHttpEngine/qhttpsocket.h" +class QTcpSocket; class QHttpSocketPrivate : public QObject { @@ -48,11 +46,11 @@ public: ReadFinished } readState; - QByteArray requestMethod; + QHttpSocket::Method requestMethod; QByteArray requestRawPath; QString requestPath; - QQueryStringMap requestQueryString; - QHttpHeaderMap requestHeaders; + QHttpSocket::QQueryStringMap requestQueryString; + QHttpSocket::QHttpHeaderMap requestHeaders; qint64 requestDataRead; qint64 requestDataTotal; @@ -65,7 +63,7 @@ public: int responseStatusCode; QByteArray responseStatusReason; - QHttpHeaderMap responseHeaders; + QHttpSocket::QHttpHeaderMap responseHeaders; qint64 responseHeaderRemaining; private Q_SLOTS: diff --git a/src/qiodevicecopier.cpp b/src/qiodevicecopier.cpp index 3f61490..c7a139d 100644 --- a/src/qiodevicecopier.cpp +++ b/src/qiodevicecopier.cpp @@ -20,9 +20,11 @@ * IN THE SOFTWARE. */ +#include #include -#include "QHttpEngine/qiodevicecopier.h" +#include + #include "qiodevicecopier_p.h" // Default value for the bufferSize property @@ -39,7 +41,7 @@ QIODeviceCopierPrivate::QIODeviceCopierPrivate(QIODeviceCopier *copier, QIODevic void QIODeviceCopierPrivate::onReadyRead() { - if(dest->write(src->readAll()) == -1) { + if (dest->write(src->readAll()) == -1) { Q_EMIT q->error(dest->errorString()); src->close(); } @@ -48,7 +50,7 @@ void QIODeviceCopierPrivate::onReadyRead() void QIODeviceCopierPrivate::onReadChannelFinished() { // Read any data that remains and signal the end of the operation - if(src->bytesAvailable()) { + if (src->bytesAvailable()) { onReadyRead(); } @@ -63,14 +65,14 @@ void QIODeviceCopierPrivate::nextBlock() qint64 dataRead = src->read(data.data(), bufferSize); // If an error occurred during the read, emit an error - if(dataRead == -1) { + if (dataRead == -1) { Q_EMIT q->error(src->errorString()); Q_EMIT q->finished(); return; } // Write the data to the destination device - if(dest->write(data.constData(), dataRead) == -1) { + if (dest->write(data.constData(), dataRead) == -1) { Q_EMIT q->error(dest->errorString()); Q_EMIT q->finished(); return; @@ -79,10 +81,10 @@ void QIODeviceCopierPrivate::nextBlock() // Check if the end of the device has been reached - if so, // emit the finished signal and if not, continue to read // data at the next iteration of the event loop - if(src->atEnd()) { + if (src->atEnd()) { Q_EMIT q->finished(); } else { - QTimer::singleShot(0, this, SLOT(nextBlock())); + QTimer::singleShot(0, this, &QIODeviceCopierPrivate::nextBlock); } } @@ -90,8 +92,8 @@ QIODeviceCopier::QIODeviceCopier(QIODevice *src, QIODevice *dest, QObject *paren : QObject(parent), d(new QIODeviceCopierPrivate(this, src, dest)) { - connect(src, SIGNAL(destroyed()), this, SLOT(stop())); - connect(dest, SIGNAL(destroyed()), this, SLOT(stop())); + connect(src, &QIODevice::destroyed, this, &QIODeviceCopier::stop); + connect(dest, &QIODevice::destroyed, this, &QIODeviceCopier::stop); } void QIODeviceCopier::setBufferSize(qint64 size) @@ -101,16 +103,16 @@ void QIODeviceCopier::setBufferSize(qint64 size) void QIODeviceCopier::start() { - if(!d->src->isOpen()) { - if(!d->src->open(QIODevice::ReadOnly)) { + if (!d->src->isOpen()) { + if (!d->src->open(QIODevice::ReadOnly)) { Q_EMIT error(tr("Unable to open source device for reading")); Q_EMIT finished(); return; } } - if(!d->dest->isOpen()) { - if(!d->dest->open(QIODevice::WriteOnly)) { + if (!d->dest->isOpen()) { + if (!d->dest->open(QIODevice::WriteOnly)) { Q_EMIT error(tr("Unable to open destination device for writing")); Q_EMIT finished(); return; @@ -123,17 +125,19 @@ void QIODeviceCopier::start() // readyRead() and readChannelFinished() are only emitted for sequential // devices - for other types of devices, it is necessary to check atEnd() // in order to determine whether the end of the device has been reached - connect(d->src, SIGNAL(readyRead()), d, SLOT(onReadyRead())); - connect(d->src, SIGNAL(readChannelFinished()), d, SLOT(onReadChannelFinished())); + connect(d->src, &QIODevice::readyRead, d, &QIODeviceCopierPrivate::onReadyRead); + connect(d->src, &QIODevice::readChannelFinished, d, &QIODeviceCopierPrivate::onReadChannelFinished); // The first read from the device needs to be triggered - QTimer::singleShot(0, d, d->src->isSequential() ? SLOT(onReadyRead()) : SLOT(nextBlock())); + QTimer::singleShot(0, d, d->src->isSequential() ? + &QIODeviceCopierPrivate::onReadyRead : + &QIODeviceCopierPrivate::nextBlock); } void QIODeviceCopier::stop() { - disconnect(d->src, SIGNAL(readyRead()), d, SLOT(onReadyRead())); - disconnect(d->src, SIGNAL(readChannelFinished()), d, SLOT(onReadChannelFinished())); + disconnect(d->src, &QIODevice::readyRead, d, &QIODeviceCopierPrivate::onReadyRead); + disconnect(d->src, &QIODevice::readChannelFinished, d, &QIODeviceCopierPrivate::onReadChannelFinished); Q_EMIT finished(); } diff --git a/src/qiodevicecopier_p.h b/src/qiodevicecopier_p.h index aa94a0c..a47880e 100644 --- a/src/qiodevicecopier_p.h +++ b/src/qiodevicecopier_p.h @@ -23,10 +23,10 @@ #ifndef QHTTPENGINE_QIODEVICECOPIERPRIVATE_H #define QHTTPENGINE_QIODEVICECOPIERPRIVATE_H -#include #include -#include "QHttpEngine/qiodevicecopier.h" +class QIODevice; +class QIODeviceCopier; class QIODeviceCopierPrivate : public QObject { @@ -41,7 +41,7 @@ public: qint64 bufferSize; -private Q_SLOTS: +public Q_SLOTS: void onReadyRead(); void onReadChannelFinished(); diff --git a/src/qlocalfile.cpp b/src/qlocalfile.cpp index 7e380e7..9405bf4 100644 --- a/src/qlocalfile.cpp +++ b/src/qlocalfile.cpp @@ -30,7 +30,8 @@ # include #endif -#include "QHttpEngine/qlocalfile.h" +#include + #include "qlocalfile_p.h" QLocalFilePrivate::QLocalFilePrivate(QLocalFile *localFile) @@ -62,12 +63,12 @@ bool QLocalFilePrivate::setPermission() // Create a new ACL with a single access control entry PACL pACL; - if(SetEntriesInAclW(1, &ea, NULL, &pACL) != ERROR_SUCCESS) { + if (SetEntriesInAclW(1, &ea, NULL, &pACL) != ERROR_SUCCESS) { return false; } // Apply the ACL to the file - if(SetNamedSecurityInfoW((LPWSTR)q->fileName().utf16(), + if (SetNamedSecurityInfoW((LPWSTR)q->fileName().utf16(), SE_FILE_OBJECT, DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION, NULL, diff --git a/src/qlocalfile_p.h b/src/qlocalfile_p.h index 3db73a1..c92f372 100644 --- a/src/qlocalfile_p.h +++ b/src/qlocalfile_p.h @@ -25,7 +25,7 @@ #include -#include "QHttpEngine/qlocalfile.h" +class QLocalFile; class QLocalFilePrivate : public QObject { diff --git a/src/qobjecthandler.cpp b/src/qobjecthandler.cpp index 5072b28..2e3ee5c 100644 --- a/src/qobjecthandler.cpp +++ b/src/qobjecthandler.cpp @@ -30,14 +30,12 @@ #include #include #include -#include -#include "QHttpEngine/qobjecthandler.h" +#include +#include + #include "qobjecthandler_p.h" -const QString MethodGET = "GET"; -const QString MethodPOST = "POST"; - QObjectHandlerPrivate::QObjectHandlerPrivate(QObjectHandler *handler) : QObject(handler), q(handler) @@ -52,7 +50,7 @@ void QObjectHandlerPrivate::invokeSlot(QHttpSocket *socket, int index, const QVa statusCode = QHttpSocket::OK; // If this is a POST request, then decode the request body - if (socket->method() == MethodPOST) { + if (socket->method() == QHttpSocket::POST) { // Attempt to decode the JSON from the socket QJsonParseError error; @@ -111,12 +109,12 @@ void QObjectHandler::process(QHttpSocket *socket, const QString &path) QUrl url(path); QVariantMap query = d->convertQueryString(url.query()); QString slotName = QString("%1_%2") - .arg(QString(socket->method().toLower())) + .arg(socket->method() == QHttpSocket::GET ? "get" : "post") .arg(url.path()); // Determine the parameters the slot should have based on the method QString parameters; - if (socket->method() == MethodGET) { + if (socket->method() == QHttpSocket::GET) { parameters = "QVariantMap"; } else { parameters = "QVariantMap,QVariantMap"; diff --git a/src/qobjecthandler_p.h b/src/qobjecthandler_p.h index bd5b48a..de65cd0 100644 --- a/src/qobjecthandler_p.h +++ b/src/qobjecthandler_p.h @@ -25,8 +25,8 @@ #include -#include "QHttpEngine/qhttpsocket.h" -#include "QHttpEngine/qobjecthandler.h" +class QHttpSocket; +class QObjectHandler; class QObjectHandlerPrivate : public QObject { diff --git a/tests/TestQFilesystemHandler.cpp b/tests/TestQFilesystemHandler.cpp index e9bff1f..0bacdc8 100644 --- a/tests/TestQFilesystemHandler.cpp +++ b/tests/TestQFilesystemHandler.cpp @@ -106,7 +106,7 @@ void TestQFilesystemHandler::testRequests() QTRY_COMPARE(client.statusCode(), statusCode); - if(!data.isNull()) { + if (!data.isNull()) { QTRY_COMPARE(client.data(), data); } } @@ -114,7 +114,7 @@ void TestQFilesystemHandler::testRequests() bool TestQFilesystemHandler::createFile(const QString &path) { QFile file(QDir(dir.path()).absoluteFilePath(path)); - if(!file.open(QIODevice::WriteOnly)) { + if (!file.open(QIODevice::WriteOnly)) { return false; } diff --git a/tests/TestQHttpHandler.cpp b/tests/TestQHttpHandler.cpp index 5fcd388..24e138a 100644 --- a/tests/TestQHttpHandler.cpp +++ b/tests/TestQHttpHandler.cpp @@ -99,7 +99,7 @@ void TestQHttpHandler::testRedirect() QSimpleHttpClient client(pair.client()); QHttpSocket socket(pair.server(), &pair); - client.sendHeaders("GET", path, QHttpHeaderMap()); + client.sendHeaders("GET", path); QTRY_VERIFY(socket.isHeadersParsed()); QHttpHandler handler; @@ -108,7 +108,7 @@ void TestQHttpHandler::testRedirect() QTRY_COMPARE(client.statusCode(), statusCode); - if(statusCode == QHttpSocket::Found) { + if (statusCode == QHttpSocket::Found) { QFETCH(QByteArray, location); QCOMPARE(client.headers().value("Location"), location); } @@ -153,7 +153,7 @@ void TestQHttpHandler::testSubHandler() QSimpleHttpClient client(pair.client()); QHttpSocket socket(pair.server(), &pair); - client.sendHeaders("GET", path, QHttpHeaderMap()); + client.sendHeaders("GET", path); QTRY_VERIFY(socket.isHeadersParsed()); DummyHandler subHandler; diff --git a/tests/TestQHttpParser.cpp b/tests/TestQHttpParser.cpp index 6b52087..ea96b18 100644 --- a/tests/TestQHttpParser.cpp +++ b/tests/TestQHttpParser.cpp @@ -25,12 +25,14 @@ #include #include +#include #include typedef QList QByteArrayList; -Q_DECLARE_METATYPE(QQueryStringMap) -Q_DECLARE_METATYPE(QHttpHeaderMap) +Q_DECLARE_METATYPE(QHttpSocket::Method) +Q_DECLARE_METATYPE(QHttpSocket::QQueryStringMap) +Q_DECLARE_METATYPE(QHttpSocket::QHttpHeaderMap) const QIByteArray Key1 = "a"; const QByteArray Value1 = "b"; @@ -70,7 +72,7 @@ private Q_SLOTS: private: - QHttpHeaderMap headers; + QHttpSocket::QHttpHeaderMap headers; }; TestQHttpParser::TestQHttpParser() @@ -134,27 +136,27 @@ void TestQHttpParser::testParsePath_data() { QTest::addColumn("rawPath"); QTest::addColumn("path"); - QTest::addColumn("map"); + QTest::addColumn("map"); QTest::newRow("no query string") << QByteArray("/path") << QString("/path") - << QQueryStringMap(); + << QHttpSocket::QQueryStringMap(); QTest::newRow("single parameter") << QByteArray("/path?a=b") << QString("/path") - << QQueryStringMap({{"a", "b"}}); + << QHttpSocket::QQueryStringMap({{"a", "b"}}); } void TestQHttpParser::testParsePath() { QFETCH(QByteArray, rawPath); QFETCH(QString, path); - QFETCH(QQueryStringMap, map); + QFETCH(QHttpSocket::QQueryStringMap, map); QString outPath; - QQueryStringMap outMap; + QHttpSocket::QQueryStringMap outMap; QVERIFY(QHttpParser::parsePath(rawPath, outPath, outMap)); @@ -166,7 +168,7 @@ void TestQHttpParser::testParseHeaderList_data() { QTest::addColumn("success"); QTest::addColumn("lines"); - QTest::addColumn("headers"); + QTest::addColumn("headers"); QTest::newRow("empty line") << false @@ -183,11 +185,11 @@ void TestQHttpParser::testParseHeaderList() QFETCH(bool, success); QFETCH(QByteArrayList, lines); - QHttpHeaderMap outHeaders; + QHttpSocket::QHttpHeaderMap outHeaders; QCOMPARE(QHttpParser::parseHeaderList(lines, outHeaders), success); - if(success) { - QFETCH(QHttpHeaderMap, headers); + if (success) { + QFETCH(QHttpSocket::QHttpHeaderMap, headers); QCOMPARE(outHeaders, headers); } } @@ -214,11 +216,11 @@ void TestQHttpParser::testParseHeaders() QFETCH(QByteArray, data); QByteArrayList outParts; - QHttpHeaderMap outHeaders; + QHttpSocket::QHttpHeaderMap outHeaders; QCOMPARE(QHttpParser::parseHeaders(data, outParts, outHeaders), success); - if(success) { + if (success) { QFETCH(QByteArrayList, parts); QCOMPARE(outParts, parts); } @@ -228,7 +230,7 @@ void TestQHttpParser::testParseRequestHeaders_data() { QTest::addColumn("success"); QTest::addColumn("data"); - QTest::addColumn("method"); + QTest::addColumn("method"); QTest::addColumn("path"); QTest::newRow("bad HTTP version") @@ -247,14 +249,14 @@ void TestQHttpParser::testParseRequestHeaders() QFETCH(bool, success); QFETCH(QByteArray, data); - QByteArray outMethod; + QHttpSocket::Method outMethod; QByteArray outPath; - QHttpHeaderMap outHeaders; + QHttpSocket::QHttpHeaderMap outHeaders; QCOMPARE(QHttpParser::parseRequestHeaders(data, outMethod, outPath, outHeaders), success); - if(success) { - QFETCH(QByteArray, method); + if (success) { + QFETCH(QHttpSocket::Method, method); QFETCH(QByteArray, path); QCOMPARE(method, outMethod); @@ -287,11 +289,11 @@ void TestQHttpParser::testParseResponseHeaders() int outStatusCode; QByteArray outStatusReason; - QHttpHeaderMap outHeaders; + QHttpSocket::QHttpHeaderMap outHeaders; QCOMPARE(QHttpParser::parseResponseHeaders(data, outStatusCode, outStatusReason, outHeaders), success); - if(success) { + if (success) { QFETCH(int, statusCode); QFETCH(QByteArray, statusReason); diff --git a/tests/TestQHttpServer.cpp b/tests/TestQHttpServer.cpp index 0e9bac3..499ff86 100644 --- a/tests/TestQHttpServer.cpp +++ b/tests/TestQHttpServer.cpp @@ -67,7 +67,7 @@ void TestQHttpServer::testServer() QTRY_COMPARE(socket.state(), QAbstractSocket::ConnectedState); QSimpleHttpClient client(&socket); - client.sendHeaders("GET", "/test", QHttpHeaderMap()); + client.sendHeaders("GET", "/test"); QTRY_VERIFY(handler.mSocket != 0); QCOMPARE(handler.mPath, QString("test")); diff --git a/tests/TestQHttpSocket.cpp b/tests/TestQHttpSocket.cpp index 5dac150..025a9c3 100644 --- a/tests/TestQHttpSocket.cpp +++ b/tests/TestQHttpSocket.cpp @@ -30,7 +30,7 @@ #include "common/qsimplehttpclient.h" #include "common/qsocketpair.h" -Q_DECLARE_METATYPE(QQueryStringMap) +Q_DECLARE_METATYPE(QHttpSocket::QQueryStringMap) // Utility macro (avoids duplication) that creates a pair of connected // sockets, a QSimpleHttpClient for the client and a QHttpSocket for the @@ -64,7 +64,7 @@ private Q_SLOTS: private: - QHttpHeaderMap headers; + QHttpSocket::QHttpHeaderMap headers; }; TestQHttpSocket::TestQHttpSocket() @@ -79,7 +79,7 @@ void TestQHttpSocket::testProperties() client.sendHeaders(Method, Path, headers); - QTRY_COMPARE(server.method(), Method); + QTRY_COMPARE(server.method(), QHttpSocket::POST); QCOMPARE(server.rawPath(), Path); QCOMPARE(server.headers(), headers); @@ -150,7 +150,7 @@ void TestQHttpSocket::testSignals() QVERIFY(bytesWrittenSpy.count() > 0); qint64 bytesWritten = 0; - for(int i = 0; i < bytesWrittenSpy.count(); ++i) { + for (int i = 0; i < bytesWrittenSpy.count(); ++i) { bytesWritten += bytesWrittenSpy.at(i).at(0).toLongLong(); } QCOMPARE(bytesWritten, Data.length()); diff --git a/tests/TestQObjectHandler.cpp b/tests/TestQObjectHandler.cpp index c27865a..1472ae3 100644 --- a/tests/TestQObjectHandler.cpp +++ b/tests/TestQObjectHandler.cpp @@ -136,7 +136,7 @@ void TestQObjectHandler::testRequests() QSimpleHttpClient client(pair.client()); QHttpSocket socket(pair.server(), &pair); - QHttpHeaderMap headers; + QHttpSocket::QHttpHeaderMap headers; headers.insert("Content-Length", QByteArray::number(data.length())); client.sendHeaders(method, path, headers); diff --git a/tests/common/CMakeLists.txt b/tests/common/CMakeLists.txt index 5e58d40..0790596 100644 --- a/tests/common/CMakeLists.txt +++ b/tests/common/CMakeLists.txt @@ -4,6 +4,8 @@ set(SRC ) add_library(common STATIC ${SRC}) -target_link_libraries(common QHttpEngine) - -qt5_use_modules(common Network) +set_target_properties(common PROPERTIES + CXX_STANDARD 11 + CXX_STANDARD_REQUIRED ON +) +target_link_libraries(common Qt5::Network QHttpEngine) diff --git a/tests/common/qsimplehttpclient.cpp b/tests/common/qsimplehttpclient.cpp index 267e8c4..9c06f24 100644 --- a/tests/common/qsimplehttpclient.cpp +++ b/tests/common/qsimplehttpclient.cpp @@ -33,10 +33,10 @@ QSimpleHttpClient::QSimpleHttpClient(QTcpSocket *socket) onReadyRead(); } -void QSimpleHttpClient::sendHeaders(const QByteArray &method, const QByteArray &path, const QHttpHeaderMap &headers) +void QSimpleHttpClient::sendHeaders(const QByteArray &method, const QByteArray &path, const QHttpSocket::QHttpHeaderMap &headers) { QByteArray data = method + " " + path + " HTTP/1.0\r\n"; - for(QHttpHeaderMap::const_iterator i = headers.constBegin(); i != headers.constEnd(); ++i) { + for (auto i = headers.constBegin(); i != headers.constEnd(); ++i) { data.append(i.key() + ": " + i.value() + "\r\n"); } data.append("\r\n"); @@ -51,14 +51,14 @@ void QSimpleHttpClient::sendData(const QByteArray &data) void QSimpleHttpClient::onReadyRead() { - if(mHeadersParsed) { + if (mHeadersParsed) { mData.append(mSocket->readAll()); } else { mBuffer.append(mSocket->readAll()); // Parse the headers if the double CRLF sequence was found int index = mBuffer.indexOf("\r\n\r\n"); - if(index != -1) { + if (index != -1) { QHttpParser::parseResponseHeaders(mBuffer.left(index), mStatusCode, mStatusReason, mHeaders); mHeadersParsed = true; diff --git a/tests/common/qsimplehttpclient.h b/tests/common/qsimplehttpclient.h index 4fbce38..00050bb 100644 --- a/tests/common/qsimplehttpclient.h +++ b/tests/common/qsimplehttpclient.h @@ -28,6 +28,7 @@ #include #include +#include /** * @brief Simple HTTP client for testing purposes @@ -44,7 +45,7 @@ public: QSimpleHttpClient(QTcpSocket *socket); - void sendHeaders(const QByteArray &method, const QByteArray &path, const QHttpHeaderMap &headers); + void sendHeaders(const QByteArray &method, const QByteArray &path, const QHttpSocket::QHttpHeaderMap &headers=QHttpSocket::QHttpHeaderMap()); void sendData(const QByteArray &data); int statusCode() const { @@ -55,7 +56,7 @@ public: return mStatusReason; } - QHttpHeaderMap headers() const { + QHttpSocket::QHttpHeaderMap headers() const { return mHeaders; } @@ -76,7 +77,7 @@ private: int mStatusCode; QByteArray mStatusReason; - QHttpHeaderMap mHeaders; + QHttpSocket::QHttpHeaderMap mHeaders; QByteArray mData; };