├── tests ├── auto │ ├── qhttpserverresponse │ │ ├── data │ │ │ ├── empty │ │ │ ├── text.html │ │ │ ├── text.plain │ │ │ ├── application.json │ │ │ ├── image.jpeg │ │ │ ├── image.png │ │ │ └── image.svg │ │ ├── CMakeLists.txt │ │ └── tst_qhttpserverresponse.cpp │ ├── qhttpserver │ │ ├── data │ │ │ ├── text.html │ │ │ └── application.json │ │ ├── BLACKLIST │ │ └── CMakeLists.txt │ ├── qhttpserverresponder │ │ ├── data │ │ │ └── index.html │ │ └── CMakeLists.txt │ ├── qhttpserverrequestfilter │ │ └── CMakeLists.txt │ ├── qhttpserverrouter │ │ └── CMakeLists.txt │ ├── CMakeLists.txt │ ├── qabstracthttpserver │ │ └── CMakeLists.txt │ ├── qhttpservermultithreaded │ │ └── CMakeLists.txt │ └── cmake │ │ └── CMakeLists.txt ├── benchmarks │ ├── CMakeLists.txt │ └── qhttpserver │ │ ├── CMakeLists.txt │ │ └── transfer │ │ ├── CMakeLists.txt │ │ ├── data │ │ ├── localhost.cert │ │ └── localhost.key │ │ └── tst_bench_qhttpserver_transfer.cpp └── CMakeLists.txt ├── .tag ├── examples ├── examples.pro ├── httpserver │ ├── simple │ │ ├── assets │ │ │ ├── qt-logo.png │ │ │ ├── certificate.crt │ │ │ └── private.key │ │ ├── simple.pro │ │ ├── CMakeLists.txt │ │ └── main.cpp │ ├── colorpalette │ │ ├── assets │ │ │ ├── img │ │ │ │ ├── 1-image.jpg │ │ │ │ ├── 10-image.jpg │ │ │ │ ├── 11-image.jpg │ │ │ │ ├── 12-image.jpg │ │ │ │ ├── 2-image.jpg │ │ │ │ ├── 3-image.jpg │ │ │ │ ├── 4-image.jpg │ │ │ │ ├── 5-image.jpg │ │ │ │ ├── 6-image.jpg │ │ │ │ ├── 7-image.jpg │ │ │ │ ├── 8-image.jpg │ │ │ │ └── 9-image.jpg │ │ │ ├── sessions.json │ │ │ ├── colors.json │ │ │ └── users.json │ │ ├── colorpalette.pro │ │ ├── CMakeLists.txt │ │ ├── utils.h │ │ ├── main.cpp │ │ └── apibehavior.h │ ├── CMakeLists.txt │ └── httpserver.pro └── CMakeLists.txt ├── .gitreview ├── doc ├── images │ ├── browserwindow.png │ └── restful-color-palette-server-example.png ├── examples.qdoc ├── qthttpserver-module.qdoc ├── external-resources.qdoc ├── snippets │ └── custom-converter │ │ ├── CMakeLists.txt │ │ └── main.cpp ├── logging.qdoc ├── config │ └── qthttpserver.qdocconf ├── simple-example.qdoc ├── colorpalette-example.qdoc └── index.qdoc ├── dependencies.yaml ├── src ├── CMakeLists.txt └── httpserver │ ├── qthttpserverglobal.h │ ├── qhttpserverliterals_p.h │ ├── qhttpserverliterals.cpp │ ├── qhttpserverrouterrule_p.h │ ├── qhttpserverresponse_p.h │ ├── qhttpserverrouter_p.h │ ├── qhttpserver_p.h │ ├── qhttpserverrequest_p.h │ ├── qhttpserverresponder_p.h │ ├── CMakeLists.txt │ ├── qhttpserverrequestfilter_p.h │ ├── qabstracthttpserver_p.h │ ├── qhttpserverstream.cpp │ ├── qhttpserverstream_p.h │ ├── qhttpserverwebsocketupgraderesponse.h │ ├── qhttpserverconfiguration.h │ ├── qhttpserverresponse.h │ ├── qhttpserverrouter.h │ ├── qhttpserverparser_p.h │ ├── qabstracthttpserver.h │ ├── qhttpserverhttp1protocolhandler_p.h │ ├── qhttpserverviewtraits_impl.h │ ├── qhttpserverhttp2protocolhandler_p.h │ ├── qhttpserverrequest.h │ ├── qhttpserverrequestfilter.cpp │ ├── qhttpserverrouterviewtraits.h │ ├── qhttpserverresponder.h │ ├── qhttpserverwebsocketupgraderesponse.cpp │ ├── qhttpserverrouterrule.h │ ├── qhttpserverresponse.cpp │ └── qhttpserverrequest.cpp ├── .cmake.conf ├── LICENSES ├── LicenseRef-Qt-Commercial.txt └── BSD-3-Clause.txt ├── coin ├── module_config.yaml └── axivion │ └── ci_config_linux.json ├── CMakeLists.txt ├── REUSE.toml └── licenseRule.json /tests/auto/qhttpserverresponse/data/empty: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.tag: -------------------------------------------------------------------------------- 1 | 487b2b266af378a156db37dc97f401b106483ecc 2 | -------------------------------------------------------------------------------- /tests/auto/qhttpserver/data/text.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tests/auto/qhttpserverresponse/data/text.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tests/auto/qhttpserverresponse/data/text.plain: -------------------------------------------------------------------------------- 1 | Hello World! 2 | -------------------------------------------------------------------------------- /tests/auto/qhttpserver/data/application.json: -------------------------------------------------------------------------------- 1 | { "key": "value" } 2 | -------------------------------------------------------------------------------- /tests/auto/qhttpserverresponder/data/index.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tests/auto/qhttpserverresponse/data/application.json: -------------------------------------------------------------------------------- 1 | { "key": "value" } 2 | -------------------------------------------------------------------------------- /examples/examples.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS = \ 4 | httpserver 5 | -------------------------------------------------------------------------------- /.gitreview: -------------------------------------------------------------------------------- 1 | [gerrit] 2 | host=codereview.qt-project.org 3 | project=qt/qthttpserver 4 | defaultbranch=dev 5 | -------------------------------------------------------------------------------- /doc/images/browserwindow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qthttpserver/dev/doc/images/browserwindow.png -------------------------------------------------------------------------------- /examples/httpserver/simple/assets/qt-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qthttpserver/dev/examples/httpserver/simple/assets/qt-logo.png -------------------------------------------------------------------------------- /tests/auto/qhttpserverresponse/data/image.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qthttpserver/dev/tests/auto/qhttpserverresponse/data/image.jpeg -------------------------------------------------------------------------------- /tests/auto/qhttpserverresponse/data/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qthttpserver/dev/tests/auto/qhttpserverresponse/data/image.png -------------------------------------------------------------------------------- /doc/images/restful-color-palette-server-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qthttpserver/dev/doc/images/restful-color-palette-server-example.png -------------------------------------------------------------------------------- /examples/httpserver/colorpalette/assets/img/1-image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qthttpserver/dev/examples/httpserver/colorpalette/assets/img/1-image.jpg -------------------------------------------------------------------------------- /examples/httpserver/colorpalette/assets/img/10-image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qthttpserver/dev/examples/httpserver/colorpalette/assets/img/10-image.jpg -------------------------------------------------------------------------------- /examples/httpserver/colorpalette/assets/img/11-image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qthttpserver/dev/examples/httpserver/colorpalette/assets/img/11-image.jpg -------------------------------------------------------------------------------- /examples/httpserver/colorpalette/assets/img/12-image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qthttpserver/dev/examples/httpserver/colorpalette/assets/img/12-image.jpg -------------------------------------------------------------------------------- /examples/httpserver/colorpalette/assets/img/2-image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qthttpserver/dev/examples/httpserver/colorpalette/assets/img/2-image.jpg -------------------------------------------------------------------------------- /examples/httpserver/colorpalette/assets/img/3-image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qthttpserver/dev/examples/httpserver/colorpalette/assets/img/3-image.jpg -------------------------------------------------------------------------------- /examples/httpserver/colorpalette/assets/img/4-image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qthttpserver/dev/examples/httpserver/colorpalette/assets/img/4-image.jpg -------------------------------------------------------------------------------- /examples/httpserver/colorpalette/assets/img/5-image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qthttpserver/dev/examples/httpserver/colorpalette/assets/img/5-image.jpg -------------------------------------------------------------------------------- /examples/httpserver/colorpalette/assets/img/6-image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qthttpserver/dev/examples/httpserver/colorpalette/assets/img/6-image.jpg -------------------------------------------------------------------------------- /examples/httpserver/colorpalette/assets/img/7-image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qthttpserver/dev/examples/httpserver/colorpalette/assets/img/7-image.jpg -------------------------------------------------------------------------------- /examples/httpserver/colorpalette/assets/img/8-image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qthttpserver/dev/examples/httpserver/colorpalette/assets/img/8-image.jpg -------------------------------------------------------------------------------- /examples/httpserver/colorpalette/assets/img/9-image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qthttpserver/dev/examples/httpserver/colorpalette/assets/img/9-image.jpg -------------------------------------------------------------------------------- /tests/benchmarks/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2024 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | add_subdirectory(qhttpserver) 5 | -------------------------------------------------------------------------------- /tests/benchmarks/qhttpserver/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2024 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | add_subdirectory(transfer) 5 | -------------------------------------------------------------------------------- /examples/httpserver/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | if(TARGET Qt::Gui AND TARGET Qt::Concurrent) 2 | qt_internal_add_example(colorpalette) 3 | endif() 4 | qt_internal_add_example(simple) 5 | -------------------------------------------------------------------------------- /examples/httpserver/httpserver.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS = \ 4 | simple 5 | 6 | qtHaveModule(gui): qtHaveModule(concurrent) { 7 | SUBDIRS += colorpalette 8 | } 9 | -------------------------------------------------------------------------------- /dependencies.yaml: -------------------------------------------------------------------------------- 1 | dependencies: 2 | ../qtbase: 3 | ref: df1292e2b96aab02ad6df778d8336e7958ad5d1c 4 | required: true 5 | ../qtwebsockets: 6 | ref: ecf7bc43c93b4edd49e11e342a9beae900bd0680 7 | required: false 8 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | # Generated from src.pro. 5 | 6 | set(QT_SBOM_DEFAULT_QT_LICENSE_ID_LIBRARIES "QT_COMMERCIAL_OR_GPL3") 7 | 8 | add_subdirectory(httpserver) 9 | -------------------------------------------------------------------------------- /.cmake.conf: -------------------------------------------------------------------------------- 1 | set(QT_REPO_MODULE_VERSION "6.12.0") 2 | set(QT_REPO_MODULE_PRERELEASE_VERSION_SEGMENT "alpha1") 3 | set(QT_EXTRA_INTERNAL_TARGET_DEFINES 4 | "QT_NO_CONTEXTLESS_CONNECT=1" 5 | "QT_NO_FOREACH=1" 6 | "QT_NO_URL_CAST_FROM_STRING=1" 7 | ) 8 | -------------------------------------------------------------------------------- /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | qt_examples_build_begin(EXTERNAL_BUILD) 5 | 6 | add_subdirectory(httpserver) 7 | 8 | qt_examples_build_end() 9 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | # Generated from tests.pro. 5 | 6 | if(QT_BUILD_STANDALONE_TESTS) 7 | # Add qt_find_package calls for extra dependencies that need to be found when building 8 | # the standalone tests here. 9 | endif() 10 | qt_build_tests() 11 | -------------------------------------------------------------------------------- /doc/examples.qdoc: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only 3 | 4 | /*! 5 | \group qthttpserver-examples 6 | \title Qt HTTP Server Examples 7 | \brief Examples of how to use the QtHttpServer module 8 | 9 | The examples below can be used as a guide to using the \l{QtHttpServer} API. 10 | */ 11 | -------------------------------------------------------------------------------- /src/httpserver/qthttpserverglobal.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | // Qt-Security score:significant reason:default 4 | 5 | #ifndef QTHTTPSERVERGLOBAL_H 6 | #define QTHTTPSERVERGLOBAL_H 7 | 8 | #include 9 | #include 10 | 11 | #endif // QTHTTPSERVERGLOBAL_H 12 | 13 | -------------------------------------------------------------------------------- /doc/qthttpserver-module.qdoc: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only 3 | /*! 4 | \module QtHttpServer 5 | \title Qt HTTP Server C++ Classes 6 | \ingroup modules 7 | \qtcmakepackage HttpServer 8 | \qtvariable httpserver 9 | \since 6.4 10 | \brief List of C++ classes that provide HTTP server framework. 11 | 12 | */ 13 | -------------------------------------------------------------------------------- /examples/httpserver/simple/simple.pro: -------------------------------------------------------------------------------- 1 | requires(qtHaveModule(httpserver)) 2 | 3 | TEMPLATE = app 4 | 5 | CONFIG += cmdline 6 | QT = httpserver 7 | android: QT += gui 8 | 9 | SOURCES += \ 10 | main.cpp 11 | 12 | target.path = $$[QT_INSTALL_EXAMPLES]/httpserver/simple 13 | INSTALLS += target 14 | 15 | RESOURCES += \ 16 | assets/certificate.crt \ 17 | assets/private.key \ 18 | assets/qt-logo.png 19 | 20 | CONFIG += cmdline 21 | -------------------------------------------------------------------------------- /doc/external-resources.qdoc: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only 3 | 4 | /*! 5 | \externalpage https://datatracker.ietf.org/doc/html/rfc2616 6 | \title RFC 2616 7 | */ 8 | 9 | /*! 10 | \externalpage https://datatracker.ietf.org/doc/html/rfc7617 11 | \title RFC 7617 12 | */ 13 | 14 | /*! 15 | \externalpage https://datatracker.ietf.org/doc/html/rfc9113 16 | \title RFC 9113 17 | */ 18 | -------------------------------------------------------------------------------- /doc/snippets/custom-converter/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | cmake_minimum_required(VERSION 3.16) 5 | project(custom-converter LANGUAGES CXX) 6 | 7 | find_package(Qt6 REQUIRED COMPONENTS HttpServer) 8 | 9 | qt_standard_project_setup() 10 | 11 | qt_add_executable(custom-converter 12 | main.cpp 13 | ) 14 | 15 | target_link_libraries(custom-converter PRIVATE 16 | Qt6::HttpServer 17 | ) 18 | -------------------------------------------------------------------------------- /tests/auto/qhttpserverrequestfilter/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2024 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | ##################################################################### 5 | ## tst_qhttpserverrequestfilter Test: 6 | ##################################################################### 7 | 8 | qt_internal_add_test(tst_qhttpserverrequestfilter 9 | SOURCES 10 | tst_qhttpserverrequestfilter.cpp 11 | LIBRARIES 12 | Qt::HttpServerPrivate 13 | ) 14 | -------------------------------------------------------------------------------- /LICENSES/LicenseRef-Qt-Commercial.txt: -------------------------------------------------------------------------------- 1 | Licensees holding valid commercial Qt licenses may use this software in 2 | accordance with the the terms contained in a written agreement between 3 | you and The Qt Company. Alternatively, the terms and conditions that were 4 | accepted by the licensee when buying and/or downloading the 5 | software do apply. 6 | 7 | For the latest licensing terms and conditions, see https://www.qt.io/terms-conditions. 8 | For further information use the contact form at https://www.qt.io/contact-us. 9 | -------------------------------------------------------------------------------- /coin/module_config.yaml: -------------------------------------------------------------------------------- 1 | version: 2 2 | accept_configuration: 3 | condition: property 4 | property: features 5 | not_contains_value: Disable 6 | 7 | instructions: 8 | Build: 9 | - type: EnvironmentVariable 10 | variableName: VERIFY_SOURCE_SBOM 11 | variableValue: "ON" 12 | - !include "{{qt/qtbase}}/coin_module_build_template_v2.yaml" 13 | 14 | Test: 15 | - !include "{{qt/qtbase}}/coin_module_test_template_v3.yaml" 16 | - !include "{{qt/qtbase}}/coin_module_test_docs.yaml" 17 | -------------------------------------------------------------------------------- /tests/auto/qhttpserverrouter/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | # Generated from qhttpserverrouter.pro. 5 | 6 | ##################################################################### 7 | ## tst_qhttpserverrouter Test: 8 | ##################################################################### 9 | 10 | qt_internal_add_test(tst_qhttpserverrouter 11 | SOURCES 12 | tst_qhttpserverrouter.cpp 13 | LIBRARIES 14 | Qt::HttpServer 15 | ) 16 | -------------------------------------------------------------------------------- /tests/benchmarks/qhttpserver/transfer/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2024 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | qt_internal_add_benchmark(tst_bench_qhttpserver_transfer 5 | SOURCES 6 | tst_bench_qhttpserver_transfer.cpp 7 | LIBRARIES 8 | Qt::HttpServer 9 | Qt::Test 10 | ) 11 | 12 | qt_add_resources(tst_bench_qhttpserver_transfer "certs" 13 | PREFIX "/cert" 14 | BASE "data/" 15 | FILES 16 | "data/localhost.cert" 17 | "data/localhost.key" 18 | ) 19 | -------------------------------------------------------------------------------- /tests/auto/qhttpserver/BLACKLIST: -------------------------------------------------------------------------------- 1 | # QTBUG-103712 2 | [routeGet:hello world, ssl] 3 | android 4 | [routeGet:post-and-get, get, ssl] 5 | android 6 | [routeGet:invalid-rule-method, get, ssl] 7 | android 8 | [routeGet:check custom type, data=1, ssl] 9 | android 10 | [routePost:post-and-get, post, ssl] 11 | android 12 | [routePost:any, post, ssl] 13 | android 14 | [routePost:post-body, ssl] 15 | android 16 | [routePost:post-body - huge body, chunk test, ssl] 17 | android 18 | [routeDelete:post-and-get, delete, ssl] 19 | android 20 | [routeDelete:any, delete, ssl] 21 | android 22 | -------------------------------------------------------------------------------- /tests/auto/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | # Generated from auto.pro. 5 | 6 | add_subdirectory(cmake) 7 | add_subdirectory(qhttpserver) 8 | if (QT_FEATURE_concurrent) 9 | add_subdirectory(qhttpservermultithreaded) 10 | endif() 11 | add_subdirectory(qhttpserverresponder) 12 | add_subdirectory(qhttpserverrouter) 13 | add_subdirectory(qhttpserverresponse) 14 | if(QT_FEATURE_private_tests) 15 | add_subdirectory(qabstracthttpserver) 16 | add_subdirectory(qhttpserverrequestfilter) 17 | endif() 18 | -------------------------------------------------------------------------------- /tests/auto/qabstracthttpserver/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | # Generated from qabstracthttpserver.pro. 5 | 6 | ##################################################################### 7 | ## tst_qabstracthttpserver Test: 8 | ##################################################################### 9 | 10 | qt_internal_add_test(tst_qabstracthttpserver 11 | SOURCES 12 | tst_qabstracthttpserver.cpp 13 | LIBRARIES 14 | Qt::HttpServer 15 | Qt::NetworkPrivate 16 | Qt::TestPrivate 17 | ) 18 | -------------------------------------------------------------------------------- /tests/auto/qhttpservermultithreaded/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2024 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | ##################################################################### 5 | ## tst_qhttpservermultithreaded Test: 6 | ##################################################################### 7 | 8 | qt_internal_add_test(tst_qhttpservermultithreaded 9 | DEFINES 10 | QTEST_THROW_ON_FAIL 11 | QTEST_THROW_ON_SKIP 12 | SOURCES 13 | tst_qhttpservermultithreaded.cpp 14 | LIBRARIES 15 | Qt::HttpServer Qt::Concurrent Qt::TestPrivate 16 | ) 17 | -------------------------------------------------------------------------------- /tests/auto/qhttpserverresponse/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | # Generated from qhttpserverresponse.pro. 5 | 6 | ##################################################################### 7 | ## tst_qhttpserverresponse Test: 8 | ##################################################################### 9 | 10 | # Collect test data 11 | list(APPEND test_data "data/") 12 | 13 | qt_internal_add_test(tst_qhttpserverresponse 14 | SOURCES 15 | tst_qhttpserverresponse.cpp 16 | LIBRARIES 17 | Qt::HttpServer 18 | TESTDATA ${test_data} 19 | ) 20 | -------------------------------------------------------------------------------- /tests/auto/qhttpserverresponder/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | # Generated from qhttpserverresponder.pro. 5 | 6 | ##################################################################### 7 | ## tst_qhttpserverresponder Test: 8 | ##################################################################### 9 | 10 | # Collect test data 11 | list(APPEND test_data "data/") 12 | 13 | qt_internal_add_test(tst_qhttpserverresponder 14 | SOURCES 15 | tst_qhttpserverresponder.cpp 16 | LIBRARIES 17 | Qt::HttpServer 18 | TESTDATA ${test_data} 19 | ) 20 | -------------------------------------------------------------------------------- /tests/auto/qhttpserver/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | # Generated from qhttpserver.pro. 5 | 6 | ##################################################################### 7 | ## tst_qhttpserver Test: 8 | ##################################################################### 9 | 10 | # Collect test data 11 | list(APPEND test_data "data/") 12 | 13 | qt_internal_add_test(tst_qhttpserver 14 | SOURCES 15 | tst_qhttpserver.cpp 16 | LIBRARIES 17 | Qt::HttpServer 18 | Qt::TestPrivate 19 | TESTDATA ${test_data} 20 | ) 21 | 22 | qt_internal_extend_target(tst_qhttpserver CONDITION QT_FEATURE_concurrent 23 | LIBRARIES 24 | Qt::Concurrent 25 | ) 26 | -------------------------------------------------------------------------------- /examples/httpserver/colorpalette/assets/sessions.json: -------------------------------------------------------------------------------- 1 | [ 2 | {"email":"rest.native@qt.io","password":"apassword"}, 3 | {"email":"chief.architect@qt.io","password":"apassword"}, 4 | {"email":"rising.star@qt.io","password":"apassword"}, 5 | {"email":"creative.wizard@qt.io","password":"apassword"}, 6 | {"email":"knuth.developer@qt.io","password":"apassword"}, 7 | {"email":"white.hathacker@qt.io","password":"apassword"}, 8 | {"email":"kind.programmer@qt.io","password":"apassword"}, 9 | {"email":"server.monk@qt.io","password":"apassword"}, 10 | {"email":"fast.fingers@qt.io","password":"apassword"}, 11 | {"email":"runtime.lord@qt.io","password":"apassword"}, 12 | {"email":"stack.flow@qt.io","password":"apassword"}, 13 | {"email":"cute.coder@qt.io","password":"apassword"} 14 | ] 15 | -------------------------------------------------------------------------------- /src/httpserver/qhttpserverliterals_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 Mikhail Svetkin 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | // Qt-Security score:significant reason:default 4 | 5 | #ifndef QHTTPSERVERLITERALS_P_H 6 | #define QHTTPSERVERLITERALS_P_H 7 | 8 | // 9 | // W A R N I N G 10 | // ------------- 11 | // 12 | // This file is not part of the Qt API. It exists for the convenience 13 | // of QHttpServer. This header file may change from version to 14 | // version without notice, or even be removed. 15 | // 16 | // We mean it. 17 | 18 | #include 19 | 20 | #include 21 | 22 | QT_BEGIN_NAMESPACE 23 | 24 | namespace QHttpServerLiterals { 25 | 26 | QByteArray contentTypeXEmpty(); 27 | QByteArray contentTypeTextHtml(); 28 | QByteArray contentTypeJson(); 29 | 30 | } 31 | 32 | QT_END_NAMESPACE 33 | 34 | #endif // QHTTPSERVERLITERALS_P_H 35 | -------------------------------------------------------------------------------- /examples/httpserver/colorpalette/assets/colors.json: -------------------------------------------------------------------------------- 1 | [{"name":"cerulean","year":2000,"color":"#98B2D1","pantone_value":"15-4020"},{"name":"fuchsia rose","year":2001,"color":"#C74375","pantone_value":"17-2031"},{"name":"true red","year":2002,"color":"#BF1932","pantone_value":"19-1664"},{"name":"aqua sky","year":2003,"color":"#7BC4C4","pantone_value":"14-4811"},{"name":"tigerlily","year":2004,"color":"#E2583E","pantone_value":"17-1456"},{"name":"blue turquoise","year":2005,"color":"#53B0AE","pantone_value":"15-5217"},{"name":"sand dollar","year":2006,"color":"#DECDBE","pantone_value":"13-1106"},{"name":"chili pepper","year":2007,"color":"#9B1B30","pantone_value":"19-1557"},{"name":"blue iris","year":2008,"color":"#5A5B9F","pantone_value":"18-3943"},{"name":"mimosa","year":2009,"color":"#F0C05A","pantone_value":"14-0848"},{"name":"turquoise","year":2010,"color":"#45B5AA","pantone_value":"15-5519"},{"name":"honeysuckle","year":2011,"color":"#D94F70","pantone_value":"18-2120"}] 2 | -------------------------------------------------------------------------------- /examples/httpserver/colorpalette/colorpalette.pro: -------------------------------------------------------------------------------- 1 | requires(qtHaveModule(httpserver)) 2 | requires(qtHaveModule(gui)) 3 | requires(qtHaveModule(concurrent)) 4 | 5 | TEMPLATE = app 6 | 7 | QT += httpserver gui concurrent 8 | 9 | SOURCES += \ 10 | main.cpp 11 | 12 | HEADERS += \ 13 | apibehavior.h \ 14 | types.h \ 15 | utils.h 16 | 17 | target.path = $$[QT_INSTALL_EXAMPLES]/httpserver/colorpalette 18 | INSTALLS += target 19 | 20 | RESOURCES += \ 21 | assets/colors.json \ 22 | assets/users.json \ 23 | assets/sessions.json \ 24 | assets/img/1-image.jpg \ 25 | assets/img/2-image.jpg \ 26 | assets/img/3-image.jpg \ 27 | assets/img/4-image.jpg \ 28 | assets/img/5-image.jpg \ 29 | assets/img/6-image.jpg \ 30 | assets/img/7-image.jpg \ 31 | assets/img/8-image.jpg \ 32 | assets/img/9-image.jpg \ 33 | assets/img/10-image.jpg \ 34 | assets/img/11-image.jpg \ 35 | assets/img/12-image.jpg 36 | 37 | CONFIG += cmdline 38 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | # Generated from qthttpserver.pro. 5 | 6 | cmake_minimum_required(VERSION 3.16) 7 | 8 | include(.cmake.conf) 9 | project(QtHttpServer 10 | VERSION "${QT_REPO_MODULE_VERSION}" 11 | DESCRIPTION "Qt HTTP Server" 12 | HOMEPAGE_URL "https://qt.io/" 13 | LANGUAGES CXX C 14 | ) 15 | 16 | find_package(Qt6 ${PROJECT_VERSION} CONFIG REQUIRED COMPONENTS BuildInternals) 17 | 18 | # This should be called as early as possible, just after find_package(BuildInternals) where it is 19 | # defined. 20 | qt_internal_project_setup() 21 | 22 | find_package(Qt6 ${PROJECT_VERSION} CONFIG REQUIRED COMPONENTS Core Network) 23 | find_package(Qt6 ${PROJECT_VERSION} CONFIG OPTIONAL_COMPONENTS Concurrent WebSockets Gui) 24 | if(NOT QT_FEATURE_mimetype) 25 | message(NOTICE "QHttpServer mimetype-dependency missing, skipping build") 26 | return() 27 | endif() 28 | 29 | qt_build_repo() 30 | -------------------------------------------------------------------------------- /src/httpserver/qhttpserverliterals.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 Mikhail Svetkin 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | // Qt-Security score:significant reason:default 4 | 5 | #include "qhttpserverliterals_p.h" 6 | 7 | #include 8 | 9 | QT_BEGIN_NAMESPACE 10 | 11 | // Don't use QByteArrayLiteral, as this library may be unloaded before all 12 | // references to the data are destroyed - by allocating on the heap, the last 13 | // user will free the data instead of referencing unloaded data 14 | 15 | QByteArray QHttpServerLiterals::contentTypeXEmpty() 16 | { 17 | static QByteArray ba("application/x-empty"); 18 | return ba; 19 | } 20 | 21 | QByteArray QHttpServerLiterals::contentTypeTextHtml() 22 | { 23 | static QByteArray ba("text/html"); 24 | return ba; 25 | } 26 | 27 | QByteArray QHttpServerLiterals::contentTypeJson() 28 | { 29 | static QByteArray ba("application/json"); 30 | return ba; 31 | } 32 | 33 | QT_END_NAMESPACE 34 | -------------------------------------------------------------------------------- /src/httpserver/qhttpserverrouterrule_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | // Qt-Security score:significant reason:default 4 | 5 | #ifndef QHTTPSERVERROUTERRULE_P_H 6 | #define QHTTPSERVERROUTERRULE_P_H 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | // 15 | // W A R N I N G 16 | // ------------- 17 | // 18 | // This file is not part of the Qt API. It exists for the convenience 19 | // of QHttpServer. This header file may change from version to 20 | // version without notice, or even be removed. 21 | // 22 | // We mean it. 23 | 24 | QT_BEGIN_NAMESPACE 25 | 26 | class QHttpServerRouterRulePrivate 27 | { 28 | public: 29 | QString pathPattern; 30 | QHttpServerRequest::Methods methods; 31 | QtPrivate::SlotObjUniquePtr routerHandler; 32 | QPointer context; 33 | 34 | QRegularExpression pathRegexp; 35 | }; 36 | 37 | QT_END_NAMESPACE 38 | 39 | #endif // QHTTPSERVERROUTERRULE_P_H 40 | -------------------------------------------------------------------------------- /coin/axivion/ci_config_linux.json: -------------------------------------------------------------------------------- 1 | { 2 | "Project": { 3 | "BuildSystemIntegration": { 4 | "child_order": [ 5 | "GCCSetup", 6 | "CMake", 7 | "LinkLibraries" 8 | ] 9 | }, 10 | "CMake": { 11 | "_active": true, 12 | "_copy_from": "CMakeIntegration", 13 | "build_environment": {}, 14 | "build_options": "-j4", 15 | "generate_options": "--fresh", 16 | "generator": "Ninja" 17 | }, 18 | "GCCSetup": { 19 | "_active": true, 20 | "_copy_from": "Command", 21 | "build_command": "gccsetup --cc gcc --cxx g++ --config ../../../axivion/" 22 | }, 23 | "LinkLibraries": { 24 | "_active": true, 25 | "_copy_from": "AxivionLinker", 26 | "input_files": [ 27 | "build/lib/lib*.so*.ir" 28 | ], 29 | "ir": "build/$(env:TESTED_MODULE_COIN).ir" 30 | } 31 | }, 32 | "_Format": "1.0", 33 | "_Version": "7.6.2", 34 | "_VersionNum": [ 35 | 7, 36 | 6, 37 | 2, 38 | 12725 39 | ] 40 | } 41 | -------------------------------------------------------------------------------- /src/httpserver/qhttpserverresponse_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | // Qt-Security score:significant reason:default 4 | 5 | #ifndef QHTTPSERVERRESPONSE_P_H 6 | #define QHTTPSERVERRESPONSE_P_H 7 | 8 | // 9 | // W A R N I N G 10 | // ------------- 11 | // 12 | // This file is not part of the Qt API. It exists for the convenience 13 | // of QHttpServerResponse. This header file may change from version to 14 | // version without notice, or even be removed. 15 | // 16 | // We mean it. 17 | 18 | #include 19 | 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | 26 | QT_BEGIN_NAMESPACE 27 | 28 | class QHttpServerResponsePrivate 29 | { 30 | public: 31 | QHttpServerResponsePrivate(QByteArray &&d, const QHttpServerResponse::StatusCode sc); 32 | QHttpServerResponsePrivate(const QHttpServerResponse::StatusCode sc); 33 | 34 | QByteArray data; 35 | QHttpServerResponse::StatusCode statusCode; 36 | QHttpHeaders headers; 37 | }; 38 | 39 | QT_END_NAMESPACE 40 | 41 | #endif // QHTTPSERVERRESPONSE_P_H 42 | -------------------------------------------------------------------------------- /examples/httpserver/simple/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | cmake_minimum_required(VERSION 3.16) 5 | project(simple LANGUAGES CXX) 6 | 7 | if(NOT DEFINED INSTALL_EXAMPLESDIR) 8 | set(INSTALL_EXAMPLESDIR "examples") 9 | endif() 10 | 11 | set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/httpserver/${PROJECT_NAME}") 12 | 13 | find_package(Qt6 REQUIRED COMPONENTS HttpServer) 14 | 15 | if(ANDROID) 16 | find_package(Qt6 REQUIRED COMPONENTS Gui) 17 | endif() 18 | 19 | qt_standard_project_setup() 20 | 21 | qt_add_executable(simple 22 | main.cpp 23 | ) 24 | 25 | target_link_libraries(simple PRIVATE 26 | Qt6::HttpServer 27 | ) 28 | 29 | if(ANDROID) 30 | target_link_libraries(simple PRIVATE 31 | Qt::Gui 32 | ) 33 | endif() 34 | 35 | qt_add_resources(simple "assets" 36 | PREFIX 37 | "/" 38 | FILES 39 | assets/certificate.crt 40 | assets/private.key 41 | assets/qt-logo.png 42 | ) 43 | 44 | install(TARGETS simple 45 | RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" 46 | BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" 47 | LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" 48 | ) 49 | -------------------------------------------------------------------------------- /src/httpserver/qhttpserverrouter_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | // Qt-Security score:significant reason:default 4 | 5 | #ifndef QHTTPSERVERROUTER_P_H 6 | #define QHTTPSERVERROUTER_P_H 7 | 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | // 18 | // W A R N I N G 19 | // ------------- 20 | // 21 | // This file is not part of the Qt API. It exists for the convenience 22 | // of QHttpServer. This header file may change from version to 23 | // version without notice, or even be removed. 24 | // 25 | // We mean it. 26 | 27 | QT_BEGIN_NAMESPACE 28 | 29 | class QHttpServerRouterPrivate 30 | { 31 | public: 32 | QHttpServerRouterPrivate(QAbstractHttpServer *server); 33 | 34 | QHash converters; 35 | std::vector> rules; 36 | QAbstractHttpServer *server; 37 | 38 | bool verifyThreadAffinity(const QObject *contextObject) const; 39 | }; 40 | 41 | QT_END_NAMESPACE 42 | 43 | #endif // QHTTPSERVERROUTER_P_H 44 | -------------------------------------------------------------------------------- /doc/snippets/custom-converter/main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | //! [Define class] 14 | struct CustomArg { 15 | int data = 10; 16 | 17 | CustomArg() {} ; 18 | CustomArg(const QString &urlArg) : data(urlArg.toInt()) {} 19 | }; 20 | //! [Define class] 21 | 22 | int main(int argc, char *argv[]) 23 | { 24 | QCoreApplication app(argc, argv); 25 | QHttpServer server; 26 | auto tcpServer = std::make_unique(); 27 | if (!tcpServer->listen(QHostAddress::Any, 1999) || !server.bind(tcpServer.get())) { 28 | qWarning() << "Server failed to listen on port 1999."; 29 | return -1; 30 | } 31 | tcpServer.release(); 32 | 33 | //! [Add converter and route] 34 | server.router()->addConverter(u"[+-]?\\d+"); 35 | server.route("/customTest/", [] (const CustomArg custom) { return QString::number(custom.data); }); 36 | //! [Add converter and route] 37 | 38 | qInfo().noquote() << "Server listening on port 1999."; 39 | 40 | return app.exec(); 41 | } 42 | -------------------------------------------------------------------------------- /examples/httpserver/colorpalette/assets/users.json: -------------------------------------------------------------------------------- 1 | [ 2 | {"email":"rest.native@qt.io","first_name":"Rest","last_name":"Native","avatar":"/img/faces/1-image.jpg"}, 3 | {"email":"chief.architect@qt.io","first_name":"Chief","last_name":"Architect","avatar":"/img/faces/2-image.jpg"}, 4 | {"email":"rising.star@qt.io","first_name":"Rising","last_name":"Star","avatar":"/img/faces/3-image.jpg"}, 5 | {"email":"creative.wizard@qt.io","first_name":"Creative","last_name":"Wizard","avatar":"/img/faces/4-image.jpg"}, 6 | {"email":"knuth.developer@qt.io","first_name":"Knuth","last_name":"Developer","avatar":"/img/faces/5-image.jpg"}, 7 | {"email":"white.hathacker@qt.io","first_name":"White","last_name":"Hathacker","avatar":"/img/faces/6-image.jpg"}, 8 | {"email":"kind.programmer@qt.io","first_name":"Kind","last_name":"Programmer","avatar":"/img/faces/7-image.jpg"}, 9 | {"email":"server.monk@qt.io","first_name":"Server","last_name":"Monk","avatar":"/img/faces/8-image.jpg"}, 10 | {"email":"fast.fingers@qt.io","first_name":"Fast","last_name":"Fingers","avatar":"/img/faces/9-image.jpg"}, 11 | {"email":"runtime.lord@qt.io","first_name":"Runtime","last_name":"Lord","avatar":"/img/faces/10-image.jpg"}, 12 | {"email":"stack.flow@qt.io","first_name":"Stack","last_name":"Flow","avatar":"/img/faces/11-image.jpg"}, 13 | {"email":"cute.coder@qt.io","first_name":"Cute","last_name":"Coder","avatar":"/img/faces/12-image.jpg"} 14 | ] 15 | -------------------------------------------------------------------------------- /LICENSES/BSD-3-Clause.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) . 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 | 5 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 7 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 8 | 9 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 10 | -------------------------------------------------------------------------------- /examples/httpserver/colorpalette/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | cmake_minimum_required(VERSION 3.16) 5 | project(colorpaletteserver LANGUAGES CXX) 6 | 7 | if(NOT DEFINED INSTALL_EXAMPLESDIR) 8 | set(INSTALL_EXAMPLESDIR "examples") 9 | endif() 10 | 11 | set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/httpserver/${PROJECT_NAME}") 12 | 13 | find_package(Qt6 REQUIRED COMPONENTS HttpServer Gui Concurrent) 14 | 15 | qt_standard_project_setup() 16 | 17 | qt_add_executable(colorpaletteserver 18 | apibehavior.h 19 | types.h 20 | utils.h 21 | main.cpp 22 | ) 23 | 24 | qt_add_resources(colorpaletteserver "assets" 25 | PREFIX "/" 26 | FILES 27 | assets/colors.json 28 | assets/users.json 29 | assets/sessions.json 30 | assets/img/1-image.jpg 31 | assets/img/2-image.jpg 32 | assets/img/3-image.jpg 33 | assets/img/4-image.jpg 34 | assets/img/5-image.jpg 35 | assets/img/6-image.jpg 36 | assets/img/7-image.jpg 37 | assets/img/8-image.jpg 38 | assets/img/9-image.jpg 39 | assets/img/10-image.jpg 40 | assets/img/11-image.jpg 41 | assets/img/12-image.jpg 42 | ) 43 | 44 | target_link_libraries(colorpaletteserver PRIVATE 45 | Qt::HttpServer 46 | Qt::Gui 47 | Qt::Concurrent 48 | ) 49 | 50 | install(TARGETS colorpaletteserver 51 | RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" 52 | BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" 53 | LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" 54 | ) 55 | -------------------------------------------------------------------------------- /src/httpserver/qhttpserver_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | // Qt-Security score:significant reason:default 4 | 5 | #ifndef QHTTPSERVER_P_H 6 | #define QHTTPSERVER_P_H 7 | 8 | // 9 | // W A R N I N G 10 | // ------------- 11 | // 12 | // This file is not part of the Qt API. It exists for the convenience 13 | // of QHttpServer. This header file may change from version to 14 | // version without notice, or even be removed. 15 | // 16 | // We mean it. 17 | 18 | #include 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | 27 | #include 28 | 29 | QT_BEGIN_NAMESPACE 30 | 31 | class QHttpServerPrivate: public QAbstractHttpServerPrivate 32 | { 33 | Q_DECLARE_PUBLIC(QHttpServer) 34 | 35 | public: 36 | QHttpServerPrivate(QHttpServer *p); 37 | 38 | QHttpServerRouter router; 39 | struct AfterRequestHandler 40 | { 41 | QPointer context; 42 | QtPrivate::SlotObjUniquePtr slotObject; 43 | }; 44 | std::vector afterRequestHandlers; 45 | struct MissingHandler 46 | { 47 | QPointer context = nullptr; 48 | QtPrivate::SlotObjUniquePtr slotObject; 49 | } missingHandler; 50 | 51 | void callMissingHandler(const QHttpServerRequest &request, QHttpServerResponder &responder); 52 | }; 53 | 54 | QT_END_NAMESPACE 55 | 56 | #endif // QHTTPSERVER_P_H 57 | -------------------------------------------------------------------------------- /tests/auto/cmake/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | # This is an automatic test for the CMake configuration files. 5 | # To run it manually, 6 | # 1) mkdir build # Create a build directory 7 | # 2) cd build 8 | # 3) # Run cmake on this directory 9 | # `$qt_prefix/bin/qt-cmake ..` or `cmake -DCMAKE_PREFIX_PATH=/path/to/qt ..` 10 | # 4) ctest # Run ctest 11 | 12 | cmake_minimum_required(VERSION 3.16) 13 | project(httpserver_cmake_tests) 14 | enable_testing() 15 | 16 | set(required_packages Core HttpServer) 17 | 18 | # Setup the test when called as a completely standalone project. 19 | if(TARGET Qt6::Core) 20 | # Tests are built as part of the repository's build tree. 21 | # Setup paths so that the Qt packages are found. 22 | qt_internal_set_up_build_dir_package_paths() 23 | endif() 24 | 25 | find_package(Qt6 REQUIRED COMPONENTS ${required_packages}) 26 | 27 | # Setup common test variables which were previously set by ctest_testcase_common.prf. 28 | set(CMAKE_MODULES_UNDER_TEST "${required_packages}") 29 | 30 | foreach(qt_package ${CMAKE_MODULES_UNDER_TEST}) 31 | set(package_name "${QT_CMAKE_EXPORT_NAMESPACE}${qt_package}") 32 | if(${package_name}_FOUND) 33 | set(CMAKE_${qt_package}_MODULE_MAJOR_VERSION "${${package_name}_VERSION_MAJOR}") 34 | set(CMAKE_${qt_package}_MODULE_MINOR_VERSION "${${package_name}_VERSION_MINOR}") 35 | set(CMAKE_${qt_package}_MODULE_PATCH_VERSION "${${package_name}_VERSION_PATCH}") 36 | endif() 37 | endforeach() 38 | 39 | include("${_Qt6CTestMacros}") 40 | 41 | set(module_includes 42 | HttpServer QHttpServer 43 | ) 44 | 45 | _qt_internal_test_module_includes( 46 | ${module_includes} 47 | ) 48 | -------------------------------------------------------------------------------- /src/httpserver/qhttpserverrequest_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | // Qt-Security score:significant reason:default 4 | 5 | #ifndef QHTTPSERVERREQUEST_P_H 6 | #define QHTTPSERVERREQUEST_P_H 7 | 8 | #include 9 | 10 | #include 11 | 12 | // 13 | // W A R N I N G 14 | // ------------- 15 | // 16 | // This file is not part of the Qt API. It exists for the convenience 17 | // of QHttpServer. This header file may change from version to 18 | // version without notice, or even be removed. 19 | // 20 | // We mean it. 21 | 22 | QT_BEGIN_NAMESPACE 23 | 24 | class QHttp2Stream; 25 | 26 | class QHttpServerRequestPrivate : public QSharedData 27 | { 28 | friend class QHttpServerParser; 29 | 30 | public: 31 | QHttpServerRequestPrivate(const QHostAddress &remoteAddress, quint16 remotePort, 32 | const QHostAddress &localAddress, quint16 localPort); 33 | #if QT_CONFIG(ssl) 34 | QHttpServerRequestPrivate(const QHostAddress &remoteAddress, quint16 remotePort, 35 | const QHostAddress &localAddress, quint16 localPort, 36 | const QSslConfiguration &sslConfiguration); 37 | #endif 38 | QHttpServerRequestPrivate() = default; 39 | QHttpServerRequestPrivate(const QHttpServerRequestPrivate &other) = default; 40 | 41 | QUrl url; 42 | QHttpServerRequest::Method method; 43 | QHttpHeaders headers; 44 | 45 | qint64 contentLength() const; 46 | 47 | QHostAddress remoteAddress; 48 | quint16 remotePort; 49 | QHostAddress localAddress; 50 | quint16 localPort; 51 | int majorVersion; 52 | int minorVersion; 53 | #if QT_CONFIG(ssl) 54 | QSslConfiguration sslConfiguration; 55 | #endif 56 | QByteArray body; 57 | }; 58 | 59 | QT_END_NAMESPACE 60 | 61 | #endif // QHTTPSERVERREQUEST_P_H 62 | -------------------------------------------------------------------------------- /doc/logging.qdoc: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only 3 | 4 | /*! 5 | \page qthttpserver-logging.html 6 | \title Qt HTTP Server Logging 7 | \brief Shows how the QtHttpServer module logging can be configured. 8 | 9 | The Qt HTTP Server logs using the \l {QLoggingCategory} {QLoggingCategory} 10 | class. The logging categories starting with \c "qt.httpserver" are used by 11 | the different parts of the Qt Http Server. These can be enabled and disabled 12 | as described in \l{QLoggingCategory}. 13 | 14 | To dynamically enable or disable what is being logged call 15 | \l {QLoggingCategory::setFilterRules()}. A server can add a URL to change 16 | the filter rules, by using the \l QHttpServer::route() function as shown below. 17 | 18 | \code 19 | #include 20 | #include 21 | #include 22 | 23 | int main(int argc, char** argv) 24 | { 25 | QCoreApplication app(argc, argv); 26 | QHttpServer server; 27 | auto tcpserver = std::make_unique(); 28 | if (!tcpserver->listen(QHostAddress::LocalHost, 8000) || !server.bind(tcpserver.get())) 29 | return -1; 30 | tcpserver.release(); 31 | 32 | server.route("/loggingFilter", [] (const QHttpServerRequest &request) { 33 | QString filter; 34 | QTextStream result(&filter); 35 | for (auto pair : request.query().queryItems()) { 36 | if (!filter.isEmpty()) 37 | result << "\n"; 38 | result << pair.first << "=" << pair.second; 39 | } 40 | QLoggingCategory::setFilterRules(filter); 41 | return filter; 42 | }); 43 | 44 | return app.exec(); 45 | } 46 | \endcode 47 | 48 | The filter rules can now be set using: \c 49 | {"http://127.0.0.1:8000/loggingFilter?qt.httpserver=true&appname.access=true"}. 50 | In this case all Qt HTTP Server logging will be enabled, and in addition the 51 | hypothetical logging category \c{appname.access} is enabled. 52 | 53 | \sa QLoggingCategory, QHttpServer 54 | */ 55 | -------------------------------------------------------------------------------- /doc/config/qthttpserver.qdocconf: -------------------------------------------------------------------------------- 1 | include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf) 2 | include($QT_INSTALL_DOCS/global/externalsites.qdocconf) 3 | 4 | project = QtHttpServer 5 | description = Qt Lightweight HTTP Server Reference Documentation 6 | version = $QT_VERSION 7 | 8 | depends += qtcore qtnetwork qtwebsockets qtdoc qmake qtcmake 9 | 10 | headerdirs += ../../src/httpserver 11 | 12 | sourcedirs += .. \ 13 | ../../src/httpserver 14 | 15 | exampledirs += \ 16 | ../../examples/httpserver/ \ 17 | ../snippets 18 | 19 | imagedirs += ../images 20 | 21 | examplesinstallpath = httpserver 22 | 23 | defines += QT_WEBSOCKETS_LIB 24 | 25 | qhp.projects = QtHttpServer 26 | 27 | qhp.QtHttpServer.file = qthttpserver.qhp 28 | qhp.QtHttpServer.namespace = org.qt-project.qthttpserver.$QT_VERSION_TAG 29 | qhp.QtHttpServer.virtualFolder = QtHttpServer 30 | qhp.QtHttpServer.indexTitle = Qt HTTP Server 31 | qhp.QtHttpServer.indexRoot = 32 | 33 | qhp.QtHttpServer.subprojects = logging examples classes 34 | 35 | qhp.QtHttpServer.subprojects.classes.title = C++ Classes 36 | qhp.QtHttpServer.subprojects.classes.indexTitle = Qt HTTP Server C++ Classes 37 | qhp.QtHttpServer.subprojects.classes.selectors = class fake:headerfile 38 | qhp.QtHttpServer.subprojects.classes.sortPages = true 39 | 40 | qhp.QtHttpServer.subprojects.examples.title = Examples 41 | qhp.QtHttpServer.subprojects.examples.indexTitle = Qt HTTP Server Examples 42 | qhp.QtHttpServer.subprojects.examples.selectors = example 43 | qhp.QtHttpServer.subprojects.examples.sortPages = true 44 | 45 | qhp.QtHttpServer.subprojects.logging.title = Logging 46 | qhp.QtHttpServer.subprojects.logging.indexTitle = Qt HTTP Server Logging 47 | qhp.QtHttpServer.subprojects.logging.selectors = group:none 48 | 49 | navigation.cppclassespage = "Qt HTTP Server C++ Classes" 50 | navigation.landingpage = "Qt HTTP Server" 51 | 52 | manifestmeta.highlighted.names = "QtHttpServer/Simple HTTP Server" 53 | 54 | # Enforce zero documentation warnings in CI 55 | warninglimit = 0 56 | -------------------------------------------------------------------------------- /src/httpserver/qhttpserverresponder_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | // Qt-Security score:significant reason:default 4 | 5 | #ifndef QHTTPSERVERRESPONDER_P_H 6 | #define QHTTPSERVERRESPONDER_P_H 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include 22 | 23 | // 24 | // W A R N I N G 25 | // ------------- 26 | // 27 | // This file is not part of the Qt API. It exists for the convenience 28 | // of QHttpServer. This header file may change from version to 29 | // version without notice, or even be removed. 30 | // 31 | // We mean it. 32 | 33 | QT_BEGIN_NAMESPACE 34 | 35 | class QHttpServerResponderPrivate 36 | { 37 | public: 38 | QHttpServerResponderPrivate(QHttpServerStream *stream); 39 | ~QHttpServerResponderPrivate(); 40 | 41 | void write(const QByteArray &body, const QHttpHeaders &headers, 42 | QHttpServerResponder::StatusCode status); 43 | void write(QHttpServerResponder::StatusCode status); 44 | void write(QIODevice *data, const QHttpHeaders &headers, 45 | QHttpServerResponder::StatusCode status); 46 | void writeBeginChunked(const QHttpHeaders &headers, QHttpServerResponder::StatusCode status); 47 | void writeChunk(const QByteArray &body); 48 | void writeEndChunked(const QByteArray &data, const QHttpHeaders &trailers); 49 | void cancel(); 50 | 51 | #if defined(QT_DEBUG) 52 | const QPointer stream; 53 | #else 54 | QHttpServerStream *const stream; 55 | #endif 56 | quint32 m_streamId = 0; 57 | QAtomicInteger canceled = false; 58 | }; 59 | 60 | QT_END_NAMESPACE 61 | 62 | #endif // QHTTPSERVERRESPONDER_P_H 63 | -------------------------------------------------------------------------------- /doc/simple-example.qdoc: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only 3 | 4 | /*! 5 | \ingroup qthttpserver-examples 6 | \title Simple HTTP Server 7 | \examplecategory {Web Technologies} 8 | \brief Simple example of how to set up an HTTP server. 9 | \image browserwindow.png {Simple HTTP server output in browser} 10 | 11 | The Simple HTTP Server shows how to set up an HTTP server using the 12 | QHttpServer class. It listens to two sockets: one TCP socket and one 13 | SSL socket. Different callbacks are set up to demonstrate how to use 14 | the \l{QHttpServer::}{route()} function. 15 | 16 | A QHttpServer object is created, and a simple \l{QHttpServer::}{route()} 17 | handles the path \c "/" by returning \c{Hello world}: 18 | \snippet simple/main.cpp Setting up HTTP server 19 | 20 | Then we register a callback that serves the server's assets to the client: 21 | \snippet simple/main.cpp Returning assets 22 | 23 | Here we use the QHttpServerRequest object to return the client's IP address: 24 | \snippet simple/main.cpp Using QHttpServerRequest 25 | 26 | For one of the paths, \c {"/auth"}, \l{RFC 7617}{Basic HTTP Authentication} 27 | is used: 28 | \snippet simple/main.cpp Using basic authentication 29 | 30 | Then we use the \l{QHttpServer::}{addAfterRequestHandler()} function to 31 | change the QHttpServerResponse object after it has been handled by the 32 | callbacks registered by \l{QHttpServer::}{route()} by adding HTTP headers 33 | to the response: 34 | \snippet simple/main.cpp Using addAfterRequestHandler() 35 | 36 | A QTcpServer listening to a port is bound to the HTTP server using the 37 | \l{QAbstractHttpServer::}{bind()} function: 38 | \snippet simple/main.cpp Binding the TCP server 39 | 40 | And then \l QSslConfiguration is used to create an SSL configuration for a 41 | QHttpServer to serve HTTPS traffic: 42 | \snippet simple/main.cpp HTTPS Configuration example 43 | 44 | After everything is set up, all that remains is to start handling incoming 45 | requests: 46 | \snippet simple/main.cpp Start handling requests 47 | 48 | \example simple 49 | */ 50 | -------------------------------------------------------------------------------- /examples/httpserver/simple/assets/certificate.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIFszCCA5ugAwIBAgIUfpP54qSLfus/pFUIBDizbnrDjE4wDQYJKoZIhvcNAQEL 3 | BQAwaDELMAkGA1UEBhMCRlIxDzANBgNVBAgMBkZyYW5jZTERMA8GA1UEBwwIR3Jl 4 | bm9ibGUxFjAUBgNVBAoMDVF0Q29udHJpYnV0b3IxHTAbBgNVBAMMFHFodHRwc3Nl 5 | cnZlcnRlc3QuY29tMCAXDTIyMDIwNzE0MzE0NVoYDzIyNjgwNzA3MTQzMTQ1WjBo 6 | MQswCQYDVQQGEwJGUjEPMA0GA1UECAwGRnJhbmNlMREwDwYDVQQHDAhHcmVub2Js 7 | ZTEWMBQGA1UECgwNUXRDb250cmlidXRvcjEdMBsGA1UEAwwUcWh0dHBzc2VydmVy 8 | dGVzdC5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC92u1m1Wq7 9 | CIbXb693c6NFWJt0rY5vvcM45aBvmsiBD4HZTNw4VrTGyJHJz9tqb0IQSqCflgdK 10 | f3kske83d1uwDy+sWohdOSKwUC4cmqyaxhlsAiIJfy3W2VxSZCwmaNnUgqGTfuWA 11 | YwqRzbw6H8IdtOuEllZ1DKgFs1vwp6pIeR49i7T8Ey07+WuRcmNXoFeArwGA6ol8 12 | 6qsYKwG9b6ypnP0PnVkEFVvdgKsFk/bQ1UDnFlSo4XBLeOf72E7VeUlzCIUDdXNT 13 | u5JW3bOPOFfSIfDoY5VuNHghK2of/LShr1H2ZBrSGbNDstxX02KCFfmQzw+yBP2L 14 | peG/aeayOk+t4tiBeheqkNGsvQ9HQJK2za5xF1+EyFjxWI2hqtnXZnYJNo3GIc8b 15 | M1g0k9pAbjSjcsRtDcY/uKBnyCj999JX6RklLmO4AcKxS81QDiC8V9VcvHOgbqp7 16 | AtdIJeioPIn1PuDgvzVbX2GwHFWnyAOpUCIGemD4ZMtoLr1Y6b04xcRE5M6WKfuD 17 | GVDSlk77b8ze4UWj+FeUgf8xvk08qWk0GqAumojC0Yy6C3sPH0mgzBa8QGXMyB7J 18 | xiY1fBIex1DmTEVLm5i5kSuLrZeuT9ZaV6/88MJF1xJSGuNVI2i0VC94YpLALnPY 19 | U4AhmKgDSY/GwGLFJpBjx+GJoLnJ1TDgXQIDAQABo1MwUTAdBgNVHQ4EFgQUK7Un 20 | 0JA3DBUVhclrm6pIZsO60U4wHwYDVR0jBBgwFoAUK7Un0JA3DBUVhclrm6pIZsO6 21 | 0U4wDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAuvSFAgfgurDT 22 | /dbXuJ0O+FuGg4NOTNRil5ji3DnMzReIHpSiKiXu76PHHRFnlosvfAFOHlpYntun 23 | LhbUAxim/iIgWZR33uzvqXMXBORZ0zffjy2SjGCW8ZJYyTmg9c0tc0jEjv7owtlU 24 | m6tUXMOs9U0CzvEKLt0K0dMALaLkXtscuzEWA4PHVvnvTu0Wyjj/8n+DgYzY09kC 25 | YF0lJfcG6bddDgspmYyFpULeGGP7+qwgGh4cVBtY5I4Htr3p7hDo6UGDF6AsMQZF 26 | 1CAEgBVRbJgI2GTnptpm9k3EFKwQ81z5O+NnP3ZsuuZ3CEVaPHyQf/POLAIhmZLt 27 | 0vS9qoRiS4uMUJDXz2kJFBOFHki073eMvHiKtlpYOlJXMQ4MkHCydjeeuhHcgUCq 28 | ZDWuQMmq/8tMwf4YtvxYtXzAMVW9dM8BgWu2G8/JwPMGUGhLfKkHmc8dlQzGDe/W 29 | K/uVHlJZNF4Y0eXVlq9DUhpvKOjGc8A208wQlsTUgPxljgJ2+4F3D+t0luc3h65m 30 | 25iw8eRGuYDoCQLG7u7MI0g8A0H+0h9Xrt8PQql86vmQhmTUhKfedVGOo2t2Bcfn 31 | ignL7f4e1m2jh0oWTLhuP1hnVFN4KAKpVIJXhbEkH59cLCN6ARXiEHCM9rmK5Rgk 32 | NQZlAZc2w1Ha9lqisaWWpt42QVhQM64= 33 | -----END CERTIFICATE----- 34 | -------------------------------------------------------------------------------- /tests/benchmarks/qhttpserver/transfer/data/localhost.cert: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIFuzCCA6OgAwIBAgIUOjZ3F96HqFMwq8sWF9EtBZmEJsAwDQYJKoZIhvcNAQEN 3 | BQAwbTELMAkGA1UEBhMCTk8xDTALBgNVBAgMBE9zbG8xDTALBgNVBAcMBE9zbG8x 4 | FzAVBgNVBAoMDlRoZSBRdCBQcm9qZWN0MRMwEQYDVQQLDApIdHRwU2VydmVyMRIw 5 | EAYDVQQDDAlsb2NhbGhvc3QwHhcNMjQwNjEwMTMyMzI3WhcNMjUwNjEwMTMyMzI3 6 | WjBtMQswCQYDVQQGEwJOTzENMAsGA1UECAwET3NsbzENMAsGA1UEBwwET3NsbzEX 7 | MBUGA1UECgwOVGhlIFF0IFByb2plY3QxEzARBgNVBAsMCkh0dHBTZXJ2ZXIxEjAQ 8 | BgNVBAMMCWxvY2FsaG9zdDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB 9 | AOsy7zkiA3FbVhKIJ3egIIqR7COdnj3SJNUFGbMBzdcIgmBvA0OH48OnPMOcVT60 10 | os/x01aUZd1EksVNNi0x57Pwf0v7fMQfhdRFNnuAs3ISA6uzuIGhj3EFKNYe9EpV 11 | dKQdAfqoqlEKO1bH3NDCbsFEzElq8HIyzMgIND1UPt1j57eBsS/3Fd+x5uyoqSaF 12 | qNM/XNtdeYJ3n9MyMUqFzHD4pYpuFa5Z/yD726bL2+UrN4bjAv+7IqKZALpSk0B/ 13 | Qj5yJX/FXWPBjOUJ2nKg09Z2JMC0vFCBSWBeIoDcH93lBAMK3EKLx5+fdQdwh4KC 14 | hPxW80sLs5K4OOB+sQOrLHiBgbQliV6HEKIgTiggvioLNn0OBn2rjU2+3wx7rjLd 15 | Bt7upl3HQ1M4LAFWhskDpP2wbEiMLq5zUTrcudzcaG3Zbe4VmjED9mWlMXFUc17n 16 | xUiKteYz3me9JdlxVLCT1/rYP6DjKOMF4kcvMZi3dwxclWpglMSbmJo1fQvORI8l 17 | y2xKw73XeOn6c/ZmbjoGVixrySGFQsx9GEWA9osBFIGWMdAMv+4w0ry7Hl/vJO/o 18 | cgBPZd8V6P4++pA61pkuaTtROHpLCaAuO0GM/9oOdVPYFbc1DnkB5golPkq//GBL 19 | eOR3f1Ww4H3ArDZ+UXL0E4dHhhz5Zpu4AW3e82LSr97JAgMBAAGjUzBRMB0GA1Ud 20 | DgQWBBThu0uUmw1m+Eh9sjqCe2v+euKbUzAfBgNVHSMEGDAWgBThu0uUmw1m+Eh9 21 | sjqCe2v+euKbUzAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBDQUAA4ICAQCw 22 | zQdh3b6df5Aaw1a8iZBK/4Pqiy77vYJTUXKj/6/PY9mlApcxpfs6tnTwdh5fkHsV 23 | QRMQFZGPow+wy5tG54WvP2pDb5vgwnFCSm0lyWsLDCNbL+qJkKM93T8b9QqPRpmz 24 | 8sSZ+YoJKIrvRSKEoArvMzjC9/16LI/v9ln5sFF6m8ttTwBAhrySNwDHPS25aPuw 25 | 3zO4aMftaYbe7gsU4296luGfgH1AoPAdRibyVgFYKKYciF4HUQ3rFCHCFwJvy7fi 26 | zXOeTqF4tb8Msy1q2U8NCM2J+y5XyNTpbcxDfb0ZfyWsyrE3vlJzcuTVyz4Y6yBq 27 | 2x2H54DYmeQp4lycyNpPSHM4BFIsEHkvhnRoE9JIjBhRhEqAYaMYtKiKhqJj/zcW 28 | 6UMVHU9TlQ33eu9LP2uWGV3YBsSIE29Rtny53SyPGeXML3mdUZ9T/uavUv7EFtmf 29 | qrP7zDWaJ5fmCIxqtPR16amJA2877DKBNC53h4i0iNewaQ75pBO4RDg46Wqjkpag 30 | PA4MuXcqnF52ZOlf/PU7/kxUk8ttvUgAsXLNmSRN+Xr7QZaPV6yF6RP/vYUiDYWo 31 | HuflsTefiPnCKqdbaX2cQstrqVOcNc472vM5ZQC9xdS9yU9pf6tIcer9XXdFAE6f 32 | 90ka+5c3y00r28StOsuIvbSahFrcKIwGFCqKGjPb3g== 33 | -----END CERTIFICATE----- 34 | -------------------------------------------------------------------------------- /REUSE.toml: -------------------------------------------------------------------------------- 1 | version = 1 2 | 3 | [[annotations]] 4 | path = ["tests/auto/qhttpserver/data/text.html", 5 | "tests/auto/qhttpserverresponse/data/*", 6 | "tests/auto/qhttpserverresponder/data/index.html", 7 | "tests/benchmarks/qhttpserver/transfer/data/*", 8 | "tests/auto/qhttpserver/data/application.json"] 9 | precedence = "closest" 10 | SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." 11 | SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR GPL-3.0-only" 12 | 13 | [[annotations]] 14 | path = ["**.pro", "**.qrc", "**CMakeLists.txt", ".cmake.conf", "**.yaml", 15 | "**.cfg", "**BLACKLIST", "**ci_config_linux.json", ".tag"] 16 | precedence = "closest" 17 | comment = "build system" 18 | SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." 19 | SPDX-License-Identifier = "BSD-3-Clause" 20 | 21 | [[annotations]] 22 | path = ["**/.gitattributes", "**.gitignore", "**.gitreview"] 23 | precedence = "closest" 24 | comment = "version control system. Infrastructure" 25 | SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." 26 | SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR BSD-3-Clause" 27 | 28 | [[annotations]] 29 | path = ["examples/**"] 30 | comment = "this must be after the build system table because example and snippets take precedence over build system" 31 | precedence = "closest" 32 | SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." 33 | SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR BSD-3-Clause" 34 | 35 | [[annotations]] 36 | path = ["doc/images/**", "**/README*", "**.qdocconf"] 37 | comment = "documentation" 38 | precedence = "closest" 39 | SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." 40 | SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only" 41 | 42 | [[annotations]] 43 | path = ["**.toml", "licenseRule.json"] 44 | comment = "linfrastructure" 45 | precedence = "override" 46 | SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." 47 | SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR BSD-3-Clause" 48 | 49 | [[annotations]] 50 | path = ["**/qt_attribution.json"] 51 | comment = "documentation" 52 | precedence = "override" 53 | SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." 54 | SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only" 55 | 56 | -------------------------------------------------------------------------------- /src/httpserver/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | # Generated from httpserver.pro. 5 | 6 | ##################################################################### 7 | ## HttpServer Module: 8 | ##################################################################### 9 | 10 | qt_internal_add_module(HttpServer 11 | SOURCES 12 | qabstracthttpserver.cpp qabstracthttpserver.h qabstracthttpserver_p.h 13 | qhttpserver.cpp qhttpserver.h qhttpserver_p.h 14 | qhttpserverconfiguration.cpp qhttpserverconfiguration.h 15 | qhttpserverhttp1protocolhandler.cpp qhttpserverhttp1protocolhandler_p.h 16 | qhttpserverliterals.cpp qhttpserverliterals_p.h 17 | qhttpserverparser.cpp qhttpserverparser_p.h 18 | qhttpserverrequest.cpp qhttpserverrequest.h qhttpserverrequest_p.h 19 | qhttpserverrequestfilter.cpp qhttpserverrequestfilter_p.h 20 | qhttpserverresponder.cpp qhttpserverresponder.h qhttpserverresponder_p.h 21 | qhttpserverresponse.cpp qhttpserverresponse.h qhttpserverresponse_p.h 22 | qhttpserverrouter.cpp qhttpserverrouter.h qhttpserverrouter_p.h 23 | qhttpserverrouterrule.cpp qhttpserverrouterrule.h qhttpserverrouterrule_p.h 24 | qhttpserverrouterviewtraits.h 25 | qhttpserverstream.cpp qhttpserverstream_p.h 26 | qhttpserverviewtraits_impl.h 27 | qhttpserverwebsocketupgraderesponse.cpp qhttpserverwebsocketupgraderesponse.h 28 | qthttpserverglobal.h 29 | LIBRARIES 30 | Qt::CorePrivate 31 | Qt::NetworkPrivate 32 | PUBLIC_LIBRARIES 33 | Qt::Core 34 | Qt::Network 35 | PRIVATE_MODULE_INTERFACE 36 | Qt::CorePrivate 37 | Qt::NetworkPrivate 38 | ) 39 | 40 | ## Scopes: 41 | ##################################################################### 42 | 43 | qt_internal_extend_target(HttpServer CONDITION QT_FEATURE_http AND QT_FEATURE_ssl 44 | SOURCES 45 | qhttpserverhttp2protocolhandler.cpp qhttpserverhttp2protocolhandler_p.h 46 | ) 47 | 48 | qt_internal_extend_target(HttpServer CONDITION TARGET Qt::WebSockets 49 | LIBRARIES 50 | Qt::WebSocketsPrivate 51 | PUBLIC_LIBRARIES 52 | Qt::WebSockets 53 | PRIVATE_MODULE_INTERFACE 54 | Qt::WebSocketsPrivate 55 | ) 56 | 57 | qt_internal_add_docs(HttpServer 58 | ../../doc/config/qthttpserver.qdocconf 59 | ) 60 | -------------------------------------------------------------------------------- /examples/httpserver/colorpalette/utils.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | #ifndef UTILS_H 4 | #define UTILS_H 5 | 6 | #include "types.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | static std::optional readFileToByteArray(const QString &path) 18 | { 19 | QFile file(path); 20 | if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) 21 | return std::nullopt; 22 | 23 | return file.readAll(); 24 | } 25 | 26 | static std::optional byteArrayToJsonArray(const QByteArray &arr) 27 | { 28 | QJsonParseError err; 29 | const auto json = QJsonDocument::fromJson(arr, &err); 30 | if (err.error || !json.isArray()) 31 | return std::nullopt; 32 | return json.array(); 33 | } 34 | 35 | static std::optional byteArrayToJsonObject(const QByteArray &arr) 36 | { 37 | QJsonParseError err; 38 | const auto json = QJsonDocument::fromJson(arr, &err); 39 | if (err.error || !json.isObject()) 40 | return std::nullopt; 41 | return json.object(); 42 | } 43 | 44 | template 45 | static IdMap tryLoadFromFile(const FromJsonFactory &itemFactory, const QString &path) 46 | { 47 | const auto maybeBytes = readFileToByteArray(path); 48 | if (maybeBytes) { 49 | const auto maybeArray = byteArrayToJsonArray(*maybeBytes); 50 | if (maybeArray) { 51 | return IdMap(itemFactory, *maybeArray); 52 | } else { 53 | qDebug() << "Content of " << path << " is not json array."; 54 | } 55 | } else { 56 | qDebug() << "Reading file " << path << " failed."; 57 | } 58 | return IdMap(); 59 | } 60 | 61 | static QByteArray getValueFromHeader(const QHttpHeaders &headers, 62 | QByteArrayView headerName) 63 | { 64 | return headers.value(headerName).toByteArray(); 65 | } 66 | 67 | static std::optional getTokenFromRequest(const QHttpServerRequest &request) 68 | { 69 | std::optional token; 70 | if (auto bytes = getValueFromHeader(request.headers(), "token"); !bytes.isEmpty()) { 71 | token = bytes; 72 | } 73 | return token; 74 | } 75 | 76 | #endif // UTILS_H 77 | -------------------------------------------------------------------------------- /src/httpserver/qhttpserverrequestfilter_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | // Qt-Security score:significant reason:default 4 | 5 | #ifndef QHTTPSERVERREQUESTFILTER_P_H 6 | #define QHTTPSERVERREQUESTFILTER_P_H 7 | 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | // 15 | // W A R N I N G 16 | // ------------- 17 | // 18 | // This file is not part of the Qt API. It exists for the convenience 19 | // of QHttpServer. This header file may change from version to 20 | // version without notice, or even be removed. 21 | // 22 | // We mean it. 23 | 24 | QT_BEGIN_NAMESPACE 25 | 26 | namespace QHttpServerRequestFilterPrivate { 27 | extern const Q_HTTPSERVER_EXPORT int cPeriodDurationMSec; 28 | } 29 | 30 | class QHttpServerRequestFilter 31 | { 32 | public: 33 | // Rule Of Zero applies! 34 | 35 | Q_HTTPSERVER_EXPORT void setConfiguration(const QHttpServerConfiguration &config); 36 | 37 | Q_HTTPSERVER_EXPORT bool isRequestAllowed(const QHostAddress &peerAddress) const; 38 | 39 | Q_HTTPSERVER_EXPORT bool isRequestWithinRate(const QHostAddress &peerAddress); 40 | Q_HTTPSERVER_EXPORT bool isRequestWithinRate(const QHostAddress &peerAddress, qint64 currTimeMSec); 41 | 42 | Q_HTTPSERVER_EXPORT bool isUrlSizeAllowed(qsizetype urlSize) const; 43 | Q_HTTPSERVER_EXPORT bool isTotalHeaderSizeAllowed(qsizetype headerSize) const; 44 | Q_HTTPSERVER_EXPORT bool isHeaderFieldSizeAllowed(qsizetype headerSize) const; 45 | Q_HTTPSERVER_EXPORT bool isNumberOfHeaderFieldsAllowed(qsizetype headerSize) const; 46 | Q_HTTPSERVER_EXPORT bool isBodySizeAllowed(qint64 bodySize) const; 47 | 48 | private: 49 | struct IpInfo 50 | { 51 | IpInfo() : m_thisPeriodEnd(0) {} 52 | IpInfo(qint64 thisPeriodEnd) : m_thisPeriodEnd(thisPeriodEnd) {} 53 | 54 | bool isGarbage(qint64 currTime) const; 55 | 56 | qint64 m_thisPeriodEnd = 0; 57 | unsigned m_nRequests = 0; 58 | }; 59 | 60 | void cleanIpInfoGarbage(QHash::iterator it, qint64 currTime); 61 | 62 | unsigned maxRequestPerPeriod() const; 63 | 64 | QHttpServerConfiguration m_config; 65 | QHash ipInfo; 66 | }; 67 | 68 | QT_END_NAMESPACE 69 | 70 | #endif // QHTTPSERVERREQUESTFILTER_P_H 71 | -------------------------------------------------------------------------------- /src/httpserver/qabstracthttpserver_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | // Qt-Security score:significant reason:default 4 | 5 | #ifndef QABSTRACTHTTPSERVER_P_H 6 | #define QABSTRACTHTTPSERVER_P_H 7 | 8 | // 9 | // W A R N I N G 10 | // ------------- 11 | // 12 | // This file is not part of the Qt API. It exists for the convenience 13 | // of QHttpServer. This header file may change from version to 14 | // version without notice, or even be removed. 15 | // 16 | // We mean it. 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | 25 | #include 26 | #include 27 | 28 | #include 29 | 30 | #if defined(QT_WEBSOCKETS_LIB) 31 | #include 32 | #endif // defined(QT_WEBSOCKETS_LIB) 33 | 34 | #if QT_CONFIG(ssl) 35 | #include 36 | #endif 37 | 38 | QT_BEGIN_NAMESPACE 39 | 40 | class QHttpServerRequest; 41 | 42 | class QAbstractHttpServerPrivate: public QObjectPrivate 43 | { 44 | public: 45 | Q_DECLARE_PUBLIC(QAbstractHttpServer) 46 | 47 | QAbstractHttpServerPrivate(); 48 | 49 | #if defined(QT_WEBSOCKETS_LIB) 50 | QWebSocketServer websocketServer { 51 | QCoreApplication::applicationName() + QLatin1Char('/') + QCoreApplication::applicationVersion(), 52 | QWebSocketServer::NonSecureMode 53 | }; 54 | #endif // defined(QT_WEBSOCKETS_LIB) 55 | 56 | void handleNewConnections(); 57 | bool verifyThreadAffinity(const QObject *contextObject) const; 58 | 59 | #if QT_CONFIG(localserver) 60 | void handleNewLocalConnections(); 61 | #endif 62 | 63 | void createHttp1Handler(QIODevice *socket); 64 | #if QT_CONFIG(ssl) && QT_CONFIG(http) 65 | void createHttp2Handler(QIODevice *socket); 66 | #endif 67 | void restartHeartbeatTimer(); 68 | 69 | #if defined(QT_WEBSOCKETS_LIB) 70 | mutable bool handlingWebSocketUpgrade = false; 71 | struct WebSocketUpgradeVerifier 72 | { 73 | QPointer context; 74 | QtPrivate::SlotObjUniquePtr slotObject; 75 | }; 76 | std::vector webSocketUpgradeVerifiers; 77 | #endif // defined(QT_WEBSOCKETS_LIB) 78 | #if QT_CONFIG(ssl) 79 | QHttp2Configuration h2Configuration; 80 | #endif 81 | QHttpServerConfiguration configuration; 82 | QHttpServerRequestFilter requestFilter; 83 | QTimer heartbeatTimer; 84 | }; 85 | 86 | QT_END_NAMESPACE 87 | 88 | #endif // QABSTRACTHTTPSERVER_P_H 89 | -------------------------------------------------------------------------------- /src/httpserver/qhttpserverstream.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | // Qt-Security score:significant reason:default 4 | 5 | #include "qhttpserverstream_p.h" 6 | #include 7 | 8 | #include 9 | 10 | #if QT_CONFIG(ssl) 11 | #include 12 | #endif 13 | #if QT_CONFIG(localserver) 14 | #include 15 | #endif 16 | 17 | QT_BEGIN_NAMESPACE 18 | 19 | static QHttpServerParser initParserFromSocket(QIODevice *socket, QHttpServerRequestFilter *filter) 20 | { 21 | QTcpSocket *tcpSocket = qobject_cast(socket); 22 | if (tcpSocket) { 23 | return QHttpServerParser(tcpSocket->peerAddress(), tcpSocket->peerPort(), 24 | tcpSocket->localAddress(), tcpSocket->localPort(), filter); 25 | } 26 | return QHttpServerParser(QHostAddress::LocalHost, 0, QHostAddress::LocalHost, 0, filter); 27 | } 28 | 29 | #if QT_CONFIG(ssl) 30 | static QSslConfiguration initSslConfigurationFromSocket(QIODevice *socket) 31 | { 32 | if (auto *ssl = qobject_cast(socket)) 33 | return ssl->sslConfiguration(); 34 | 35 | return QSslConfiguration(); 36 | } 37 | #endif 38 | 39 | QHttpServerStream::QHttpServerStream(QIODevice *socket, QHttpServerRequestFilter *filter, 40 | QObject *parent) 41 | : QObject(parent) 42 | , parser(initParserFromSocket(socket, filter)) 43 | #if QT_CONFIG(ssl) 44 | , sslConfiguration(initSslConfigurationFromSocket(socket)) 45 | #endif 46 | , clientSocket(socket) 47 | { 48 | } 49 | 50 | void QHttpServerStream::connectResponder(QHttpServerResponderPrivate *responder) 51 | { 52 | if (QTcpSocket *tcpSocket = qobject_cast(clientSocket)) { 53 | responderConnections.insert(responder->m_streamId, 54 | connect(tcpSocket, &QAbstractSocket::disconnected, tcpSocket, 55 | [responder]() { responder->cancel(); })); 56 | #if QT_CONFIG(localserver) 57 | } else if (QLocalSocket *localSocket = qobject_cast(clientSocket)) { 58 | responderConnections.insert(responder->m_streamId, 59 | connect(localSocket, &QLocalSocket::disconnected, localSocket, 60 | [responder]() { responder->cancel(); })); 61 | #endif 62 | } 63 | } 64 | 65 | void QHttpServerStream::disconnectResponder(quint32 streamId) 66 | { 67 | auto connection = responderConnections.take(streamId); 68 | if (connection) 69 | disconnect(connection); 70 | } 71 | 72 | QT_END_NAMESPACE 73 | -------------------------------------------------------------------------------- /src/httpserver/qhttpserverstream_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | // Qt-Security score:significant reason:default 4 | 5 | #ifndef QHTTPSERVERSTREAM_P_H 6 | #define QHTTPSERVERSTREAM_P_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #if QT_CONFIG(ssl) 14 | #include 15 | #endif 16 | 17 | #include 18 | 19 | // 20 | // W A R N I N G 21 | // ------------- 22 | // 23 | // This file is not part of the Qt API. It exists for the convenience 24 | // of QHttpServer. This header file may change from version to 25 | // version without notice, or even be removed. 26 | // 27 | // We mean it. 28 | 29 | QT_BEGIN_NAMESPACE 30 | 31 | class QTcpSocket; 32 | class QHttpServerResponderPrivate; 33 | 34 | class QHttpServerStream : public QObject 35 | { 36 | Q_OBJECT 37 | 38 | friend class QHttpServerResponderPrivate; 39 | 40 | protected: 41 | QHttpServerStream(QIODevice *socket, QHttpServerRequestFilter *filter, 42 | QObject *parent = nullptr); 43 | 44 | virtual void responderDestroyed(quint32 streamId) = 0; 45 | virtual void startHandlingRequest() = 0; 46 | virtual void socketDisconnected() = 0; 47 | 48 | virtual void write(const QByteArray &body, const QHttpHeaders &headers, 49 | QHttpServerResponder::StatusCode status, quint32 streamId) = 0; 50 | virtual void write(QHttpServerResponder::StatusCode status, quint32 streamId) = 0; 51 | virtual void write(QIODevice *data, const QHttpHeaders &headers, 52 | QHttpServerResponder::StatusCode status, quint32 streamId) = 0; 53 | 54 | virtual void writeBeginChunked(const QHttpHeaders &headers, 55 | QHttpServerResponder::StatusCode status, 56 | quint32 streamId) = 0; 57 | virtual void writeChunk(const QByteArray &body, quint32 streamId) = 0; 58 | virtual void writeEndChunked(const QByteArray &data, const 59 | QHttpHeaders &trailers, 60 | quint32 streamId) = 0; 61 | 62 | void connectResponder(QHttpServerResponderPrivate *responder); 63 | void disconnectResponder(quint32 streamId); 64 | 65 | QHttpServerParser parser; 66 | #if QT_CONFIG(ssl) 67 | QSslConfiguration sslConfiguration; 68 | #endif 69 | QHash responderConnections; 70 | QIODevice *clientSocket; 71 | }; 72 | 73 | QT_END_NAMESPACE 74 | 75 | #endif // QHTTPSERVERSTREAM_P_H 76 | -------------------------------------------------------------------------------- /src/httpserver/qhttpserverwebsocketupgraderesponse.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | // Qt-Security score:significant reason:default 4 | 5 | #ifndef QHTTPSERVERWEBSOCKETUPGRADERESPONSE_H 6 | #define QHTTPSERVERWEBSOCKETUPGRADERESPONSE_H 7 | 8 | #include 9 | 10 | #include 11 | 12 | #include 13 | 14 | QT_BEGIN_NAMESPACE 15 | 16 | class QHttpServerWebSocketUpgradeResponsePrivate; 17 | class QHttpServerWebSocketUpgradeResponse final 18 | { 19 | 20 | public: 21 | Q_HTTPSERVER_EXPORT 22 | QHttpServerWebSocketUpgradeResponse(const QHttpServerWebSocketUpgradeResponse &other); 23 | QHttpServerWebSocketUpgradeResponse(QHttpServerWebSocketUpgradeResponse &&other) noexcept 24 | : responseType(std::move(other.responseType)) 25 | , errorStatus(std::move(other.errorStatus)) 26 | , errorMessage(std::move(other.errorMessage)) 27 | , reserved(std::exchange(other.reserved, nullptr)) 28 | { 29 | } 30 | 31 | Q_HTTPSERVER_EXPORT ~QHttpServerWebSocketUpgradeResponse(); 32 | Q_HTTPSERVER_EXPORT QHttpServerWebSocketUpgradeResponse & 33 | operator=(const QHttpServerWebSocketUpgradeResponse &other); 34 | QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QHttpServerWebSocketUpgradeResponse) 35 | 36 | void swap(QHttpServerWebSocketUpgradeResponse &other) noexcept 37 | { 38 | std::swap(responseType, other.responseType); 39 | std::swap(errorStatus, other.errorStatus); 40 | errorMessage.swap(other.errorMessage); 41 | std::swap(reserved, other.reserved); 42 | } 43 | 44 | enum class ResponseType { 45 | Accept, 46 | Deny, 47 | PassToNext, 48 | }; 49 | 50 | [[nodiscard]] ResponseType type() const { return responseType; }; 51 | [[nodiscard]] int denyStatus() const { return errorStatus; } 52 | [[nodiscard]] const QByteArray &denyMessage() const & { return errorMessage; } 53 | [[nodiscard]] QByteArray denyMessage() && { return std::move(errorMessage); } 54 | 55 | Q_HTTPSERVER_EXPORT static QHttpServerWebSocketUpgradeResponse accept(); 56 | Q_HTTPSERVER_EXPORT static QHttpServerWebSocketUpgradeResponse deny(); 57 | Q_HTTPSERVER_EXPORT static QHttpServerWebSocketUpgradeResponse deny(int status, 58 | QByteArray message); 59 | Q_HTTPSERVER_EXPORT static QHttpServerWebSocketUpgradeResponse passToNext(); 60 | 61 | private: 62 | QHttpServerWebSocketUpgradeResponse() = delete; 63 | Q_IMPLICIT QHttpServerWebSocketUpgradeResponse(ResponseType type); 64 | QHttpServerWebSocketUpgradeResponse(ResponseType type, int status, QByteArray message); 65 | 66 | ResponseType responseType; 67 | int errorStatus = 403; 68 | QByteArray errorMessage; 69 | void *reserved = nullptr; 70 | }; 71 | 72 | Q_DECLARE_SHARED(QHttpServerWebSocketUpgradeResponse) 73 | 74 | QT_END_NAMESPACE 75 | 76 | #endif // QHTTPSERVERWEBSOCKETUPGRADERESPONSE_H 77 | -------------------------------------------------------------------------------- /src/httpserver/qhttpserverconfiguration.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | // Qt-Security score:significant reason:default 4 | 5 | #ifndef QHTTPSERVERCONFIGURATION_H 6 | #define QHTTPSERVERCONFIGURATION_H 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | QT_BEGIN_NAMESPACE 17 | 18 | class QHttpServerConfigurationPrivate; 19 | QT_DECLARE_QESDP_SPECIALIZATION_DTOR(QHttpServerConfigurationPrivate) 20 | 21 | class QHttpServerConfiguration 22 | { 23 | public: 24 | Q_HTTPSERVER_EXPORT QHttpServerConfiguration(); 25 | Q_HTTPSERVER_EXPORT QHttpServerConfiguration(const QHttpServerConfiguration &other); 26 | QHttpServerConfiguration(QHttpServerConfiguration &&other) noexcept = default; 27 | Q_HTTPSERVER_EXPORT QHttpServerConfiguration &operator = (const QHttpServerConfiguration &other); 28 | 29 | QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QHttpServerConfiguration) 30 | void swap(QHttpServerConfiguration &other) noexcept { d.swap(other.d); } 31 | 32 | Q_HTTPSERVER_EXPORT ~QHttpServerConfiguration(); 33 | 34 | Q_HTTPSERVER_EXPORT void setRateLimitPerSecond(quint32 maxRequests); 35 | Q_HTTPSERVER_EXPORT quint32 rateLimitPerSecond() const; 36 | 37 | Q_HTTPSERVER_EXPORT void setKeepAliveTimeout(std::chrono::seconds timeout); 38 | Q_HTTPSERVER_EXPORT std::chrono::seconds keepAliveTimeout() const; 39 | 40 | Q_HTTPSERVER_EXPORT void setWhitelist(QSpan> subnetList); 41 | Q_HTTPSERVER_EXPORT QSpan> whitelist() const; 42 | 43 | Q_HTTPSERVER_EXPORT void setBlacklist(QSpan> subnetList); 44 | Q_HTTPSERVER_EXPORT QSpan> blacklist() const; 45 | 46 | Q_HTTPSERVER_EXPORT void setMaxUrlSize(qint64 maxUrlSize); 47 | Q_HTTPSERVER_EXPORT qint64 maxUrlSize() const; 48 | 49 | Q_HTTPSERVER_EXPORT void setMaxTotalHeaderSize(qint64 maxTotalHeadersSize); 50 | Q_HTTPSERVER_EXPORT qint64 maxTotalHeaderSize() const; 51 | 52 | Q_HTTPSERVER_EXPORT void setMaxHeaderFieldSize(qint64 maxSingleHeaderSize); 53 | Q_HTTPSERVER_EXPORT qint64 maxHeaderFieldSize() const; 54 | 55 | Q_HTTPSERVER_EXPORT void setMaxNumberOfHeaderFields(qint64 maxNumberOfHeaders); 56 | Q_HTTPSERVER_EXPORT qint64 maxNumberOfHeaderFields() const; 57 | 58 | Q_HTTPSERVER_EXPORT void setMaxBodySize(qint64 maxBodySize); 59 | Q_HTTPSERVER_EXPORT qint64 maxBodySize() const; 60 | 61 | private: 62 | QExplicitlySharedDataPointer d; 63 | 64 | friend Q_HTTPSERVER_EXPORT bool 65 | comparesEqual(const QHttpServerConfiguration &lhs, const QHttpServerConfiguration &rhs) noexcept; 66 | Q_DECLARE_EQUALITY_COMPARABLE(QHttpServerConfiguration) 67 | }; 68 | Q_DECLARE_SHARED(QHttpServerConfiguration) 69 | 70 | QT_END_NAMESPACE 71 | 72 | #endif // QHTTPSERVERCONFIGURATION_H 73 | -------------------------------------------------------------------------------- /doc/colorpalette-example.qdoc: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only 3 | 4 | /*! 5 | \ingroup qthttpserver-examples 6 | \title RESTful API Server 7 | \examplecategory {Web Technologies} 8 | \brief Example of how to create a RESTful API server using the QHttpServer. 9 | 10 | \image restful-color-palette-server-example.png {Qt HTTP RESTful API server} 11 | \example colorpalette 12 | 13 | This example shows how to create and host simple RESTful web APIs in a small 14 | application using the QHttpServer class. This server accepts calls in REST 15 | style and can be used with its counterpart example 16 | \l {Qt Quick Demo - RESTful API client} {RESTful Color Palette API client} 17 | on the client side. 18 | 19 | An application that obeys the REST constraints may be informally described as 20 | RESTful. The RESTful API Server allows create, read, update and delete 21 | operations of colors (unknown resource to be compatible with Reqres API) and 22 | users. The RESTful API Server also provides login/logout functionality. 23 | The example is based on \l {https://reqres.in/}{Reqres API}. 24 | 25 | To run the server application, execute server binary: 26 | \code 27 | ./colorpaletteserver 28 | \endcode 29 | or 30 | \code 31 | ./colorpaletteserver --port 1234 32 | \endcode 33 | An optional \c port parameter may be provided to specify the port 34 | on which the server shall run. 35 | 36 | \snippet colorpalette/main.cpp GET paginated list example 37 | In the example above, the route is specified for the GET method, 38 | which returns the JSON array with paginated list of items stored. 39 | To achieve that, the \l QHttpServer::route() method is used with the 40 | \l QHttpServerRequest::Method::Get enumeration. 41 | 42 | \snippet colorpalette/main.cpp GET single item example 43 | To get a single item from the list of entities, the item ID is passed 44 | in the request query. 45 | 46 | \snippet colorpalette/main.cpp POST example 47 | In this example, the route accepts POST method, which adds a new entry to 48 | the item list and returns a JSON object that represents the added entry. 49 | This request must be authorized. To authorize the request the value of 50 | the header \c TOKEN must be equal to previously returned token from 51 | the \c api/login or the \c api/register methods. 52 | 53 | \snippet colorpalette/apibehavior.h POST return different status code example 54 | Besides new entry as JSON object POST methods returns also different 55 | HTTP status code: \c Created for new entries, or \c AlreadyReported for pre-existing entries. 56 | This example makes use of an overload of QHttpServerResponse::QHttpServerResponse 57 | to send a JSON object and corresponding HTTP status code. 58 | 59 | To create an entry, the request body must be a JSON object with 60 | \c email \c first_name \c last_name and \c avatar fields - to create new users. 61 | For example: 62 | \code 63 | { 64 | "email": "jane.doe@qt.io", 65 | "first_name": "Jane", 66 | "last_name": "Doe", 67 | "avatar": "/img/faces/1-image.jpg" 68 | } 69 | \endcode 70 | */ 71 | -------------------------------------------------------------------------------- /src/httpserver/qhttpserverresponse.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | // Qt-Security score:significant reason:default 4 | 5 | #ifndef QHTTPSERVERRESPONSE_H 6 | #define QHTTPSERVERRESPONSE_H 7 | 8 | #include 9 | #include 10 | 11 | QT_BEGIN_NAMESPACE 12 | 13 | class QJsonObject; 14 | 15 | class QHttpServerResponsePrivate; 16 | class QHttpServerResponse final 17 | { 18 | Q_DECLARE_PRIVATE(QHttpServerResponse) 19 | Q_DISABLE_COPY(QHttpServerResponse) 20 | 21 | friend class QHttpServerResponder; 22 | public: 23 | using StatusCode = QHttpServerResponder::StatusCode; 24 | 25 | QHttpServerResponse(QHttpServerResponse &&other) noexcept 26 | : d_ptr(std::exchange(other.d_ptr, nullptr)) {} 27 | QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QHttpServerResponse) 28 | void swap(QHttpServerResponse &other) noexcept { qt_ptr_swap(d_ptr, other.d_ptr); } 29 | 30 | Q_HTTPSERVER_EXPORT Q_IMPLICIT QHttpServerResponse(StatusCode statusCode); 31 | 32 | Q_HTTPSERVER_EXPORT Q_IMPLICIT QHttpServerResponse(const char *data, 33 | StatusCode status = StatusCode::Ok); 34 | 35 | Q_HTTPSERVER_EXPORT Q_IMPLICIT QHttpServerResponse(const QString &data, 36 | StatusCode status = StatusCode::Ok); 37 | 38 | Q_HTTPSERVER_EXPORT Q_IMPLICIT QHttpServerResponse(const QByteArray &data, 39 | StatusCode status = StatusCode::Ok); 40 | Q_HTTPSERVER_EXPORT Q_IMPLICIT QHttpServerResponse(QByteArray &&data, 41 | StatusCode status = StatusCode::Ok); 42 | 43 | Q_HTTPSERVER_EXPORT Q_IMPLICIT QHttpServerResponse(const QJsonObject &data, 44 | StatusCode status = StatusCode::Ok); 45 | Q_HTTPSERVER_EXPORT Q_IMPLICIT QHttpServerResponse(const QJsonArray &data, 46 | StatusCode status = StatusCode::Ok); 47 | 48 | Q_HTTPSERVER_EXPORT Q_IMPLICIT QHttpServerResponse(const QByteArray &mimeType, 49 | const QByteArray &data, 50 | StatusCode status = StatusCode::Ok); 51 | Q_HTTPSERVER_EXPORT Q_IMPLICIT QHttpServerResponse(const QByteArray &mimeType, 52 | QByteArray &&data, 53 | StatusCode status = StatusCode::Ok); 54 | 55 | Q_HTTPSERVER_EXPORT ~QHttpServerResponse(); 56 | Q_HTTPSERVER_EXPORT static QHttpServerResponse fromFile(const QString &fileName); 57 | 58 | Q_HTTPSERVER_EXPORT QByteArray data() const; 59 | 60 | Q_HTTPSERVER_EXPORT QByteArray mimeType() const; 61 | 62 | Q_HTTPSERVER_EXPORT StatusCode statusCode() const; 63 | 64 | Q_HTTPSERVER_EXPORT QHttpHeaders headers() const; 65 | Q_HTTPSERVER_EXPORT void setHeaders(const QHttpHeaders &newHeaders); 66 | Q_HTTPSERVER_EXPORT void setHeaders(QHttpHeaders &&newHeaders); 67 | 68 | private: 69 | QHttpServerResponsePrivate *d_ptr; 70 | }; 71 | 72 | QT_END_NAMESPACE 73 | 74 | #endif // QHTTPSERVERRESPONSE_H 75 | -------------------------------------------------------------------------------- /examples/httpserver/simple/assets/private.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIJKAIBAAKCAgEAvdrtZtVquwiG12+vd3OjRVibdK2Ob73DOOWgb5rIgQ+B2Uzc 3 | OFa0xsiRyc/bam9CEEqgn5YHSn95LJHvN3dbsA8vrFqIXTkisFAuHJqsmsYZbAIi 4 | CX8t1tlcUmQsJmjZ1IKhk37lgGMKkc28Oh/CHbTrhJZWdQyoBbNb8KeqSHkePYu0 5 | /BMtO/lrkXJjV6BXgK8BgOqJfOqrGCsBvW+sqZz9D51ZBBVb3YCrBZP20NVA5xZU 6 | qOFwS3jn+9hO1XlJcwiFA3VzU7uSVt2zjzhX0iHw6GOVbjR4IStqH/y0oa9R9mQa 7 | 0hmzQ7LcV9NighX5kM8PsgT9i6Xhv2nmsjpPreLYgXoXqpDRrL0PR0CSts2ucRdf 8 | hMhY8ViNoarZ12Z2CTaNxiHPGzNYNJPaQG40o3LEbQ3GP7igZ8go/ffSV+kZJS5j 9 | uAHCsUvNUA4gvFfVXLxzoG6qewLXSCXoqDyJ9T7g4L81W19hsBxVp8gDqVAiBnpg 10 | +GTLaC69WOm9OMXEROTOlin7gxlQ0pZO+2/M3uFFo/hXlIH/Mb5NPKlpNBqgLpqI 11 | wtGMugt7Dx9JoMwWvEBlzMgeycYmNXwSHsdQ5kxFS5uYuZEri62Xrk/WWlev/PDC 12 | RdcSUhrjVSNotFQveGKSwC5z2FOAIZioA0mPxsBixSaQY8fhiaC5ydUw4F0CAwEA 13 | AQKCAgB5M4AG/Aus5x6d/hC4YzxCEvT7IakisLQmaIFpfhiuO6YbgTO9S60Qkg5w 14 | FZ/vbKNyHxI3juGMr6A90dQzRqFj3e4DS7BuQwFgKW+mlx/Flt231AzCn0w2MoD7 15 | oDOHObyGK/bWYFZHBfNDbWHSgV+88zi/ZfI/uxqwuPXixkaxCZFCnSOnIN7pwKrp 16 | KWs+D4CNCCwfjprDAlTDkwEDXH2PskbjZwHi13fUCkYjw3f3jYxnehwFzBWSONdw 17 | MYDySwGWzEOOF7bOJ5qeld4BemimH0DaOmi0+A4QrtSLIxp1daUPdIyiwAFvIIoG 18 | D0592WV/CpDshr8OHZHmTscV1J/0OTNa3Pr5K9L24mSIf2Zd85X9nl3qLbYPqdCJ 19 | 1lQUYOiPO0us58y6V1vS6CWK1J3fVMCcmIUDHoAelHPKrgU9tHjCTj0Dk3LYz/hm 20 | oK9I4OE0TKfWkUgSogB753sR/0ssnTeIFy9RAEPZXlJ9EGiNU3f8ZnuoAOi6pFWi 21 | OO80K1sAhuDjX67O6OoqFMCWJTd1oXjLqjbLBsVeGH5kiZHZVqdAAtISV7f8jAQR 22 | wEc2OgDJ6e38HYgwtqtR3Vkv7tVXfWx0Z9SYqtJWQv+CAwoPUvD+Bhok4iW2k1U7 23 | Fq4iVHMl1n4ljZBgkHCl9Y8+h1qo5f+PgjsKblaiPS8EUCL8yQKCAQEA9I8/vpsu 24 | 8H/je7kLUlikkKiKDydU1tt/QRH33x5ZdCIHkXvGkd5GhGyZ8sngHJkOlteGBcVx 25 | 2kZC+4c3bKn5Pke38U+W8Xw2ZUm3zTn11Trlg2EhTdl+UTW/BBFt8o/hHYLW3nuT 26 | y+VO3uZYtghGwYBwAeuYBRYRFpnZS9n0yMOwt9jCbqjSpL+QnY4HFcY3NWBE2MFg 27 | JerVtpSEZFCeYksUU3IOCU0Ol0IjfmMy9XjEkkmeb4E7OFjHH1F7VaHT2ZlhhHzf 28 | TKYvHWotFS621oDl8LBtD/8ZS0cYNpVfoJbKDhNMMAZlGXq6fDwj9d76SU70BMc+ 29 | PacThaAAY7ke/wKCAQEAxryPThH3GXvhIoakEtlS+dnNgIsOuGZYQj2CniKjmIv7 30 | D9OGEd7UC+BxDtVMiq4Sq7vYeUcJ1g9EW1hwwjQIswbW5IGoUuUHpBe9jB1h88Cg 31 | uMWGvtNJzZM0t4arlUrouIz8jxE6mcIysvRAIoFT+D8fzITOIVDx7l6qDbT51jbB 32 | d886V1cN8/FdyEa08w+ChkAR/s+57KQMjBsUeAPAMac2ocgYsSE1YoXcMdZYfQfy 33 | QSJZOt0hTYrOUFlrBBmTGRRv/kKbNeDnr2jjWPRzzupuOUejOUki/z2Ts/lY3vtv 34 | 8dA1kjwR/kgVXK+xa3LsZsYlu3myEashT+YMj1HcowKCAQEAinoWeSI7yPhRYfwc 35 | egsxW6vjSMNXmbV97+VxukfgFQ8zw+AXRv9aZJ9t6HkAypCsHyN4gwoS9qp0QSKG 36 | cqQoOmi3sg8EBEb2MhI03iMknRGVZff4uLEfgnJxb6dC32cy69frPN0yifCU4UgD 37 | EUfMcML+KUgysyaUlHyW+wk2Pvv3s5IsPiaf56OFCoGiZ2TuW+3f7fBJNg8r5g9g 38 | i8DOfg/POZTKd9/HFETh/i3DbBVvEPpYmQDO/I/gaE5mDM3uPDdKbY+bjTZIVVqK 39 | noTuCLXB/bCYgMdMlkByaG3aUP8w+BlbOZJVasEAmVogbpdMl3f6Wj5LcvOI7U/1 40 | CIKJFwKCAQALXyK8Dt8awDHjrdyZj4Hl9gaCQnK3LnQCZk6hCc5enjPhdfMH9r4f 41 | Z9pQRPg6PzemR/tdBSmU7A63Q1pAYoXU6KFHNfwRsjU7uHgKGmxObElGCVdqd+CT 42 | OMcdcUFEK6MhXD/fV9cIkUohX0SENO4/GC2ToE3DLkSJpTUJz78z+LIdTuhBsyOD 43 | P95j5VfZSJvpXqUo9W3oEoL9SVdkfqJytOS1YSO4jvPlDU/KMj+h9+Buxa5hZeHP 44 | 9A9WHae39laqarb1z43eCV54dQH9Rw+RWWyxLl4ymvK7tCRNegkRyUVgis9l7LYC 45 | 3NEMGqmGQm8wekoSbiY4SJiBX+J8GO0NAoIBAE5nwz0iU4+ZFbuknqI76MVkL6xC 46 | llcZHCOpZZIpXTZmCqWySQycqFO3U8BxD2DTxsNAKH0YsnaihHyNgp1g5fzFnPb8 47 | HlVuHhCfJN5Ywo1gfCNHaRJIMYgjPAD+ewTDSowbzH2HlpUt5NOQJWuiZfxPDJll 48 | qmRAqZ3fyf8AP7pXxj5p0y8AUPtkmjk7h8hxstbvcmQvtTDzgkqeBYwZhEtGemdY 49 | OCi7UuXYjRwDfnka2nAdB9lv4ExvU5lkrJVZXONYUwToArAxRtdKMqCfl36JILMA 50 | C4+9sOeTo6HtZRvPVNLMX/rkWIv+onFgblfb8guA2wz1JUT00fNxQPt1k8s= 51 | -----END RSA PRIVATE KEY----- 52 | -------------------------------------------------------------------------------- /src/httpserver/qhttpserverrouter.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | // Qt-Security score:significant reason:default 4 | 5 | #ifndef QHTTPSERVERROUTER_H 6 | #define QHTTPSERVERROUTER_H 7 | 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | QT_BEGIN_NAMESPACE 19 | 20 | class QAbstractHttpServer; 21 | class QHttpServerResponder; 22 | class QHttpServerRequest; 23 | class QHttpServerRouterRule; 24 | 25 | class QHttpServerRouterPrivate; 26 | class QHttpServerRouter 27 | { 28 | Q_DECLARE_PRIVATE(QHttpServerRouter) 29 | Q_DISABLE_COPY_MOVE(QHttpServerRouter) 30 | 31 | public: 32 | Q_HTTPSERVER_EXPORT QHttpServerRouter(QAbstractHttpServer *server); 33 | Q_HTTPSERVER_EXPORT ~QHttpServerRouter(); 34 | 35 | template 36 | bool addConverter(QAnyStringView regexp) { 37 | // The QMetaType converter registry is shared by all parts of Qt which uses it. 38 | // Only register a converter if it is not already registered. If registering fails, 39 | // check that it has been registered by a different thread between the two calls 40 | // or return false. The registerConverter function will output an warning if a 41 | // converter is already registered. 42 | if (!QMetaType::hasRegisteredConverterFunction() 43 | && !QMetaType::registerConverter() 44 | && !QMetaType::hasRegisteredConverterFunction()) 45 | return false; 46 | 47 | addConverter(QMetaType::fromType(), regexp); 48 | return true; 49 | } 50 | 51 | Q_HTTPSERVER_EXPORT void addConverter(QMetaType metaType, QAnyStringView regexp); 52 | Q_HTTPSERVER_EXPORT void removeConverter(QMetaType metaType); 53 | Q_HTTPSERVER_EXPORT void clearConverters(); 54 | Q_HTTPSERVER_EXPORT const QHash &converters() const &; 55 | Q_HTTPSERVER_EXPORT QHash converters() &&; 56 | 57 | template> 58 | QHttpServerRouterRule *addRule(std::unique_ptr rule) 59 | { 60 | return addRuleHelper( 61 | std::move(rule), 62 | typename ViewTraits::Arguments::Indexes{}); 63 | } 64 | 65 | Q_HTTPSERVER_EXPORT bool handleRequest(const QHttpServerRequest &request, 66 | QHttpServerResponder &responder) const; 67 | 68 | private: 69 | template 70 | QHttpServerRouterRule *addRuleHelper(std::unique_ptr rule, 71 | std::index_sequence) 72 | { 73 | return addRuleImpl(std::move(rule), {ViewTraits::Arguments::template metaType()...}); 74 | } 75 | 76 | Q_HTTPSERVER_EXPORT QHttpServerRouterRule *addRuleImpl(std::unique_ptr rule, 77 | std::initializer_list metaTypes); 78 | 79 | std::unique_ptr d_ptr; 80 | }; 81 | 82 | QT_END_NAMESPACE 83 | 84 | #endif // QHTTPSERVERROUTER_H 85 | -------------------------------------------------------------------------------- /src/httpserver/qhttpserverparser_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | // Qt-Security score:significant reason:default 4 | 5 | #ifndef QHTTPSERVERPARSER_P_H 6 | #define QHTTPSERVERPARSER_P_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #if __has_include() 13 | #include 14 | #else 15 | #include 16 | #endif 17 | 18 | // 19 | // W A R N I N G 20 | // ------------- 21 | // 22 | // This file is not part of the Qt API. It exists for the convenience 23 | // of QHttpServer. This header file may change from version to 24 | // version without notice, or even be removed. 25 | // 26 | // We mean it. 27 | 28 | QT_BEGIN_NAMESPACE 29 | 30 | class QHttp2Stream; 31 | 32 | class QHttpServerParser 33 | { 34 | friend class QHttpServerRequest; 35 | 36 | public: 37 | QHttpServerParser(const QHostAddress &remoteAddress, quint16 remotePort, 38 | const QHostAddress &localAddress, quint16 localPort, 39 | QHttpServerRequestFilter *filter); 40 | 41 | quint16 port = 0; 42 | 43 | enum class State { 44 | NothingDone, 45 | ReadingRequestLine, 46 | ReadingHeader, 47 | ExpectContinue, 48 | ReadingData, 49 | AllDone, 50 | } state = State::NothingDone; 51 | 52 | QHttpHeaderParser headerParser; 53 | 54 | bool parseRequestLine(QByteArrayView line); 55 | qsizetype readRequestLine(QIODevice *socket); 56 | qsizetype readHeader(QIODevice *socket); 57 | qsizetype sendContinue(QIODevice *socket); 58 | qsizetype readBodyFast(QIODevice *socket); 59 | qsizetype readRequestBodyRaw(QIODevice *socket, qsizetype size); 60 | qsizetype readRequestBodyChunked(QIODevice *socket); 61 | qsizetype getChunkSize(QIODevice *socket, qsizetype *chunkSize); 62 | void sendError(QIODevice *socket, QHttpServerResponder::StatusCode error); 63 | bool isUrlSizeAllowed(QByteArrayView requestLine); 64 | 65 | bool parse(QIODevice *socket); 66 | #if QT_CONFIG(http) 67 | bool parse(QHttp2Stream *socket); 68 | #endif 69 | void clear(); 70 | 71 | qint64 contentLength() const; 72 | QByteArray headerField(const QByteArray &name) const 73 | { return headerParser.combinedHeaderValue(name); } 74 | QString getClientIpAddressAndPort() const; 75 | 76 | QHostAddress remoteAddress; 77 | quint16 remotePort; 78 | QHostAddress localAddress; 79 | quint16 localPort; 80 | QHttpServerRequestFilter *filter; 81 | QUrl url; 82 | QHttpServerRequest::Method method; 83 | QHttpHeaders headers; 84 | QByteArray body; 85 | 86 | bool handling{false}; 87 | qsizetype bodyLength; 88 | qsizetype contentRead; 89 | bool chunkedTransferEncoding; 90 | bool lastChunkRead; 91 | qsizetype currentChunkRead; 92 | qsizetype currentChunkSize; 93 | bool upgrade; 94 | int majorVersion; 95 | int minorVersion; 96 | 97 | QByteArray fragment; 98 | QByteDataBuffer bodyBuffer; 99 | }; 100 | 101 | QT_END_NAMESPACE 102 | 103 | #endif // QHTTPSERVERPARSER_P_H 104 | -------------------------------------------------------------------------------- /tests/benchmarks/qhttpserver/transfer/data/localhost.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQDrMu85IgNxW1YS 3 | iCd3oCCKkewjnZ490iTVBRmzAc3XCIJgbwNDh+PDpzzDnFU+tKLP8dNWlGXdRJLF 4 | TTYtMeez8H9L+3zEH4XURTZ7gLNyEgOrs7iBoY9xBSjWHvRKVXSkHQH6qKpRCjtW 5 | x9zQwm7BRMxJavByMszICDQ9VD7dY+e3gbEv9xXfsebsqKkmhajTP1zbXXmCd5/T 6 | MjFKhcxw+KWKbhWuWf8g+9umy9vlKzeG4wL/uyKimQC6UpNAf0I+ciV/xV1jwYzl 7 | CdpyoNPWdiTAtLxQgUlgXiKA3B/d5QQDCtxCi8efn3UHcIeCgoT8VvNLC7OSuDjg 8 | frEDqyx4gYG0JYlehxCiIE4oIL4qCzZ9DgZ9q41Nvt8Me64y3Qbe7qZdx0NTOCwB 9 | VobJA6T9sGxIjC6uc1E63Lnc3Ght2W3uFZoxA/ZlpTFxVHNe58VIirXmM95nvSXZ 10 | cVSwk9f62D+g4yjjBeJHLzGYt3cMXJVqYJTEm5iaNX0LzkSPJctsSsO913jp+nP2 11 | Zm46BlYsa8khhULMfRhFgPaLARSBljHQDL/uMNK8ux5f7yTv6HIAT2XfFej+PvqQ 12 | OtaZLmk7UTh6SwmgLjtBjP/aDnVT2BW3NQ55AeYKJT5Kv/xgS3jkd39VsOB9wKw2 13 | flFy9BOHR4Yc+WabuAFt3vNi0q/eyQIDAQABAoICAACIUR0VoAEe0jEwzHkTfFtf 14 | 9PNIMTJl4kY2sJ4UghcramMmQTFDEp+P5n3xYcqGbWtv2lkC9T+U3wmyEO41g5cn 15 | U1x0TW4ivaJzRSouqolWs9osyh1GBL1+Y98nOwmbi6vu8mETRm5wSd3ajjwNQqOu 16 | oJFGfBSgG5FU3mxon0tQRXcnhKONiUfEPvf4ckiXayBOT4siGSsz0uFvJsgqySGU 17 | 2IgZk3Q9eSvFkjPcmIr6Z/Hm2+wBDBUm6EbjtrhhyWA7kSzqwRk/mA5xMSTLCyu8 18 | QP1MM3RxtH0yvVyCExLlKLcKjGDcsOciPOk3RqFDoyIwnrSj6kRJ5TwR4Vv3JF7A 19 | 3L203PYwl003qAO780zJcn54PHPe59N/55ZEUBveNodqyrpA9T2BiKSVTguh4VqS 20 | y8iUftxC8cjfTwXMrlfValyiRHaVszFmdD2aLw2ZZByB2FZ3L2ifvMg0XwCYnUYz 21 | O3+DCdDjVB+xU5jy5EFEpI9qUGVWIse85JMsr6sUQdIuxqebsXgCAmpozjY/Iw7Y 22 | KAWMq5FFPLFkjoNLHBf5LXkGWTyvB1oMcKU6gYTy29FC4OvnKo9oABzLDRADR/O9 23 | gvs8xCbel13XqHUjCQ5jabd8GpaJgnaN+rR8bTExO6/XyQQTm1191zUZxVZBZHYQ 24 | sqgpar0cqftlfDhtZXfhAoIBAQD82HqmAwzPPxPcoxxgF6aEIW4TVSSTagUkKmgH 25 | sGyOCSPkHtNvlGao5GhzO4uwZNz8foGb0PmJlGiL7FUxZZyDoAo+JGV6qD4ByG6y 26 | 1NWgWyzlNWgSYBeK+wEauR6Dv6z9IVuQjvCNucd0xaq4di8m7FUbGpefVvKepVSY 27 | JjcqCUs/wECzZ8C7VzEEU2+NbglgzN4ot9eB7OCQcMuBcqgYQHpHk42bsES88J+Y 28 | tA1pWvcLION68st0eFmsc8MiZVdh6wcW5w0J56YmV3MHr/0evhmQijVtKOkmtZS8 29 | mJOuypGYCNpqsZyp+7IRvBsJn0FK+MMoFGkgXUCfuIUmIKAhAoIBAQDuIhjAlRvs 30 | 41sB64EjJxMrJ1FwlSBm8uvmQZw29J63jZLN5GpRp6dJyvQ0z42ut+eB7LJmcKxo 31 | QY8Uz+5oH3n5YD6hl0NiAWtSE0rLn1eOOOUoP+cfVocnwv4ILaKvDTGXfL53WLnu 32 | G/QPU4PnynSSDDDg3qJBSP1Xwj9+2tAGSGElLKp6avbRQLZWCJWtptI6cr32VEd9 33 | ENvGMsIXOi9KtNBc/AL0ZkV0PyU5wrOw4cZJWI3kyMhcfBlf1a2OH+P/T5vA8WIy 34 | XoFDM6XMbC7g2B2g8LffyprycJ2hmYL7WkwFBGo9cOuEVnfz6nzUuqegSyqsnPwy 35 | HUdmR73E5QmpAoIBAQDrhd8het/YwSIIOSv6Wq1ykQ1PFtV+N5jYamQDHZTQ7bSw 36 | DwLXAf5qvnCJPmNNiXbMAC9M7Gk1fbew9xEYdVVIyrAf2JlqmwM/d+udy2G/AI8e 37 | ZxQtYbMsc8lAkkXZZZeHJyZ6zptG+VHQ9TuknfooIKbaG3g3Ja/UlZ7qJ1blYkjk 38 | 9nmOZEwEdiCjrfDQZjp4H/2lIjKtxPAdu+PlDd+Ez7LXr5uN9bDh6qZPgRCpHeHX 39 | TOh5I2bfdCfb2u1ewdWW0W4GKG1d15lOR9FPzOBUXbHEkOlZaG1d8HC/CMUwYWMj 40 | osOJ9S5ArMLfgEATQ3R3mKd5UyHl0teasC/fJy7hAoIBAFN1nck5OT1P/aBxoqPo 41 | WP6B3Dgh++Y481aS3iYgm9PnCXGhwWV25dmmCOrNZ3G5wKi3hVsD2Fj9ySDZM0xI 42 | 493zzl+h/RrHNo7gdhFhejU9WYs+wkkocVwNKi1BmUfSzvOx46s+bIO4RlRsx8kg 43 | GrTpEuRtAt7wruHoEYrrM4dQLMPzoJghDvoNvRnwDk17LykO9+byaM+7bdtMBNxR 44 | Jyv+rRw5sutnQKZaTzisNYAj0PP51lk9yYMod1gwMpCiOq1LgGIh93GBz7n2ywAX 45 | VmK1O8UhOMB1aNLZh1WQ0Og5IHWNs5JvFgwephHVuARymrdCQOWYa4dA3bpKIId2 46 | YmkCggEAfx8yO2/mXrZPc/J24djZQ25dGgTjRekx6s2RDn9Xmp6Py3GQUPs/t7zH 47 | 04vZsN0RMIfxBSmPJwNJ2sLKmNy4yCJd4F4OYH6gktGRGf2SDBPomP3tVHQWdl34 48 | kH1YppFr4Jlnq1xvO1x8qnGe0oUhOpGFrZ4ahyJTc0Nw+uZkHbesBy22ca8zkWE3 49 | 0HF3r1AMQyO35q4af6vkkDzNetnIlXkvM3AQiCoxokCU76IVX0KEERNa35pCxuaL 50 | DCBpqxYNEYRKxci5qoe+3O16Eeq5oXtZFey1m68GdKJ7V+uVKceWjOexRrh9BwRw 51 | sZfbt1qjc6MHdhEAr4BuPIV6dRF+cA== 52 | -----END PRIVATE KEY----- 53 | -------------------------------------------------------------------------------- /tests/auto/qhttpserverresponse/data/image.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 20 | 22 | image/svg+xml 23 | 25 | 26 | 27 | 28 | 29 | 31 | 51 | 55 | 59 | 63 | 67 | 68 | -------------------------------------------------------------------------------- /src/httpserver/qabstracthttpserver.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | // Qt-Security score:significant reason:default 4 | 5 | #ifndef QABSTRACTHTTPSERVER_H 6 | #define QABSTRACTHTTPSERVER_H 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | #if QT_CONFIG(ssl) 17 | #include 18 | #endif 19 | 20 | #if defined(QT_WEBSOCKETS_LIB) 21 | #include 22 | #endif // defined(QT_WEBSOCKETS_LIB) 23 | 24 | #include 25 | #include 26 | 27 | QT_BEGIN_NAMESPACE 28 | 29 | class QHttpServerRequest; 30 | class QHttpServerResponder; 31 | class QLocalServer; 32 | class QTcpServer; 33 | 34 | class QAbstractHttpServerPrivate; 35 | class Q_HTTPSERVER_EXPORT QAbstractHttpServer : public QObject 36 | { 37 | Q_OBJECT 38 | friend class QHttpServerHttp1ProtocolHandler; 39 | friend class QHttpServerHttp2ProtocolHandler; 40 | 41 | public: 42 | explicit QAbstractHttpServer(QObject *parent = nullptr); 43 | ~QAbstractHttpServer() override; 44 | 45 | QList serverPorts() const; 46 | bool bind(QTcpServer *server); 47 | QList servers() const; 48 | 49 | #if QT_CONFIG(localserver) 50 | bool bind(QLocalServer *server); 51 | QList localServers() const; 52 | #endif 53 | 54 | #if QT_CONFIG(ssl) 55 | QHttp2Configuration http2Configuration() const; 56 | void setHttp2Configuration(const QHttp2Configuration &configuration); 57 | #endif 58 | 59 | void setConfiguration(const QHttpServerConfiguration &config); 60 | QHttpServerConfiguration configuration() const; 61 | 62 | #if defined(QT_WEBSOCKETS_LIB) 63 | Q_SIGNALS: 64 | void newWebSocketConnection(); 65 | 66 | private: 67 | using WebSocketUpgradeVerifierPrototype = 68 | QHttpServerWebSocketUpgradeResponse (*)(const QHttpServerRequest &request); 69 | template 70 | using if_compatible_callable = typename std::enable_if< 71 | QtPrivate::AreFunctionsCompatible::value, 72 | bool>::type; 73 | 74 | void addWebSocketUpgradeVerifierImpl(const QObject *context, 75 | QtPrivate::QSlotObjectBase *slotObjRaw); 76 | 77 | public: 78 | bool hasPendingWebSocketConnections() const; 79 | std::unique_ptr nextPendingWebSocketConnection(); 80 | 81 | #ifdef Q_QDOC 82 | template 83 | void addWebSocketUpgradeVerifier(const QObject *context, Handler &&func) 84 | #else 85 | template = true> 86 | void addWebSocketUpgradeVerifier( 87 | const typename QtPrivate::ContextTypeForFunctor::ContextType *context, 88 | Handler &&func) 89 | #endif 90 | { 91 | addWebSocketUpgradeVerifierImpl( 92 | context, 93 | QtPrivate::makeCallableObject( 94 | std::forward(func))); 95 | } 96 | 97 | private: 98 | QHttpServerWebSocketUpgradeResponse 99 | verifyWebSocketUpgrade(const QHttpServerRequest &request) const; 100 | #endif // defined(QT_WEBSOCKETS_LIB) 101 | 102 | protected: 103 | QAbstractHttpServer(QAbstractHttpServerPrivate &dd, QObject *parent = nullptr); 104 | 105 | virtual bool handleRequest(const QHttpServerRequest &request, 106 | QHttpServerResponder &responder) = 0; 107 | virtual void missingHandler(const QHttpServerRequest &request, 108 | QHttpServerResponder &responder) = 0; 109 | 110 | private: 111 | Q_DECLARE_PRIVATE(QAbstractHttpServer) 112 | }; 113 | 114 | QT_END_NAMESPACE 115 | 116 | #endif // QABSTRACTHTTPSERVER_H 117 | -------------------------------------------------------------------------------- /src/httpserver/qhttpserverhttp1protocolhandler_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | // Qt-Security score:significant reason:default 4 | 5 | #ifndef QHttpServerHttp1ProtocolHandler_H 6 | #define QHttpServerHttp1ProtocolHandler_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | // 18 | // W A R N I N G 19 | // ------------- 20 | // 21 | // This file is not part of the Qt API. It exists for the convenience 22 | // of QHttpServer. This header file may change from version to 23 | // version without notice, or even be removed. 24 | // 25 | // We mean it. 26 | 27 | QT_BEGIN_NAMESPACE 28 | 29 | class QTcpSocket; 30 | class QAbstractHttpServer; 31 | #if QT_CONFIG(localserver) 32 | class QLocalSocket; 33 | #endif 34 | template 35 | struct QHttpServerHttp1IOChunkedTransfer; 36 | 37 | class QHttpServerHttp1ProtocolHandler : public QHttpServerStream 38 | { 39 | Q_OBJECT 40 | 41 | friend class QAbstractHttpServerPrivate; 42 | friend class QHttpServerResponder; 43 | 44 | private: 45 | QHttpServerHttp1ProtocolHandler(QAbstractHttpServer *server, QIODevice *socket, 46 | QHttpServerRequestFilter *filter, 47 | QHttpServerConfiguration *config); 48 | 49 | void responderDestroyed(quint32 streamId) final; 50 | void startHandlingRequest() final; 51 | void socketDisconnected() final; 52 | 53 | void handleReadyRead(); 54 | 55 | void write(const QByteArray &body, const QHttpHeaders &headers, 56 | QHttpServerResponder::StatusCode status, quint32 streamId) final; 57 | void write(QHttpServerResponder::StatusCode status, quint32 streamId) final; 58 | void write(QIODevice *data, const QHttpHeaders &headers, 59 | QHttpServerResponder::StatusCode status, quint32 streamId) final; 60 | void writeBeginChunked(const QHttpHeaders &headers, 61 | QHttpServerResponder::StatusCode status, 62 | quint32 streamId) final; 63 | void writeChunk(const QByteArray &body, quint32 streamId) final; 64 | void writeEndChunked(const QByteArray &data, 65 | const QHttpHeaders &trailers, 66 | quint32 streamId) final; 67 | 68 | void writeStatusAndHeaders(QHttpServerResponder::StatusCode status, 69 | const QHttpHeaders &headers); 70 | void writeHeader(const QByteArray &key, const QByteArray &value); 71 | void write(const QByteArray &data); 72 | void write(const char *body, qint64 size); 73 | 74 | void addConnectionAndKeepAliveHeaders(QHttpHeaders &headers); 75 | void checkKeepAliveTimeout(); 76 | void resumeListening(); 77 | void closeConnection(); 78 | 79 | QAbstractHttpServer *server; 80 | QIODevice *socket; 81 | QTcpSocket *tcpSocket; 82 | #if QT_CONFIG(localserver) 83 | QLocalSocket *localSocket; 84 | #endif 85 | QHttpServerRequestFilter *m_filter; 86 | QHttpServerConfiguration *m_configuration; 87 | 88 | enum class TransferState { 89 | Ready, 90 | HeadersSent, 91 | ChunkedTransferBegun, 92 | IODeviceTransferBegun, 93 | } state = TransferState::Ready; 94 | 95 | // To avoid destroying the object when socket object is destroyed while 96 | // a request is still being handled. 97 | bool handlingRequest = false; 98 | bool protocolChanged = false; 99 | QElapsedTimer lastActiveTimer; 100 | bool useHttp1_1 = false; 101 | bool keepAlive = true; 102 | void completeWriting(); 103 | 104 | template 105 | friend struct QHttpServerHttp1IOChunkedTransfer; 106 | }; 107 | 108 | QT_END_NAMESPACE 109 | 110 | #endif // QHttpServerHttp1ProtocolHandler_H 111 | -------------------------------------------------------------------------------- /src/httpserver/qhttpserverviewtraits_impl.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2020 Mikhail Svetkin 2 | // Copyright (C) 2019 The Qt Company Ltd. 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | // Qt-Security score:significant reason:default 5 | 6 | #ifndef QHTTPSERVERVIEWTRAITS_IMPL_H 7 | #define QHTTPSERVERVIEWTRAITS_IMPL_H 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | QT_BEGIN_NAMESPACE 18 | 19 | namespace QtPrivate { 20 | 21 | template 22 | struct FunctionTraitsHelper 23 | { 24 | static constexpr const int ArgumentCount = sizeof ... (Args); 25 | static constexpr const int ArgumentIndexMax = ArgumentCount - 1; 26 | using ReturnType = ReturnT; 27 | 28 | template 29 | struct Arg { 30 | using Type = typename std::tuple_element>::type; 31 | 32 | using CleanType = q20::remove_cvref_t; 33 | 34 | static constexpr bool CopyConstructible = std::is_copy_constructible_v; 35 | }; 36 | }; 37 | 38 | template 39 | struct FunctionTraitsImpl; 40 | 41 | template 42 | struct FunctionTraitsImpl : public FunctionTraitsImpl 43 | { 44 | }; 45 | 46 | template 47 | struct FunctionTraitsImpl : public FunctionTraitsHelper 48 | { 49 | }; 50 | 51 | template 52 | struct FunctionTraitsImpl 53 | : public FunctionTraitsHelper 54 | { 55 | }; 56 | 57 | template 58 | struct FunctionTraitsImpl 59 | : public FunctionTraitsHelper 60 | { 61 | }; 62 | 63 | template 64 | using FunctionTraits = FunctionTraitsImpl>; 65 | 66 | template 67 | struct CheckAny { 68 | static constexpr bool Value = (T::Value || ...); 69 | static constexpr bool TypeMatched = (T::TypeMatched || ...); 70 | static constexpr bool StaticAssert = (T::StaticAssert || ...); 71 | }; 72 | 73 | template 74 | struct ViewTraits { 75 | using FTraits = FunctionTraits; 76 | using ArgumentIndexes = typename std::make_index_sequence; 77 | 78 | template 79 | struct SpecialHelper { 80 | using Arg = typename FTraits::template Arg; 81 | using CleanSpecialT = q20::remove_cvref_t; 82 | 83 | static constexpr bool TypeMatched = std::is_same::value; 84 | static constexpr bool TypeCVRefMatched = std::is_same::value; 85 | 86 | static constexpr bool ValidPosition = 87 | (I == FTraits::ArgumentIndexMax || 88 | I == FTraits::ArgumentIndexMax - 1); 89 | static constexpr bool ValidAll = TypeCVRefMatched && ValidPosition; 90 | 91 | static constexpr bool AssertCondition = 92 | DisableStaticAssert || !TypeMatched || TypeCVRefMatched; 93 | 94 | static constexpr bool AssertConditionOrder = 95 | DisableStaticAssert || !TypeMatched || ValidPosition; 96 | 97 | static constexpr bool StaticAssert = AssertCondition && AssertConditionOrder; 98 | 99 | static_assert(AssertConditionOrder, 100 | "ViewHandler arguments error: " 101 | "QHttpServerRequest or QHttpServerResponder" 102 | " can only be one of the two last arguments"); 103 | }; 104 | 105 | template 106 | struct Special { 107 | using Helper = SpecialHelper; 108 | static constexpr bool Value = Helper::ValidAll; 109 | static constexpr bool TypeMatched = Helper::TypeMatched; 110 | static constexpr bool StaticAssert = Helper::StaticAssert; 111 | static constexpr bool AssertCondition = Helper::AssertCondition; 112 | }; 113 | }; 114 | 115 | } // namespace QtPrivate 116 | 117 | QT_END_NAMESPACE 118 | 119 | #endif // QHTTPSERVERVIEWTRAITS_IMPL_H 120 | -------------------------------------------------------------------------------- /tests/auto/qhttpserverresponse/tst_qhttpserverresponse.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 Tasuku Suzuki 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #if QT_CONFIG(mimetype) 10 | #include 11 | #endif 12 | 13 | QT_BEGIN_NAMESPACE 14 | 15 | using namespace Qt::Literals; 16 | 17 | class tst_QHttpServerResponse : public QObject 18 | { 19 | Q_OBJECT 20 | 21 | private slots: 22 | void mimeTypeDetection_data(); 23 | void mimeTypeDetection(); 24 | void mimeTypeDetectionFromFile_data(); 25 | void mimeTypeDetectionFromFile(); 26 | void headers(); 27 | }; 28 | 29 | void tst_QHttpServerResponse::mimeTypeDetection_data() 30 | { 31 | QTest::addColumn("content"); 32 | 33 | QTest::addRow("application/x-zerosize") 34 | << QFINDTESTDATA("data/empty"); 35 | 36 | QTest::addRow("text/plain") 37 | << QFINDTESTDATA("data/text.plain"); 38 | 39 | QTest::addRow("text/html") 40 | << QFINDTESTDATA("data/text.html"); 41 | 42 | QTest::addRow("image/png") 43 | << QFINDTESTDATA("data/image.png"); 44 | 45 | QTest::addRow("image/jpeg") 46 | << QFINDTESTDATA("data/image.jpeg"); 47 | 48 | QTest::addRow("image/svg+xml") 49 | << QFINDTESTDATA("data/image.svg"); 50 | } 51 | 52 | void tst_QHttpServerResponse::mimeTypeDetection() 53 | { 54 | #if !QT_CONFIG(mimetype) 55 | QSKIP("Test requires QMimeDatabase"); 56 | #else 57 | QFETCH(QString, content); 58 | 59 | QFile file(content); 60 | QVERIFY(file.open(QFile::ReadOnly)); 61 | QByteArray data = file.readAll(); 62 | QHttpServerResponse response(data); 63 | file.close(); 64 | 65 | const QMimeType mimeType = QMimeDatabase().mimeTypeForData(data); 66 | QCOMPARE(response.mimeType(), mimeType.name()); 67 | #endif 68 | } 69 | 70 | void tst_QHttpServerResponse::mimeTypeDetectionFromFile_data() 71 | { 72 | QTest::addColumn("content"); 73 | 74 | QTest::addRow("application/x-zerosize") 75 | << QFINDTESTDATA("data/empty"); 76 | 77 | QTest::addRow("text/plain") 78 | << QFINDTESTDATA("data/text.plain"); 79 | 80 | QTest::addRow("text/html") 81 | << QFINDTESTDATA("data/text.html"); 82 | 83 | QTest::addRow("image/png") 84 | << QFINDTESTDATA("data/image.png"); 85 | 86 | QTest::addRow("image/jpeg") 87 | << QFINDTESTDATA("data/image.jpeg"); 88 | 89 | QTest::addRow("image/svg+xml") 90 | << QFINDTESTDATA("data/image.svg"); 91 | 92 | QTest::addRow("application/json") 93 | << QFINDTESTDATA("data/application.json"); 94 | } 95 | 96 | void tst_QHttpServerResponse::mimeTypeDetectionFromFile() 97 | { 98 | #if !QT_CONFIG(mimetype) 99 | QSKIP("Test requires QMimeDatabase"); 100 | #else 101 | QFETCH(QString, content); 102 | const QMimeType mimeType = QMimeDatabase().mimeTypeForFile(content); 103 | 104 | const QByteArray responseMimeType = QHttpServerResponse::fromFile(content).mimeType(); 105 | QCOMPARE(responseMimeType, mimeType.name()); 106 | #endif 107 | } 108 | 109 | void tst_QHttpServerResponse::headers() 110 | { 111 | QHttpServerResponse resp(""); 112 | 113 | const QByteArray test1 = "test1"_ba; 114 | const QByteArray test2 = "test2"_ba; 115 | const QByteArray zero = "application/x-zerosize"_ba; 116 | 117 | QHttpHeaders h = resp.headers(); 118 | QVERIFY(!h.contains(QHttpHeaders::WellKnownHeader::ContentLength)); 119 | const auto contentTypeValues = h.values(QHttpHeaders::WellKnownHeader::ContentType); 120 | QCOMPARE(contentTypeValues.size(), 1); 121 | QCOMPARE(contentTypeValues.first(), zero); 122 | 123 | h.append(QHttpHeaders::WellKnownHeader::ContentType, test1); 124 | h.append(QHttpHeaders::WellKnownHeader::ContentLength, test2); 125 | resp.setHeaders(h); 126 | QCOMPARE(resp.headers().toListOfPairs(), h.toListOfPairs()); 127 | 128 | resp.setHeaders({}); 129 | QVERIFY(resp.headers().isEmpty()); 130 | 131 | auto tmp = h; 132 | resp.setHeaders(std::move(tmp)); 133 | QCOMPARE(resp.headers().toListOfPairs(), h.toListOfPairs()); 134 | } 135 | 136 | QT_END_NAMESPACE 137 | 138 | QTEST_MAIN(tst_QHttpServerResponse) 139 | 140 | #include "tst_qhttpserverresponse.moc" 141 | -------------------------------------------------------------------------------- /src/httpserver/qhttpserverhttp2protocolhandler_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | // Qt-Security score:significant reason:default 4 | 5 | #ifndef QHttpServerHttp2ProtocolHandler_H 6 | #define QHttpServerHttp2ProtocolHandler_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | 19 | // 20 | // W A R N I N G 21 | // ------------- 22 | // 23 | // This file is not part of the Qt API. It exists for the convenience 24 | // of QHttpServer. This header file may change from version to 25 | // version without notice, or even be removed. 26 | // 27 | // We mean it. 28 | 29 | QT_REQUIRE_CONFIG(http); 30 | QT_REQUIRE_CONFIG(ssl); 31 | 32 | QT_BEGIN_NAMESPACE 33 | 34 | class QTcpSocket; 35 | class QAbstractHttpServer; 36 | class QHttp2Connection; 37 | class QHttp2Stream; 38 | 39 | struct QHttpServerHttp2Queue 40 | { 41 | QQueue data; 42 | HPack::HttpHeader trailers; 43 | bool allEnqueued = false; 44 | }; 45 | 46 | struct QHttpServerHttp2Data 47 | { 48 | qsizetype numberOfHeaders = 0; 49 | qsizetype headersSize = 0; 50 | qsizetype dataSize = 0; 51 | bool done = false; 52 | }; 53 | 54 | class QHttpServerHttp2ProtocolHandler : public QHttpServerStream 55 | { 56 | Q_OBJECT 57 | 58 | friend class QAbstractHttpServerPrivate; 59 | 60 | private: 61 | QHttpServerHttp2ProtocolHandler(QAbstractHttpServer *server, 62 | QIODevice *socket, 63 | QHttpServerRequestFilter *filter); 64 | 65 | void responderDestroyed(quint32 streamId) final; 66 | void startHandlingRequest() final; 67 | void socketDisconnected() final; 68 | 69 | void write(const QByteArray &body, const QHttpHeaders &headers, 70 | QHttpServerResponder::StatusCode status, quint32 streamId) final; 71 | void write(QHttpServerResponder::StatusCode status, quint32 streamId) final; 72 | void write(QIODevice *data, const QHttpHeaders &headers, 73 | QHttpServerResponder::StatusCode status, quint32 streamId) final; 74 | void writeBeginChunked(const QHttpHeaders &headers, 75 | QHttpServerResponder::StatusCode status, 76 | quint32 streamId) final; 77 | void writeChunk(const QByteArray &body, quint32 streamId) final; 78 | void writeEndChunked(const QByteArray &data, 79 | const QHttpHeaders &trailers, 80 | quint32 streamId) final; 81 | 82 | void writeHeadersAndStatus(const QHttpHeaders &headers, 83 | QHttpServerResponder::StatusCode status, 84 | bool endStream, 85 | quint32 streamId); 86 | 87 | void checkKeepAliveTimeout(); 88 | 89 | private slots: 90 | void onStreamCreated(QHttp2Stream *stream); 91 | void onStreamClosed(quint32 streamId); 92 | void onStreamHalfClosed(quint32 streamId); 93 | void sendToStream(quint32 streamId); 94 | void onHeadersReceived(quint32 id, const HPack::HttpHeader &headers); 95 | void onDataReceived(quint32 id, qsizetype size); 96 | 97 | private: 98 | QHttp2Stream * getStream(quint32 streamId) const; 99 | void enqueueChunk(const QByteArray &body, bool allEnqueued, const QHttpHeaders &trailers, 100 | quint32 streamId); 101 | 102 | QAbstractHttpServer *m_server; 103 | QIODevice *m_socket; 104 | QTcpSocket *m_tcpSocket; 105 | QHttpServerRequestFilter *m_filter; 106 | QHttp2Connection *m_connection; 107 | QHash> m_streamConnections; 108 | QHash m_streamQueue; 109 | QHash m_streamData; 110 | QHash m_responders; 111 | qint32 m_responderCounter = 0; 112 | QElapsedTimer lastActiveTimer; 113 | }; 114 | 115 | QT_END_NAMESPACE 116 | 117 | #endif // QHttpServerHttp2ProtocolHandler_H 118 | -------------------------------------------------------------------------------- /src/httpserver/qhttpserverrequest.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | // Qt-Security score:significant reason:default 4 | 5 | #ifndef QHTTPSERVERREQUEST_H 6 | #define QHTTPSERVERREQUEST_H 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #if QT_CONFIG(ssl) 15 | #include 16 | #endif 17 | 18 | #include 19 | 20 | QT_BEGIN_NAMESPACE 21 | 22 | class QRegularExpression; 23 | class QString; 24 | class QHttpHeaders; 25 | class QHttpServerParser; 26 | 27 | class QHttpServerRequestPrivate; 28 | QT_DECLARE_QESDP_SPECIALIZATION_DTOR(QHttpServerRequestPrivate) 29 | 30 | class QHttpServerRequest final 31 | { 32 | friend class QHttpServerResponse; 33 | friend class QHttpServerParser; 34 | friend class QHttpServerStream; 35 | friend class QHttpServerHttp1ProtocolHandler; 36 | friend class QHttpServerHttp2ProtocolHandler; 37 | 38 | Q_GADGET_EXPORT(Q_HTTPSERVER_EXPORT) 39 | 40 | public: 41 | Q_HTTPSERVER_EXPORT QHttpServerRequest(); 42 | Q_HTTPSERVER_EXPORT QHttpServerRequest(const QHttpServerRequest &other); 43 | Q_HTTPSERVER_EXPORT QHttpServerRequest &operator=(const QHttpServerRequest &other); 44 | QHttpServerRequest(QHttpServerRequest &&other) noexcept = default; 45 | QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QHttpServerRequest) 46 | Q_HTTPSERVER_EXPORT ~QHttpServerRequest(); 47 | void swap(QHttpServerRequest &other) noexcept { d.swap(other.d); } 48 | 49 | enum class Method 50 | { 51 | Unknown = 0x0000, 52 | Get = 0x0001, 53 | Put = 0x0002, 54 | Delete = 0x0004, 55 | Post = 0x0008, 56 | Head = 0x0010, 57 | Options = 0x0020, 58 | Patch = 0x0040, 59 | Connect = 0x0080, 60 | Trace = 0x0100, 61 | 62 | AnyKnown = Get | Put | Delete | Post | Head | Options | Patch | Connect | Trace, 63 | }; 64 | Q_ENUM(Method) 65 | Q_DECLARE_FLAGS(Methods, Method) 66 | Q_FLAG(Methods) 67 | 68 | Q_HTTPSERVER_EXPORT QByteArray value(const QByteArray &key) const; 69 | Q_HTTPSERVER_EXPORT QUrl url() const; 70 | Q_HTTPSERVER_EXPORT QUrlQuery query() const; 71 | Q_HTTPSERVER_EXPORT Method method() const; 72 | Q_HTTPSERVER_EXPORT const QHttpHeaders &headers() const &; 73 | Q_HTTPSERVER_EXPORT QHttpHeaders headers() &&; 74 | Q_HTTPSERVER_EXPORT QByteArray body() const; 75 | Q_HTTPSERVER_EXPORT QHostAddress remoteAddress() const; 76 | Q_HTTPSERVER_EXPORT quint16 remotePort() const; 77 | Q_HTTPSERVER_EXPORT QHostAddress localAddress() const; 78 | Q_HTTPSERVER_EXPORT quint16 localPort() const; 79 | #if QT_CONFIG(ssl) 80 | Q_HTTPSERVER_EXPORT QSslConfiguration sslConfiguration() const; 81 | #endif 82 | 83 | private: 84 | #if !defined(QT_NO_DEBUG_STREAM) 85 | friend Q_HTTPSERVER_EXPORT QDebug operator<<(QDebug debug, const QHttpServerRequest &request); 86 | #endif 87 | 88 | Q_HTTPSERVER_EXPORT static QHttpServerRequest create(const QHttpServerParser &parser); 89 | #if QT_CONFIG(ssl) 90 | Q_HTTPSERVER_EXPORT static QHttpServerRequest create(const QHttpServerParser &parser, 91 | const QSslConfiguration &configuration); 92 | #endif 93 | 94 | Q_HTTPSERVER_EXPORT explicit QHttpServerRequest(const QHostAddress &remoteAddress, 95 | quint16 remotePort, 96 | const QHostAddress &localAddress, 97 | quint16 localPort); 98 | #if QT_CONFIG(ssl) 99 | Q_HTTPSERVER_EXPORT explicit QHttpServerRequest(const QHostAddress &remoteAddress, 100 | quint16 remotePort, 101 | const QHostAddress &localAddress, 102 | quint16 localPort, 103 | const QSslConfiguration &sslConfiguration); 104 | #endif 105 | 106 | QExplicitlySharedDataPointer d; 107 | }; 108 | 109 | Q_DECLARE_SHARED(QHttpServerRequest) 110 | 111 | Q_DECLARE_OPERATORS_FOR_FLAGS(QHttpServerRequest::Methods) 112 | 113 | QT_END_NAMESPACE 114 | 115 | #endif // QHTTPSERVERREQUEST_H 116 | -------------------------------------------------------------------------------- /licenseRule.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "comment": ["file_pattern_ending: strings matched against the end of a file name.", 4 | "location keys: regular expression matched against the beginning of", 5 | "the file path (relative to the git submodule root).", 6 | "spdx: list of SPDX-License-Expression's allowed in the matching files.", 7 | "-------------------------------------------------------", 8 | "Files with the following endings are Build System licensed,", 9 | "unless they are examples", 10 | "Files with other endings can also be build system files" 11 | ], 12 | "file_pattern_ending": ["CMakeLists.txt", ".cmake", ".pro", ".pri", ".prf", 13 | "configure", "configure.bat", "cmake.in", "plist.in", "CMakeLists.txt.in", 14 | ".cmake.conf", ".tag", "ci_config_linux.json", 15 | ".yaml", "BLACKLIST"], 16 | "location": { 17 | "": { 18 | "comment": "Default", 19 | "file type": "build system", 20 | "spdx": ["BSD-3-Clause"] 21 | }, 22 | "(.*)(examples/|snippets/)": { 23 | "comment": "Example takes precedent", 24 | "file type": "examples and snippets", 25 | "spdx": ["LicenseRef-Qt-Commercial OR BSD-3-Clause"] 26 | } 27 | } 28 | }, 29 | { 30 | "comments": ["Files with the following endings are infrastructure licensed"], 31 | "file_pattern_ending": [".gitattributes", ".gitignore", ".gitmodules", ".gitreview", 32 | "_clang-format", "licenseRule.json", "REUSE.toml"], 33 | "location":{ 34 | "": { 35 | "comment": "Default", 36 | "file type": "infrastructure", 37 | "spdx": ["LicenseRef-Qt-Commercial OR BSD-3-Clause"] 38 | } 39 | } 40 | }, 41 | { 42 | "comments": ["Files with the following endings are Tool licensed,", 43 | "unless they are examples.", 44 | "Files with other endings can also be tool files."], 45 | "file_pattern_ending": [".sh", ".py", ".pl", ".bat", ".ps1"], 46 | "location":{ 47 | "": { 48 | "comment": "Default", 49 | "file type": "tools and utils", 50 | "spdx": ["LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0"] 51 | }, 52 | "(.*)(examples/|snippets/)": { 53 | "comment": "Example takes precedent", 54 | "file type": "examples and snippets", 55 | "spdx": ["LicenseRef-Qt-Commercial OR BSD-3-Clause"] 56 | } 57 | } 58 | }, 59 | { 60 | "comment": "Files with the following endings are Documentation licensed.", 61 | "file_pattern_ending": [".qdoc", ".qdocinc" , ".qdocconf", "README", "qt_attribution.json"], 62 | "location":{ 63 | "": { 64 | "comment": "", 65 | "file type": "documentation", 66 | "spdx": ["LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only"] 67 | } 68 | } 69 | }, 70 | { 71 | "comment": ["All other files", 72 | "The licensing is defined only by the file location in the Qt module repository.", 73 | "NO key for this case!", 74 | "This needs to be the last entry of the file."], 75 | "location": { 76 | "": { 77 | "comment": "Default", 78 | "file type": "module and plugin", 79 | "spdx": ["LicenseRef-Qt-Commercial OR GPL-3.0-only"] 80 | }, 81 | "src/": { 82 | "comment": "Default", 83 | "file type": "module and plugin", 84 | "spdx": ["LicenseRef-Qt-Commercial OR GPL-3.0-only"] 85 | }, 86 | "tests/": { 87 | "comment": "Default", 88 | "file type": "test", 89 | "spdx": ["LicenseRef-Qt-Commercial OR GPL-3.0-only"] 90 | }, 91 | "(.*)(examples/|snippets/)": { 92 | "comment": "Default", 93 | "file type": "examples and snippets", 94 | "spdx": ["LicenseRef-Qt-Commercial OR BSD-3-Clause"] 95 | }, 96 | "doc/images/": { 97 | "comment": "Default", 98 | "file type": "documentation", 99 | "spdx": ["LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only"] 100 | } 101 | } 102 | } 103 | ] 104 | -------------------------------------------------------------------------------- /src/httpserver/qhttpserverrequestfilter.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | // Qt-Security score:significant reason:default 4 | 5 | #include "qhttpserverrequestfilter_p.h" 6 | 7 | #include 8 | 9 | #include 10 | 11 | QT_BEGIN_NAMESPACE 12 | 13 | const int QHttpServerRequestFilterPrivate::cPeriodDurationMSec = 1000; 14 | 15 | // compromise value to remove some garbage without processing the entire array. 16 | static constexpr int cCleanupThreshold = 10; 17 | 18 | unsigned int QHttpServerRequestFilter::maxRequestPerPeriod() const 19 | { 20 | return m_config.rateLimitPerSecond(); 21 | } 22 | 23 | void QHttpServerRequestFilter::setConfiguration(const QHttpServerConfiguration &config) 24 | { 25 | m_config = config; 26 | } 27 | 28 | bool QHttpServerRequestFilter::isRequestAllowed(const QHostAddress &peerAddress) const 29 | { 30 | const auto matches = [](const QHostAddress &addr) { 31 | return [&addr] (const auto &subnet) { 32 | return addr.isInSubnet(subnet); 33 | }; 34 | }; 35 | 36 | if (const auto whitelist = m_config.whitelist(); !whitelist.empty()) 37 | return std::any_of(whitelist.cbegin(), whitelist.cend(), matches(peerAddress)); 38 | 39 | const auto blacklist = m_config.blacklist(); 40 | return std::none_of(blacklist.cbegin(), blacklist.cend(), matches(peerAddress)); 41 | } 42 | 43 | bool QHttpServerRequestFilter::isRequestWithinRate(const QHostAddress &peerAddress) 44 | { 45 | return isRequestWithinRate(peerAddress, QDateTime::currentMSecsSinceEpoch()); 46 | } 47 | 48 | bool QHttpServerRequestFilter::isRequestWithinRate(const QHostAddress &peerAddress, 49 | qint64 currTimeMSec) 50 | { 51 | using namespace QHttpServerRequestFilterPrivate; 52 | 53 | if (m_config.rateLimitPerSecond() == 0) 54 | return true; 55 | 56 | const auto it = ipInfo.tryEmplace(peerAddress, currTimeMSec + cPeriodDurationMSec).iterator; 57 | 58 | bool result = true; 59 | if (it->isGarbage(currTimeMSec)) { 60 | // did not make any requests for a whole period? start the new one. 61 | it->m_thisPeriodEnd = currTimeMSec + cPeriodDurationMSec; 62 | it->m_nRequests = 1; 63 | } else if (currTimeMSec > it->m_thisPeriodEnd) { 64 | // showed up during next period, update info 65 | it->m_thisPeriodEnd += cPeriodDurationMSec; 66 | it->m_nRequests = 1; 67 | } else { 68 | // check whether we exceeded 69 | if (++it->m_nRequests > maxRequestPerPeriod()) 70 | result = false; // too many requests 71 | } 72 | 73 | // clean more garbage then we create 74 | cleanIpInfoGarbage(it, currTimeMSec); 75 | 76 | return result; 77 | } 78 | 79 | /*! 80 | \internal 81 | */ 82 | bool QHttpServerRequestFilter::isUrlSizeAllowed(qsizetype urlSize) const 83 | { 84 | auto limit = m_config.maxUrlSize(); 85 | return limit < 0 || limit >= qint64(urlSize); 86 | } 87 | 88 | /*! 89 | \internal 90 | */ 91 | bool QHttpServerRequestFilter::isTotalHeaderSizeAllowed(qsizetype headerSize) const 92 | { 93 | auto limit = m_config.maxTotalHeaderSize(); 94 | return limit < 0 || limit >= qint64(headerSize); 95 | } 96 | 97 | /*! 98 | \internal 99 | */ 100 | bool QHttpServerRequestFilter::isHeaderFieldSizeAllowed(qsizetype headerSize) const 101 | { 102 | auto limit = m_config.maxHeaderFieldSize(); 103 | return limit < 0 || limit >= qint64(headerSize); 104 | } 105 | 106 | /*! 107 | \internal 108 | */ 109 | bool QHttpServerRequestFilter::isNumberOfHeaderFieldsAllowed(qsizetype headerSize) const 110 | { 111 | auto limit = m_config.maxNumberOfHeaderFields(); 112 | return limit < 0 || limit >= qint64(headerSize); 113 | } 114 | 115 | /*! 116 | \internal 117 | */ 118 | bool QHttpServerRequestFilter::isBodySizeAllowed(qint64 bodySize) const 119 | { 120 | auto limit = m_config.maxBodySize(); 121 | return limit < 0 || limit >= bodySize; 122 | } 123 | 124 | void QHttpServerRequestFilter::cleanIpInfoGarbage(QHash::iterator it, 125 | qint64 currTime) 126 | { 127 | Q_ASSERT(ipInfo.begin() != ipInfo.end()); 128 | 129 | const auto myIp = it.key(); 130 | ++it; 131 | // check the range after the current ip 132 | for (int i = 0; i < cCleanupThreshold; ++i) { 133 | if (it == ipInfo.end()) 134 | it = ipInfo.begin(); 135 | 136 | if (it.key() == myIp) 137 | break; 138 | 139 | if (it->isGarbage(currTime)) 140 | it = ipInfo.erase(it); 141 | else 142 | ++it; 143 | } 144 | } 145 | 146 | bool QHttpServerRequestFilter::IpInfo::isGarbage(qint64 currTime) const 147 | { 148 | // ip info is garbage if we got no requests during next period 149 | return (currTime >= m_thisPeriodEnd + QHttpServerRequestFilterPrivate::cPeriodDurationMSec); 150 | } 151 | 152 | QT_END_NAMESPACE 153 | -------------------------------------------------------------------------------- /doc/index.qdoc: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only 3 | 4 | /*! 5 | \page qthttpserver-index.html 6 | \since 6.4 7 | \title Qt HTTP Server 8 | \brief Provides a lightweight server implementing the HTTP protocol. 9 | 10 | Qt HTTP Server supports building HTTP server functionality into an application. 11 | Common use cases are exposing the application's functionality through 12 | REST APIs, or making devices in a trusted environment configurable also via HTTP. 13 | The limitations are described in \l{Limitations and Security}. 14 | 15 | \section1 Overview 16 | 17 | Qt HTTP Server provides building blocks for embedding a lightweight HTTP server 18 | based on \l{RFC 2616} and \l{RFC 9113} in an application. There are classes for 19 | the messages sent and received, and for the various parts of an HTTP server. 20 | 21 | The QHttpServer class has a \l{QHttpServer::}{route()} function to bind 22 | callables to different incoming URLs. These callables can take as arguments 23 | an \l{QHttpServerRouter::addConverter}{extensible} collection of different 24 | copyable types that are parsed from the URL. Types supported are most numeric 25 | types, QString, QByteArray, and QUrl. Optionally the callables can also take 26 | QHttpServerRequest and QHttpServerResponder objects as arguments. The 27 | QHttpServerRequest class contains all the information of an incoming request, 28 | and is needed to get the \l{QHttpServerRequest::}{body()} from a POST HTTP 29 | request. The callables either return a QHttpServerResponse object or respond 30 | using the QHttpServerResponder argument. The QHttpServerResponse class 31 | contains a complete response and has numerous constructors for different types, 32 | while the QHttpServerResponder has various methods for writing back to the 33 | client. 34 | 35 | The QHttpServer class also has an \l{QHttpServer::}{addAfterRequestHandler()} 36 | function to process a QHttpServerResponse further, and a 37 | \l{QHttpServer::}{setMissingHandler()} function to override the default 38 | behavior of returning \c{404 Not Found} when no routes are matched. From 39 | the QAbstractHttpServer class it inherits a \l{QAbstractHttpServer::}{bind()} 40 | function to bind to a listening QTcpServer, QSslServer, or QLocalServer. 41 | 42 | An HTTP server can also be created by subclassing the QAbstractHttpServer 43 | class and overriding the \l{QAbstractHttpServer::}{handleRequest()} and 44 | \l{QAbstractHttpServer::}{missingHandler()} functions. 45 | 46 | Runtime logging can be configured as described \l{qthttpserver-logging.html}{here}. 47 | 48 | \section1 Limitations and Security 49 | 50 | Qt HTTP Server does not have many of the more advanced features and optimizations 51 | that general-purpose HTTP servers have. It also has not seen 52 | the same scrutiny regarding various attack vectors over the network. 53 | Use Qt HTTP Server, therefore, only for local connections 54 | or in a trusted network, and do not expose the ports to the internet. 55 | 56 | You can add HTTPS support as a basic security measure, though. If Qt is compiled 57 | with support for TLS, you can bind the HTTP server to a QSslServer object, 58 | providing Transport Layer Security handling. 59 | 60 | The \l{QSslSocket::SupportedFeature::ServerSideAlpn} feature from the 61 | active TLS backend is needed for HTTP/2 support. To check if a backend 62 | supports this, use \l{QSslSocket::isFeatureSupported}. 63 | 64 | \section1 Using the Module 65 | 66 | Using a Qt module requires linking against the module library, either 67 | directly or through other dependencies. Several build tools have dedicated 68 | support for this, including CMake and qmake. 69 | 70 | \section2 Building with CMake 71 | 72 | Use the \c find_package() command to locate the needed module components in 73 | the Qt6 package: 74 | 75 | \badcode 76 | find_package(Qt6 REQUIRED COMPONENTS HttpServer) 77 | target_link_libraries(mytarget PRIVATE Qt6::HttpServer) 78 | \endcode 79 | 80 | See also the \l{Build with CMake} overview. 81 | 82 | \section2 Building with qmake 83 | 84 | To configure the module for building with qmake, add the module as a value 85 | of the QT variable in the project's .pro file: 86 | 87 | \badcode 88 | QT += httpserver 89 | \endcode 90 | 91 | \section1 Licenses 92 | 93 | Qt HTTP Server is available under commercial licenses from \l{The Qt Company}. 94 | In addition, it is available under the \l {GNU General Public License, version 3}. 95 | See \l{Qt Licensing} for further details. 96 | 97 | \section1 Reference 98 | \list 99 | \li \l{Qt HTTP Server Logging} 100 | \li \l{Qt HTTP Server C++ Classes}{C++ Classes} 101 | \endlist 102 | 103 | \section1 Examples 104 | 105 | The module provides the following \l{Qt HTTP Server Examples}{Examples} as a guide to using 106 | the API. 107 | */ 108 | -------------------------------------------------------------------------------- /tests/benchmarks/qhttpserver/transfer/tst_bench_qhttpserver_transfer.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #include 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #if QT_CONFIG(ssl) 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #endif 20 | 21 | using namespace Qt::StringLiterals; 22 | using namespace std::chrono_literals; 23 | 24 | class tst_bench_QHttpServer_transfer : public QObject 25 | { 26 | Q_OBJECT 27 | public: 28 | tst_bench_QHttpServer_transfer(); 29 | private slots: 30 | void transferPayload_data(); 31 | void transferPayload(); 32 | private: 33 | QHttpServer server; 34 | bool testHttp2 = false; 35 | bool testTls = false; 36 | quint16 ports[2] = {0, 0}; 37 | }; 38 | 39 | tst_bench_QHttpServer_transfer::tst_bench_QHttpServer_transfer() 40 | { 41 | auto *tcpServer = new QTcpServer(&server); 42 | if (!tcpServer->listen()) 43 | qFatal("Failed to listen on TCP"); 44 | ports[0] = tcpServer->serverPort(); 45 | server.bind(tcpServer); 46 | qDebug() << "Test HTTP on port" << ports[0]; 47 | #if QT_CONFIG(ssl) 48 | if (QSslSocket::supportsSsl()) { 49 | testHttp2 = QSslSocket::isFeatureSupported(QSsl::SupportedFeature::ServerSideAlpn); 50 | testTls = true; 51 | auto *sslServer = new QSslServer(&server); 52 | sslServer->setHandshakeTimeout(std::numeric_limits::max()); 53 | QSslConfiguration sslConfig = sslServer->sslConfiguration(); 54 | sslConfig.setPeerVerifyMode(QSslSocket::VerifyNone); 55 | if (testHttp2) 56 | sslConfig.setAllowedNextProtocols({ QSslConfiguration::ALPNProtocolHTTP2 }); 57 | const auto certs = QSslCertificate::fromPath(u":/cert/localhost.cert"_s); 58 | if (certs.isEmpty()) 59 | qFatal("Failed to load certificate"); 60 | sslConfig.setLocalCertificate(certs.first()); 61 | QFile key(u":/cert/localhost.key"_s); 62 | if (!key.open(QIODevice::ReadOnly)) 63 | qFatal("Failed to open key file"); 64 | sslConfig.setPrivateKey(QSslKey(&key, QSsl::KeyAlgorithm::Rsa)); 65 | sslServer->setSslConfiguration(sslConfig); 66 | if (!sslServer->listen(QHostAddress::LocalHost)) 67 | qFatal("Failed to listen on TLS"); 68 | ports[1] = sslServer->serverPort(); 69 | server.bind(sslServer); 70 | qDebug() << "Testing TLS with" << QSslSocket::sslLibraryBuildVersionString(); 71 | qDebug() << "Testing HTTPS on port" << ports[1]; 72 | } 73 | #endif 74 | 75 | QByteArray bigdata = "1"_ba.repeated(1024 * 1024 * 100); 76 | using HTTP = QHttpServerRequest::Method; 77 | server.route("/bytearray", HTTP::Get, 78 | [=](QHttpServerResponder &resp) { 79 | resp.write(bigdata, "application/octet-stream"); 80 | }); 81 | 82 | server.route("/qbuffer", HTTP::Get, 83 | [=](QHttpServerResponder &resp) { 84 | auto *buf = new QBuffer; 85 | buf->setData(bigdata); 86 | buf->open(QIODevice::ReadOnly); 87 | resp.write(buf, "application/octet-stream"); 88 | }); 89 | } 90 | 91 | enum TransferProtocol { 92 | HTTP, 93 | HTTPS, 94 | HTTP2, 95 | }; 96 | 97 | void tst_bench_QHttpServer_transfer::transferPayload_data() 98 | { 99 | QTest::addColumn("path"); 100 | QTest::addColumn("transferProtocol"); 101 | 102 | QTest::addRow("bytearray") << "/bytearray" << HTTP; 103 | QTest::addRow("qbuffer") << "/qbuffer" << HTTP; 104 | if (testHttp2) { 105 | QTest::addRow("bytearray-http2") << "/bytearray" << HTTP2; 106 | QTest::addRow("qbuffer-http2") << "/qbuffer" << HTTP2; 107 | } 108 | if (testTls) { 109 | QTest::addRow("bytearray-tls") << "/bytearray" << HTTPS; 110 | QTest::addRow("qbuffer-tls") << "/qbuffer" << HTTPS; 111 | } 112 | } 113 | 114 | void tst_bench_QHttpServer_transfer::transferPayload() 115 | { 116 | QFETCH(QString, path); 117 | QFETCH(TransferProtocol, transferProtocol); 118 | const bool tls = transferProtocol != HTTP; 119 | 120 | QNetworkAccessManager qnam; 121 | QNetworkRequest req; 122 | QUrl url; 123 | url.setHost("127.0.0.1"); 124 | url.setScheme(tls ? "https" : "http"); 125 | url.setPort(ports[tls ? 1 : 0]); 126 | url.setPath(path); 127 | req.setUrl(url); 128 | 129 | req.setAttribute(QNetworkRequest::Http2AllowedAttribute, transferProtocol == HTTP2); 130 | 131 | #if QT_CONFIG(ssl) 132 | if (tls) { 133 | QSslConfiguration sslConfig = req.sslConfiguration(); 134 | sslConfig.setPeerVerifyMode(QSslSocket::VerifyNone); 135 | req.setSslConfiguration(sslConfig); 136 | } 137 | #endif 138 | 139 | QBENCHMARK { 140 | QNetworkReply *reply = qnam.get(req); 141 | QObject::connect(reply, &QNetworkReply::sslErrors, reply, 142 | qOverload<>(&QNetworkReply::ignoreSslErrors)); 143 | qint64 total = 0; 144 | const auto replyReady = [&reply]() -> bool { 145 | return reply->isFinished() || reply->bytesAvailable(); 146 | }; 147 | while (!replyReady()) { 148 | bool res = QTest::qWaitFor(replyReady, 5s); 149 | QVERIFY(res); 150 | total += reply->readAll().size(); 151 | } 152 | QCOMPARE(total, 1024 * 1024 * 100); 153 | delete reply; 154 | } 155 | 156 | } 157 | 158 | QTEST_MAIN(tst_bench_QHttpServer_transfer) 159 | 160 | #include "tst_bench_qhttpserver_transfer.moc" 161 | -------------------------------------------------------------------------------- /src/httpserver/qhttpserverrouterviewtraits.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2020 Mikhail Svetkin 2 | // Copyright (C) 2019 The Qt Company Ltd. 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | // Qt-Security score:significant reason:default 5 | 6 | #ifndef QHTTPSERVERROUTERVIEWTRAITS_H 7 | #define QHTTPSERVERROUTERVIEWTRAITS_H 8 | 9 | #include 10 | 11 | QT_BEGIN_NAMESPACE 12 | 13 | class QHttpServerRequest; 14 | class QHttpServerResponder; 15 | 16 | namespace QtPrivate { 17 | 18 | template 19 | struct RouterViewTraitsHelper : ViewTraits { 20 | using VTraits = ViewTraits; 21 | using FunctionTraits = typename VTraits::FTraits; 22 | 23 | template 24 | struct ArgumentChecker : FunctionTraits::template Arg { 25 | using IsRequestCLvalue = typename VTraits::template Special; 26 | using IsRequestValue = typename VTraits::template Special; 27 | using IsRequest = CheckAny; 28 | static_assert(IsRequest::StaticAssert, 29 | "ViewHandler arguments error: " 30 | "QHttpServerRequest can only be passed by value or as a const Lvalue"); 31 | 32 | using IsResponderLvalue = typename VTraits::template Special; 33 | using IsResponderRvalue = typename VTraits::template Special; 34 | using IsResponder = CheckAny; 35 | static_assert(IsResponder::StaticAssert, 36 | "ViewHandler arguments error: " 37 | "QHttpServerResponder can only be passed as a reference or Rvalue " 38 | "reference"); 39 | 40 | using IsSpecial = CheckAny; 41 | 42 | struct IsSimple { 43 | static constexpr bool TypeMatched = !IsSpecial::TypeMatched && 44 | I < FunctionTraits::ArgumentCount && 45 | FunctionTraits::ArgumentIndexMax != -1; 46 | static constexpr bool Value = 47 | !IsSpecial::Value && FunctionTraits::template Arg::CopyConstructible; 48 | 49 | static constexpr bool StaticAssert = 50 | DisableStaticAssert || Value || !TypeMatched; 51 | 52 | 53 | static_assert(StaticAssert, 54 | "ViewHandler arguments error: " 55 | "Type is not copy constructible"); 56 | }; 57 | 58 | using CheckOk = CheckAny; 59 | 60 | static constexpr bool Value = CheckOk::Value; 61 | static constexpr bool StaticAssert = CheckOk::StaticAssert; 62 | }; 63 | 64 | 65 | struct Arguments { 66 | template 67 | struct ArgumentsReturn { 68 | template 69 | using Arg = ArgumentChecker; 70 | 71 | template 72 | static constexpr QMetaType metaType() noexcept 73 | { 74 | using Type = typename FunctionTraits::template Arg::CleanType; 75 | constexpr bool Simple = Arg::IsSimple::Value; 76 | 77 | if constexpr (Simple && std::is_copy_assignable_v) 78 | return QMetaType::fromType(); 79 | else 80 | return QMetaType::fromType(); 81 | } 82 | 83 | static constexpr std::size_t Count = FunctionTraits::ArgumentCount; 84 | static constexpr std::size_t CapturableCount = 85 | (0 + ... + static_cast(Arg::IsSimple::Value)); 86 | 87 | static constexpr std::size_t SpecialsCount = Count - CapturableCount; 88 | 89 | static constexpr bool Value = (Arg::Value && ...); 90 | static constexpr bool StaticAssert = (Arg::StaticAssert && ...); 91 | 92 | using Indexes = std::index_sequence; 93 | 94 | using CapturableIndexes = std::make_index_sequence; 95 | 96 | using SpecialIndexes = std::make_index_sequence; 97 | 98 | using Last = Arg; 99 | using SecondLast = Arg; 100 | }; 101 | 102 | template 103 | static constexpr ArgumentsReturn eval(std::index_sequence) noexcept; 104 | }; 105 | 106 | template 107 | struct BindType { 108 | template 109 | struct FunctionWrapper { 110 | using Type = std::function; 111 | }; 112 | 113 | template 114 | using OffsetArg = typename FunctionTraits::template Arg::Type; 115 | 116 | template 117 | static constexpr typename FunctionWrapper...>::Type 118 | eval(std::index_sequence) noexcept; 119 | }; 120 | }; 121 | 122 | 123 | } // namespace QtPrivate 124 | 125 | template 126 | struct QHttpServerRouterViewTraits 127 | { 128 | using Helpers = typename QtPrivate::RouterViewTraitsHelper; 129 | using ReturnType = typename Helpers::FunctionTraits::ReturnType; 130 | using Arguments = decltype(Helpers::Arguments::eval(typename Helpers::ArgumentIndexes{})); 131 | using BindableType = decltype(Helpers::template BindType::eval( 132 | typename Arguments::SpecialIndexes{})); 133 | }; 134 | 135 | 136 | QT_END_NAMESPACE 137 | 138 | #endif // QHTTPSERVERROUTERVIEWTRAITS_H 139 | -------------------------------------------------------------------------------- /src/httpserver/qhttpserverresponder.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | // Qt-Security score:significant reason:default 4 | 5 | #ifndef QHTTPSERVERRESPONDER_H 6 | #define QHTTPSERVERRESPONDER_H 7 | 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | QT_BEGIN_NAMESPACE 19 | 20 | class QHttpServerStream; 21 | class QHttpServerRequest; 22 | class QHttpServerResponse; 23 | 24 | class QHttpServerResponderPrivate; 25 | class QHttpServerResponder final 26 | { 27 | Q_GADGET_EXPORT(Q_HTTPSERVER_EXPORT) 28 | Q_DECLARE_PRIVATE(QHttpServerResponder) 29 | 30 | friend class QHttpServerHttp1ProtocolHandler; 31 | friend class QHttpServerHttp2ProtocolHandler; 32 | 33 | public: 34 | enum class StatusCode { 35 | // 1xx: Informational 36 | Continue = 100, 37 | SwitchingProtocols, 38 | Processing, 39 | 40 | // 2xx: Success 41 | Ok = 200, 42 | Created, 43 | Accepted, 44 | NonAuthoritativeInformation, 45 | NoContent, 46 | ResetContent, 47 | PartialContent, 48 | MultiStatus, 49 | AlreadyReported, 50 | IMUsed = 226, 51 | 52 | // 3xx: Redirection 53 | MultipleChoices = 300, 54 | MovedPermanently, 55 | Found, 56 | SeeOther, 57 | NotModified, 58 | UseProxy, 59 | // 306: not used, was proposed as "Switch Proxy" but never standardized 60 | TemporaryRedirect = 307, 61 | PermanentRedirect, 62 | 63 | // 4xx: Client Error 64 | BadRequest = 400, 65 | Unauthorized, 66 | PaymentRequired, 67 | Forbidden, 68 | NotFound, 69 | MethodNotAllowed, 70 | NotAcceptable, 71 | ProxyAuthenticationRequired, 72 | RequestTimeout, 73 | Conflict, 74 | Gone, 75 | LengthRequired, 76 | PreconditionFailed, 77 | PayloadTooLarge, 78 | UriTooLong, 79 | UnsupportedMediaType, 80 | RequestRangeNotSatisfiable, 81 | ExpectationFailed, 82 | ImATeapot, 83 | MisdirectedRequest = 421, 84 | UnprocessableEntity, 85 | Locked, 86 | FailedDependency, 87 | UpgradeRequired = 426, 88 | PreconditionRequired = 428, 89 | TooManyRequests, 90 | RequestHeaderFieldsTooLarge = 431, 91 | UnavailableForLegalReasons = 451, 92 | 93 | // 5xx: Server Error 94 | InternalServerError = 500, 95 | NotImplemented, 96 | BadGateway, 97 | ServiceUnavailable, 98 | GatewayTimeout, 99 | HttpVersionNotSupported, 100 | VariantAlsoNegotiates, 101 | InsufficientStorage, 102 | LoopDetected, 103 | NotExtended = 510, 104 | NetworkAuthenticationRequired, 105 | NetworkConnectTimeoutError = 599, 106 | }; 107 | Q_ENUM(StatusCode) 108 | 109 | QHttpServerResponder(QHttpServerResponder &&other) noexcept 110 | : d_ptr(std::exchange(other.d_ptr, nullptr)) 111 | { 112 | } 113 | QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QHttpServerResponder) 114 | 115 | Q_HTTPSERVER_EXPORT ~QHttpServerResponder(); 116 | 117 | void swap(QHttpServerResponder &other) noexcept { qt_ptr_swap(d_ptr, other.d_ptr); } 118 | 119 | Q_HTTPSERVER_EXPORT void write(QIODevice *data, const QHttpHeaders &headers, 120 | StatusCode status = StatusCode::Ok); 121 | 122 | Q_HTTPSERVER_EXPORT void write(QIODevice *data, const QByteArray &mimeType, 123 | StatusCode status = StatusCode::Ok); 124 | 125 | Q_HTTPSERVER_EXPORT void write(const QJsonDocument &document, const QHttpHeaders &headers, 126 | StatusCode status = StatusCode::Ok); 127 | 128 | Q_HTTPSERVER_EXPORT void write(const QJsonDocument &document, 129 | StatusCode status = StatusCode::Ok); 130 | 131 | Q_HTTPSERVER_EXPORT void write(const QByteArray &data, const QHttpHeaders &headers, 132 | StatusCode status = StatusCode::Ok); 133 | 134 | Q_HTTPSERVER_EXPORT void write(const QByteArray &data, const QByteArray &mimeType, 135 | StatusCode status = StatusCode::Ok); 136 | 137 | Q_HTTPSERVER_EXPORT void write(const QHttpHeaders &headers, StatusCode status = StatusCode::Ok); 138 | 139 | Q_HTTPSERVER_EXPORT void write(StatusCode status = StatusCode::Ok); 140 | 141 | Q_HTTPSERVER_EXPORT void sendResponse(const QHttpServerResponse &response); 142 | 143 | Q_HTTPSERVER_EXPORT void writeBeginChunked(const QHttpHeaders &headers, 144 | StatusCode status = StatusCode::Ok); 145 | 146 | Q_HTTPSERVER_EXPORT void writeBeginChunked(const QByteArray &mimeType, 147 | StatusCode status = StatusCode::Ok); 148 | 149 | Q_HTTPSERVER_EXPORT void writeBeginChunked(const QHttpHeaders &headers, 150 | QList trailerNames, 151 | StatusCode status = StatusCode::Ok); 152 | 153 | Q_HTTPSERVER_EXPORT void writeChunk(const QByteArray &data); 154 | 155 | Q_HTTPSERVER_EXPORT void writeEndChunked(const QByteArray &data, const QHttpHeaders &trailers); 156 | 157 | Q_HTTPSERVER_EXPORT void writeEndChunked(const QByteArray &data); 158 | 159 | Q_HTTPSERVER_EXPORT bool isResponseCanceled(); 160 | 161 | private: 162 | Q_HTTPSERVER_EXPORT QHttpServerResponder(QHttpServerStream *stream); 163 | Q_DISABLE_COPY(QHttpServerResponder) 164 | 165 | QHttpServerResponderPrivate *d_ptr; 166 | }; 167 | 168 | QT_END_NAMESPACE 169 | 170 | #endif // QHTTPSERVERRESPONDER_H 171 | -------------------------------------------------------------------------------- /src/httpserver/qhttpserverwebsocketupgraderesponse.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | // Qt-Security score:significant reason:default 4 | 5 | #include 6 | 7 | #include 8 | 9 | QT_BEGIN_NAMESPACE 10 | 11 | using namespace Qt::Literals::StringLiterals; 12 | 13 | /*! 14 | \class QHttpServerWebSocketUpgradeResponse 15 | \since 6.8 16 | \inmodule QtHttpServer 17 | \brief Response to return when verifying WebSocket upgrades on HTTP server. 18 | 19 | Use this class to return when determining whether a socket upgrade should 20 | succeed. If type() is \l Accept upgrade the socket, if type() is \l Deny 21 | send an error with the given denyStatus() and denyMessage(), and if type() 22 | is \l PassToNext proceed to the next registered handler. 23 | If all handlers return \l PassToNext or none exist, 24 | QAbstractHttpServer::missingHandler() is executed. 25 | 26 | \sa QAbstractHttpServer::addWebSocketUpgradeVerifier(), 27 | QAbstractHttpServer::missingHandler() 28 | */ 29 | 30 | /*! 31 | \enum QHttpServerWebSocketUpgradeResponse::ResponseType 32 | 33 | Response types 34 | 35 | \value Accept Accept the WebSocket upgrade request. 36 | \value Deny Deny the WebSocket upgrade request. 37 | \value PassToNext Pass the Websocket upgrade decision to the next verifier if any. 38 | \sa QAbstractHttpServer::addWebSocketUpgradeVerifier(), type() 39 | */ 40 | 41 | /*! 42 | \internal 43 | */ 44 | QHttpServerWebSocketUpgradeResponse::QHttpServerWebSocketUpgradeResponse(ResponseType type) 45 | : responseType(type), errorMessage("Forbidden"_ba), reserved(nullptr) 46 | { 47 | } 48 | 49 | /*! 50 | \internal 51 | */ 52 | QHttpServerWebSocketUpgradeResponse::QHttpServerWebSocketUpgradeResponse(ResponseType type, 53 | int status, 54 | QByteArray message) 55 | : responseType(type), errorStatus(status), errorMessage(message), reserved(nullptr) 56 | { 57 | } 58 | 59 | /*\fn QHttpServerWebSocketUpgradeResponse::QHttpServerWebSocketUpgradeResponse(QHttpServerWebSocketUpgradeResponse &&other) noexcept 60 | 61 | Move-constructs an instance of a QHttpServerWebSocketUpgradeResponse object from \a other. 62 | */ 63 | 64 | /*! 65 | Copy-constructs an instance of a QHttpServerWebSocketUpgradeResponse object from \a other. 66 | */ 67 | QHttpServerWebSocketUpgradeResponse::QHttpServerWebSocketUpgradeResponse( 68 | const QHttpServerWebSocketUpgradeResponse &other) 69 | : responseType(other.responseType), 70 | errorStatus(other.errorStatus), 71 | errorMessage(other.errorMessage), 72 | reserved(nullptr) 73 | { 74 | } 75 | 76 | /*! 77 | Destroys a QHttpServerWebSocketUpgradeResponse object. 78 | */ 79 | QHttpServerWebSocketUpgradeResponse::~QHttpServerWebSocketUpgradeResponse() noexcept = default; 80 | 81 | /*! 82 | \fn QHttpServerWebSocketUpgradeResponse &QHttpServerWebSocketUpgradeResponse::operator=(QHttpServerWebSocketUpgradeResponse &&other) noexcept 83 | 84 | Move-assigns the values of \a other to this object. 85 | */ 86 | 87 | /*! 88 | Copy-assigns the values of \a other to this object. 89 | */ 90 | QHttpServerWebSocketUpgradeResponse & 91 | QHttpServerWebSocketUpgradeResponse::operator=(const QHttpServerWebSocketUpgradeResponse &other) 92 | { 93 | responseType = other.responseType; 94 | errorStatus = other.errorStatus; 95 | errorMessage = other.errorMessage; 96 | reserved = nullptr; 97 | return *this; 98 | } 99 | 100 | /*! 101 | \fn void QHttpServerWebSocketUpgradeResponse::swap(QHttpServerWebSocketUpgradeResponse &other) noexcept 102 | Swaps the contents of this with \a other 103 | */ 104 | 105 | /*! 106 | Creates an instance of QHttpServerWebSocketUpgradeResponse with type() 107 | \l Accept. 108 | 109 | \sa ResponseType, type() 110 | */ 111 | QHttpServerWebSocketUpgradeResponse QHttpServerWebSocketUpgradeResponse::accept() 112 | { 113 | return QHttpServerWebSocketUpgradeResponse::ResponseType::Accept; 114 | } 115 | 116 | /*! 117 | Creates an instance of QHttpServerWebSocketUpgradeResponse with 118 | \l type() \l Deny, \l denyStatus() \c 403 and the \l denyMessage() 119 | \c "Forbidden". 120 | 121 | \sa ResponseType, type(), denyStatus(), denyMessage() 122 | */ 123 | QHttpServerWebSocketUpgradeResponse QHttpServerWebSocketUpgradeResponse::deny() 124 | { 125 | return QHttpServerWebSocketUpgradeResponse::ResponseType::Deny; 126 | } 127 | 128 | /*! 129 | Creates an instance of QHttpServerWebSocketUpgradeResponse with type() 130 | \l Deny, denyStatus() \a status and denyMessage() \a message. 131 | 132 | \sa ResponseType, type(), denyStatus(), denyMessage() 133 | */ 134 | QHttpServerWebSocketUpgradeResponse QHttpServerWebSocketUpgradeResponse::deny(int status, 135 | QByteArray message) 136 | { 137 | return { QHttpServerWebSocketUpgradeResponse::ResponseType::Deny, status, message }; 138 | } 139 | 140 | /*! 141 | Creates an instance of QHttpServerWebSocketUpgradeResponse with type() \l PassToNext. 142 | 143 | \sa ResponseType, type() 144 | */ 145 | QHttpServerWebSocketUpgradeResponse QHttpServerWebSocketUpgradeResponse::passToNext() 146 | { 147 | return QHttpServerWebSocketUpgradeResponse::ResponseType::PassToNext; 148 | } 149 | 150 | /*! 151 | \fn QHttpServerWebSocketUpgradeResponse::ResponseType QHttpServerWebSocketUpgradeResponse::type() const 152 | 153 | Returns the type of response. 154 | 155 | \sa ResponseType 156 | */ 157 | 158 | /*! 159 | \fn int QHttpServerWebSocketUpgradeResponse::denyStatus() const 160 | 161 | Returns the HTTP status code to return if type() is \l Deny. 162 | */ 163 | 164 | /*! 165 | \fn const QByteArray &QHttpServerWebSocketUpgradeResponse::denyMessage() const & 166 | 167 | Returns the error message to return if type() is \l Deny. 168 | */ 169 | 170 | /*! 171 | \fn QByteArray QHttpServerWebSocketUpgradeResponse::denyMessage() && 172 | 173 | Returns the error message to return if type() is \l Deny. 174 | */ 175 | 176 | QT_END_NAMESPACE 177 | -------------------------------------------------------------------------------- /src/httpserver/qhttpserverrouterrule.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | // Qt-Security score:significant reason:default 4 | 5 | #ifndef QHTTPSERVERROUTERRULE_H 6 | #define QHTTPSERVERROUTERRULE_H 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | QT_BEGIN_NAMESPACE 19 | 20 | class QString; 21 | class QHttpServerRequest; 22 | class QHttpServerResponder; 23 | class QRegularExpressionMatch; 24 | class QHttpServerRouter; 25 | 26 | class QHttpServerRouterRulePrivate; 27 | class Q_HTTPSERVER_EXPORT QHttpServerRouterRule 28 | { 29 | Q_DECLARE_PRIVATE(QHttpServerRouterRule) 30 | Q_DISABLE_COPY_MOVE(QHttpServerRouterRule) 31 | 32 | private: 33 | using RouterHandlerPrototype = void (*)(const QRegularExpressionMatch &, 34 | const QHttpServerRequest &, QHttpServerResponder &); 35 | 36 | template 37 | using if_routerhandler_prototype_compatible = typename std::enable_if< 38 | QtPrivate::AreFunctionsCompatible::value, bool>::type; 39 | 40 | QHttpServerRouterRule(const QString &pathPattern, const QHttpServerRequest::Methods methods, 41 | const QObject *context, QtPrivate::QSlotObjectBase *slotObjRaw); 42 | 43 | public: 44 | #ifdef Q_QDOC 45 | template 46 | QHttpServerRouterRule( 47 | const QString &pathPattern, const QHttpServerRequest::Methods methods, 48 | const QObject *receiver, 49 | Functor &&slot); 50 | 51 | template 52 | QHttpServerRouterRule( 53 | const QString &pathPattern, 54 | const QObject *receiver, 55 | Functor &&slot); 56 | #else 57 | template = true> 58 | QHttpServerRouterRule( 59 | const QString &pathPattern, 60 | const typename QtPrivate::ContextTypeForFunctor::ContextType *context, 61 | Handler &&func) 62 | : QHttpServerRouterRule( 63 | pathPattern, QHttpServerRequest::Method::AnyKnown, context, 64 | QtPrivate::makeCallableObject(std::forward(func))) 65 | { 66 | } 67 | 68 | template = true> 69 | QHttpServerRouterRule( 70 | const QString &pathPattern, const QHttpServerRequest::Methods methods, 71 | const typename QtPrivate::ContextTypeForFunctor::ContextType *context, 72 | Handler &&func) 73 | : QHttpServerRouterRule( 74 | pathPattern, methods, context, 75 | QtPrivate::makeCallableObject(std::forward(func))) 76 | { 77 | } 78 | #endif 79 | 80 | #ifdef Q_QDOC 81 | template > 82 | static typename ViewTraits::BindableType bindCaptured( 83 | QObject *receiver, 84 | Functor &&slot, 85 | const QRegularExpressionMatch &match) const; 86 | # else 87 | template> 88 | static typename ViewTraits::BindableType bindCaptured( 89 | const typename QtPrivate::ContextTypeForFunctor::ContextType *context, 90 | ViewHandler &&handler, 91 | const QRegularExpressionMatch &match) 92 | { 93 | return bindCapturedImpl( 94 | context, std::forward(handler), match, 95 | typename ViewTraits::Arguments::CapturableIndexes{}); 96 | } 97 | #endif 98 | 99 | const QObject *contextObject() const; 100 | 101 | virtual ~QHttpServerRouterRule(); 102 | 103 | protected: 104 | bool exec(const QHttpServerRequest &request, QHttpServerResponder &responder) const; 105 | 106 | bool hasValidMethods() const; 107 | 108 | bool createPathRegexp(std::initializer_list metaTypes, 109 | const QHash &converters); 110 | 111 | virtual bool matches(const QHttpServerRequest &request, 112 | QRegularExpressionMatch *match) const; 113 | 114 | QHttpServerRouterRule(QHttpServerRouterRulePrivate *d); 115 | 116 | // Implementation of C++20 std::bind_front() in C++17 117 | template 118 | static auto bind_front(F &&f, Args &&...args) 119 | { 120 | return [f = std::forward(f), 121 | args = std::make_tuple(std::forward(args)...)](auto &&...callArgs) { 122 | return std::apply(f, 123 | std::tuple_cat(args, 124 | std::forward_as_tuple(std::forward( 125 | callArgs)...))); 126 | }; 127 | } 128 | 129 | template 130 | static typename ViewTraits::BindableType bindCapturedImpl( 131 | const typename QtPrivate::ContextTypeForFunctor::ContextType *context, 132 | ViewHandler &&handler, 133 | const QRegularExpressionMatch &match, 134 | std::index_sequence) 135 | { 136 | if constexpr (std::is_member_function_pointer_v) { 137 | return bind_front( 138 | handler, const_cast::ContextType*>(context), 139 | QVariant(match.captured(Cx + 1)) 140 | .value::CleanType>()...); 141 | } else { 142 | Q_UNUSED(context); 143 | return bind_front( 144 | handler, 145 | QVariant(match.captured(Cx + 1)) 146 | .value::CleanType>()...); 147 | } 148 | } 149 | 150 | private: 151 | std::unique_ptr d_ptr; 152 | 153 | friend class QHttpServerRouter; 154 | }; 155 | 156 | QT_END_NAMESPACE 157 | 158 | #endif // QHTTPSERVERROUTERRULE_H 159 | -------------------------------------------------------------------------------- /examples/httpserver/colorpalette/main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | #include "apibehavior.h" 5 | #include "types.h" 6 | #include "utils.h" 7 | #include 8 | #include 9 | 10 | #define SCHEME "http" 11 | #define HOST "127.0.0.1" 12 | #define PORT 49425 13 | 14 | template 15 | void addCrudRoutes(QHttpServer &httpServer, const QString &apiPath, CrudApi &api, 16 | const SessionApi &sessionApi) 17 | { 18 | //! [GET paginated list example] 19 | httpServer.route( 20 | QString("%1").arg(apiPath), QHttpServerRequest::Method::Get, 21 | [&api](const QHttpServerRequest &request) { return api.getPaginatedList(request); }); 22 | //! [GET paginated list example] 23 | 24 | //! [GET single item example] 25 | httpServer.route(QString("%1/").arg(apiPath), QHttpServerRequest::Method::Get, 26 | [&api](qint64 itemId) { return api.getItem(itemId); }); 27 | //! [GET single item example] 28 | 29 | //! [POST example] 30 | httpServer.route(QString("%1").arg(apiPath), QHttpServerRequest::Method::Post, 31 | [&api, &sessionApi](const QHttpServerRequest &request) { 32 | if (!sessionApi.authorize(request)) { 33 | return QHttpServerResponse( 34 | QHttpServerResponder::StatusCode::Unauthorized); 35 | } 36 | return api.postItem(request); 37 | }); 38 | //! [POST example] 39 | 40 | httpServer.route(QString("%1/").arg(apiPath), QHttpServerRequest::Method::Put, 41 | [&api, &sessionApi](qint64 itemId, const QHttpServerRequest &request) { 42 | if (!sessionApi.authorize(request)) { 43 | return QHttpServerResponse( 44 | QHttpServerResponder::StatusCode::Unauthorized); 45 | } 46 | return api.updateItem(itemId, request); 47 | }); 48 | 49 | httpServer.route(QString("%1/").arg(apiPath), QHttpServerRequest::Method::Patch, 50 | [&api, &sessionApi](qint64 itemId, const QHttpServerRequest &request) { 51 | if (!sessionApi.authorize(request)) { 52 | return QHttpServerResponse( 53 | QHttpServerResponder::StatusCode::Unauthorized); 54 | } 55 | return api.updateItemFields(itemId, request); 56 | }); 57 | 58 | httpServer.route(QString("%1/").arg(apiPath), QHttpServerRequest::Method::Delete, 59 | [&api, &sessionApi](qint64 itemId, const QHttpServerRequest &request) { 60 | if (!sessionApi.authorize(request)) { 61 | return QHttpServerResponse( 62 | QHttpServerResponder::StatusCode::Unauthorized); 63 | } 64 | return api.deleteItem(itemId); 65 | }); 66 | } 67 | 68 | int main(int argc, char *argv[]) 69 | { 70 | QCoreApplication app(argc, argv); 71 | 72 | QCommandLineParser parser; 73 | parser.addOptions({ 74 | { "port", QCoreApplication::translate("main", "The port the server listens on."), 75 | "port" }, 76 | }); 77 | parser.addHelpOption(); 78 | parser.process(app); 79 | 80 | quint16 portArg = PORT; 81 | if (!parser.value("port").isEmpty()) 82 | portArg = parser.value("port").toUShort(); 83 | 84 | auto colorFactory = std::make_unique(); 85 | auto colors = tryLoadFromFile(*colorFactory, ":/assets/colors.json"); 86 | CrudApi colorsApi(std::move(colors), std::move(colorFactory)); 87 | 88 | auto userFactory = std::make_unique(SCHEME, HOST, portArg); 89 | auto users = tryLoadFromFile(*userFactory, ":/assets/users.json"); 90 | CrudApi usersApi(std::move(users), std::move(userFactory)); 91 | 92 | auto sessionEntryFactory = std::make_unique(); 93 | auto sessions = tryLoadFromFile(*sessionEntryFactory, ":/assets/sessions.json"); 94 | SessionApi sessionApi(std::move(sessions), std::move(sessionEntryFactory)); 95 | 96 | // Setup QHttpServer 97 | QHttpServer httpServer; 98 | httpServer.route("/", []() { 99 | return "Qt Colorpalette example server. Please see documentation for API description"; 100 | }); 101 | 102 | addCrudRoutes(httpServer, "/api/unknown", colorsApi, sessionApi); 103 | addCrudRoutes(httpServer, "/api/users", usersApi, sessionApi); 104 | 105 | // Login resource 106 | httpServer.route( 107 | "/api/login", QHttpServerRequest::Method::Post, 108 | [&sessionApi](const QHttpServerRequest &request) { return sessionApi.login(request); }); 109 | 110 | httpServer.route("/api/register", QHttpServerRequest::Method::Post, 111 | [&sessionApi](const QHttpServerRequest &request) { 112 | return sessionApi.registerSession(request); 113 | }); 114 | 115 | httpServer.route("/api/logout", QHttpServerRequest::Method::Post, 116 | [&sessionApi](const QHttpServerRequest &request) { 117 | return sessionApi.logout(request); 118 | }); 119 | 120 | // Images resource 121 | httpServer.route("/img/faces/-image.jpg", QHttpServerRequest::Method::Get, 122 | [](qint64 imageId, const QHttpServerRequest &) { 123 | return QHttpServerResponse::fromFile( 124 | QString(":/assets/img/%1-image.jpg").arg(imageId)); 125 | }); 126 | 127 | auto tcpserver = std::make_unique(); 128 | if (!tcpserver->listen(QHostAddress::Any, portArg) || !httpServer.bind(tcpserver.get())) { 129 | qDebug() << QCoreApplication::translate("QHttpServerExample", 130 | "Server failed to listen on a port."); 131 | return 0; 132 | } 133 | quint16 port = tcpserver->serverPort(); 134 | tcpserver.release(); 135 | 136 | qDebug() << QCoreApplication::translate( 137 | "QHttpServerExample", 138 | "Running on http://127.0.0.1:%1/ (Press CTRL+C to quit)") 139 | .arg(port); 140 | 141 | return app.exec(); 142 | } 143 | -------------------------------------------------------------------------------- /examples/httpserver/simple/main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2018 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | #include 5 | #include 6 | 7 | #if QT_CONFIG(ssl) 8 | # include 9 | # include 10 | # include 11 | #endif 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | using namespace Qt::StringLiterals; 20 | 21 | static inline QString host(const QHttpServerRequest &request) 22 | { 23 | return QString::fromLatin1(request.value("Host")); 24 | } 25 | 26 | int main(int argc, char *argv[]) 27 | { 28 | //! [Setting up HTTP server] 29 | QCoreApplication app(argc, argv); 30 | 31 | QHttpServer httpServer; 32 | httpServer.route("/", []() { 33 | return "Hello world"; 34 | }); 35 | //! [Setting up HTTP server] 36 | 37 | httpServer.route("/query", [] (const QHttpServerRequest &request) { 38 | return host(request) + u"/query/"_s; 39 | }); 40 | 41 | httpServer.route("/query/", [] (qint32 id, const QHttpServerRequest &request) { 42 | return u"%1/query/%2"_s.arg(host(request)).arg(id); 43 | }); 44 | 45 | httpServer.route("/query//log", [] (qint32 id, const QHttpServerRequest &request) { 46 | return u"%1/query/%2/log"_s.arg(host(request)).arg(id); 47 | }); 48 | 49 | httpServer.route("/query//log/", [] (qint32 id, float threshold, 50 | const QHttpServerRequest &request) { 51 | return u"%1/query/%2/log/%3"_s.arg(host(request)).arg(id).arg(threshold); 52 | }); 53 | 54 | httpServer.route("/user/", [] (const qint32 id) { 55 | return u"User "_s + QString::number(id); 56 | }); 57 | 58 | httpServer.route("/user//detail", [] (const qint32 id) { 59 | return u"User %1 detail"_s.arg(id); 60 | }); 61 | 62 | httpServer.route("/user//detail/", [] (const qint32 id, const qint32 year) { 63 | return u"User %1 detail year - %2"_s.arg(id).arg(year); 64 | }); 65 | 66 | httpServer.route("/json/", [] { 67 | return QJsonObject{ 68 | { 69 | {"key1", "1"}, 70 | {"key2", "2"}, 71 | {"key3", "3"} 72 | } 73 | }; 74 | }); 75 | 76 | //! [Returning assets] 77 | httpServer.route("/assets/", [] (const QUrl &url) { 78 | return QHttpServerResponse::fromFile(u":/assets/"_s + url.path()); 79 | }); 80 | //! [Returning assets] 81 | 82 | //! [Using QHttpServerRequest] 83 | httpServer.route("/remote_address", [](const QHttpServerRequest &request) { 84 | return request.remoteAddress().toString(); 85 | }); 86 | //! [Using QHttpServerRequest] 87 | 88 | // Basic authentication example (RFC 7617) 89 | //! [Using basic authentication] 90 | httpServer.route("/auth", [](const QHttpServerRequest &request) { 91 | auto auth = request.value("authorization").simplified(); 92 | 93 | if (auth.size() > 6 && auth.first(6).toLower() == "basic ") { 94 | auto token = auth.sliced(6); 95 | auto userPass = QByteArray::fromBase64(token); 96 | 97 | if (auto colon = userPass.indexOf(':'); colon > 0) { 98 | auto userId = userPass.first(colon); 99 | auto password = userPass.sliced(colon + 1); 100 | 101 | if (userId == "Aladdin" && password == "open sesame") 102 | return QHttpServerResponse("text/plain", "Success\n"); 103 | } 104 | } 105 | QHttpServerResponse resp("text/plain", "Authentication required\n", 106 | QHttpServerResponse::StatusCode::Unauthorized); 107 | auto h = resp.headers(); 108 | h.append(QHttpHeaders::WellKnownHeader::WWWAuthenticate, 109 | R"(Basic realm="Simple example", charset="UTF-8")"); 110 | resp.setHeaders(std::move(h)); 111 | return std::move(resp); 112 | }); 113 | //! [Using basic authentication] 114 | 115 | //! [Using addAfterRequestHandler()] 116 | httpServer.addAfterRequestHandler(&httpServer, [](const QHttpServerRequest &, QHttpServerResponse &resp) { 117 | auto h = resp.headers(); 118 | h.append(QHttpHeaders::WellKnownHeader::Server, "Qt HTTP Server"); 119 | resp.setHeaders(std::move(h)); 120 | }); 121 | //! [Using addAfterRequestHandler()] 122 | 123 | //! [Binding the TCP server] 124 | auto tcpserver = std::make_unique(); 125 | if (!tcpserver->listen() || !httpServer.bind(tcpserver.get())) { 126 | qWarning() << QCoreApplication::translate("QHttpServerExample", 127 | "Server failed to listen on a port."); 128 | return -1; 129 | } 130 | quint16 port = tcpserver->serverPort(); 131 | tcpserver.release(); 132 | //! [Binding the TCP server] 133 | 134 | #if QT_CONFIG(ssl) 135 | //! [HTTPS Configuration example] 136 | QSslConfiguration conf = QSslConfiguration::defaultConfiguration(); 137 | const auto sslCertificateChain = 138 | QSslCertificate::fromPath(QStringLiteral(":/assets/certificate.crt")); 139 | if (sslCertificateChain.empty()) { 140 | qWarning() << QCoreApplication::translate("QHttpServerExample", 141 | "Couldn't retrieve SSL certificate from file."); 142 | return -1; 143 | } 144 | QFile privateKeyFile(QStringLiteral(":/assets/private.key")); 145 | if (!privateKeyFile.open(QIODevice::ReadOnly)) { 146 | qWarning() << QCoreApplication::translate("QHttpServerExample", 147 | "Couldn't open file for reading: %1") 148 | .arg(privateKeyFile.errorString()); 149 | return -1; 150 | } 151 | 152 | conf.setLocalCertificate(sslCertificateChain.front()); 153 | conf.setPrivateKey(QSslKey(&privateKeyFile, QSsl::Rsa)); 154 | conf.setAllowedNextProtocols({ QSslConfiguration::ALPNProtocolHTTP2 }); // Add HTTP/2 support 155 | 156 | privateKeyFile.close(); 157 | 158 | auto sslserver = std::make_unique(); 159 | sslserver->setSslConfiguration(conf); 160 | if (!sslserver->listen() || !httpServer.bind(sslserver.get())) { 161 | qWarning() << QCoreApplication::translate("QHttpServerExample", 162 | "Server failed to listen on a port."); 163 | return -1; 164 | } 165 | quint16 sslPort = sslserver->serverPort(); 166 | sslserver.release(); 167 | 168 | //! [HTTPS Configuration example] 169 | 170 | qInfo().noquote() 171 | << QCoreApplication::translate("QHttpServerExample", 172 | "Running on http://127.0.0.1:%1/ and " 173 | "https://127.0.0.1:%2/ (Press CTRL+C to quit)") 174 | .arg(port).arg(sslPort); 175 | #else 176 | qInfo().noquote() 177 | << QCoreApplication::translate("QHttpServerExample", 178 | "Running on http://127.0.0.1:%1/" 179 | "(Press CTRL+C to quit)").arg(port); 180 | #endif 181 | //! [Start handling requests] 182 | return app.exec(); 183 | //! [Start handling requests] 184 | } 185 | -------------------------------------------------------------------------------- /examples/httpserver/colorpalette/apibehavior.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | #ifndef APIBEHAVIOR_H 4 | #define APIBEHAVIOR_H 5 | 6 | #include "types.h" 7 | #include "utils.h" 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | template 15 | class CrudApi 16 | { 17 | }; 18 | 19 | template 20 | class CrudApi, 22 | std::is_base_of>>> 23 | { 24 | public: 25 | explicit CrudApi(const IdMap &data, std::unique_ptr> factory) 26 | : data(data), factory(std::move(factory)) 27 | { 28 | } 29 | 30 | QFuture getPaginatedList(const QHttpServerRequest &request) const 31 | { 32 | using PaginatorType = Paginator>; 33 | std::optional maybePage; 34 | std::optional maybePerPage; 35 | std::optional maybeDelay; 36 | if (request.query().hasQueryItem("page")) 37 | maybePage = request.query().queryItemValue("page").toLongLong(); 38 | if (request.query().hasQueryItem("per_page")) 39 | maybePerPage = request.query().queryItemValue("per_page").toLongLong(); 40 | if (request.query().hasQueryItem("delay")) 41 | maybeDelay = request.query().queryItemValue("delay").toLongLong(); 42 | 43 | if ((maybePage && *maybePage < 1) || (maybePerPage && *maybePerPage < 1)) { 44 | return QtConcurrent::run([]() { 45 | return QHttpServerResponse(QHttpServerResponder::StatusCode::BadRequest); 46 | }); 47 | } 48 | 49 | PaginatorType paginator(data, maybePage ? *maybePage : PaginatorType::defaultPage, 50 | maybePerPage ? *maybePerPage : PaginatorType::defaultPageSize); 51 | 52 | return QtConcurrent::run([paginator = std::move(paginator), maybeDelay]() { 53 | if (maybeDelay) 54 | QThread::sleep(*maybeDelay); 55 | return paginator.isValid() 56 | ? QHttpServerResponse(paginator.toJson()) 57 | : QHttpServerResponse(QHttpServerResponder::StatusCode::NoContent); 58 | }); 59 | } 60 | 61 | QHttpServerResponse getItem(qint64 itemId) const 62 | { 63 | const auto item = data.find(itemId); 64 | return item != data.end() ? QHttpServerResponse(item->toJson()) 65 | : QHttpServerResponse(QHttpServerResponder::StatusCode::NotFound); 66 | } 67 | 68 | //! [POST return different status code example] 69 | QHttpServerResponse postItem(const QHttpServerRequest &request) 70 | { 71 | const std::optional json = byteArrayToJsonObject(request.body()); 72 | if (!json) 73 | return QHttpServerResponse(QHttpServerResponder::StatusCode::BadRequest); 74 | 75 | const std::optional item = factory->fromJson(*json); 76 | if (!item) 77 | return QHttpServerResponse(QHttpServerResponder::StatusCode::BadRequest); 78 | if (data.contains(item->id)) 79 | return QHttpServerResponse(QHttpServerResponder::StatusCode::AlreadyReported); 80 | 81 | const auto entry = data.insert(item->id, *item); 82 | return QHttpServerResponse(entry->toJson(), QHttpServerResponder::StatusCode::Created); 83 | } 84 | //! [POST return different status code example] 85 | 86 | QHttpServerResponse updateItem(qint64 itemId, const QHttpServerRequest &request) 87 | { 88 | const std::optional json = byteArrayToJsonObject(request.body()); 89 | if (!json) 90 | return QHttpServerResponse(QHttpServerResponder::StatusCode::BadRequest); 91 | 92 | auto item = data.find(itemId); 93 | if (item == data.end()) 94 | return QHttpServerResponse(QHttpServerResponder::StatusCode::NoContent); 95 | if (!item->update(*json)) 96 | return QHttpServerResponse(QHttpServerResponder::StatusCode::BadRequest); 97 | 98 | return QHttpServerResponse(item->toJson()); 99 | } 100 | 101 | QHttpServerResponse updateItemFields(qint64 itemId, const QHttpServerRequest &request) 102 | { 103 | const std::optional json = byteArrayToJsonObject(request.body()); 104 | if (!json) 105 | return QHttpServerResponse(QHttpServerResponder::StatusCode::BadRequest); 106 | 107 | auto item = data.find(itemId); 108 | if (item == data.end()) 109 | return QHttpServerResponse(QHttpServerResponder::StatusCode::NoContent); 110 | item->updateFields(*json); 111 | 112 | return QHttpServerResponse(item->toJson()); 113 | } 114 | 115 | QHttpServerResponse deleteItem(qint64 itemId) 116 | { 117 | if (!data.remove(itemId)) 118 | return QHttpServerResponse(QHttpServerResponder::StatusCode::NoContent); 119 | return QHttpServerResponse(QHttpServerResponder::StatusCode::Ok); 120 | } 121 | 122 | private: 123 | IdMap data; 124 | std::unique_ptr> factory; 125 | }; 126 | 127 | class SessionApi 128 | { 129 | public: 130 | explicit SessionApi(const IdMap &sessions, 131 | std::unique_ptr> factory) 132 | : sessions(sessions), factory(std::move(factory)) 133 | { 134 | } 135 | 136 | QHttpServerResponse registerSession(const QHttpServerRequest &request) 137 | { 138 | const auto json = byteArrayToJsonObject(request.body()); 139 | if (!json) 140 | return QHttpServerResponse(QHttpServerResponder::StatusCode::BadRequest); 141 | const auto item = factory->fromJson(*json); 142 | if (!item) 143 | return QHttpServerResponse(QHttpServerResponder::StatusCode::BadRequest); 144 | 145 | const auto session = sessions.insert(item->id, *item); 146 | session->startSession(); 147 | return QHttpServerResponse(session->toJson()); 148 | } 149 | 150 | QHttpServerResponse login(const QHttpServerRequest &request) 151 | { 152 | const auto json = byteArrayToJsonObject(request.body()); 153 | 154 | if (!json || !json->contains("email") || !json->contains("password")) 155 | return QHttpServerResponse(QHttpServerResponder::StatusCode::BadRequest); 156 | 157 | auto maybeSession = std::find_if( 158 | sessions.begin(), sessions.end(), 159 | [email = json->value("email").toString(), 160 | password = json->value("password").toString()](const auto &it) { 161 | return it.password == password && it.email == email; 162 | }); 163 | if (maybeSession == sessions.end()) { 164 | return QHttpServerResponse(QHttpServerResponder::StatusCode::NotFound); 165 | } 166 | maybeSession->startSession(); 167 | return QHttpServerResponse(maybeSession->toJson()); 168 | } 169 | 170 | QHttpServerResponse logout(const QHttpServerRequest &request) 171 | { 172 | const auto maybeToken = getTokenFromRequest(request); 173 | if (!maybeToken) 174 | return QHttpServerResponse(QHttpServerResponder::StatusCode::BadRequest); 175 | 176 | auto maybeSession = std::find(sessions.begin(), sessions.end(), *maybeToken); 177 | if (maybeSession != sessions.end()) 178 | maybeSession->endSession(); 179 | return QHttpServerResponse(QHttpServerResponder::StatusCode::Ok); 180 | } 181 | 182 | bool authorize(const QHttpServerRequest &request) const 183 | { 184 | const auto maybeToken = getTokenFromRequest(request); 185 | if (maybeToken) { 186 | const auto maybeSession = std::find(sessions.begin(), sessions.end(), *maybeToken); 187 | return maybeSession != sessions.end() && *maybeSession == *maybeToken; 188 | } 189 | return false; 190 | } 191 | 192 | private: 193 | IdMap sessions; 194 | std::unique_ptr> factory; 195 | }; 196 | 197 | #endif // APIBEHAVIOR_H 198 | -------------------------------------------------------------------------------- /src/httpserver/qhttpserverresponse.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | // Qt-Security score:significant reason:default 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | QT_BEGIN_NAMESPACE 18 | 19 | /*! 20 | \class QHttpServerResponse 21 | \since 6.4 22 | \inmodule QtHttpServer 23 | \brief Encapsulates an HTTP response. 24 | 25 | API for creating, reading and modifying a response from an HTTP server, 26 | and for writing its contents to a QHttpServerResponder. 27 | It has numerous constructors, and \c static function \c fromFile for 28 | constructing it from the contents of a file. There are functions for 29 | setting, getting, and removing headers, and for getting the data, status 30 | code and mime type. 31 | */ 32 | 33 | /*! 34 | \internal 35 | */ 36 | QHttpServerResponsePrivate::QHttpServerResponsePrivate( 37 | QByteArray &&d, const QHttpServerResponse::StatusCode sc) 38 | : data(std::move(d)), 39 | statusCode(sc) 40 | { } 41 | 42 | /*! 43 | \internal 44 | */ 45 | QHttpServerResponsePrivate::QHttpServerResponsePrivate(const QHttpServerResponse::StatusCode sc) 46 | : statusCode(sc) 47 | { } 48 | 49 | /*! 50 | \typealias QHttpServerResponse::StatusCode 51 | 52 | Type alias for QHttpServerResponder::StatusCode 53 | */ 54 | 55 | /*! 56 | \fn QHttpServerResponse::QHttpServerResponse(QHttpServerResponse &&other) noexcept 57 | 58 | Move-constructs a new QHttpServerResponse from \a other. 59 | */ 60 | 61 | /*! 62 | \fn QHttpServerResponse &QHttpServerResponse::operator=( 63 | QHttpServerResponse &&other) noexcept 64 | 65 | Move-assigns \a other to this QHttpServerResponse instance. 66 | */ 67 | 68 | /*! 69 | \fn void QHttpServerResponse::swap(QHttpServerResponse &other) 70 | 71 | Swaps this QHttpServerResponse with \a other. This operation is very 72 | fast and never fails. 73 | */ 74 | 75 | /*! 76 | Creates a QHttpServerResponse object with the status code \a statusCode. 77 | */ 78 | QHttpServerResponse::QHttpServerResponse(QHttpServerResponse::StatusCode statusCode) 79 | : QHttpServerResponse(QHttpServerLiterals::contentTypeXEmpty(), QByteArray(), statusCode) 80 | { 81 | } 82 | 83 | /*! 84 | Creates a QHttpServerResponse object from \a data with the status code \a status. 85 | */ 86 | QHttpServerResponse::QHttpServerResponse(const char *data, StatusCode status) 87 | : QHttpServerResponse(QByteArray::fromRawData(data, qstrlen(data)), status) 88 | { 89 | } 90 | 91 | /*! 92 | Creates a QHttpServerResponse object from \a data with the status code \a status. 93 | */ 94 | QHttpServerResponse::QHttpServerResponse(const QString &data, StatusCode status) 95 | : QHttpServerResponse(data.toUtf8(), status) 96 | { 97 | } 98 | 99 | /*! 100 | Creates a QHttpServerResponse object from \a data with the status code \a status. 101 | */ 102 | QHttpServerResponse::QHttpServerResponse(const QByteArray &data, StatusCode status) 103 | : QHttpServerResponse(QMimeDatabase().mimeTypeForData(data).name().toLocal8Bit(), data, status) 104 | { 105 | } 106 | 107 | /*! 108 | Move-constructs a QHttpServerResponse whose body will contain the given 109 | \a data with the status code \a status. 110 | */ 111 | QHttpServerResponse::QHttpServerResponse(QByteArray &&data, StatusCode status) 112 | : QHttpServerResponse(QMimeDatabase().mimeTypeForData(data).name().toLocal8Bit(), 113 | std::move(data), status) 114 | { 115 | } 116 | 117 | /*! 118 | Creates a QHttpServerResponse object from \a data with the status code \a status. 119 | */ 120 | QHttpServerResponse::QHttpServerResponse(const QJsonObject &data, StatusCode status) 121 | : QHttpServerResponse(QHttpServerLiterals::contentTypeJson(), 122 | QJsonDocument(data).toJson(QJsonDocument::Compact), status) 123 | { 124 | } 125 | 126 | /*! 127 | Creates a QHttpServerResponse object from \a data with the status code \a status. 128 | */ 129 | QHttpServerResponse::QHttpServerResponse(const QJsonArray &data, StatusCode status) 130 | : QHttpServerResponse(QHttpServerLiterals::contentTypeJson(), 131 | QJsonDocument(data).toJson(QJsonDocument::Compact), status) 132 | { 133 | } 134 | 135 | /*! 136 | \fn QHttpServerResponse::QHttpServerResponse(const QByteArray &mimeType, 137 | const QByteArray &data, 138 | StatusCode status) 139 | \fn QHttpServerResponse::QHttpServerResponse(const QByteArray &mimeType, 140 | QByteArray &&data, 141 | StatusCode status) 142 | 143 | Creates a QHttpServer response. 144 | 145 | The response will use the given \a status code and deliver the \a data as 146 | its body, with a \c ContentType header describing it as being of MIME type 147 | \a mimeType. 148 | */ 149 | QHttpServerResponse::QHttpServerResponse(const QByteArray &mimeType, 150 | const QByteArray &data, 151 | StatusCode status) 152 | : d_ptr(new QHttpServerResponsePrivate(QByteArray(data), status)) 153 | { 154 | if (!mimeType.isEmpty()) { 155 | d_ptr->headers.append(QHttpHeaders::WellKnownHeader::ContentType, mimeType); 156 | } 157 | } 158 | 159 | QHttpServerResponse::QHttpServerResponse(const QByteArray &mimeType, 160 | QByteArray &&data, 161 | StatusCode status) 162 | : d_ptr(new QHttpServerResponsePrivate(std::move(data), status)) 163 | { 164 | if (!mimeType.isEmpty()) { 165 | d_ptr->headers.append(QHttpHeaders::WellKnownHeader::ContentType, mimeType); 166 | } 167 | } 168 | 169 | /*! 170 | Destroys a QHttpServerResponse object. 171 | */ 172 | QHttpServerResponse::~QHttpServerResponse() 173 | { 174 | delete d_ptr; 175 | }; 176 | 177 | /*! 178 | Returns a QHttpServerResponse from the content of the file \a fileName. 179 | 180 | It is the caller's responsibility to sanity-check the filename, and to have 181 | a well-defined policy for which files the server will request. 182 | */ 183 | QHttpServerResponse QHttpServerResponse::fromFile(const QString &fileName) 184 | { 185 | QFile file(fileName); 186 | if (!file.open(QFile::ReadOnly)) 187 | return QHttpServerResponse(StatusCode::NotFound); 188 | const QByteArray data = file.readAll(); 189 | file.close(); 190 | const QByteArray mimeType = QMimeDatabase().mimeTypeForFileNameAndData(fileName, data).name().toLocal8Bit(); 191 | return QHttpServerResponse(mimeType, data); 192 | } 193 | 194 | /*! 195 | Returns the response body. 196 | */ 197 | QByteArray QHttpServerResponse::data() const 198 | { 199 | Q_D(const QHttpServerResponse); 200 | return d->data; 201 | } 202 | 203 | /*! 204 | Returns the status code. 205 | */ 206 | QHttpServerResponse::StatusCode QHttpServerResponse::statusCode() const 207 | { 208 | Q_D(const QHttpServerResponse); 209 | return d->statusCode; 210 | } 211 | 212 | /*! 213 | Returns the value of the HTTP \c "Content-Type" header. 214 | 215 | \note Default value is \c{"text/html"}. 216 | */ 217 | QByteArray QHttpServerResponse::mimeType() const 218 | { 219 | Q_D(const QHttpServerResponse); 220 | return d->headers.value(QHttpHeaders::WellKnownHeader::ContentType, 221 | QHttpServerLiterals::contentTypeTextHtml()).toByteArray(); 222 | } 223 | 224 | /*! 225 | Returns the currently set HTTP headers. 226 | 227 | \since 6.8 228 | */ 229 | QHttpHeaders QHttpServerResponse::headers() const 230 | { 231 | Q_D(const QHttpServerResponse); 232 | return d->headers; 233 | } 234 | 235 | /*! 236 | Sets \a newHeaders as the HTTP headers, overriding any previously set headers. 237 | 238 | \since 6.8 239 | */ 240 | void QHttpServerResponse::setHeaders(QHttpHeaders &&newHeaders) 241 | { 242 | Q_D(QHttpServerResponse); 243 | d->headers = std::move(newHeaders); 244 | } 245 | 246 | /*! 247 | \overload 248 | \since 6.8 249 | */ 250 | void QHttpServerResponse::setHeaders(const QHttpHeaders &newHeaders) 251 | { 252 | Q_D(QHttpServerResponse); 253 | d->headers = newHeaders; 254 | } 255 | 256 | QT_END_NAMESPACE 257 | -------------------------------------------------------------------------------- /src/httpserver/qhttpserverrequest.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | // Qt-Security score:significant reason:default 4 | 5 | #include "qhttpserverrequest_p.h" 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #if QT_CONFIG(ssl) 15 | #include 16 | #endif 17 | #if QT_CONFIG(http) 18 | #include 19 | #endif 20 | 21 | QT_BEGIN_NAMESPACE 22 | 23 | using namespace Qt::StringLiterals; 24 | 25 | QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QHttpServerRequestPrivate) 26 | 27 | #if !defined(QT_NO_DEBUG_STREAM) 28 | 29 | /*! 30 | \fn QDebug QHttpServerRequest::operator<<(QDebug debug, const QHttpServerRequest &request) 31 | 32 | Writes information about \a request to the \a debug stream. 33 | 34 | \sa QDebug 35 | */ 36 | Q_HTTPSERVER_EXPORT QDebug operator<<(QDebug debug, const QHttpServerRequest &request) 37 | { 38 | QDebugStateSaver saver(debug); 39 | debug.nospace() << "QHttpServerRequest("; 40 | debug << "(Url: " << request.url() << ")"; 41 | debug << "(Headers: " << request.headers() << ")"; 42 | debug << "(RemoteHost: " << request.remoteAddress() << ")"; 43 | debug << "(BodySize: " << request.body().size() << ")"; 44 | debug << ')'; 45 | return debug; 46 | } 47 | 48 | #endif 49 | 50 | /*! 51 | \internal 52 | */ 53 | QHttpServerRequestPrivate::QHttpServerRequestPrivate(const QHostAddress &remoteAddress, 54 | quint16 remotePort, 55 | const QHostAddress &localAddress, 56 | quint16 localPort) 57 | : remoteAddress(remoteAddress), 58 | remotePort(remotePort), 59 | localAddress(localAddress), 60 | localPort(localPort) 61 | { 62 | } 63 | 64 | #if QT_CONFIG(ssl) 65 | /*! 66 | \internal 67 | */ 68 | QHttpServerRequestPrivate::QHttpServerRequestPrivate(const QHostAddress &remoteAddress, 69 | quint16 remotePort, 70 | const QHostAddress &localAddress, 71 | quint16 localPort, 72 | const QSslConfiguration &sslConfiguration) 73 | : remoteAddress(remoteAddress), 74 | remotePort(remotePort), 75 | localAddress(localAddress), 76 | localPort(localPort), 77 | sslConfiguration(sslConfiguration) 78 | { 79 | } 80 | #endif 81 | 82 | /*! 83 | \class QHttpServerRequest 84 | \since 6.4 85 | \inmodule QtHttpServer 86 | \brief Encapsulates an HTTP request. 87 | 88 | API for accessing the different parameters of an incoming request. 89 | */ 90 | 91 | /*! 92 | \enum QHttpServerRequest::Method 93 | 94 | This enum type specifies an HTTP request method: 95 | 96 | \value Unknown 97 | An unknown method. 98 | \value Get 99 | HTTP GET method. 100 | \value Put 101 | HTTP PUT method. 102 | \value Delete 103 | HTTP DELETE method. 104 | \value Post 105 | HTTP POST method. 106 | \value Head 107 | HTTP HEAD method. 108 | \value Options 109 | HTTP OPTIONS method. 110 | \value Patch 111 | HTTP PATCH method (\l {https://www.rfc-editor.org/rfc/rfc5789}{RFC 5789}). 112 | \value Connect 113 | HTTP CONNECT method. 114 | \value Trace 115 | HTTP TRACE method. 116 | \value AnyKnown 117 | Combination of all known methods. 118 | */ 119 | 120 | /*! 121 | \internal 122 | */ 123 | QHttpServerRequest::QHttpServerRequest(const QHostAddress &remoteAddress, quint16 remotePort, 124 | const QHostAddress &localAddress, quint16 localPort) 125 | : d(new QHttpServerRequestPrivate(remoteAddress, remotePort, localAddress, localPort)) 126 | {} 127 | 128 | #if QT_CONFIG(ssl) 129 | /*! 130 | \internal 131 | */ 132 | QHttpServerRequest::QHttpServerRequest(const QHostAddress &remoteAddress, quint16 remotePort, 133 | const QHostAddress &localAddress, quint16 localPort, 134 | const QSslConfiguration &sslConfiguration) 135 | : d(new QHttpServerRequestPrivate(remoteAddress, remotePort, localAddress, localPort, 136 | sslConfiguration)) 137 | {} 138 | #endif 139 | 140 | /*! 141 | Constructs a QHttpServerRequest. 142 | 143 | \since 6.10 144 | */ 145 | QHttpServerRequest::QHttpServerRequest() = default; 146 | 147 | /*! 148 | Copy constructs a QHttpServerRequest using \a other. 149 | 150 | \since 6.10 151 | */ 152 | QHttpServerRequest::QHttpServerRequest(const QHttpServerRequest &other) = default; 153 | 154 | /*! 155 | Assigns a QHttpServerRequest using \a other. 156 | 157 | \since 6.10 158 | */ 159 | QHttpServerRequest &QHttpServerRequest::operator=(const QHttpServerRequest &other) = default; 160 | 161 | /*! 162 | \fn QHttpServerRequest::QHttpServerRequest(QHttpServerRequest &&other) noexcept 163 | 164 | Move constructs a QHttpServerRequest using \a other. 165 | 166 | \since 6.10 167 | */ 168 | 169 | /*! 170 | \fn QHttpServerRequest &QHttpServerRequest::operator=(QHttpServerRequest &&other) noexcept 171 | 172 | Move assigns a QHttpServerRequest using \a other. 173 | 174 | \since 6.10 175 | */ 176 | 177 | /*! 178 | \fn void QHttpServerRequest::swap(QHttpServerRequest &other) noexcept 179 | 180 | Swaps values between this and \a other. 181 | 182 | \since 6.10 183 | */ 184 | 185 | /*! 186 | Destroys a QHttpServerRequest 187 | */ 188 | QHttpServerRequest::~QHttpServerRequest() { } 189 | 190 | /*! 191 | Returns the combined value of all headers with the named \a key. 192 | */ 193 | QByteArray QHttpServerRequest::value(const QByteArray &key) const 194 | { 195 | return d->headers.combinedValue(key); 196 | } 197 | 198 | /*! 199 | Returns the URL the request asked for. 200 | */ 201 | QUrl QHttpServerRequest::url() const 202 | { 203 | return d->url; 204 | } 205 | 206 | /*! 207 | Returns the query in the request. 208 | */ 209 | QUrlQuery QHttpServerRequest::query() const 210 | { 211 | return QUrlQuery(d->url.query()); 212 | } 213 | 214 | /*! 215 | Returns the method of the request. 216 | */ 217 | QHttpServerRequest::Method QHttpServerRequest::method() const 218 | { 219 | return d->method; 220 | } 221 | 222 | /*! 223 | \fn const QHttpHeaders &QHttpServerRequest::headers() const & 224 | \fn QHttpHeaders QHttpServerRequest::headers() && 225 | 226 | Returns all the request headers. 227 | */ 228 | const QHttpHeaders &QHttpServerRequest::headers() const & 229 | { 230 | return d->headers; 231 | } 232 | 233 | QHttpHeaders QHttpServerRequest::headers() && 234 | { 235 | return std::move(d->headers); 236 | } 237 | 238 | /*! 239 | Returns the body of the request. 240 | */ 241 | QByteArray QHttpServerRequest::body() const 242 | { 243 | return d->body; 244 | } 245 | 246 | /*! 247 | Returns the address of the origin host of the request. 248 | */ 249 | QHostAddress QHttpServerRequest::remoteAddress() const 250 | { 251 | return d->remoteAddress; 252 | } 253 | 254 | /*! 255 | Returns the port of the origin host of the request. 256 | 257 | \since 6.5 258 | */ 259 | quint16 QHttpServerRequest::remotePort() const 260 | { 261 | return d->remotePort; 262 | } 263 | 264 | /*! 265 | Returns the host address of the local socket which received the request. 266 | 267 | \since 6.5 268 | */ 269 | QHostAddress QHttpServerRequest::localAddress() const 270 | { 271 | return d->localAddress; 272 | } 273 | 274 | /*! 275 | Returns the port of the local socket which received the request. 276 | 277 | \since 6.5 278 | */ 279 | quint16 QHttpServerRequest::localPort() const 280 | { 281 | return d->localPort; 282 | } 283 | 284 | #if QT_CONFIG(ssl) 285 | /*! 286 | Returns the configuration of the established TLS connection. 287 | The configurations will return true for isNull() if the connection 288 | is not using TLS. 289 | 290 | \since 6.7 291 | */ 292 | QSslConfiguration QHttpServerRequest::sslConfiguration() const 293 | { 294 | return d->sslConfiguration; 295 | } 296 | #endif 297 | 298 | /*! 299 | \internal 300 | */ 301 | QHttpServerRequest QHttpServerRequest::create(const QHttpServerParser &parser) 302 | { 303 | QHttpServerRequest request(parser.remoteAddress, parser.remotePort, parser.localAddress, 304 | parser.localPort); 305 | request.d->url = parser.url; 306 | request.d->method = parser.method; 307 | request.d->headers = parser.headers; 308 | request.d->body = parser.body; 309 | request.d->majorVersion = parser.majorVersion; 310 | request.d->minorVersion = parser.minorVersion; 311 | return request; 312 | } 313 | 314 | #if QT_CONFIG(ssl) 315 | /*! 316 | \internal 317 | */ 318 | QHttpServerRequest QHttpServerRequest::create(const QHttpServerParser &parser, 319 | const QSslConfiguration &configuration) 320 | { 321 | QHttpServerRequest request = create(parser); 322 | request.d->sslConfiguration = configuration; 323 | return request; 324 | } 325 | #endif 326 | 327 | QT_END_NAMESPACE 328 | 329 | #include "moc_qhttpserverrequest.cpp" 330 | --------------------------------------------------------------------------------