git.iko.soy/cinny-click-packaging
on main help sign in
58 files changed+3885−265
since splitsnapshots
unifiedsplit
.github/ISSUE_TEMPLATE/bug_report.md+32 .github/ISSUE_TEMPLATE/feature_request.md+22 .github/workflows/build.yml+31 .gitlab-ci.yml−56 .gitmodules+3 CMakeLists.txt+5−2 README.md+3−3 cinny.apparmor+2 libs/CMakeLists.txt+1 libs/http-parser+1 libs/qhttp/CMakeLists.txt+57 libs/qhttp/LICENSE+22 libs/qhttp/private/httpparser.hxx+119 libs/qhttp/private/httpreader.hxx+78 libs/qhttp/private/httpwriter.hxx+109 libs/qhttp/private/qhttpbase.hpp+52 libs/qhttp/private/qhttpclient_private.hpp+196 libs/qhttp/private/qhttpclientrequest_private.hpp+57 libs/qhttp/private/qhttpclientresponse_private.hpp+51 libs/qhttp/private/qhttpserver_private.hpp+90 libs/qhttp/private/qhttpserverconnection_private.hpp+175 libs/qhttp/private/qhttpserverrequest_private.hpp+51 libs/qhttp/private/qhttpserverresponse_private.hpp+62 libs/qhttp/private/qsocket.hpp+126 libs/qhttp/qhttpabstracts.cpp+114 libs/qhttp/qhttpabstracts.hpp+190 libs/qhttp/qhttpclient.cpp+284 libs/qhttp/qhttpclient.hpp+182 libs/qhttp/qhttpclientrequest.cpp+98 libs/qhttp/qhttpclientrequest.hpp+67 libs/qhttp/qhttpclientresponse.cpp+66 libs/qhttp/qhttpclientresponse.hpp+78 libs/qhttp/qhttpfwd.hpp+221 libs/qhttp/qhttpserver.cpp+118 libs/qhttp/qhttpserver.hpp+131 libs/qhttp/qhttpserverconnection.cpp+217 libs/qhttp/qhttpserverconnection.hpp+87 libs/qhttp/qhttpserverrequest.cpp+81 libs/qhttp/qhttpserverrequest.hpp+82 libs/qhttp/qhttpserverresponse.cpp+90 libs/qhttp/qhttpserverresponse.hpp+70 libs/qhttp/src.pro+42 main.cpp+41−3 manifest.json.in+1−1 patches/0002-Fix-loading-on-older-browsers.patch → patches/0002-Fix-loading-on-older-browsers.patch_ignore patches/0004-Create-data-url-instead-of-object-url.patch+21−15 patches/0006-Download-media-using-qml-backend.patch+5−14 patches/0008-Set-push-notifications-to-UTs-push-hook.patch+22−42 patches/0009--Add-credits.patch+13−13 patches/0010-Open-SSO-login-in-a-new-window.patch+25 patches/0011-Remove-unused-elements.patch+37 patches/0012-Rename-session-name-to-Cinny-Ubuntu-Touch.patch+25 patches/0013-Disable-cinny-s-notification-sound.patch+36 po/cinny.nitanmarcel.pot+10−6 prebuild.sh+11−3 qml/Main.qml+11−81 qml/qml.qrc.depends−7 svg/cinny_18.svg+64−19
.github/ISSUE_TEMPLATE/bug_report.mdnew file+32
@@ -0,0 +1,32 @@
1+---
2+name: Bug report
3+about: Create a report to help us improve
4+title: ''
5+labels: ''
6+assignees: ''
7+
8+---
9+
10+# Please follow the general troubleshooting steps first:
11+
12+- [ ] This bug is not reproducible on https://app.cinny.in
13+- [ ] This bug is not mentioned in any issues here or in the [upstream repository](https://github.com/cinnyapp/cinny)
14+
15+**Describe the bug**
16+A clear and concise description of what the bug is.
17+
18+**To Reproduce**
19+Steps to reproduce the behavior:
20+1. Go to '...'
21+2. Click on '....'
22+3. Scroll down to '....'
23+4. See error
24+
25+**Expected behavior**
26+A clear and concise description of what you expected to happen.
27+
28+**Screenshots**
29+If applicable, add screenshots to help explain your problem.
30+
31+**Additional context**
32+Add any other context about the problem here.
.github/ISSUE_TEMPLATE/feature_request.mdnew file+22
@@ -0,0 +1,22 @@
1+---
2+name: Feature request
3+about: Suggest an idea for this project
4+title: ''
5+labels: ''
6+assignees: ''
7+
8+---
9+
10+- [ ] This feature request can't be implemented in the [upstream repository](https://github.com/cinnyapp/cinny)
11+
12+**Is your feature request related to a problem? Please describe.**
13+A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
14+
15+**Describe the solution you'd like**
16+A clear and concise description of what you want to happen.
17+
18+**Describe alternatives you've considered**
19+A clear and concise description of any alternative solutions or features you've considered.
20+
21+**Additional context**
22+Add any other context or screenshots about the feature request here.
.github/workflows/build.ymlnew file+31
@@ -0,0 +1,31 @@
1+name: Clickable Build
2+
3+on:
4+ push:
5+
6+jobs:
7+ build:
8+ strategy:
9+ matrix:
10+ arch: [amd64, arm64, armhf]
11+ runs-on: ubuntu-latest
12+ steps:
13+ - name: Checkout
14+ uses: actions/checkout@v3
15+ with:
16+ submodules: 'true'
17+ - name: Parse version
18+ run: |
19+ echo ARTIFACT_VERSION=$(cat prebuild.sh | grep "export REPO_VERSION=" | awk -F'"' '$0=$2')$(cat prebuild.sh | grep "export CLICK_VERSION_PREFIX=" | awk -F'"' '$0=$2') >> $GITHUB_ENV
20+ - name: Install clickable
21+ run: |
22+ python3 -m pip install clickable-ut
23+ - name: Build
24+ run: |
25+ clickable build --arch ${{ matrix.arch }}
26+ - name: Upload Artifacts
27+ uses: actions/upload-artifact@v3
28+ with:
29+ name: cinny.nitanmarcel_${{ env.ARTIFACT_VERSION }}_${{ matrix.arch }}
30+ path: build/*/app/*.click
31+ if-no-files-found: error
.gitlab-ci.ymldeleted−56
@@ -1,56 +0,0 @@
1−---
2−###############################################################################
3−# Define all YAML node anchors
4−###############################################################################
5−.node_anchors:
6− # `stage`
7− stage_build: &stage_build 'build'
8− # `image`
9− image_clickable_amd64: &image_clickable_amd64 'clickable/ci-16.04-amd64'
10− image_clickable_arm64: &image_clickable_arm64 'clickable/ci-16.04-arm64'
11− image_clickable_armhf: &image_clickable_armhf 'clickable/ci-16.04-armhf'
12− # `artifacts.paths`
13− paths_amd64: &paths_amd64
14− - 'build/x86_64-linux-gnu/app/*.click'
15− paths_arm64: &paths_arm64
16− - 'build/aarch64-linux-gnu/app/*.click'
17− paths_armhf: &paths_armhf
18− - 'build/arm-linux-gnueabihf/app/*.click'
19−
20−###############################################################################
21−# Define stages
22−###############################################################################
23−stages:
24− - *stage_build
25−
26−###############################################################################
27−# Define `build` template
28−###############################################################################
29−.build_click:
30− stage: *stage_build
31− script:
32− - 'clickable build'
33− - 'clickable review'
34− artifacts:
35− expire_in: '1 week'
36−
37−###############################################################################
38−# `build` stage: build clicks for `armhf`, `arm64` & `amd64`
39−###############################################################################
40−xenial_armhf_click:
41− extends: '.build_click'
42− image: *image_clickable_armhf
43− artifacts:
44− paths: *paths_armhf
45−
46−xenial_arm64_click:
47− extends: '.build_click'
48− image: *image_clickable_arm64
49− artifacts:
50− paths: *paths_arm64
51−
52−xenial_amd64_click:
53− extends: '.build_click'
54− image: *image_clickable_amd64
55− artifacts:
56− paths: *paths_amd64
.gitmodulesnew file+3
@@ -0,0 +1,3 @@
1+[submodule "libs/http-parser"]
2+ path = libs/http-parser
3+ url = https://github.com/nodejs/http-parser.git
CMakeLists.txt+5−2
@@ -3,7 +3,9 @@ project(cinny C CXX)
33
44# Automatically create moc files
55set(CMAKE_AUTOMOC ON)
6−set(CMAKE_CXX_STANDARD 11)
6+set(CMAKE_CXX_STANDARD 14)
7+
8+include(GNUInstallDirs)
79
810find_package(Qt5Core REQUIRED)
911find_package(Qt5Qml REQUIRED)
@@ -52,7 +54,7 @@ qt5_add_resources(QT_RESOURCES qml/qml.qrc)
5254qt5_add_resources(QT_RESOURCES assets/assets.qrc)
5355add_executable(${PROJECT_NAME} main.cpp ${QT_RESOURCES})
5456set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS_RELEASE -s)
55−target_link_libraries(${PROJECT_NAME} Qt5::Gui Qt5::Qml Qt5::Quick Qt5::QuickControls2)
57+target_link_libraries(${PROJECT_NAME} QHttp Qt5::Gui Qt5::Qml Qt5::Quick Qt5::QuickControls2)
5658install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX})
5759
5860# Translations
@@ -79,6 +81,7 @@ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${DESKTOP_FILE_NAME} DESTINATION ${DAT
7981add_subdirectory(po)
8082add_subdirectory(plugins)
8183add_subdirectory(push)
84+add_subdirectory(libs)
8285
8386# Make source files visible in qtcreator
8487file(GLOB_RECURSE PROJECT_SRC_FILES
README.md+3−3
@@ -4,11 +4,11 @@ Cinny is a Matrix client focusing primarily on simple, elegant and secure interf
44
55## License
66
7−Cinny source package licensed under [MIT](https://github.com/ajbura/cinny/blob/dev/LICENSE) (c) 2021 Ajay Bura (ajbura) and contributors.
7+Cinny source package licensed under [MIT](https://github.com/cinnyapp/cinny/blob/dev/LICENSE) (c) 2021 Ajay Bura (ajbura) and contributors.
88
99[Graphics](/svg/) by Ajay Bura (ajbura) licensed under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/) (c) by Ajay Bura (ajbura).
1010
11−Cinny mobile adaptation by [C0ffeeCode](https://github.com/C0ffeeCode/cinny/commits/adapt-mobile-width) under [MIT](https://github.com/ajbura/cinny/blob/dev/LICENSE) (c) 2021 Ajay Bura (ajbura) and contributors.
12−
1311Click packaging by [Marcel Alexandru Nitan](https://github.com/nitanmarcel/cinny-click-packaging) [GPLv3](https://github.com/nitanmarcel/cinny-click-packaging/blob/dev/LICENSE) (C) 2022 Marcel Alexandru Nitan.
1412
13+[![OpenStore](https://open-store.io/badges/en_US.png)](https://open-store.io/app/cinny.nitanmarcel)
14+
cinny.apparmor+2
@@ -2,6 +2,8 @@
22 "policy_groups": [
33 "networking",
44 "content_exchange",
5+ "audio",
6+ "video",
57 "content_exchange_source",
68 "keep-display-on",
79 "webview",
libs/CMakeLists.txtnew file+1
@@ -0,0 +1 @@
1+add_subdirectory(qhttp)
libs/http-parsernew file+1

Submodule changed.

libs/qhttp/CMakeLists.txtnew file+57
@@ -0,0 +1,57 @@
1+project(qhttp C CXX)
2+cmake_minimum_required(VERSION 3.0.0)
3+
4+
5+find_package(Qt5Core REQUIRED)
6+find_package(Qt5Network REQUIRED)
7+
8+set(CMAKE_AUTOMOC ON)
9+set(CMAKE_AUTORCC ON)
10+
11+set(QHTTP "QHttp")
12+
13+set(SRC
14+ ../http-parser/http_parser.c
15+ ../http-parser/http_parser.h
16+ qhttpabstracts.cpp
17+ qhttpabstracts.hpp
18+ qhttpfwd.hpp
19+ qhttpserver.cpp
20+ qhttpserver.hpp
21+ qhttpserverconnection.cpp
22+ qhttpserverconnection.hpp
23+ qhttpserverrequest.cpp
24+ qhttpserverrequest.hpp
25+ qhttpserverresponse.cpp
26+ qhttpserverresponse.hpp
27+ )
28+
29+set(CMAKE_INCLUDE_CURRENT_DIR ON)
30+set(CMAKE_AUTOMOC ON)
31+
32+add_library(${QHTTP} SHARED ${SRC})
33+
34+
35+
36+set(CMAKE_AUTOMOC ON)
37+set(CMAKE_AUTORCC ON)
38+
39+target_link_libraries(${QHTTP} PUBLIC
40+ Qt5::Core
41+ Qt5::Network
42+)
43+
44+target_include_directories(${QHTTP} PUBLIC
45+ .
46+ ../
47+)
48+
49+target_compile_definitions(${QHTTP} PUBLIC
50+ QHTTP_DYNAMIC_LIB
51+ QHTTP_HAS_CLIENT
52+ QHTTP_MEMORY_LOG=0
53+)
54+
55+install(TARGETS ${QHTTP} LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
56+)
57+
libs/qhttp/LICENSEnew file+22
@@ -0,0 +1,22 @@
1+The MIT License (MIT)
2+
3+Copyright (c) 2014 Amir Zamani
4+
5+Permission is hereby granted, free of charge, to any person obtaining a copy of
6+this software and associated documentation files (the "Software"), to deal in
7+the Software without restriction, including without limitation the rights to
8+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9+the Software, and to permit persons to whom the Software is furnished to do so,
10+subject to the following conditions:
11+
12+The above copyright notice and this permission notice shall be included in all
13+copies or substantial portions of the Software.
14+
15+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21+
22+
libs/qhttp/private/httpparser.hxxnew file+119
@@ -0,0 +1,119 @@
1+/** @file httpparser.hxx
2+ *
3+ * @copyright (C) 2016
4+ * @date 2016.05.26
5+ * @version 1.0.0
6+ * @author amir zamani <azadkuh@live.com>
7+ *
8+ */
9+
10+#ifndef __QHTTP_HTTPPARSER_HXX__
11+#define __QHTTP_HTTPPARSER_HXX__
12+
13+#include "qhttpbase.hpp"
14+///////////////////////////////////////////////////////////////////////////////
15+namespace qhttp {
16+namespace details {
17+///////////////////////////////////////////////////////////////////////////////
18+
19+
20+/// base HttpParser based on joyent http_parser
21+template<class TImpl>
22+class HttpParser
23+{
24+public:
25+ explicit HttpParser(http_parser_type type) {
26+ // create http_parser object
27+ iparser.data = static_cast<TImpl*>(this);
28+ http_parser_init(&iparser, type);
29+
30+ memset(&iparserSettings, 0, sizeof(http_parser_settings));
31+ iparserSettings.on_message_begin = onMessageBegin;
32+ iparserSettings.on_url = onUrl;
33+ iparserSettings.on_status = onStatus;
34+ iparserSettings.on_header_field = onHeaderField;
35+ iparserSettings.on_header_value = onHeaderValue;
36+ iparserSettings.on_headers_complete = onHeadersComplete;
37+ iparserSettings.on_body = onBody;
38+ iparserSettings.on_message_complete = onMessageComplete;
39+ }
40+
41+ size_t parse(const char* data, size_t length) {
42+ return http_parser_execute(&iparser,
43+ &iparserSettings,
44+ data,
45+ length);
46+ }
47+
48+public: // callback functions for http_parser_settings
49+ static int onMessageBegin(http_parser* p) {
50+ return me(p)->messageBegin(p);
51+ }
52+
53+ static int onUrl(http_parser* p, const char* at, size_t length) {
54+ return me(p)->url(p, at, length);
55+ }
56+
57+ static int onStatus(http_parser* p, const char* at, size_t length) {
58+ return me(p)->status(p, at, length);
59+ }
60+
61+ static int onHeaderField(http_parser* p, const char* at, size_t length) {
62+ return me(p)->headerField(p, at, length);
63+ }
64+
65+ static int onHeaderValue(http_parser* p, const char* at, size_t length) {
66+ return me(p)->headerValue(p, at, length);
67+ }
68+
69+ static int onHeadersComplete(http_parser* p) {
70+ return me(p)->headersComplete(p);
71+ }
72+
73+ static int onBody(http_parser* p, const char* at, size_t length) {
74+ return me(p)->body(p, at, length);
75+ }
76+
77+ static int onMessageComplete(http_parser* p) {
78+ return me(p)->messageComplete(p);
79+ }
80+
81+
82+protected:
83+ // The ones we are reading in from the parser
84+ QByteArray itempHeaderField;
85+ QByteArray itempHeaderValue;
86+ // if connection has a timeout, these fields will be used
87+ quint32 itimeOut = 0;
88+ QBasicTimer itimer;
89+ // uniform socket object
90+ QSocket isocket;
91+ // if connection should persist
92+ bool ikeepAlive = false;
93+
94+ // joyent http_parser
95+ http_parser iparser;
96+ http_parser_settings iparserSettings;
97+
98+ static auto me(http_parser* p) {
99+ return static_cast<TImpl*>(p->data);
100+ }
101+}; //
102+
103+/// basic request parser (server)
104+template<class TImpl>
105+struct HttpRequestParser : public HttpParser<TImpl> {
106+ HttpRequestParser() : HttpParser<TImpl>(HTTP_REQUEST) {}
107+};
108+
109+/// basic response parser (clinet)
110+template<class TImpl>
111+struct HttpResponseParser : public HttpParser<TImpl> {
112+ HttpResponseParser() : HttpParser<TImpl>(HTTP_RESPONSE) {}
113+};
114+
115+///////////////////////////////////////////////////////////////////////////////
116+} // namespace details
117+} // namespace qhttp
118+///////////////////////////////////////////////////////////////////////////////
119+#endif // __QHTTP_HTTPPARSER_HXX__
libs/qhttp/private/httpreader.hxxnew file+78
@@ -0,0 +1,78 @@
1+/** @file httpreader.hxx
2+ *
3+ * @copyright (C) 2016
4+ * @date 2016.05.26
5+ * @version 1.0.0
6+ * @author amir zamani <azadkuh@live.com>
7+ *
8+ */
9+
10+#ifndef __QHTTP_HTTPREADER_HXX__
11+#define __QHTTP_HTTPREADER_HXX__
12+
13+#include "qhttpbase.hpp"
14+///////////////////////////////////////////////////////////////////////////////
15+namespace qhttp {
16+namespace details {
17+///////////////////////////////////////////////////////////////////////////////
18+
19+// usage in client::QHttpResponse, server::QHttpRequest
20+template<class TBase>
21+class HttpReader : public TBase
22+{
23+public:
24+ enum TReadState {
25+ EEmpty,
26+ EPartial,
27+ EComplete,
28+ ESent
29+ };
30+
31+public:
32+ void collectData(int atMost) {
33+ icollectRequired = true;
34+ icollectCapacity = atMost;
35+ icollectedData.clear();
36+ if ( atMost > 0 )
37+ icollectedData.reserve(atMost);
38+ }
39+
40+ bool append(const char* data, size_t length) {
41+ if ( !icollectRequired ) // not allowed to collect data
42+ return false;
43+
44+ int newLength = icollectedData.length() + (int) length;
45+
46+ if ( icollectCapacity > 0 && newLength > icollectCapacity )
47+ return false; // the capacity is full
48+
49+ icollectedData.append(data, length);
50+ return true;
51+ }
52+
53+ // call cb if the message is not finalized yet
54+ template<class Func>
55+ void finalizeSending(Func cb) {
56+ if ( ireadState != EComplete ) {
57+ ireadState = EComplete;
58+ isuccessful = true;
59+
60+ cb();
61+ }
62+ }
63+
64+public:
65+ bool isuccessful = false;
66+ TReadState ireadState = EEmpty;
67+
68+ /// shall I collect incoming body data by myself?
69+ bool icollectRequired = false;
70+ int icollectCapacity = 0;
71+ QByteArray icollectedData;
72+};
73+
74+///////////////////////////////////////////////////////////////////////////////
75+} // namespace details
76+} // namespace qhttp
77+///////////////////////////////////////////////////////////////////////////////
78+#endif // __QHTTP_HTTPREADER_HXX__
libs/qhttp/private/httpwriter.hxxnew file+109
@@ -0,0 +1,109 @@
1+/** @file httpwriter.hxx
2+ *
3+ * @copyright (C) 2016
4+ * @date 2016.05.26
5+ * @version 1.0.0
6+ * @author amir zamani <azadkuh@live.com>
7+ *
8+ */
9+
10+#ifndef __QHTTP_HTTPWRITER_HXX__
11+#define __QHTTP_HTTPWRITER_HXX__
12+
13+#include "qhttpbase.hpp"
14+
15+///////////////////////////////////////////////////////////////////////////////
16+namespace qhttp {
17+namespace details {
18+///////////////////////////////////////////////////////////////////////////////
19+
20+// usage in client::QHttpRequest, server::QHttpResponse
21+template<class TBase, class TImpl>
22+class HttpWriter : public TBase
23+{
24+public:
25+ bool addHeader(const QByteArray &field, const QByteArray &value) {
26+ if ( ifinished )
27+ return false;
28+
29+ TBase::iheaders.insert(field.toLower(), value);
30+ return true;
31+ }
32+
33+ bool writeHeader(const QByteArray& field, const QByteArray& value) {
34+ if ( ifinished )
35+ return false;
36+
37+ QByteArray buffer = QByteArray(field)
38+ .append(": ")
39+ .append(value)
40+ .append("\r\n");
41+
42+ isocket.writeRaw(buffer);
43+ return true;
44+ }
45+
46+ bool writeData(const QByteArray& data) {
47+ if ( ifinished )
48+ return false;
49+
50+ ensureWritingHeaders();
51+ isocket.writeRaw(data);
52+ return true;
53+ }
54+
55+ bool endPacket(const QByteArray& data) {
56+ if ( !writeData(data) )
57+ return false;
58+
59+ isocket.flush();
60+ ifinished = true;
61+ return true;
62+ }
63+
64+ void ensureWritingHeaders() {
65+ if ( ifinished || iheaderWritten )
66+ return;
67+
68+ TImpl* me = static_cast<TImpl*>(this);
69+ isocket.writeRaw(me->makeTitle());
70+ writeHeaders();
71+
72+ iheaderWritten = true;
73+ }
74+
75+ void writeHeaders(bool doFlush = false) {
76+ if ( ifinished || iheaderWritten )
77+ return;
78+
79+ if ( TBase::iheaders.keyHasValue("connection", "keep-alive") )
80+ ikeepAlive = true;
81+ else
82+ TBase::iheaders.insert("connection", "close");
83+
84+ TImpl* me = static_cast<TImpl*>(this);
85+ me->prepareHeadersToWrite();
86+
87+ TBase::iheaders.forEach([this](const auto& cit) {
88+ this->writeHeader(cit.key(), cit.value());
89+ });
90+
91+ isocket.writeRaw("\r\n");
92+ if ( doFlush )
93+ isocket.flush();
94+ }
95+
96+public:
97+ QSocket isocket;
98+
99+ bool ifinished = false;
100+ bool iheaderWritten = false;
101+ bool ikeepAlive = false;
102+};
103+
104+
105+///////////////////////////////////////////////////////////////////////////////
106+} // namespace details
107+} // namespace qhttp
108+///////////////////////////////////////////////////////////////////////////////
109+#endif // __QHTTP_HTTPWRITER_HXX__
libs/qhttp/private/qhttpbase.hppnew file+52
@@ -0,0 +1,52 @@
1+/** base classes for private implementations.
2+ * https://github.com/azadkuh/qhttp
3+ *
4+ * @author amir zamani
5+ * @version 2.0.0
6+ * @date 2014-07-11
7+ */
8+
9+#ifndef QHTTPBASE_HPP
10+#define QHTTPBASE_HPP
11+
12+#include "qhttpfwd.hpp"
13+
14+#include "qsocket.hpp"
15+#include <QHostAddress>
16+#include <QBasicTimer>
17+
18+#include "http-parser/http_parser.h"
19+
20+///////////////////////////////////////////////////////////////////////////////
21+namespace qhttp {
22+namespace details {
23+///////////////////////////////////////////////////////////////////////////////
24+
25+struct HttpBase
26+{
27+ QString iversion;
28+ THeaderHash iheaders;
29+}; // struct HttpBase
30+
31+///////////////////////////////////////////////////////////////////////////////
32+
33+struct HttpRequestBase : public HttpBase
34+{
35+ QUrl iurl;
36+ THttpMethod imethod;
37+}; // HttpRequestBase
38+
39+///////////////////////////////////////////////////////////////////////////////
40+
41+struct HttpResponseBase : public HttpBase
42+{
43+ TStatusCode istatus = ESTATUS_BAD_REQUEST;
44+
45+ HttpResponseBase() { iversion = "1.1"; }
46+}; // HttpResponseBase
47+
48+///////////////////////////////////////////////////////////////////////////////
49+} // namespace details
50+} // namespace qhttp
51+///////////////////////////////////////////////////////////////////////////////
52+#endif // QHTTPBASE_HPP
libs/qhttp/private/qhttpclient_private.hppnew file+196
@@ -0,0 +1,196 @@
1+/** private imeplementation.
2+ * https://github.com/azadkuh/qhttp
3+ *
4+ * @author amir zamani
5+ * @version 2.0.0
6+ * @date 2014-07-11
7+ */
8+
9+#ifndef QHTTPCLIENT_PRIVATE_HPP
10+#define QHTTPCLIENT_PRIVATE_HPP
11+///////////////////////////////////////////////////////////////////////////////
12+
13+#include "qhttpclient.hpp"
14+#include "httpparser.hxx"
15+#include "qhttpclientrequest_private.hpp"
16+#include "qhttpclientresponse_private.hpp"
17+
18+///////////////////////////////////////////////////////////////////////////////
19+namespace qhttp {
20+namespace client {
21+///////////////////////////////////////////////////////////////////////////////
22+
23+class QHttpClientPrivate :
24+ public details::HttpResponseParser<QHttpClientPrivate>
25+{
26+ Q_DECLARE_PUBLIC(QHttpClient)
27+
28+public:
29+ explicit QHttpClientPrivate(QHttpClient* q) : q_ptr(q) {
30+ QObject::connect(
31+ q_func(), &QHttpClient::disconnected,
32+ [this](){ release(); }
33+ );
34+
35+ QHTTP_LINE_DEEPLOG
36+ }
37+
38+ virtual ~QHttpClientPrivate() {
39+ QHTTP_LINE_DEEPLOG
40+ }
41+
42+ void release() {
43+ // if socket drops and http_parser can not call messageComplete,
44+ // dispatch the ilastResponse
45+ finalizeConnection();
46+
47+ isocket.disconnectAllQtConnections();
48+ isocket.release();
49+
50+ if ( ilastRequest ) {
51+ ilastRequest->deleteLater();
52+ ilastRequest = nullptr;
53+ }
54+
55+ if ( ilastResponse ) {
56+ ilastResponse->deleteLater();
57+ ilastResponse = nullptr;
58+ }
59+
60+ // must be called! or the later http_parser_execute() may fail
61+ http_parser_init(&iparser, HTTP_RESPONSE);
62+ }
63+
64+ void initializeSocket() {
65+ if ( isocket.isOpen() ) {
66+ // no need to reconnect. do nothing and simply return
67+ if ( ikeepAlive )
68+ return;
69+
70+ // close previous connection now!
71+ // instead being called by emitted disconnected signal
72+ release();
73+ }
74+
75+ ikeepAlive = false;
76+
77+ // create a tcp connection
78+ if ( isocket.ibackendType == ETcpSocket ) {
79+ initTcpSocket();
80+
81+ } else if ( isocket.ibackendType == ELocalSocket ) {
82+ initLocalSocket();
83+ }
84+ }
85+
86+public:
87+ int messageBegin(http_parser* parser);
88+ int url(http_parser*, const char*, size_t) {
89+ return 0; // not used in parsing incoming respone.
90+ }
91+ int status(http_parser* parser, const char* at, size_t length) ;
92+ int headerField(http_parser* parser, const char* at, size_t length);
93+ int headerValue(http_parser* parser, const char* at, size_t length);
94+ int headersComplete(http_parser* parser);
95+ int body(http_parser* parser, const char* at, size_t length);
96+ int messageComplete(http_parser* parser);
97+
98+protected:
99+ void onConnected() {
100+ iconnectingTimer.stop();
101+
102+ if ( itimeOut > 0 )
103+ itimer.start(itimeOut, Qt::CoarseTimer, q_func());
104+
105+ if ( ireqHandler )
106+ ireqHandler(ilastRequest);
107+ else
108+ q_func()->onRequestReady(ilastRequest);
109+ }
110+
111+ void onReadyRead() {
112+ while ( isocket.bytesAvailable() > 0 ) {
113+ char buffer[4097] = {0};
114+ size_t readLength = (size_t) isocket.readRaw(buffer, 4096);
115+
116+ parse(buffer, readLength);
117+ }
118+ }
119+
120+ void finalizeConnection() {
121+ if ( ilastResponse == nullptr )
122+ return;
123+
124+ ilastResponse->d_func()->finalizeSending([this]{
125+ emit ilastResponse->end();
126+ });
127+ }
128+
129+private:
130+ void initTcpSocket() {
131+ QTcpSocket* sok = new QTcpSocket(q_func());
132+ isocket.itcpSocket = sok;
133+
134+ QObject::connect(
135+ sok, &QTcpSocket::connected,
136+ [this](){ onConnected(); }
137+ );
138+ QObject::connect(
139+ sok, &QTcpSocket::readyRead,
140+ [this](){ onReadyRead(); }
141+ );
142+ QObject::connect(
143+ sok, &QTcpSocket::bytesWritten,
144+ [this](qint64){
145+ const auto& ts = isocket.itcpSocket;
146+ if ( ts->bytesToWrite() == 0 && ilastRequest )
147+ emit ilastRequest->allBytesWritten();
148+ });
149+ QObject::connect(
150+ sok, &QTcpSocket::disconnected,
151+ q_func(), &QHttpClient::disconnected
152+ );
153+ }
154+
155+ void initLocalSocket() {
156+ QLocalSocket* sok = new QLocalSocket(q_func());
157+ isocket.ilocalSocket = sok;
158+
159+ QObject::connect(
160+ sok, &QLocalSocket::connected,
161+ [this](){ onConnected(); }
162+ );
163+ QObject::connect(
164+ sok, &QLocalSocket::readyRead,
165+ [this](){ onReadyRead(); }
166+ );
167+ QObject::connect(
168+ sok, &QLocalSocket::bytesWritten,
169+ [this](qint64){
170+ const auto* ls = isocket.ilocalSocket;
171+ if ( ls->bytesToWrite() == 0 && ilastRequest )
172+ emit ilastRequest->allBytesWritten();
173+ });
174+ QObject::connect(
175+ sok, &QLocalSocket::disconnected,
176+ q_func(), &QHttpClient::disconnected
177+ );
178+ }
179+
180+protected:
181+ QHttpClient* const q_ptr;
182+
183+ QHttpRequest* ilastRequest = nullptr;
184+ QHttpResponse* ilastResponse = nullptr;
185+ TRequstHandler ireqHandler;
186+ TResponseHandler irespHandler;
187+
188+ QBasicTimer iconnectingTimer;
189+};
190+
191+///////////////////////////////////////////////////////////////////////////////
192+} // namespace client
193+} // namespace qhttp
194+///////////////////////////////////////////////////////////////////////////////
195+
196+#endif // QHTTPCLIENT_PRIVATE_HPP
libs/qhttp/private/qhttpclientrequest_private.hppnew file+57
@@ -0,0 +1,57 @@
1+/** private imeplementation.
2+ * https://github.com/azadkuh/qhttp
3+ *
4+ * @author amir zamani
5+ * @version 2.0.0
6+ * @date 2014-07-11
7+ */
8+
9+#ifndef QHTTPCLIENT_REQUEST_PRIVATE_HPP
10+#define QHTTPCLIENT_REQUEST_PRIVATE_HPP
11+///////////////////////////////////////////////////////////////////////////////
12+#include "httpwriter.hxx"
13+#include "qhttpclient.hpp"
14+#include "qhttpclientrequest.hpp"
15+
16+#include <QTcpSocket>
17+
18+///////////////////////////////////////////////////////////////////////////////
19+namespace qhttp {
20+namespace client {
21+///////////////////////////////////////////////////////////////////////////////
22+class QHttpRequestPrivate :
23+ public details::HttpWriter<details::HttpRequestBase, QHttpRequestPrivate>
24+{
25+ Q_DECLARE_PUBLIC(QHttpRequest)
26+
27+public:
28+ explicit QHttpRequestPrivate(QHttpClient* cli, QHttpRequest* q) : q_ptr(q), iclient(cli) {
29+ QHTTP_LINE_DEEPLOG
30+ }
31+
32+ virtual ~QHttpRequestPrivate() {
33+ QHTTP_LINE_DEEPLOG
34+ }
35+
36+ void initialize() {
37+ iversion = "1.1";
38+
39+ isocket.ibackendType = iclient->backendType();
40+ isocket.itcpSocket = iclient->tcpSocket();
41+ isocket.ilocalSocket = iclient->localSocket();
42+ }
43+
44+ QByteArray makeTitle();
45+
46+ void prepareHeadersToWrite();
47+
48+protected:
49+ QHttpRequest* const q_ptr;
50+ QHttpClient* const iclient;
51+};
52+
53+///////////////////////////////////////////////////////////////////////////////
54+} // namespace client
55+} // namespace qhttp
56+///////////////////////////////////////////////////////////////////////////////
57+#endif // QHTTPCLIENT_REQUEST_PRIVATE_HPP
libs/qhttp/private/qhttpclientresponse_private.hppnew file+51
@@ -0,0 +1,51 @@
1+/** private imeplementation.
2+ * https://github.com/azadkuh/qhttp
3+ *
4+ * @author amir zamani
5+ * @version 2.0.0
6+ * @date 2014-07-11
7+ */
8+
9+#ifndef QHTTPCLIENT_RESPONSE_PRIVATE_HPP
10+#define QHTTPCLIENT_RESPONSE_PRIVATE_HPP
11+///////////////////////////////////////////////////////////////////////////////
12+
13+#include "httpreader.hxx"
14+#include "qhttpclient.hpp"
15+#include "qhttpclientresponse.hpp"
16+
17+///////////////////////////////////////////////////////////////////////////////
18+namespace qhttp {
19+namespace client {
20+///////////////////////////////////////////////////////////////////////////////
21+class QHttpResponsePrivate :
22+ public details::HttpReader<details::HttpResponseBase>
23+{
24+ Q_DECLARE_PUBLIC(QHttpResponse)
25+ QHttpResponse* const q_ptr;
26+
27+public:
28+ explicit QHttpResponsePrivate(QHttpClient* cli, QHttpResponse* q)
29+ : q_ptr(q), iclient(cli) {
30+ QHTTP_LINE_DEEPLOG
31+ }
32+
33+ virtual ~QHttpResponsePrivate() {
34+ QHTTP_LINE_DEEPLOG
35+ }
36+
37+ void initialize() {
38+ }
39+
40+public:
41+ QString icustomStatusMessage;
42+
43+protected:
44+ QHttpClient* const iclient;
45+};
46+
47+///////////////////////////////////////////////////////////////////////////////
48+} // namespace client
49+} // namespace qhttp
50+///////////////////////////////////////////////////////////////////////////////
51+#endif // QHTTPCLIENT_RESPONSE_PRIVATE_HPP
libs/qhttp/private/qhttpserver_private.hppnew file+90
@@ -0,0 +1,90 @@
1+/** private imeplementation.
2+ * https://github.com/azadkuh/qhttp
3+ *
4+ * @author amir zamani
5+ * @version 2.0.0
6+ * @date 2014-07-11
7+ */
8+
9+#ifndef QHTTPSERVER_PRIVATE_HPP
10+#define QHTTPSERVER_PRIVATE_HPP
11+///////////////////////////////////////////////////////////////////////////////
12+
13+#include "qhttpserver.hpp"
14+#include "qhttpserverconnection.hpp"
15+#include "qhttpserverrequest.hpp"
16+#include "qhttpserverresponse.hpp"
17+
18+#include <QTcpServer>
19+#include <QLocalServer>
20+///////////////////////////////////////////////////////////////////////////////
21+namespace qhttp {
22+namespace server {
23+///////////////////////////////////////////////////////////////////////////////
24+
25+class QHttpServerPrivate
26+{
27+public:
28+ template<class TServer>
29+ class BackendServer : public TServer
30+ {
31+ public:
32+ QHttpServer* iserver;
33+
34+ explicit BackendServer(QHttpServer* s) : TServer(s), iserver(s) {
35+ }
36+
37+ protected:
38+ // if it's a QTcpServer
39+ virtual void incomingConnection(qintptr socketDescriptor) {
40+ iserver->incomingConnection(socketDescriptor);
41+ }
42+
43+ // if it's a QLocalServer
44+ virtual void incomingConnection(quintptr socketDescriptor) {
45+ iserver->incomingConnection((qintptr) socketDescriptor);
46+ }
47+ };
48+
49+ using TTcpServer = QScopedPointer<BackendServer<QTcpServer>>;
50+ using TLocalServer = QScopedPointer<BackendServer<QLocalServer>>;
51+
52+public:
53+ quint32 itimeOut = 0;
54+ TServerHandler ihandler = nullptr;
55+
56+ TBackend ibackend = ETcpSocket;
57+
58+ TTcpServer itcpServer;
59+ TLocalServer ilocalServer;
60+
61+public:
62+ explicit QHttpServerPrivate() {
63+ QHTTP_LINE_DEEPLOG
64+ }
65+
66+ virtual ~QHttpServerPrivate() {
67+ QHTTP_LINE_DEEPLOG
68+ }
69+
70+ void initialize(TBackend backend, QHttpServer* parent) {
71+ ibackend = backend;
72+
73+ if ( ibackend == ETcpSocket ) {
74+ itcpServer.reset( new BackendServer<QTcpServer>(parent) );
75+ ilocalServer.reset( nullptr );
76+
77+ } else if ( ibackend == ELocalSocket ) {
78+ itcpServer.reset( nullptr );
79+ ilocalServer.reset( new BackendServer<QLocalServer>(parent) );
80+ }
81+ }
82+
83+};
84+
85+///////////////////////////////////////////////////////////////////////////////
86+} // namespace server
87+} // namespace qhttp
88+///////////////////////////////////////////////////////////////////////////////
89+
90+#endif // QHTTPSERVER_PRIVATE_HPP
libs/qhttp/private/qhttpserverconnection_private.hppnew file+175
@@ -0,0 +1,175 @@
1+/** private imeplementation.
2+ * https://github.com/azadkuh/qhttp
3+ *
4+ * @author amir zamani
5+ * @version 2.0.0
6+ * @date 2014-07-11
7+ */
8+
9+#ifndef QHTTPSERVER_CONNECTION_PRIVATE_HPP
10+#define QHTTPSERVER_CONNECTION_PRIVATE_HPP
11+///////////////////////////////////////////////////////////////////////////////
12+
13+#include "qhttpserverconnection.hpp"
14+#include "httpparser.hxx"
15+#include "qhttpserverrequest.hpp"
16+#include "qhttpserverresponse.hpp"
17+
18+#include "private/qhttpserverrequest_private.hpp"
19+#include "private/qhttpserverresponse_private.hpp"
20+
21+#include <QBasicTimer>
22+#include <QFile>
23+///////////////////////////////////////////////////////////////////////////////
24+namespace qhttp {
25+namespace server {
26+///////////////////////////////////////////////////////////////////////////////
27+class QHttpConnectionPrivate :
28+ public details::HttpRequestParser<QHttpConnectionPrivate>
29+{
30+ Q_DECLARE_PUBLIC(QHttpConnection)
31+
32+public:
33+ explicit QHttpConnectionPrivate(QHttpConnection* q) : q_ptr(q) {
34+
35+ QObject::connect(
36+ q_func(), &QHttpConnection::disconnected,
37+ [this](){ release(); }
38+ );
39+
40+ QHTTP_LINE_DEEPLOG
41+ }
42+
43+ virtual ~QHttpConnectionPrivate() {
44+ QHTTP_LINE_DEEPLOG
45+ }
46+
47+ void createSocket(qintptr sokDesc, TBackend bend) {
48+ isocket.ibackendType = bend;
49+
50+ if ( bend == ETcpSocket ) {
51+ initTcpSocket(sokDesc);
52+
53+ } else if ( bend == ELocalSocket ) {
54+ initLocalSocket(sokDesc);
55+ }
56+ }
57+
58+ void release() {
59+ // if socket drops and http_parser can not call
60+ // messageComplete, dispatch the ilastRequest
61+ finalizeConnection();
62+
63+ isocket.disconnectAllQtConnections();
64+ isocket.release();
65+
66+ if ( ilastRequest ) {
67+ ilastRequest->deleteLater();
68+ ilastRequest = nullptr;
69+ }
70+
71+ if ( ilastResponse ) {
72+ ilastResponse->deleteLater();
73+ ilastResponse = nullptr;
74+ }
75+
76+ q_func()->deleteLater();
77+ }
78+
79+public:
80+ void onReadyRead() {
81+ while ( isocket.bytesAvailable() > 0 ) {
82+ char buffer[4097] = {0};
83+ size_t readLength = (size_t) isocket.readRaw(buffer, 4096);
84+
85+ parse(buffer, readLength);
86+ }
87+ }
88+
89+ void finalizeConnection() {
90+ if ( ilastRequest == nullptr )
91+ return;
92+
93+ ilastRequest->d_func()->finalizeSending([this]{
94+ emit ilastRequest->end();
95+ });
96+ }
97+
98+public:
99+ int messageBegin(http_parser* parser);
100+ int url(http_parser* parser, const char* at, size_t length);
101+ int status(http_parser*, const char*, size_t) {
102+ return 0; // not used in parsing incoming request.
103+ }
104+ int headerField(http_parser* parser, const char* at, size_t length);
105+ int headerValue(http_parser* parser, const char* at, size_t length);
106+ int headersComplete(http_parser* parser);
107+ int body(http_parser* parser, const char* at, size_t length);
108+ int messageComplete(http_parser* parser);
109+
110+private:
111+ void initTcpSocket(qintptr sokDesc) {
112+ QTcpSocket* sok = new QTcpSocket( q_func() );
113+ isocket.itcpSocket = sok;
114+ sok->setSocketDescriptor(sokDesc);
115+
116+ QObject::connect(
117+ sok, &QTcpSocket::readyRead,
118+ [this](){ onReadyRead(); }
119+ );
120+ QObject::connect(
121+ sok, &QTcpSocket::bytesWritten,
122+ [this](){
123+ auto btw = isocket.itcpSocket->bytesToWrite();
124+ if ( btw == 0 && ilastResponse )
125+ emit ilastResponse->allBytesWritten();
126+ });
127+ QObject::connect(
128+ sok, &QTcpSocket::disconnected,
129+ q_func(), &QHttpConnection::disconnected,
130+ Qt::QueuedConnection
131+ );
132+ }
133+
134+ void initLocalSocket(qintptr sokDesc) {
135+ QLocalSocket* sok = new QLocalSocket( q_func() );
136+ isocket.ilocalSocket = sok;
137+ sok->setSocketDescriptor(sokDesc);
138+
139+ QObject::connect(
140+ sok, &QLocalSocket::readyRead,
141+ [this](){ onReadyRead(); }
142+ );
143+ QObject::connect(
144+ sok, &QLocalSocket::bytesWritten,
145+ [this](){
146+ auto btw = isocket.ilocalSocket->bytesToWrite();
147+ if ( btw == 0 && ilastResponse )
148+ emit ilastResponse->allBytesWritten();
149+ });
150+ QObject::connect(
151+ sok, &QLocalSocket::disconnected,
152+ q_func(), &QHttpConnection::disconnected,
153+ Qt::QueuedConnection
154+ );
155+ }
156+
157+protected:
158+ QHttpConnection* const q_ptr;
159+
160+ QByteArray itempUrl;
161+
162+ // Since there can only be one request/response pair per connection at any
163+ // time even with pipelining.
164+ QHttpRequest* ilastRequest = nullptr;
165+ QHttpResponse* ilastResponse = nullptr;
166+
167+ TServerHandler ihandler = nullptr;
168+
169+};
170+
171+///////////////////////////////////////////////////////////////////////////////
172+} // namespace server
173+} // namespace qhttp
174+///////////////////////////////////////////////////////////////////////////////
175+#endif // QHTTPSERVER_CONNECTION_PRIVATE_HPP
libs/qhttp/private/qhttpserverrequest_private.hppnew file+51
@@ -0,0 +1,51 @@
1+/** private imeplementation.
2+ * https://github.com/azadkuh/qhttp
3+ *
4+ * @author amir zamani
5+ * @version 2.0.0
6+ * @date 2014-07-11
7+ */
8+
9+#ifndef QHTTPSERVER_REQUEST_PRIVATE_HPP
10+#define QHTTPSERVER_REQUEST_PRIVATE_HPP
11+///////////////////////////////////////////////////////////////////////////////
12+
13+#include "httpreader.hxx"
14+#include "qhttpserverrequest.hpp"
15+#include "qhttpserverconnection.hpp"
16+
17+///////////////////////////////////////////////////////////////////////////////
18+namespace qhttp {
19+namespace server {
20+///////////////////////////////////////////////////////////////////////////////
21+class QHttpRequestPrivate :
22+ public details::HttpReader<details::HttpRequestBase>
23+{
24+protected:
25+ Q_DECLARE_PUBLIC(QHttpRequest)
26+ QHttpRequest* const q_ptr;
27+
28+public:
29+ explicit QHttpRequestPrivate(QHttpConnection* conn, QHttpRequest* q) : q_ptr(q), iconnection(conn) {
30+ QHTTP_LINE_DEEPLOG
31+ }
32+
33+ virtual ~QHttpRequestPrivate() {
34+ QHTTP_LINE_DEEPLOG
35+ }
36+
37+ void initialize() {
38+ }
39+
40+public:
41+ QString iremoteAddress;
42+ quint16 iremotePort = 0;
43+
44+ QHttpConnection* const iconnection = nullptr;
45+};
46+
47+///////////////////////////////////////////////////////////////////////////////
48+} // namespace server
49+} // namespace qhttp
50+///////////////////////////////////////////////////////////////////////////////
51+#endif // QHTTPSERVER_REQUEST_PRIVATE_HPP
libs/qhttp/private/qhttpserverresponse_private.hppnew file+62
@@ -0,0 +1,62 @@
1+/** private imeplementation.
2+ * https://github.com/azadkuh/qhttp
3+ *
4+ * @author amir zamani
5+ * @version 2.0.0
6+ * @date 2014-07-11
7+ */
8+
9+#ifndef QHTTPSERVER_RESPONSE_PRIVATE_HPP
10+#define QHTTPSERVER_RESPONSE_PRIVATE_HPP
11+///////////////////////////////////////////////////////////////////////////////
12+#include "httpwriter.hxx"
13+#include "qhttpserverresponse.hpp"
14+#include "qhttpserver.hpp"
15+#include "qhttpserverconnection.hpp"
16+
17+#include <QDateTime>
18+#include <QLocale>
19+#include <QTcpSocket>
20+
21+///////////////////////////////////////////////////////////////////////////////
22+namespace qhttp {
23+namespace server {
24+///////////////////////////////////////////////////////////////////////////////
25+class QHttpResponsePrivate :
26+ public details::HttpWriter<details::HttpResponseBase, QHttpResponsePrivate>
27+{
28+ Q_DECLARE_PUBLIC(QHttpResponse)
29+
30+public:
31+ explicit QHttpResponsePrivate(QHttpConnection* conn, QHttpResponse* q)
32+ : q_ptr(q), iconnection(conn) {
33+ QHTTP_LINE_DEEPLOG
34+ }
35+
36+ virtual ~QHttpResponsePrivate() {
37+ QHTTP_LINE_DEEPLOG
38+ }
39+
40+ void initialize() {
41+ isocket.ibackendType = iconnection->backendType();
42+ isocket.ilocalSocket = iconnection->localSocket();
43+ isocket.itcpSocket = iconnection->tcpSocket();
44+
45+ QObject::connect(iconnection, &QHttpConnection::disconnected,
46+ q_func(), &QHttpResponse::deleteLater);
47+ }
48+
49+ QByteArray makeTitle();
50+
51+ void prepareHeadersToWrite();
52+
53+protected:
54+ QHttpResponse* const q_ptr;
55+ QHttpConnection* const iconnection;
56+};
57+
58+///////////////////////////////////////////////////////////////////////////////
59+} // namespace server
60+} // namespace qhttp
61+///////////////////////////////////////////////////////////////////////////////
62+#endif // QHTTPSERVER_RESPONSE_PRIVATE_HPP
libs/qhttp/private/qsocket.hppnew file+126
@@ -0,0 +1,126 @@
1+/** @file qsocket.hpp
2+ *
3+ * @copyright (C) 2016
4+ * @date 2016.05.26
5+ * @version 1.0.0
6+ * @author amir zamani <azadkuh@live.com>
7+ *
8+ */
9+
10+#ifndef __QHTTP_SOCKET_HPP__
11+#define __QHTTP_SOCKET_HPP__
12+
13+#include "qhttpfwd.hpp"
14+
15+#include <QTcpSocket>
16+#include <QLocalSocket>
17+#include <QUrl>
18+///////////////////////////////////////////////////////////////////////////////
19+namespace qhttp {
20+namespace details {
21+///////////////////////////////////////////////////////////////////////////////
22+
23+/** an adapter for different socket types.
24+ * the main purpose of QHttp was to create a small HTTP server with ability to
25+ * support UNIX sockets (QLocalSocket)
26+ */
27+class QSocket
28+{
29+public:
30+ void close() {
31+ if ( itcpSocket )
32+ itcpSocket->close();
33+
34+ if ( ilocalSocket )
35+ ilocalSocket->close();
36+ }
37+
38+ void release() {
39+ close();
40+ if ( itcpSocket )
41+ itcpSocket->deleteLater();
42+
43+ if ( ilocalSocket )
44+ ilocalSocket->deleteLater();
45+
46+ itcpSocket = nullptr;
47+ ilocalSocket = nullptr;
48+ }
49+
50+ void flush() {
51+ if ( itcpSocket )
52+ itcpSocket->flush();
53+
54+ else if ( ilocalSocket )
55+ ilocalSocket->flush();
56+ }
57+
58+ bool isOpen() const {
59+ if ( ibackendType == ETcpSocket && itcpSocket )
60+ return itcpSocket->isOpen()
61+ && itcpSocket->state() == QTcpSocket::ConnectedState;
62+
63+ else if ( ibackendType == ELocalSocket && ilocalSocket )
64+ return ilocalSocket->isOpen()
65+ && ilocalSocket->state() == QLocalSocket::ConnectedState;
66+
67+ return false;
68+ }
69+
70+ void connectTo(const QUrl& url) {
71+ if ( ilocalSocket )
72+ ilocalSocket->connectToServer(url.path());
73+ }
74+
75+ void connectTo(const QString& host, quint16 port) {
76+ if ( itcpSocket )
77+ itcpSocket->connectToHost(host, port);
78+ }
79+
80+ qint64 readRaw(char* buffer, int maxlen) {
81+ if ( itcpSocket )
82+ return itcpSocket->read(buffer, maxlen);
83+
84+ else if ( ilocalSocket )
85+ return ilocalSocket->read(buffer, maxlen);
86+
87+ return 0;
88+ }
89+
90+ void writeRaw(const QByteArray& data) {
91+ if ( itcpSocket )
92+ itcpSocket->write(data);
93+
94+ else if ( ilocalSocket )
95+ ilocalSocket->write(data);
96+ }
97+
98+ qint64 bytesAvailable() {
99+ if ( itcpSocket )
100+ return itcpSocket->bytesAvailable();
101+
102+ else if ( ilocalSocket )
103+ return ilocalSocket->bytesAvailable();
104+
105+ return 0;
106+ }
107+
108+ void disconnectAllQtConnections() {
109+ if ( itcpSocket )
110+ QObject::disconnect(itcpSocket, 0, 0, 0);
111+
112+ if ( ilocalSocket )
113+ QObject::disconnect(ilocalSocket, 0, 0, 0);
114+ }
115+
116+public:
117+ TBackend ibackendType = ETcpSocket;
118+ QTcpSocket* itcpSocket = nullptr;
119+ QLocalSocket* ilocalSocket = nullptr;
120+}; // class QSocket
121+
122+///////////////////////////////////////////////////////////////////////////////
123+} // namespace details
124+} // namespace qhttp
125+///////////////////////////////////////////////////////////////////////////////
126+#endif // __QHTTP_SOCKET_HPP__
libs/qhttp/qhttpabstracts.cppnew file+114
@@ -0,0 +1,114 @@
1+#include "qhttpabstracts.hpp"
2+#include "http-parser/http_parser.h"
3+
4+///////////////////////////////////////////////////////////////////////////////
5+namespace qhttp {
6+///////////////////////////////////////////////////////////////////////////////
7+#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
8+# error "to compile QHttp classes, Qt 5.0 or later is needed."
9+#endif
10+
11+#define HTTP_STATUS_MAP(XX) \
12+ XX(100, "Continue") \
13+ XX(101, "Switching Protocols") \
14+ /* RFC 2518) obsoleted by RFC 4918 */ \
15+ XX(102, "Processing") \
16+ XX(200, "OK") \
17+ XX(201, "Created") \
18+ XX(202, "Accepted") \
19+ XX(203, "Non-Authoritative Information") \
20+ XX(204, "No Content") \
21+ XX(205, "Reset Content") \
22+ XX(206, "Partial Content") \
23+ /* RFC 4918 */ \
24+ XX(207, "Multi-Status") \
25+ XX(300, "Multiple Choices") \
26+ XX(301, "Moved Permanently") \
27+ XX(302, "Moved Temporarily") \
28+ XX(303, "See Other") \
29+ XX(304, "Not Modified") \
30+ XX(305, "Use Proxy") \
31+ XX(307, "Temporary Redirect") \
32+ XX(400, "Bad Request") \
33+ XX(401, "Unauthorized") \
34+ XX(402, "Payment Required") \
35+ XX(403, "Forbidden") \
36+ XX(404, "Not Found") \
37+ XX(405, "Method Not Allowed") \
38+ XX(406, "Not Acceptable") \
39+ XX(407, "Proxy Authentication Required") \
40+ XX(408, "Request Time-out") \
41+ XX(409, "Conflict") \
42+ XX(410, "Gone") \
43+ XX(411, "Length Required") \
44+ XX(412, "Precondition Failed") \
45+ XX(413, "Request Entity Too Large") \
46+ XX(414, "Request-URI Too Large") \
47+ XX(415, "Unsupported Media Type") \
48+ XX(416, "Requested Range Not Satisfiable") \
49+ XX(417, "Expectation Failed") \
50+ /* RFC 2324 */ \
51+ XX(418, "I\"m a teapot") \
52+ /* RFC 4918 */ \
53+ XX(422, "Unprocessable Entity") \
54+ /* RFC 4918 */ \
55+ XX(423, "Locked") \
56+ /* RFC 4918 */ \
57+ XX(424, "Failed Dependency") \
58+ /* RFC 4918 */ \
59+ XX(425, "Unordered Collection") \
60+ /* RFC 2817 */ \
61+ XX(426, "Upgrade Required") \
62+ XX(500, "Internal Server Error") \
63+ XX(501, "Not Implemented") \
64+ XX(502, "Bad Gateway") \
65+ XX(503, "Service Unavailable") \
66+ XX(504, "Gateway Time-out") \
67+ XX(505, "HTTP Version not supported") \
68+ /* RFC 2295 */ \
69+ XX(506, "Variant Also Negotiates") \
70+ /* RFC 4918 */ \
71+ XX(507, "Insufficient Storage") \
72+ XX(509, "Bandwidth Limit Exceeded") \
73+ /* RFC 2774 */ \
74+ XX(510, "Not Extended")
75+
76+#define PATCH_STATUS_CODES(n,s) {n, s},
77+static struct {
78+ int code;
79+ const char* message;
80+} g_status_codes[] {
81+ HTTP_STATUS_MAP(PATCH_STATUS_CODES)
82+};
83+#undef PATCH_STATUS_CODES
84+
85+///////////////////////////////////////////////////////////////////////////////
86+
87+const char*
88+Stringify::toString(TStatusCode code) {
89+ size_t count = sizeof(g_status_codes) / sizeof(g_status_codes[0]);
90+ for ( size_t i = 0; i < count; i++ ) {
91+ if ( g_status_codes[i].code == code )
92+ return g_status_codes[i].message;
93+ }
94+
95+ return nullptr;
96+}
97+
98+const char*
99+Stringify::toString(THttpMethod method) {
100+ return http_method_str(static_cast<http_method>(method));
101+}
102+
103+///////////////////////////////////////////////////////////////////////////////
104+
105+QHttpAbstractInput::QHttpAbstractInput(QObject* parent) : QObject(parent) {
106+}
107+
108+QHttpAbstractOutput::QHttpAbstractOutput(QObject *parent) : QObject(parent) {
109+}
110+
111+
112+///////////////////////////////////////////////////////////////////////////////
113+} // namespace qhttp
114+///////////////////////////////////////////////////////////////////////////////
libs/qhttp/qhttpabstracts.hppnew file+190
@@ -0,0 +1,190 @@
1+/** interfaces of QHttp' incomming and outgoing classes.
2+ * https://github.com/azadkuh/qhttp
3+ *
4+ * @author amir zamani
5+ * @version 2.0.0
6+ * @date 2014-07-11
7+ */
8+
9+#ifndef QHTTPABSTRACTS_HPP
10+#define QHTTPABSTRACTS_HPP
11+
12+///////////////////////////////////////////////////////////////////////////////
13+#include "qhttpfwd.hpp"
14+
15+#include <QObject>
16+#include <functional>
17+///////////////////////////////////////////////////////////////////////////////
18+namespace qhttp {
19+///////////////////////////////////////////////////////////////////////////////
20+
21+/** a utility class to give the string representation of qhttp types. */
22+class QHTTP_API Stringify
23+{
24+public:
25+ /** returns the standard message for an HTTP status code. */
26+ static const char* toString(TStatusCode);
27+
28+ /** returns the standars name of an HTTP method. */
29+ static const char* toString(THttpMethod);
30+};
31+
32+///////////////////////////////////////////////////////////////////////////////
33+
34+/** an interface for input (incoming) HTTP packets.
35+ * server::QHttpRequest or client::QHttpResponse inherit from this class. */
36+class QHTTP_API QHttpAbstractInput : public QObject
37+{
38+ Q_OBJECT
39+
40+public:
41+ /** Return all the headers in the incomming packet.
42+ * This returns a reference. If you want to store headers
43+ * somewhere else, where the request may be deleted,
44+ * make sure you store them as a copy.
45+ * @note All header names are <b>lowercase</b> . */
46+ virtual const THeaderHash& headers() const=0;
47+
48+ /** The HTTP version of the packet.
49+ * @return A string in the form of "x.x" */
50+ virtual const QString& httpVersion() const=0;
51+
52+ /** If this packet was successfully received.
53+ * Set before end() has been emitted, stating whether
54+ * the message was properly received. This is false
55+ * until the receiving the full request has completed. */
56+ virtual bool isSuccessful() const=0;
57+
58+signals:
59+ /** Emitted when new body data has been received.
60+ * @param data Received data.
61+ * @note This may be emitted zero or more times depending on the transfer type.
62+ * @see onData();
63+ */
64+ void data(QByteArray data);
65+
66+ /** Emitted when the incomming packet has been fully received.
67+ * @note The no more data() signals will be emitted after this.
68+ * @see onEnd();
69+ */
70+ void end();
71+
72+public:
73+ /** optionally set a handler for data() signal.
74+ * @param dataHandler a std::function or lambda handler to receive incoming data.
75+ * @note if you set this handler, the data() signal won't be emitted anymore.
76+ */
77+ template<class Func>
78+ void onData(Func f) {
79+ QObject::connect(this, &QHttpAbstractInput::data, f);
80+ }
81+
82+
83+ /** optionally set a handler for end() signal.
84+ * @param endHandler a std::function or lambda handler to receive end notification.
85+ * @note if you set this handler, the end() signal won't be emitted anymore.
86+ */
87+ template<class Func>
88+ void onEnd(Func f) {
89+ QObject::connect(this, &QHttpAbstractInput::end, f);
90+ }
91+
92+public:
93+ /** tries to collect all the incoming data internally.
94+ * @note if you call this method, data() signal won't be emitted and
95+ * onData() will have no effect.
96+ *
97+ * @param atMost maximum acceptable incoming data. if the incoming data
98+ * exceeds this value, the connection won't read any more data and
99+ * end() signal will be emitted.
100+ * default value (-1) means read data as "content-length" or unlimited if
101+ * the body size is unknown.
102+ */
103+ virtual void collectData(int atMost = -1) =0;
104+
105+ /** returns the collected data requested by collectData(). */
106+ virtual const QByteArray& collectedData()const =0;
107+
108+
109+public:
110+ virtual ~QHttpAbstractInput() = default;
111+
112+ explicit QHttpAbstractInput(QObject* parent);
113+
114+ Q_DISABLE_COPY(QHttpAbstractInput)
115+};
116+
117+///////////////////////////////////////////////////////////////////////////////
118+
119+/** an interface for output (outgoing) HTTP packets.
120+ * server::QHttpResponse or client::QHttpRequest inherit from this class. */
121+class QHTTP_API QHttpAbstractOutput : public QObject
122+{
123+ Q_OBJECT
124+
125+public:
126+ /** changes the HTTP version string ex: "1.1" or "1.0".
127+ * version is "1.1" set by default. */
128+ virtual void setVersion(const QString& versionString)=0;
129+
130+ /** helper function. @sa addHeader */
131+ template<typename T>
132+ void addHeaderValue(const QByteArray &field, T value);
133+
134+ /** adds an HTTP header to the packet.
135+ * @note this method does not actually write anything to socket, just prepares the headers(). */
136+ virtual void addHeader(const QByteArray& field, const QByteArray& value)=0;
137+
138+ /** returns all the headers that already been set. */
139+ virtual THeaderHash& headers()=0;
140+
141+ /** writes a block of data into the HTTP packet.
142+ * @note headers are written (flushed) before any data.
143+ * @warning after calling this method add a new header, set staus code, set Url have no effect! */
144+ virtual void write(const QByteArray &data)=0;
145+
146+ /** ends (finishes) the outgoing packet by calling write().
147+ * headers and data will be flushed to the underlying socket.
148+ *
149+ * @sa write() */
150+ virtual void end(const QByteArray &data = QByteArray())=0;
151+
152+signals:
153+ /** Emitted when all the data has been sent.
154+ * this signal indicates that the underlaying socket has transmitted all
155+ * of it's buffered data. */
156+ void allBytesWritten();
157+
158+ /** Emitted when the packet is finished and reports if it was the last packet.
159+ * if it was the last packet (google for "Connection: keep-alive / close")
160+ * the http connection (socket) will be closed automatically. */
161+ void done(bool wasTheLastPacket);
162+
163+public:
164+ virtual ~QHttpAbstractOutput() = default;
165+
166+protected:
167+ explicit QHttpAbstractOutput(QObject* parent);
168+
169+ Q_DISABLE_COPY(QHttpAbstractOutput)
170+};
171+
172+template<> inline void
173+QHttpAbstractOutput::addHeaderValue<int>(const QByteArray &field, int value) {
174+ addHeader(field, QString::number(value).toLatin1());
175+}
176+
177+template<> inline void
178+QHttpAbstractOutput::addHeaderValue<size_t>(const QByteArray &field, size_t value) {
179+ addHeader(field, QString::number(value).toLatin1());
180+}
181+
182+template<> inline void
183+QHttpAbstractOutput::addHeaderValue<QString>(const QByteArray &field, QString value) {
184+ addHeader(field, value.toUtf8());
185+}
186+
187+///////////////////////////////////////////////////////////////////////////////
188+} // namespace qhttp
189+///////////////////////////////////////////////////////////////////////////////
190+#endif // QHTTPABSTRACTS_HPP
libs/qhttp/qhttpclient.cppnew file+284
@@ -0,0 +1,284 @@
1+#include "private/qhttpclient_private.hpp"
2+
3+#include <QTimerEvent>
4+///////////////////////////////////////////////////////////////////////////////
5+namespace qhttp {
6+namespace client {
7+///////////////////////////////////////////////////////////////////////////////
8+QHttpClient::QHttpClient(QObject *parent)
9+ : QObject(parent), d_ptr(new QHttpClientPrivate(this)) {
10+ QHTTP_LINE_LOG
11+}
12+
13+QHttpClient::QHttpClient(QHttpClientPrivate &dd, QObject *parent)
14+ : QObject(parent), d_ptr(&dd) {
15+ QHTTP_LINE_LOG
16+}
17+
18+QHttpClient::~QHttpClient() {
19+ QHTTP_LINE_LOG
20+}
21+
22+quint32
23+QHttpClient::timeOut() const {
24+ return d_func()->itimeOut;
25+}
26+
27+void
28+QHttpClient::setTimeOut(quint32 t) {
29+ d_func()->itimeOut = t;
30+}
31+
32+bool
33+QHttpClient::isOpen() const {
34+ return d_func()->isocket.isOpen();
35+}
36+
37+void
38+QHttpClient::killConnection() {
39+ Q_D(QHttpClient);
40+
41+ d->iconnectingTimer.stop();
42+ d->itimer.stop();
43+ d->isocket.close();
44+}
45+
46+TBackend
47+QHttpClient::backendType() const {
48+ return d_func()->isocket.ibackendType;
49+}
50+
51+QTcpSocket*
52+QHttpClient::tcpSocket() const {
53+ return d_func()->isocket.itcpSocket;
54+}
55+
56+QLocalSocket*
57+QHttpClient::localSocket() const {
58+ return d_func()->isocket.ilocalSocket;
59+}
60+
61+void
62+QHttpClient::setConnectingTimeOut(quint32 timeout) {
63+ Q_D(QHttpClient);
64+
65+ if ( timeout == 0 ) {
66+ d->iconnectingTimer.stop();
67+
68+ } else {
69+ d->iconnectingTimer.start(timeout,
70+ Qt::CoarseTimer,
71+ this
72+ );
73+ }
74+}
75+
76+bool
77+QHttpClient::request(THttpMethod method, QUrl url,
78+ const TRequstHandler &reqHandler,
79+ const TResponseHandler &resHandler) {
80+ Q_D(QHttpClient);
81+
82+ d->ireqHandler = nullptr;
83+ d->irespHandler = nullptr;
84+
85+ // if url is a local file (UNIX socket) the host could be empty!
86+ if ( !url.isValid() || url.isEmpty() /*|| url.host().isEmpty()*/ )
87+ return false;
88+
89+ // process handlers
90+ if ( resHandler ) {
91+ d->irespHandler = resHandler;
92+
93+ if ( reqHandler )
94+ d->ireqHandler = reqHandler;
95+ else
96+ d->ireqHandler = [](QHttpRequest* req) ->void {
97+ req->addHeader("connection", "close");
98+ req->end();
99+ };
100+ }
101+
102+ auto requestCreator = [this, method, url]() {
103+ // create request object
104+ if ( d_ptr->ilastRequest )
105+ d_ptr->ilastRequest->deleteLater();
106+
107+ d_ptr->ilastRequest = new QHttpRequest(this);
108+ QObject::connect(d_ptr->ilastRequest, &QHttpRequest::done, [this](bool wasTheLastPacket){
109+ d_ptr->ikeepAlive = !wasTheLastPacket;
110+ });
111+
112+ d_ptr->ilastRequest->d_ptr->imethod = method;
113+ d_ptr->ilastRequest->d_ptr->iurl = url;
114+ };
115+
116+ // connecting to host/server must be the last thing. (after all function handlers and ...)
117+ // check for type
118+ if ( url.scheme().toLower() == QLatin1String("file") ) {
119+ d->isocket.ibackendType = ELocalSocket;
120+ d->initializeSocket();
121+
122+ requestCreator();
123+
124+ if ( d->isocket.isOpen() )
125+ d->onConnected();
126+ else
127+ d->isocket.connectTo(url);
128+
129+ } else {
130+ d->isocket.ibackendType = ETcpSocket;
131+ d->initializeSocket();
132+
133+ requestCreator();
134+
135+ if ( d->isocket.isOpen() )
136+ d->onConnected();
137+ else
138+ d->isocket.connectTo(url.host(), url.port(80));
139+ }
140+
141+ return true;
142+}
143+
144+void
145+QHttpClient::timerEvent(QTimerEvent *e) {
146+ Q_D(QHttpClient);
147+
148+ if ( e->timerId() == d->itimer.timerId() ) {
149+ killConnection();
150+
151+ } else if ( e->timerId() == d->iconnectingTimer.timerId() ) {
152+ d->iconnectingTimer.stop();
153+ emit connectingTimeOut();
154+ }
155+}
156+
157+void
158+QHttpClient::onRequestReady(QHttpRequest *req) {
159+ emit httpConnected(req);
160+}
161+
162+void
163+QHttpClient::onResponseReady(QHttpResponse *res) {
164+ emit newResponse(res);
165+}
166+
167+///////////////////////////////////////////////////////////////////////////////
168+
169+// if server closes the connection, ends the response or by any other reason
170+// the socket disconnects, then the irequest and iresponse instances may have
171+// been deleted. In these situations reading more http body or emitting end()
172+// for incoming request are not possible:
173+// if ( ilastRequest == nullptr )
174+// return 0;
175+
176+
177+
178+int
179+QHttpClientPrivate::messageBegin(http_parser*) {
180+ itempHeaderField.clear();
181+ itempHeaderValue.clear();
182+
183+ return 0;
184+}
185+
186+int
187+QHttpClientPrivate::status(http_parser* parser, const char* at, size_t length) {
188+ if ( ilastResponse )
189+ ilastResponse->deleteLater();
190+
191+ ilastResponse = new QHttpResponse(q_func());
192+ ilastResponse->d_func()->istatus = static_cast<TStatusCode>(parser->status_code);
193+ ilastResponse->d_func()->iversion = QString("%1.%2")
194+ .arg(parser->http_major)
195+ .arg(parser->http_minor);
196+ ilastResponse->d_func()->icustomStatusMessage = QString::fromUtf8(at, length);
197+
198+ return 0;
199+}
200+
201+int
202+QHttpClientPrivate::headerField(http_parser*, const char* at, size_t length) {
203+ if ( ilastResponse == nullptr )
204+ return 0;
205+
206+ // insert the header we parsed previously
207+ // into the header map
208+ if ( !itempHeaderField.isEmpty() && !itempHeaderValue.isEmpty() ) {
209+ // header names are always lower-cased
210+ ilastResponse->d_func()->iheaders.insert(
211+ itempHeaderField.toLower(),
212+ itempHeaderValue.toLower()
213+ );
214+ // clear header value. this sets up a nice
215+ // feedback loop where the next time
216+ // HeaderValue is called, it can simply append
217+ itempHeaderField.clear();
218+ itempHeaderValue.clear();
219+ }
220+
221+ itempHeaderField.append(at, length);
222+ return 0;
223+}
224+
225+int
226+QHttpClientPrivate::headerValue(http_parser*, const char* at, size_t length) {
227+
228+ itempHeaderValue.append(at, length);
229+ return 0;
230+}
231+
232+int
233+QHttpClientPrivate::headersComplete(http_parser*) {
234+ if ( ilastResponse == nullptr )
235+ return 0;
236+
237+ // Insert last remaining header
238+ ilastResponse->d_func()->iheaders.insert(
239+ itempHeaderField.toLower(),
240+ itempHeaderValue.toLower()
241+ );
242+
243+ if ( irespHandler )
244+ irespHandler(ilastResponse);
245+ else
246+ q_func()->onResponseReady(ilastResponse);
247+
248+ return 0;
249+}
250+
251+int
252+QHttpClientPrivate::body(http_parser*, const char* at, size_t length) {
253+ if ( ilastResponse == nullptr )
254+ return 0;
255+
256+ ilastResponse->d_func()->ireadState = QHttpResponsePrivate::EPartial;
257+
258+ if ( ilastResponse->d_func()->icollectRequired ) {
259+ if ( !ilastResponse->d_func()->append(at, length) ) {
260+ // forcefully dispatch the ilastResponse
261+ finalizeConnection();
262+ }
263+
264+ return 0;
265+ }
266+
267+ emit ilastResponse->data(QByteArray(at, length));
268+ return 0;
269+}
270+
271+int
272+QHttpClientPrivate::messageComplete(http_parser*) {
273+ if ( ilastResponse == nullptr )
274+ return 0;
275+
276+ // response is done
277+ finalizeConnection();
278+ return 0;
279+}
280+
281+///////////////////////////////////////////////////////////////////////////////
282+} // namespace client
283+} // namespace qhttp
284+///////////////////////////////////////////////////////////////////////////////
libs/qhttp/qhttpclient.hppnew file+182
@@ -0,0 +1,182 @@
1+/** HTTP client class.
2+ * https://github.com/azadkuh/qhttp
3+ *
4+ * @author amir zamani
5+ * @version 2.0.0
6+ * @date 2014-07-11
7+ */
8+
9+#ifndef QHTTPCLIENT_HPP
10+#define QHTTPCLIENT_HPP
11+
12+// configured by src.pro
13+#if defined(QHTTP_HAS_CLIENT)
14+
15+///////////////////////////////////////////////////////////////////////////////
16+#include "qhttpfwd.hpp"
17+
18+#include <QTcpSocket>
19+#include <QUrl>
20+
21+///////////////////////////////////////////////////////////////////////////////
22+namespace qhttp {
23+namespace client {
24+///////////////////////////////////////////////////////////////////////////////
25+using TRequstHandler = std::function<void (QHttpRequest*)>;
26+using TResponseHandler = std::function<void (QHttpResponse*)>;
27+
28+/** a simple and async HTTP client class which sends a request to an HTTP server and parses the
29+ * corresponding response.
30+ * This class internally handles the memory management and life cycle of QHttpRequest and
31+ * QHttpResponse instances. you do not have to manually delete or keep their pointers.
32+ * in fact the QHttpRequest and QHttpResponse object will be deleted when the internal socket
33+ * disconnects.
34+ */
35+class QHTTP_API QHttpClient : public QObject
36+{
37+ Q_OBJECT
38+
39+ Q_PROPERTY(quint32 timeOut READ timeOut WRITE setTimeOut)
40+
41+public:
42+ explicit QHttpClient(QObject *parent = nullptr);
43+
44+ virtual ~QHttpClient();
45+
46+ /** tries to connect to a HTTP server.
47+ * when the connection is made, the reqHandler will be called
48+ * and when the response is ready, resHandler will be called.
49+ * @note httpConnected() and newResponse() won't be emitted.
50+ *
51+ * @param method an HTTP method, ex: GET, POST, ...
52+ * @param url specifies server's address, port and optional path and query strings.
53+ * if url starts with socket:// the request will be made on QLocalSocket, otherwise
54+ * normal QTcpSocket will be used.
55+ * @param resHandler response handler (a lambda, std::function object, ...)
56+ * @return true if the url is valid or false (no connection will be made).
57+ */
58+ bool request(THttpMethod method, QUrl url,
59+ const TRequstHandler& reqHandler,
60+ const TResponseHandler& resHandler);
61+
62+ /** tries to connect to a HTTP server.
63+ * when the connection is made, a default request handler is called automatically (
64+ * simply calls req->end()) and when the response is ready, resHandler will be called.
65+ * @note httpConnected() and newResponse() won't be emitted.
66+ *
67+ * @param method an HTTP method, ex: GET, POST, ...
68+ * @param url specifies server's address, port and optional path and query strings.
69+ * @param resHandler response handler (a lambda, std::function object, ...)
70+ * @return true if the url is valid or false (no connection will be made).
71+ */
72+ inline bool request(THttpMethod method, QUrl url, const TResponseHandler& resHandler) {
73+ return request(method, url, nullptr, resHandler);
74+ }
75+
76+ /** tries to connect to a HTTP server.
77+ * when the connection is made, creates and emits a QHttpRequest instance
78+ * by @sa httpConnected(QHttpRequest*).
79+ * @note both httpConnected() and newResponse() may be emitted.
80+ *
81+ * @param method an HTTP method, ex: GET, POST, ...
82+ * @param url specifies server's address, port and optional path and query strings.
83+ * @return true if the url is valid or false (no connection will be made).
84+ */
85+ inline bool request(THttpMethod method, QUrl url) {
86+ return request(method, url, nullptr, nullptr);
87+ }
88+
89+ /** checks if the connetion to the server is open. */
90+ bool isOpen() const;
91+
92+ /** forcefully close the connection. */
93+ void killConnection();
94+
95+
96+ /** returns time-out value [mSec] for ESTABLISHED connections (sockets).
97+ * @sa setTimeOut(). */
98+ quint32 timeOut()const;
99+
100+ /** set time-out for ESTABLISHED connections in miliseconds [mSec].
101+ * each (already opened) connection will be forcefully closed after this timeout.
102+ * a zero (0) value disables timer for new connections. */
103+ void setTimeOut(quint32);
104+
105+ /** set a time-out [mSec] for making a new connection (make a request).
106+ * if connecting to server takes more than this time-out value,
107+ * the @sa timedOut(quint32) signal will be emitted and connection will be killed.
108+ * 0 (default) timeout value means to disable this timer.
109+ */
110+ void setConnectingTimeOut(quint32);
111+
112+ template<class Handler>
113+ void setConnectingTimeOut(quint32 timeout, Handler&& func) {
114+ setConnectingTimeOut(timeout);
115+ QObject::connect(this, &QHttpClient::connectingTimeOut,
116+ std::forward<Handler&&>(func)
117+ );
118+ }
119+
120+ /** returns the backend type of this client. */
121+ TBackend backendType() const;
122+
123+ /** returns tcp socket of the connection if backend() == ETcpSocket. */
124+ QTcpSocket* tcpSocket() const;
125+
126+ /** returns local socket of the connection if backend() == ELocalSocket. */
127+ QLocalSocket* localSocket() const;
128+
129+signals:
130+ /** emitted when a new HTTP connection to the server is established.
131+ * if you overload onRequestReady this signal won't be emitted.
132+ * @sa onRequestReady
133+ * @sa QHttpRequest
134+ */
135+ void httpConnected(QHttpRequest* req);
136+
137+ /** emitted when a new response is received from the server.
138+ * if you overload onResponseReady this signal won't be emitted.
139+ * @sa onResponseReady
140+ * @sa QHttpResponse
141+ */
142+ void newResponse(QHttpResponse* res);
143+
144+ /** emitted when the HTTP connection drops or being disconnected. */
145+ void disconnected();
146+
147+ /// emitted when fails to connect to a HTTP server. @sa setConnectingTimeOut()
148+ void connectingTimeOut();
149+
150+
151+protected:
152+ /** called when a new HTTP connection is established.
153+ * you can overload this method, the default implementaion only emits connected().
154+ * @param req use this request instance for assinging the
155+ * request headers and sending optional body.
156+ * @see httpConnected(QHttpRequest*)
157+ */
158+ virtual void onRequestReady(QHttpRequest* req);
159+
160+ /** called when a new response is received from the server.
161+ * you can overload this method, the default implementaion only emits newResponse().
162+ * @param res use this instance for reading incoming response.
163+ * @see newResponse(QHttpResponse*)
164+ */
165+ virtual void onResponseReady(QHttpResponse* res);
166+
167+protected:
168+ explicit QHttpClient(QHttpClientPrivate&, QObject*);
169+
170+ void timerEvent(QTimerEvent*) override;
171+
172+ Q_DECLARE_PRIVATE(QHttpClient)
173+ Q_DISABLE_COPY(QHttpClient)
174+ QScopedPointer<QHttpClientPrivate> d_ptr;
175+};
176+
177+///////////////////////////////////////////////////////////////////////////////
178+} // namespace client
179+} // namespace qhttp
180+///////////////////////////////////////////////////////////////////////////////
181+#endif // QHTTP_HAS_CLIENT
182+#endif // define QHTTPCLIENT_HPP
libs/qhttp/qhttpclientrequest.cppnew file+98
@@ -0,0 +1,98 @@
1+#include "private/qhttpclientrequest_private.hpp"
2+#include "qhttpclient.hpp"
3+///////////////////////////////////////////////////////////////////////////////
4+namespace qhttp {
5+namespace client {
6+///////////////////////////////////////////////////////////////////////////////
7+QHttpRequest::QHttpRequest(QHttpClient* cli)
8+ : QHttpAbstractOutput(cli) , d_ptr(new QHttpRequestPrivate(cli, this)) {
9+ d_ptr->initialize();
10+ QHTTP_LINE_LOG
11+}
12+
13+QHttpRequest::QHttpRequest(QHttpRequestPrivate& dd, QHttpClient* cli)
14+ : QHttpAbstractOutput(cli) , d_ptr(&dd) {
15+ d_ptr->initialize();
16+ QHTTP_LINE_LOG
17+}
18+
19+QHttpRequest::~QHttpRequest() {
20+ QHTTP_LINE_LOG
21+}
22+
23+void
24+QHttpRequest::setVersion(const QString &versionString) {
25+ d_func()->iversion = versionString;
26+}
27+
28+void
29+QHttpRequest::addHeader(const QByteArray &field, const QByteArray &value) {
30+ d_func()->addHeader(field, value);
31+}
32+
33+THeaderHash&
34+QHttpRequest::headers() {
35+ return d_func()->iheaders;
36+}
37+
38+void
39+QHttpRequest::write(const QByteArray &data) {
40+ d_func()->writeData(data);
41+}
42+
43+void
44+QHttpRequest::end(const QByteArray &data) {
45+ Q_D(QHttpRequest);
46+
47+ if ( d->endPacket(data) )
48+ emit done(!d->ikeepAlive);
49+}
50+
51+QHttpClient*
52+QHttpRequest::connection() const {
53+ return d_func()->iclient;
54+}
55+
56+///////////////////////////////////////////////////////////////////////////////
57+QByteArray
58+QHttpRequestPrivate::makeTitle() {
59+
60+ QByteArray title;
61+ title.reserve(512);
62+ title.append(qhttp::Stringify::toString(imethod))
63+ .append(" ");
64+
65+ QByteArray path = iurl.path(QUrl::FullyEncoded).toLatin1();
66+ if ( path.size() == 0 )
67+ path = "/";
68+ title.append(path);
69+
70+ if ( iurl.hasQuery() )
71+ title.append("?").append(iurl.query(QUrl::FullyEncoded).toLatin1());
72+
73+
74+ title.append(" HTTP/")
75+ .append(iversion.toLatin1())
76+ .append("\r\n");
77+
78+ return title;
79+}
80+
81+void
82+QHttpRequestPrivate::prepareHeadersToWrite() {
83+
84+ if ( !iheaders.contains("host") ) {
85+ quint16 port = iurl.port();
86+ if ( port == 0 )
87+ port = 80;
88+
89+ iheaders.insert("host",
90+ QString("%1:%2").arg(iurl.host()).arg(port).toLatin1()
91+ );
92+ }
93+}
94+
95+///////////////////////////////////////////////////////////////////////////////
96+} // namespace client
97+} // namespace qhttp
98+///////////////////////////////////////////////////////////////////////////////
libs/qhttp/qhttpclientrequest.hppnew file+67
@@ -0,0 +1,67 @@
1+/** HTTP request from a client.
2+ * https://github.com/azadkuh/qhttp
3+ *
4+ * @author amir zamani
5+ * @version 2.0.0
6+ * @date 2014-07-11
7+ */
8+
9+#ifndef QHTTPCLIENT_REQUEST_HPP
10+#define QHTTPCLIENT_REQUEST_HPP
11+
12+// configured by src.pro
13+#if defined(QHTTP_HAS_CLIENT)
14+
15+///////////////////////////////////////////////////////////////////////////////
16+#include "qhttpabstracts.hpp"
17+#include <QUrl>
18+///////////////////////////////////////////////////////////////////////////////
19+namespace qhttp {
20+namespace client {
21+///////////////////////////////////////////////////////////////////////////////
22+/** a class for building a new HTTP request.
23+ * the life cycle of this class and the memory management is handled by QHttpClient.
24+ * @sa QHttpClient
25+ */
26+class QHTTP_API QHttpRequest : public QHttpAbstractOutput
27+{
28+ Q_OBJECT
29+
30+public:
31+ virtual ~QHttpRequest();
32+
33+public: // QHttpAbstractOutput methods:
34+ /** @see QHttpAbstractOutput::setVersion(). */
35+ void setVersion(const QString& versionString) override;
36+
37+ /** @see QHttpAbstractOutput::addHeader(). */
38+ void addHeader(const QByteArray& field, const QByteArray& value) override;
39+
40+ /** @see QHttpAbstractOutput::headers(). */
41+ THeaderHash& headers() override;
42+
43+ /** @see QHttpAbstractOutput::write(). */
44+ void write(const QByteArray &data) override;
45+
46+ /** @see QHttpAbstractOutput::end(). */
47+ void end(const QByteArray &data = QByteArray()) override;
48+
49+public:
50+ /** returns parent QHttpClient object. */
51+ QHttpClient* connection() const;
52+
53+protected:
54+ explicit QHttpRequest(QHttpClient*);
55+ explicit QHttpRequest(QHttpRequestPrivate&, QHttpClient*);
56+ friend class QHttpClient;
57+
58+ Q_DECLARE_PRIVATE(QHttpRequest)
59+ QScopedPointer<QHttpRequestPrivate> d_ptr;
60+};
61+
62+///////////////////////////////////////////////////////////////////////////////
63+} // namespace client
64+} // namespace qhttp
65+///////////////////////////////////////////////////////////////////////////////
66+#endif // QHTTP_HAS_CLIENT
67+#endif // define QHTTPCLIENT_REQUEST_HPP
libs/qhttp/qhttpclientresponse.cppnew file+66
@@ -0,0 +1,66 @@
1+#include "private/qhttpclientresponse_private.hpp"
2+#include "qhttpclient.hpp"
3+///////////////////////////////////////////////////////////////////////////////
4+namespace qhttp {
5+namespace client {
6+///////////////////////////////////////////////////////////////////////////////
7+QHttpResponse::QHttpResponse(QHttpClient *cli)
8+ : QHttpAbstractInput(cli), d_ptr(new QHttpResponsePrivate(cli, this)) {
9+ d_ptr->initialize();
10+ QHTTP_LINE_LOG
11+}
12+
13+QHttpResponse::QHttpResponse(QHttpResponsePrivate &dd, QHttpClient *cli)
14+ : QHttpAbstractInput(cli), d_ptr(&dd) {
15+ d_ptr->initialize();
16+ QHTTP_LINE_LOG
17+}
18+
19+QHttpResponse::~QHttpResponse() {
20+ QHTTP_LINE_LOG
21+}
22+
23+TStatusCode
24+QHttpResponse::status() const {
25+ return d_func()->istatus;
26+}
27+
28+const QString&
29+QHttpResponse::statusString() const {
30+ return d_func()->icustomStatusMessage;
31+}
32+
33+const QString&
34+QHttpResponse::httpVersion() const {
35+ return d_func()->iversion;
36+}
37+
38+const THeaderHash&
39+QHttpResponse::headers() const {
40+ return d_func()->iheaders;
41+}
42+
43+bool
44+QHttpResponse::isSuccessful() const {
45+ return d_func()->isuccessful;
46+}
47+
48+void
49+QHttpResponse::collectData(int atMost) {
50+ d_func()->collectData(atMost);
51+}
52+
53+const QByteArray&
54+QHttpResponse::collectedData() const {
55+ return d_func()->icollectedData;
56+}
57+
58+QHttpClient*
59+QHttpResponse::connection() const {
60+ return d_func()->iclient;
61+}
62+
63+///////////////////////////////////////////////////////////////////////////////
64+} // namespace client
65+} // namespace qhttp
66+///////////////////////////////////////////////////////////////////////////////
libs/qhttp/qhttpclientresponse.hppnew file+78
@@ -0,0 +1,78 @@
1+/** HTTP response received by client.
2+ * https://github.com/azadkuh/qhttp
3+ *
4+ * @author amir zamani
5+ * @version 2.0.0
6+ * @date 2014-07-11
7+ */
8+
9+#ifndef QHTTPCLIENT_RESPONSE_HPP
10+#define QHTTPCLIENT_RESPONSE_HPP
11+
12+// configured by src.pro
13+#if defined(QHTTP_HAS_CLIENT)
14+
15+///////////////////////////////////////////////////////////////////////////////
16+
17+#include "qhttpabstracts.hpp"
18+
19+#include <QUrl>
20+///////////////////////////////////////////////////////////////////////////////
21+namespace qhttp {
22+namespace client {
23+///////////////////////////////////////////////////////////////////////////////
24+/** a class for reading incoming HTTP response from a server.
25+ * the life cycle of this class and the memory management is handled by QHttpClient.
26+ * @sa QHttpClient
27+ */
28+class QHTTP_API QHttpResponse : public QHttpAbstractInput
29+{
30+ Q_OBJECT
31+
32+public:
33+ virtual ~QHttpResponse();
34+
35+public: // QHttpAbstractInput methods:
36+ /** @see QHttpAbstractInput::headers(). */
37+ const THeaderHash& headers() const override;
38+
39+ /** @see QHttpAbstractInput::httpVersion(). */
40+ const QString& httpVersion() const override;
41+
42+ /** @see QHttpAbstractInput::isSuccessful(). */
43+ bool isSuccessful() const override;
44+
45+ /** @see QHttpAbstractInput::collectData(). */
46+ void collectData(int atMost = -1) override;
47+
48+ /** @see QHttpAbstractInput::collectedData(). */
49+ const QByteArray& collectedData()const override;
50+
51+
52+public:
53+ /** The status code of this response. */
54+ TStatusCode status() const ;
55+
56+ /** The server status message as string.
57+ * may be slightly different than: @code qhttp::Stringify::toString(status()); @endcode
58+ * depending on implementation of HTTP server. */
59+ const QString& statusString() const;
60+
61+ /** returns parent QHttpClient object. */
62+ QHttpClient* connection() const;
63+
64+protected:
65+ explicit QHttpResponse(QHttpClient*);
66+ explicit QHttpResponse(QHttpResponsePrivate&, QHttpClient*);
67+ friend class QHttpClientPrivate;
68+
69+ Q_DECLARE_PRIVATE(QHttpResponse)
70+ QScopedPointer<QHttpResponsePrivate> d_ptr;
71+};
72+
73+///////////////////////////////////////////////////////////////////////////////
74+} // namespace client
75+} // namespace qhttp
76+///////////////////////////////////////////////////////////////////////////////
77+#endif // QHTTP_HAS_CLIENT
78+#endif // define QHTTPCLIENT_RESPONSE_HPP
libs/qhttp/qhttpfwd.hppnew file+221
@@ -0,0 +1,221 @@
1+/** forward declarations and general definitions of the QHttp.
2+ * https://github.com/azadkuh/qhttp
3+ *
4+ * @author amir zamani
5+ * @version 2.0.0
6+ * @date 2014-07-11
7+ */
8+
9+#ifndef QHTTPFWD_HPP
10+#define QHTTPFWD_HPP
11+///////////////////////////////////////////////////////////////////////////////
12+#include <QHash>
13+#include <QString>
14+#include <QtGlobal>
15+
16+#include <functional>
17+///////////////////////////////////////////////////////////////////////////////
18+// Qt
19+class QTcpServer;
20+class QTcpSocket;
21+class QLocalServer;
22+class QLocalSocket;
23+
24+// http_parser
25+struct http_parser_settings;
26+struct http_parser;
27+
28+///////////////////////////////////////////////////////////////////////////////
29+namespace qhttp {
30+///////////////////////////////////////////////////////////////////////////////
31+
32+/// QHash/QMap iterators are incompatibility with range for
33+template<class Iterator, class Func>
34+void for_each(Iterator first, Iterator last, Func&& f) {
35+ while ( first != last ) {
36+ f( first );
37+ ++first;
38+ }
39+}
40+
41+/** A map of request or response headers. */
42+class THeaderHash : public QHash<QByteArray, QByteArray>
43+{
44+public:
45+ /** checks for a header item, regardless of the case of the characters. */
46+ bool has(const QByteArray& key) const {
47+ return contains(key.toLower());
48+ }
49+
50+ /** checks if a header has the specified value ignoring the case of the characters. */
51+ bool keyHasValue(const QByteArray& key, const QByteArray& value) const {
52+ if ( !contains(key) )
53+ return false;
54+
55+ const QByteArray& v = QHash<QByteArray, QByteArray>::value(key);
56+ return qstrnicmp(value.constData(), v.constData(), v.size()) == 0;
57+ }
58+
59+ template<class Func>
60+ void forEach(Func&& f) const {
61+ for_each(constBegin(), constEnd(), f);
62+ }
63+};
64+
65+
66+/** Request method enumeration.
67+ * @note Taken from http_parser.h */
68+enum THttpMethod {
69+ EHTTP_DELETE = 0, ///< DELETE
70+ EHTTP_GET = 1, ///< GET
71+ EHTTP_HEAD = 2, ///< HEAD
72+ EHTTP_POST = 3, ///< POST
73+ EHTTP_PUT = 4, ///< PUT
74+ /* pathological */
75+ EHTTP_CONNECT = 5, ///< CONNECT
76+ EHTTP_OPTIONS = 6, ///< OPTIONS
77+ EHTTP_TRACE = 7, ///< TRACE
78+ /* webdav */
79+ EHTTP_COPY = 8, ///< COPY
80+ EHTTP_LOCK = 9, ///< LOCK
81+ EHTTP_MKCOL = 10, ///< MKCOL
82+ EHTTP_MOVE = 11, ///< MOVE
83+ EHTTP_PROPFIND = 12, ///< PROPFIND
84+ EHTTP_PROPPATCH = 13, ///< PROPPATCH
85+ EHTTP_SEARCH = 14, ///< SEARCH
86+ EHTTP_UNLOCK = 15, ///< UNLOCK
87+ EHTTP_BIND = 16, ///< BIND
88+ EHTTP_REBIND = 17, ///< REBIND
89+ EHTTP_UNBIND = 18, ///< UNBIND
90+ EHTTP_ACL = 19, ///< ACL
91+ /* subversion */
92+ EHTTP_REPORT = 20, ///< REPORT
93+ EHTTP_MKACTIVITY = 21, ///< MKACTIVITY
94+ EHTTP_CHECKOUT = 22, ///< CHECKOUT
95+ EHTTP_MERGE = 23, ///< MERGE
96+ /* upnp */
97+ EHTTP_MSEARCH = 24, ///< M-SEARCH
98+ EHTTP_NOTIFY = 25, ///< NOTIFY
99+ EHTTP_SUBSCRIBE = 26, ///< SUBSCRIBE
100+ EHTTP_UNSUBSCRIBE = 27, ///< UNSUBSCRIBE
101+ /* RFC-5789 */
102+ EHTTP_PATCH = 28, ///< PATCH
103+ EHTTP_PURGE = 29, ///< PURGE
104+ /* CalDAV */
105+ EHTTP_MKCALENDAR = 30, ///< MKCALENDAR
106+ /* RFC-2068, section 19.6.1.2 */
107+ EHTTP_LINK = 31, ///< LINK
108+ EHTTP_UNLINK = 32, ///< UNLINK
109+};
110+
111+/** HTTP status codes. */
112+enum TStatusCode {
113+ ESTATUS_CONTINUE = 100,
114+ ESTATUS_SWITCH_PROTOCOLS = 101,
115+ ESTATUS_OK = 200,
116+ ESTATUS_CREATED = 201,
117+ ESTATUS_ACCEPTED = 202,
118+ ESTATUS_NON_AUTHORITATIVE_INFORMATION = 203,
119+ ESTATUS_NO_CONTENT = 204,
120+ ESTATUS_RESET_CONTENT = 205,
121+ ESTATUS_PARTIAL_CONTENT = 206,
122+ ESTATUS_MULTI_STATUS = 207,
123+ ESTATUS_MULTIPLE_CHOICES = 300,
124+ ESTATUS_MOVED_PERMANENTLY = 301,
125+ ESTATUS_FOUND = 302,
126+ ESTATUS_SEE_OTHER = 303,
127+ ESTATUS_NOT_MODIFIED = 304,
128+ ESTATUS_USE_PROXY = 305,
129+ ESTATUS_TEMPORARY_REDIRECT = 307,
130+ ESTATUS_BAD_REQUEST = 400,
131+ ESTATUS_UNAUTHORIZED = 401,
132+ ESTATUS_PAYMENT_REQUIRED = 402,
133+ ESTATUS_FORBIDDEN = 403,
134+ ESTATUS_NOT_FOUND = 404,
135+ ESTATUS_METHOD_NOT_ALLOWED = 405,
136+ ESTATUS_NOT_ACCEPTABLE = 406,
137+ ESTATUS_PROXY_AUTHENTICATION_REQUIRED = 407,
138+ ESTATUS_REQUEST_TIMEOUT = 408,
139+ ESTATUS_CONFLICT = 409,
140+ ESTATUS_GONE = 410,
141+ ESTATUS_LENGTH_REQUIRED = 411,
142+ ESTATUS_PRECONDITION_FAILED = 412,
143+ ESTATUS_REQUEST_ENTITY_TOO_LARGE = 413,
144+ ESTATUS_REQUEST_URI_TOO_LONG = 414,
145+ ESTATUS_REQUEST_UNSUPPORTED_MEDIA_TYPE = 415,
146+ ESTATUS_REQUESTED_RANGE_NOT_SATISFIABLE = 416,
147+ ESTATUS_EXPECTATION_FAILED = 417,
148+ ESTATUS_INTERNAL_SERVER_ERROR = 500,
149+ ESTATUS_NOT_IMPLEMENTED = 501,
150+ ESTATUS_BAD_GATEWAY = 502,
151+ ESTATUS_SERVICE_UNAVAILABLE = 503,
152+ ESTATUS_GATEWAY_TIMEOUT = 504,
153+ ESTATUS_HTTP_VERSION_NOT_SUPPORTED = 505
154+};
155+
156+/** The backend of QHttp library. */
157+enum TBackend {
158+ ETcpSocket = 0, ///< client / server work on top of TCP/IP stack. (default)
159+ ESslSocket = 1, ///< client / server work on SSL/TLS tcp stack. (not implemented yet)
160+ ELocalSocket = 2 ///< client / server work on local socket (unix socket).
161+};
162+
163+///////////////////////////////////////////////////////////////////////////////
164+namespace server {
165+///////////////////////////////////////////////////////////////////////////////
166+class QHttpServer;
167+class QHttpConnection;
168+class QHttpRequest;
169+class QHttpResponse;
170+
171+// Privte classes
172+class QHttpServerPrivate;
173+class QHttpConnectionPrivate;
174+class QHttpRequestPrivate;
175+class QHttpResponsePrivate;
176+
177+using TServerHandler = std::function<void (QHttpRequest*, QHttpResponse*)>;
178+
179+///////////////////////////////////////////////////////////////////////////////
180+} // namespace server
181+///////////////////////////////////////////////////////////////////////////////
182+namespace client {
183+///////////////////////////////////////////////////////////////////////////////
184+class QHttpClient;
185+class QHttpRequest;
186+class QHttpResponse;
187+
188+// Private classes
189+class QHttpClientPrivate;
190+class QHttpRequestPrivate;
191+class QHttpResponsePrivate;
192+///////////////////////////////////////////////////////////////////////////////
193+} // namespace client
194+///////////////////////////////////////////////////////////////////////////////
195+#ifdef Q_OS_WIN
196+# if defined(QHTTP_EXPORT)
197+# define QHTTP_API __declspec(dllexport)
198+# else
199+# define QHTTP_API __declspec(dllimport)
200+# endif
201+#else
202+# define QHTTP_API
203+#endif
204+
205+
206+#if QHTTP_MEMORY_LOG > 0
207+# define QHTTP_LINE_LOG fprintf(stderr, "%s(): obj = %p @ %s[%d]\n",\
208+ __FUNCTION__, this, __FILE__, __LINE__);
209+#else
210+# define QHTTP_LINE_LOG
211+#endif
212+
213+#if QHTTP_MEMORY_LOG > 1
214+# define QHTTP_LINE_DEEPLOG QHTTP_LINE_LOG
215+#else
216+# define QHTTP_LINE_DEEPLOG
217+#endif
218+///////////////////////////////////////////////////////////////////////////////
219+} // namespace qhttp
220+///////////////////////////////////////////////////////////////////////////////
221+#endif // define QHTTPFWD_HPP
libs/qhttp/qhttpserver.cppnew file+118
@@ -0,0 +1,118 @@
1+#include "private/qhttpserver_private.hpp"
2+
3+///////////////////////////////////////////////////////////////////////////////
4+namespace qhttp {
5+namespace server {
6+///////////////////////////////////////////////////////////////////////////////
7+
8+QHttpServer::QHttpServer(QObject *parent)
9+ : QObject(parent), d_ptr(new QHttpServerPrivate) {
10+}
11+
12+QHttpServer::QHttpServer(QHttpServerPrivate &dd, QObject *parent)
13+ : QObject(parent), d_ptr(&dd) {
14+}
15+
16+QHttpServer::~QHttpServer() {
17+ stopListening();
18+}
19+
20+bool
21+QHttpServer::listen(const QString &socketOrPort, const TServerHandler &handler) {
22+ Q_D(QHttpServer);
23+
24+ bool isNumber = false;
25+ quint16 tcpPort = socketOrPort.toUShort(&isNumber);
26+ if ( isNumber && tcpPort > 0 )
27+ return listen(QHostAddress::Any, tcpPort, handler);
28+
29+ d->initialize(ELocalSocket, this);
30+ d->ihandler = handler;
31+ return d->ilocalServer->listen(socketOrPort);
32+}
33+
34+bool
35+QHttpServer::listen(const QHostAddress& address, quint16 port, const qhttp::server::TServerHandler& handler) {
36+ Q_D(QHttpServer);
37+
38+ d->initialize(ETcpSocket, this);
39+ d->ihandler = handler;
40+ return d->itcpServer->listen(address, port);
41+}
42+
43+bool
44+QHttpServer::isListening() const {
45+ const Q_D(QHttpServer);
46+
47+ if ( d->ibackend == ETcpSocket && d->itcpServer )
48+ return d->itcpServer->isListening();
49+
50+ else if ( d->ibackend == ELocalSocket && d->ilocalServer )
51+ return d->ilocalServer->isListening();
52+
53+ return false;
54+}
55+
56+void
57+QHttpServer::stopListening() {
58+ Q_D(QHttpServer);
59+
60+ if ( d->itcpServer )
61+ d->itcpServer->close();
62+
63+ if ( d->ilocalServer ) {
64+ d->ilocalServer->close();
65+ QLocalServer::removeServer( d->ilocalServer->fullServerName() );
66+ }
67+}
68+
69+quint32
70+QHttpServer::timeOut() const {
71+ return d_func()->itimeOut;
72+}
73+
74+void
75+QHttpServer::setTimeOut(quint32 newValue) {
76+ d_func()->itimeOut = newValue;
77+}
78+
79+TBackend
80+QHttpServer::backendType() const {
81+ return d_func()->ibackend;
82+}
83+
84+QTcpServer*
85+QHttpServer::tcpServer() const {
86+ return d_func()->itcpServer.data();
87+}
88+
89+QLocalServer*
90+QHttpServer::localServer() const {
91+ return d_func()->ilocalServer.data();
92+}
93+
94+void
95+QHttpServer::incomingConnection(qintptr handle) {
96+ QHttpConnection* conn = new QHttpConnection(this);
97+ conn->setSocketDescriptor(handle, backendType());
98+ conn->setTimeOut(d_func()->itimeOut);
99+
100+ emit newConnection(conn);
101+
102+ Q_D(QHttpServer);
103+ if ( d->ihandler )
104+ QObject::connect(conn, &QHttpConnection::newRequest, d->ihandler);
105+ else
106+ incomingConnection(conn);
107+}
108+
109+void
110+QHttpServer::incomingConnection(QHttpConnection *connection) {
111+ QObject::connect(connection, &QHttpConnection::newRequest,
112+ this, &QHttpServer::newRequest);
113+}
114+
115+///////////////////////////////////////////////////////////////////////////////
116+} // namespace server
117+} // namespace qhttp
118+///////////////////////////////////////////////////////////////////////////////
libs/qhttp/qhttpserver.hppnew file+131
@@ -0,0 +1,131 @@
1+/** HTTP server class.
2+ * https://github.com/azadkuh/qhttp
3+ *
4+ * @author amir zamani
5+ * @version 2.0.0
6+ * @date 2014-07-11
7+ */
8+
9+#ifndef QHTTPSERVER_HPP
10+#define QHTTPSERVER_HPP
11+
12+///////////////////////////////////////////////////////////////////////////////
13+#include "qhttpfwd.hpp"
14+
15+#include <QObject>
16+#include <QHostAddress>
17+///////////////////////////////////////////////////////////////////////////////
18+namespace qhttp {
19+namespace server {
20+///////////////////////////////////////////////////////////////////////////////
21+
22+/** The QHttpServer class is a fast, async (non-blocking) HTTP server. */
23+class QHTTP_API QHttpServer : public QObject
24+{
25+ Q_OBJECT
26+
27+ Q_PROPERTY(quint32 timeOut READ timeOut WRITE setTimeOut)
28+
29+public:
30+ /** construct a new HTTP Server. */
31+ explicit QHttpServer(QObject *parent = nullptr);
32+
33+ virtual ~QHttpServer();
34+
35+ /** starts a TCP or Local (unix domain socket) server.
36+ * if you provide a server handler, the newRequest() signal won't be emitted.
37+ *
38+ * @param socketOrPort could be a tcp port number as "8080" or a unix socket name as
39+ * "/tmp/sample.socket" or "sample.socket".
40+ * @param handler optional server handler (a lambda, std::function, ...)
41+ * @return false if listening fails.
42+ */
43+ bool listen(const QString& socketOrPort,
44+ const TServerHandler& handler = nullptr);
45+
46+ /** starts a TCP server on specified address and port.
47+ * if you provide a server handler, the newRequest() signal won't be emitted.
48+ *
49+ * @param address listening address as QHostAddress::Any.
50+ * @param port listening port.
51+ * @param handler optional server handler (a lambda, std::function, ...)
52+ * @return false if listening fails.
53+ */
54+ bool listen(const QHostAddress& address, quint16 port,
55+ const TServerHandler& handler = nullptr);
56+
57+ /** @overload listen() */
58+ bool listen(quint16 port) {
59+ return listen(QHostAddress::Any, port);
60+ }
61+
62+ /** returns true if server successfully listens. @sa listen() */
63+ bool isListening() const;
64+
65+ /** closes the server and stops from listening. */
66+ void stopListening();
67+
68+ /** returns timeout value [mSec] for open connections (sockets).
69+ * @sa setTimeOut(). */
70+ quint32 timeOut()const;
71+
72+ /** set time-out for new open connections in miliseconds [mSec].
73+ * new incoming connections will be forcefully closed after this time out.
74+ * a zero (0) value disables timer for new connections. */
75+ void setTimeOut(quint32);
76+
77+ /** returns the QHttpServer's backend type. */
78+ TBackend backendType() const;
79+
80+signals:
81+ /** emitted when a client makes a new request to the server if you do not override
82+ * incomingConnection(QHttpConnection *connection);
83+ * @sa incommingConnection(). */
84+ void newRequest(QHttpRequest *request, QHttpResponse *response);
85+
86+ /** emitted when a new connection comes to the server if you do not override
87+ * incomingConnection(QHttpConnection *connection);
88+ * @sa incomingConnection(); */
89+ void newConnection(QHttpConnection* connection);
90+
91+protected:
92+ /** returns the tcp server instance if the backend() == ETcpSocket. */
93+ QTcpServer* tcpServer() const;
94+
95+ /** returns the local server instance if the backend() == ELocalSocket. */
96+ QLocalServer* localServer() const;
97+
98+
99+ /** is called when server accepts a new connection.
100+ * you can override this function for using a thread-pool or ... some other reasons.
101+ *
102+ * the default implementation just connects QHttpConnection::newRequest signal.
103+ * @note if you override this method, the signal won't be emitted by QHttpServer.
104+ * (perhaps, you do not need it anymore).
105+ *
106+ * @param connection New incoming connection. */
107+ virtual void incomingConnection(QHttpConnection* connection);
108+
109+ /** overrides QTcpServer::incomingConnection() to make a new QHttpConnection.
110+ * override this function if you like to create your derived QHttpConnection instances.
111+ *
112+ * @note if you override this method, incomingConnection(QHttpConnection*) or
113+ * newRequest(QHttpRequest *, QHttpResponse *) signal won't be called.
114+ *
115+ * @see example/benchmark/server.cpp to see how to override.
116+ */
117+ virtual void incomingConnection(qintptr handle);
118+
119+private:
120+ explicit QHttpServer(QHttpServerPrivate&, QObject *parent);
121+
122+ Q_DECLARE_PRIVATE(QHttpServer)
123+ Q_DISABLE_COPY(QHttpServer)
124+ QScopedPointer<QHttpServerPrivate> d_ptr;
125+};
126+
127+///////////////////////////////////////////////////////////////////////////////
128+} // namespace server
129+} // namespace qhttp
130+///////////////////////////////////////////////////////////////////////////////
131+#endif // define QHTTPSERVER_HPP
libs/qhttp/qhttpserverconnection.cppnew file+217
@@ -0,0 +1,217 @@
1+#include "private/qhttpserverconnection_private.hpp"
2+
3+///////////////////////////////////////////////////////////////////////////////
4+namespace qhttp {
5+namespace server {
6+///////////////////////////////////////////////////////////////////////////////
7+QHttpConnection::QHttpConnection(QObject *parent)
8+ : QObject(parent), d_ptr(new QHttpConnectionPrivate(this)) {
9+ QHTTP_LINE_LOG
10+}
11+
12+QHttpConnection::QHttpConnection(QHttpConnectionPrivate& dd, QObject* parent)
13+ : QObject(parent), d_ptr(&dd) {
14+ QHTTP_LINE_LOG
15+}
16+
17+void
18+QHttpConnection::setSocketDescriptor(qintptr sokDescriptor, TBackend backendType) {
19+ d_ptr->createSocket(sokDescriptor, backendType);
20+}
21+
22+QHttpConnection::~QHttpConnection() {
23+ QHTTP_LINE_LOG
24+}
25+
26+void
27+QHttpConnection::setTimeOut(quint32 miliSeconds) {
28+ if ( miliSeconds != 0 ) {
29+ d_func()->itimeOut = miliSeconds;
30+ d_func()->itimer.start(miliSeconds, Qt::CoarseTimer, this);
31+ }
32+}
33+
34+void
35+QHttpConnection::killConnection() {
36+ d_func()->isocket.close();
37+}
38+
39+TBackend
40+QHttpConnection::backendType() const {
41+ return d_func()->isocket.ibackendType;
42+}
43+
44+QTcpSocket*
45+QHttpConnection::tcpSocket() const {
46+ return d_func()->isocket.itcpSocket;
47+}
48+
49+QLocalSocket*
50+QHttpConnection::localSocket() const {
51+ return d_func()->isocket.ilocalSocket;
52+}
53+
54+void
55+QHttpConnection::onHandler(const TServerHandler &handler) {
56+ d_func()->ihandler = handler;
57+}
58+
59+void
60+QHttpConnection::timerEvent(QTimerEvent *) {
61+ killConnection();
62+}
63+
64+///////////////////////////////////////////////////////////////////////////////
65+
66+// if user closes the connection, ends the response or by any other reason the
67+// socket disconnects, then the irequest and iresponse instances may have
68+// been deleted. In these situations reading more http body or emitting end()
69+// for incoming request are not possible:
70+// if ( ilastRequest == nullptr )
71+// return 0;
72+
73+
74+int
75+QHttpConnectionPrivate::messageBegin(http_parser*) {
76+ itempUrl.clear();
77+ itempUrl.reserve(128);
78+
79+ if ( ilastRequest )
80+ ilastRequest->deleteLater();
81+
82+ ilastRequest = new QHttpRequest(q_func());
83+ return 0;
84+}
85+
86+int
87+QHttpConnectionPrivate::url(http_parser*, const char* at, size_t length) {
88+ Q_ASSERT(ilastRequest);
89+
90+ itempUrl.append(at, length);
91+ return 0;
92+}
93+
94+int
95+QHttpConnectionPrivate::headerField(http_parser*, const char* at, size_t length) {
96+ if ( ilastRequest == nullptr )
97+ return 0;
98+
99+ // insert the header we parsed previously
100+ // into the header map
101+ if ( !itempHeaderField.isEmpty() && !itempHeaderValue.isEmpty() ) {
102+ // header names are always lower-cased
103+ ilastRequest->d_func()->iheaders.insert(
104+ itempHeaderField.toLower(),
105+ itempHeaderValue.toLower()
106+ );
107+ // clear header value. this sets up a nice
108+ // feedback loop where the next time
109+ // HeaderValue is called, it can simply append
110+ itempHeaderField.clear();
111+ itempHeaderValue.clear();
112+ }
113+
114+ itempHeaderField.append(at, length);
115+ return 0;
116+}
117+
118+int
119+QHttpConnectionPrivate::headerValue(http_parser*, const char* at, size_t length) {
120+ if ( ilastRequest == nullptr )
121+ return 0;
122+
123+ itempHeaderValue.append(at, length);
124+ return 0;
125+}
126+
127+int
128+QHttpConnectionPrivate::headersComplete(http_parser* parser) {
129+ if ( ilastRequest == nullptr )
130+ return 0;
131+
132+ ilastRequest->d_func()->iurl = QUrl(itempUrl);
133+
134+ // set method
135+ ilastRequest->d_func()->imethod =
136+ static_cast<THttpMethod>(parser->method);
137+
138+ // set version
139+ ilastRequest->d_func()->iversion = QString("%1.%2")
140+ .arg(parser->http_major)
141+ .arg(parser->http_minor);
142+
143+ // Insert last remaining header
144+ ilastRequest->d_func()->iheaders.insert(
145+ itempHeaderField.toLower(),
146+ itempHeaderValue.toLower()
147+ );
148+
149+ // set client information
150+ if ( isocket.ibackendType == ETcpSocket ) {
151+ ilastRequest->d_func()->iremoteAddress = isocket.itcpSocket->peerAddress().toString();
152+ ilastRequest->d_func()->iremotePort = isocket.itcpSocket->peerPort();
153+
154+ } else if ( isocket.ibackendType == ELocalSocket ) {
155+ ilastRequest->d_func()->iremoteAddress = isocket.ilocalSocket->fullServerName();
156+ ilastRequest->d_func()->iremotePort = 0; // not used in local sockets
157+ }
158+
159+ if ( ilastResponse )
160+ ilastResponse->deleteLater();
161+ ilastResponse = new QHttpResponse(q_func());
162+
163+ if ( parser->http_major < 1 || parser->http_minor < 1 )
164+ ilastResponse->d_func()->ikeepAlive = false;
165+
166+ // close the connection if response was the last packet
167+ QObject::connect(ilastResponse, &QHttpResponse::done, [this](bool wasTheLastPacket){
168+ ikeepAlive = !wasTheLastPacket;
169+ if ( wasTheLastPacket ) {
170+ isocket.flush();
171+ isocket.close();
172+ }
173+ });
174+
175+ // we are good to go!
176+ if ( ihandler )
177+ ihandler(ilastRequest, ilastResponse);
178+ else
179+ emit q_ptr->newRequest(ilastRequest, ilastResponse);
180+
181+ return 0;
182+}
183+
184+int
185+QHttpConnectionPrivate::body(http_parser*, const char* at, size_t length) {
186+ if ( ilastRequest == nullptr )
187+ return 0;
188+
189+ ilastRequest->d_func()->ireadState = QHttpRequestPrivate::EPartial;
190+
191+ if ( ilastRequest->d_func()->icollectRequired ) {
192+ if ( !ilastRequest->d_func()->append(at, length) ) {
193+ // forcefully dispatch the ilastRequest
194+ finalizeConnection();
195+ }
196+
197+ return 0;
198+ }
199+
200+ emit ilastRequest->data(QByteArray(at, length));
201+ return 0;
202+}
203+
204+int
205+QHttpConnectionPrivate::messageComplete(http_parser*) {
206+ if ( ilastRequest == nullptr )
207+ return 0;
208+
209+ // request is done
210+ finalizeConnection();
211+ return 0;
212+}
213+
214+///////////////////////////////////////////////////////////////////////////////
215+} // namespace server
216+} // namespace qhttp
217+///////////////////////////////////////////////////////////////////////////////
libs/qhttp/qhttpserverconnection.hppnew file+87
@@ -0,0 +1,87 @@
1+/** HTTP connection class.
2+ * https://github.com/azadkuh/qhttp
3+ *
4+ * @author amir zamani
5+ * @version 2.0.0
6+ * @date 2014-07-11
7+ */
8+
9+#ifndef QHTTPSERVER_CONNECTION_HPP
10+#define QHTTPSERVER_CONNECTION_HPP
11+///////////////////////////////////////////////////////////////////////////////
12+#include "qhttpfwd.hpp"
13+
14+#include <QObject>
15+
16+///////////////////////////////////////////////////////////////////////////////
17+namespace qhttp {
18+namespace server {
19+///////////////////////////////////////////////////////////////////////////////
20+/** a HTTP connection in the server.
21+ * this class controls the HTTP connetion and handles life cycle and the memory management
22+ * of QHttpRequest and QHttpResponse instances autoamtically.
23+ */
24+class QHTTP_API QHttpConnection : public QObject
25+{
26+ Q_OBJECT
27+
28+public:
29+ virtual ~QHttpConnection();
30+
31+ /** set an optional timer event to close the connection. */
32+ void setTimeOut(quint32 miliSeconds);
33+
34+ /** forcefully kills (closes) a connection. */
35+ void killConnection();
36+
37+ /** optionally set a handler for connection class.
38+ * @note if you set this handler, the newRequest() signal won't be emitted.
39+ */
40+ void onHandler(const TServerHandler& handler);
41+
42+ /** returns the backend type of the connection. */
43+ TBackend backendType() const;
44+
45+ /** returns connected socket if the backend() == ETcpSocket. */
46+ QTcpSocket* tcpSocket() const;
47+
48+ /** returns connected socket if the backend() == ELocalSocket. */
49+ QLocalSocket* localSocket() const;
50+
51+ /** creates a new QHttpConnection based on arguments. */
52+ static
53+ QHttpConnection* create(qintptr sokDescriptor, TBackend backendType, QObject* parent) {
54+ QHttpConnection* conn = new QHttpConnection(parent);
55+ conn->setSocketDescriptor(sokDescriptor, backendType);
56+ return conn;
57+ }
58+
59+signals:
60+ /** emitted when a pair of HTTP request and response are ready to interact.
61+ * @param req incoming request by the client.
62+ * @param res outgoing response to the client.
63+ */
64+ void newRequest(QHttpRequest* req, QHttpResponse* res);
65+
66+ /** emitted when the tcp/local socket, disconnects. */
67+ void disconnected();
68+
69+protected:
70+ explicit QHttpConnection(QObject *parent);
71+ explicit QHttpConnection(QHttpConnectionPrivate&, QObject *);
72+
73+ void setSocketDescriptor(qintptr sokDescriptor, TBackend backendType);
74+ void timerEvent(QTimerEvent*) override;
75+
76+ Q_DISABLE_COPY(QHttpConnection)
77+ Q_DECLARE_PRIVATE(QHttpConnection)
78+ QScopedPointer<QHttpConnectionPrivate> d_ptr;
79+
80+ friend class QHttpServer;
81+};
82+
83+///////////////////////////////////////////////////////////////////////////////
84+} // namespace server
85+} // namespace qhttp
86+///////////////////////////////////////////////////////////////////////////////
87+#endif // #define QHTTPSERVER_CONNECTION_HPP
libs/qhttp/qhttpserverrequest.cppnew file+81
@@ -0,0 +1,81 @@
1+#include "private/qhttpserverrequest_private.hpp"
2+
3+///////////////////////////////////////////////////////////////////////////////
4+namespace qhttp {
5+namespace server {
6+///////////////////////////////////////////////////////////////////////////////
7+QHttpRequest::QHttpRequest(QHttpConnection *conn)
8+ : QHttpAbstractInput(conn), d_ptr(new QHttpRequestPrivate(conn, this)) {
9+ d_ptr->initialize();
10+ QHTTP_LINE_LOG
11+}
12+
13+QHttpRequest::QHttpRequest(QHttpRequestPrivate &dd, QHttpConnection *conn)
14+ : QHttpAbstractInput(conn), d_ptr(&dd) {
15+ d_ptr->initialize();
16+ QHTTP_LINE_LOG
17+}
18+
19+QHttpRequest::~QHttpRequest() {
20+ QHTTP_LINE_LOG
21+}
22+
23+THttpMethod
24+QHttpRequest::method() const {
25+ return d_func()->imethod;
26+}
27+
28+const QString
29+QHttpRequest::methodString() const {
30+ return http_method_str(static_cast<http_method>(d_func()->imethod));
31+}
32+
33+const QUrl&
34+QHttpRequest::url() const {
35+ return d_func()->iurl;
36+}
37+
38+const QString&
39+QHttpRequest::httpVersion() const {
40+ return d_func()->iversion;
41+}
42+
43+const THeaderHash&
44+QHttpRequest::headers() const {
45+ return d_func()->iheaders;
46+}
47+
48+const QString&
49+QHttpRequest::remoteAddress() const {
50+ return d_func()->iremoteAddress;
51+}
52+
53+quint16
54+QHttpRequest::remotePort() const {
55+ return d_func()->iremotePort;
56+}
57+
58+bool
59+QHttpRequest::isSuccessful() const {
60+ return d_func()->isuccessful;
61+}
62+
63+void
64+QHttpRequest::collectData(int atMost) {
65+ d_func()->collectData(atMost);
66+}
67+
68+const QByteArray&
69+QHttpRequest::collectedData() const {
70+ return d_func()->icollectedData;
71+}
72+
73+QHttpConnection*
74+QHttpRequest::connection() const {
75+ return d_ptr->iconnection;
76+}
77+
78+///////////////////////////////////////////////////////////////////////////////
79+} // namespace server
80+} // namespace qhttp
81+///////////////////////////////////////////////////////////////////////////////
libs/qhttp/qhttpserverrequest.hppnew file+82
@@ -0,0 +1,82 @@
1+/** HTTP request which is received by the server.
2+ * https://github.com/azadkuh/qhttp
3+ *
4+ * @author amir zamani
5+ * @version 2.0.0
6+ * @date 2014-07-11
7+ */
8+
9+#ifndef QHTTPSERVER_REQUEST_HPP
10+#define QHTTPSERVER_REQUEST_HPP
11+///////////////////////////////////////////////////////////////////////////////
12+
13+#include "qhttpabstracts.hpp"
14+
15+#include <QUrl>
16+///////////////////////////////////////////////////////////////////////////////
17+namespace qhttp {
18+namespace server {
19+///////////////////////////////////////////////////////////////////////////////
20+/** The QHttpRequest class represents the header and body data sent by the client.
21+ * The class is <b>read-only</b>.
22+ * @sa QHttpConnection
23+ */
24+class QHTTP_API QHttpRequest : public QHttpAbstractInput
25+{
26+ Q_OBJECT
27+
28+public:
29+ virtual ~QHttpRequest();
30+
31+public: // QHttpAbstractInput methods:
32+ /** @see QHttpAbstractInput::headers(). */
33+ const THeaderHash& headers() const override;
34+
35+ /** @see QHttpAbstractInput::httpVersion(). */
36+ const QString& httpVersion() const override;
37+
38+ /** @see QHttpAbstractInput::isSuccessful(). */
39+ bool isSuccessful() const override;
40+
41+ /** @see QHttpAbstractInput::collectData(). */
42+ void collectData(int atMost = -1) override;
43+
44+ /** @see QHttpAbstractInput::collectedData(). */
45+ const QByteArray& collectedData()const override;
46+
47+
48+public:
49+ /** The method used for the request. */
50+ THttpMethod method() const ;
51+
52+ /** Returns the method string for the request.
53+ * @note This will plainly transform the enum into a string HTTP_GET -> "HTTP_GET". */
54+ const QString methodString() const;
55+
56+ /** The complete URL for the request.
57+ * This includes the path and query string. @sa path(). */
58+ const QUrl& url() const;
59+
60+ /** IP Address of the client in dotted decimal format. */
61+ const QString& remoteAddress() const;
62+
63+ /** Outbound connection port for the client. */
64+ quint16 remotePort() const;
65+
66+ /** returns the parent QHttpConnection object. */
67+ QHttpConnection* connection() const;
68+
69+protected:
70+ explicit QHttpRequest(QHttpConnection*);
71+ explicit QHttpRequest(QHttpRequestPrivate&, QHttpConnection*);
72+ friend class QHttpConnectionPrivate;
73+
74+ Q_DECLARE_PRIVATE(QHttpRequest)
75+ QScopedPointer<QHttpRequestPrivate> d_ptr;
76+};
77+
78+///////////////////////////////////////////////////////////////////////////////
79+} // namespace server
80+} // namespace qhttp
81+///////////////////////////////////////////////////////////////////////////////
82+#endif // define QHTTPSERVER_REQUEST_HPP
libs/qhttp/qhttpserverresponse.cppnew file+90
@@ -0,0 +1,90 @@
1+#include "private/qhttpserverresponse_private.hpp"
2+
3+///////////////////////////////////////////////////////////////////////////////
4+namespace qhttp {
5+namespace server {
6+///////////////////////////////////////////////////////////////////////////////
7+QHttpResponse::QHttpResponse(QHttpConnection* conn)
8+ : QHttpAbstractOutput(conn) , d_ptr(new QHttpResponsePrivate(conn, this)) {
9+ d_ptr->initialize();
10+ QHTTP_LINE_LOG
11+}
12+
13+QHttpResponse::QHttpResponse(QHttpResponsePrivate& dd, QHttpConnection* conn)
14+ : QHttpAbstractOutput(conn) , d_ptr(&dd) {
15+ d_ptr->initialize();
16+ QHTTP_LINE_LOG
17+}
18+
19+QHttpResponse::~QHttpResponse() {
20+ QHTTP_LINE_LOG
21+}
22+
23+void
24+QHttpResponse::setStatusCode(TStatusCode code) {
25+ d_func()->istatus = code;
26+}
27+
28+void
29+QHttpResponse::setVersion(const QString &versionString) {
30+ d_func()->iversion = versionString;
31+}
32+
33+void
34+QHttpResponse::addHeader(const QByteArray &field, const QByteArray &value) {
35+ d_func()->addHeader(field, value);
36+}
37+
38+THeaderHash&
39+QHttpResponse::headers() {
40+ return d_func()->iheaders;
41+}
42+
43+void
44+QHttpResponse::write(const QByteArray &data) {
45+ d_func()->writeData(data);
46+}
47+
48+void
49+QHttpResponse::end(const QByteArray &data) {
50+ Q_D(QHttpResponse);
51+
52+ if ( d->endPacket(data) )
53+ emit done(!d->ikeepAlive);
54+}
55+
56+QHttpConnection*
57+QHttpResponse::connection() const {
58+ return d_func()->iconnection;
59+}
60+
61+///////////////////////////////////////////////////////////////////////////////
62+QByteArray
63+QHttpResponsePrivate::makeTitle() {
64+
65+ QString title = QString("HTTP/%1 %2 %3\r\n")
66+ .arg(iversion)
67+ .arg(istatus)
68+ .arg(Stringify::toString(istatus));
69+
70+ return title.toLatin1();
71+}
72+
73+void
74+QHttpResponsePrivate::prepareHeadersToWrite() {
75+
76+ if ( !iheaders.contains("date") ) {
77+ // Sun, 06 Nov 1994 08:49:37 GMT - RFC 822. Use QLocale::c() so english is used for month and
78+ // day.
79+ QString dateString = QLocale::c().
80+ toString(QDateTime::currentDateTimeUtc(),
81+ "ddd, dd MMM yyyy hh:mm:ss")
82+ .append(" GMT");
83+ addHeader("date", dateString.toLatin1());
84+ }
85+}
86+
87+///////////////////////////////////////////////////////////////////////////////
88+} // namespace server
89+} // namespace qhttp
90+///////////////////////////////////////////////////////////////////////////////
libs/qhttp/qhttpserverresponse.hppnew file+70
@@ -0,0 +1,70 @@
1+/** HTTP response from a server.
2+ * https://github.com/azadkuh/qhttp
3+ *
4+ * @author amir zamani
5+ * @version 2.0.0
6+ * @date 2014-07-11
7+ */
8+
9+#ifndef QHTTPSERVER_RESPONSE_HPP
10+#define QHTTPSERVER_RESPONSE_HPP
11+
12+///////////////////////////////////////////////////////////////////////////////
13+
14+#include "qhttpabstracts.hpp"
15+
16+///////////////////////////////////////////////////////////////////////////////
17+namespace qhttp {
18+namespace server {
19+///////////////////////////////////////////////////////////////////////////////
20+/** The QHttpResponse class handles sending data back to the client as a response to a request.
21+ * @sa QHttpConnection
22+ */
23+class QHTTP_API QHttpResponse : public QHttpAbstractOutput
24+{
25+ Q_OBJECT
26+
27+public:
28+ virtual ~QHttpResponse();
29+
30+public:
31+ /** set the response HTTP status code. @sa TStatusCode.
32+ * default value is ESTATUS_BAD_REQUEST.
33+ * @sa write()
34+ */
35+ void setStatusCode(TStatusCode code);
36+
37+public: // QHttpAbstractOutput methods:
38+ /** @see QHttpAbstractOutput::setVersion(). */
39+ void setVersion(const QString& versionString) override;
40+
41+ /** @see QHttpAbstractOutput::addHeader(). */
42+ void addHeader(const QByteArray& field, const QByteArray& value) override;
43+
44+ /** @see QHttpAbstractOutput::headers(). */
45+ THeaderHash& headers() override;
46+
47+ /** @see QHttpAbstractOutput::write(). */
48+ void write(const QByteArray &data) override;
49+
50+ /** @see QHttpAbstractOutput::end(). */
51+ void end(const QByteArray &data = QByteArray()) override;
52+
53+public:
54+ /** returns the parent QHttpConnection object. */
55+ QHttpConnection* connection() const;
56+
57+protected:
58+ explicit QHttpResponse(QHttpConnection*);
59+ explicit QHttpResponse(QHttpResponsePrivate&, QHttpConnection*);
60+ friend class QHttpConnectionPrivate;
61+
62+ Q_DECLARE_PRIVATE(QHttpResponse)
63+ QScopedPointer<QHttpResponsePrivate> d_ptr;
64+};
65+
66+///////////////////////////////////////////////////////////////////////////////
67+} // namespace server
68+} // namespace qhttp
69+///////////////////////////////////////////////////////////////////////////////
70+#endif // define QHTTPSERVER_RESPONSE_HPP
libs/qhttp/src.pronew file+42
@@ -0,0 +1,42 @@
1+QT += core network
2+QT -= gui
3+
4+TARGET = qhttp
5+TEMPLATE = lib
6+
7+PRJDIR = ..
8+include($$PRJDIR/commondir.pri)
9+
10+DEFINES *= QHTTP_MEMORY_LOG=0
11+win32:DEFINES *= QHTTP_EXPORT
12+
13+# Joyent http_parser
14+SOURCES += $$PRJDIR/3rdparty/http-parser/http_parser.c
15+HEADERS += $$PRJDIR/3rdparty/http-parser/http_parser.h
16+
17+SOURCES += \
18+ qhttpabstracts.cpp \
19+ qhttpserverconnection.cpp \
20+ qhttpserverrequest.cpp \
21+ qhttpserverresponse.cpp \
22+ qhttpserver.cpp
23+
24+HEADERS += \
25+ qhttpfwd.hpp \
26+ qhttpabstracts.hpp \
27+ qhttpserverconnection.hpp \
28+ qhttpserverrequest.hpp \
29+ qhttpserverresponse.hpp \
30+ qhttpserver.hpp
31+
32+contains(DEFINES, QHTTP_HAS_CLIENT) {
33+ SOURCES += \
34+ qhttpclientrequest.cpp \
35+ qhttpclientresponse.cpp \
36+ qhttpclient.cpp
37+
38+ HEADERS += \
39+ qhttpclient.hpp \
40+ qhttpclientresponse.hpp \
41+ qhttpclientrequest.hpp
42+}
main.cpp+41−3
@@ -21,17 +21,55 @@
2121#include <QObject>
2222#include <QQuickView>
2323#include <QtQuickControls2/QQuickStyle>
24+
25+#include "qhttpserver.hpp"
26+#include "qhttpserverconnection.hpp"
27+#include "qhttpserverrequest.hpp"
28+#include "qhttpserverresponse.hpp"
29+
30+#include <map>
2431#include <stdlib.h>
2532
33+std::map<std::string, std::string> mimes;
34+
2635int main(int argc, char *argv[])
2736{
2837 QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
29− QGuiApplication *app = new QGuiApplication(argc, (char**)argv);
38+ QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
39+ QGuiApplication *app = new QGuiApplication(argc, (char **)argv);
3040 QQuickStyle::setStyle("Suru");
3141 app->setApplicationName("cinny.nitanmarcel");
3242
33− qDebug() << "Starting app from main.cpp";
34− qDebug() << "App Path " << app->applicationDirPath();
43+ mimes[".html"] = "text/html";
44+ mimes[".css"] = "text/css";
45+ mimes[".js"] = "application/javascript";
46+ mimes[".wasm"] = "application/wasm";
47+ mimes[".woff2"] = "application/font-woff2";
48+ mimes[".png"] = "image/png";
49+ mimes[".icon"] = "image/x-icon";
50+
51+ qhttp::server::QHttpServer server;
52+ server.listen(QHostAddress::LocalHost, 19999,
53+ [](qhttp::server::QHttpRequest *req, qhttp::server::QHttpResponse *res)
54+ {
55+ QString docname = "./target/" + (req->url().toString()==("/") ?("/index.html"):req->url().toString());
56+ if (!QFile(docname).exists())
57+ docname = QString("./target/index.html");
58+ QFile doc(docname);
59+ doc.open(QFile::ReadOnly);
60+
61+ res->addHeader("Content-Length", QString::number(doc.size()).toUtf8());
62+ res->addHeader("Connection", "keep-alive");
63+
64+ auto doc_str = docname.toStdString();
65+ auto doc_ext = doc_str.substr(doc_str.find_last_of('.'));
66+ if (mimes.count(doc_ext) > 0)
67+ res->addHeader("Content-Type", mimes[doc_ext].data());
68+ else
69+ res->addHeader("Content-Type", "application/octet-stream");
70+ res->setStatusCode(qhttp::TStatusCode::ESTATUS_OK);
71+ res->write(doc.readAll());
72+ });
3573
3674 QQuickView *view = new QQuickView();
3775 view->setSource(QUrl("qrc:/Main.qml"));
manifest.json.in+1−1
@@ -15,7 +15,7 @@
1515 "push-helper": "push/push.json"
1616 }
1717 },
18− "version": "1.8.2",
18+ "version": "@CLICK_VERSION@",
1919 "maintainer": "Marcel Alexandru Nitan <nitan.marcel@protonmail.com>",
2020 "framework" : "@CLICK_FRAMEWORK@"
2121}
patches/0002-Fix-loading-on-older-browsers.patch → patches/0002-Fix-loading-on-older-browsers.patch_ignorerenamed

The content is the same.

patches/0004-Create-data-url-instead-of-object-url.patch+21−15
@@ -1,35 +1,41 @@
1−From aa94e4c644747ef113927f762cb5807e4bd26cb8 Mon Sep 17 00:00:00 2001
1+From 04ce7f4f84d726f660c66e874b5bc91d77242eb5 Mon Sep 17 00:00:00 2001
22From: Marcel Alexandru Nitan <nitan.marcel@protonmail.com>
3−Date: Sat, 26 Mar 2022 00:59:51 +0200
4−Subject: [PATCH] Create data urls instead of object urls on media download
3+Date: Sat, 2 Apr 2022 00:11:12 +0300
4+Subject: [PATCH] Create data url instead of object url
55
66---
7− src/app/molecules/media/Media.jsx | 6 ++++--
8− 1 file changed, 4 insertions(+), 2 deletions(-)
7+ src/app/molecules/media/Media.jsx | 15 +++++++++++++--
8+ 1 file changed, 13 insertions(+), 2 deletions(-)
99
1010diff --git a/src/app/molecules/media/Media.jsx b/src/app/molecules/media/Media.jsx
11−index 6fc3851..5a9131c 100644
11+index 6fc3851..262aa94 100644
1212--- a/src/app/molecules/media/Media.jsx
1313+++ b/src/app/molecules/media/Media.jsx
14−@@ -41,6 +41,8 @@ function getBlobSafeMimeType(mimetype) {
15− return mimetype;
14+@@ -48,14 +48,25 @@ async function getDecryptedBlob(response, type, decryptData) {
15+ return blob;
1616 }
1717
18−+const fileReader = new FileReader();
18++function getDataUrl(blob) {
19++ return new Promise(function (resolve, reject) {
20++ const reader = new FileReader();
21++ reader.onload = function () {
22++ resolve(reader.result);
23++ }
24++ reader.onerror = reject;
25++ reader.readAsDataURL(blob);
26++ });
27++}
1928+
20− async function getDecryptedBlob(response, type, decryptData) {
21− const arrayBuffer = await response.arrayBuffer();
22− const dataArray = await encrypt.decryptAttachment(arrayBuffer, decryptData);
23−@@ -52,10 +54,10 @@ async function getUrl(link, type, decryptData) {
29+ async function getUrl(link, type, decryptData) {
2430 try {
2531 const response = await fetch(link, { method: 'GET' });
2632 if (decryptData !== null) {
2733- return URL.createObjectURL(await getDecryptedBlob(response, type, decryptData));
28−+ return fileReader.readAsDataURL(await getDecryptedBlob(response, type, decryptData));
34++ return await getDataUrl(await getDecryptedBlob(response, type, decryptData));
2935 }
3036 const blob = await response.blob();
3137- return URL.createObjectURL(blob);
32−+ return fileReader.readAsDataURL(blob);
38++ return await getDataUrl(blob);
3339 } catch (e) {
3440 return link;
3541 }
patches/0006-Download-media-using-qml-backend.patch+5−14
@@ -1,14 +1,14 @@
1−From a1936e6dc3ee25dbc41d8d4374e38b0656e05a6e Mon Sep 17 00:00:00 2001
1+From 373d90dbb1930f7b0f63b470832c418cb7632ab9 Mon Sep 17 00:00:00 2001
22From: Marcel Alexandru Nitan <nitan.marcel@protonmail.com>
3−Date: Fri, 1 Apr 2022 23:21:02 +0300
3+Date: Sat, 2 Apr 2022 15:37:03 +0300
44Subject: [PATCH] Download media using qml backend
55
66---
7− src/app/molecules/media/Media.jsx | 8 ++++----
8− 1 file changed, 4 insertions(+), 4 deletions(-)
7+ src/app/molecules/media/Media.jsx | 6 +++---
8+ 1 file changed, 3 insertions(+), 3 deletions(-)
99
1010diff --git a/src/app/molecules/media/Media.jsx b/src/app/molecules/media/Media.jsx
11−index 262aa94..88f14ea 100644
11+index 262aa94..8e89722 100644
1212--- a/src/app/molecules/media/Media.jsx
1313+++ b/src/app/molecules/media/Media.jsx
1414@@ -90,10 +90,10 @@ function FileHeader({
@@ -25,15 +25,6 @@ index 262aa94..88f14ea 100644
2525 }
2626 }
2727 return (
28−@@ -111,7 +111,7 @@ function FileHeader({
29− />
30− )
31− }
32−- <a href={url || link} download={name} target="_blank" rel="noreferrer">
33−+ <a href="ignore://" download={name} target="_blank" rel="noreferrer">
34− <IconButton
35− size="extra-small"
36− tooltip="Download"
3728--
38292.30.2
3930
patches/0008-Set-push-notifications-to-UTs-push-hook.patch+22−42
@@ -1,52 +1,44 @@
1−From 1cc3347e0bfd70f69fde9f5ccbdb79f2faf8245c Mon Sep 17 00:00:00 2001
1+From fe881f37607a0d720b8a4d7f6b9d260173f621a5 Mon Sep 17 00:00:00 2001
22From: Marcel Alexandru Nitan <nitan.marcel@protonmail.com>
3−Date: Thu, 31 Mar 2022 00:09:56 +0300
4−Subject: [PATCH] Set push notifications to UTs push hook
3+Date: Thu, 16 Jun 2022 17:09:38 +0300
4+Subject: [PATCH] Add missing import in notification hook patch
55
66---
7− src/client/initMatrix.js | 38 ++++++++++++++++++++++++++++++++++++++
8− src/client/state/cons.js | 2 +-
9− 2 files changed, 39 insertions(+), 1 deletion(-)
7+ src/client/initMatrix.js | 32 ++++++++++++++++++++++++++++++++
8+ 1 file changed, 32 insertions(+)
109
1110diff --git a/src/client/initMatrix.js b/src/client/initMatrix.js
12−index bcf5c28..3046544 100644
11+index aec2f3d..ac85e8e 100644
1312--- a/src/client/initMatrix.js
1413+++ b/src/client/initMatrix.js
1514@@ -9,6 +9,8 @@ import RoomsInput from './state/RoomsInput';
1615 import Notifications from './state/Notifications';
17− import { initHotkeys } from './event/hotkeys';
18− import { initRoomListListener } from './event/roomList';
19−+import { push } from 'micromark-util-chunked';
20−+import cons from './state/cons';
16+ import { cryptoCallbacks } from './state/secretStorageKeys';
2117
18++import cons from './state/cons';
19++
2220 global.Olm = require('@matrix-org/olm');
2321
24−@@ -19,6 +21,18 @@ class InitMatrix extends EventEmitter {
22+ // logger.disableAll();
23+@@ -18,6 +20,12 @@ class InitMatrix extends EventEmitter {
2524 await this.startClient();
2625 this.setupSync();
2726 this.listenEvents();
2827+
29−+ try {
30−+ this.setPush(QML.settings.pushToken, QML.settings.pushAppId)
28++ this.setPush(QML.settings.pushToken, QML.settings.pushAppId)
29++ QML.matrixPushTokenChanged.connect(async function (token) {
30++ this.setPush(token, QML.settings.pushAppId)
3131+
32−+ QML.matrixPushTokenChanged.connect(async function (token) {
33−+ this.setPush(token, QML.settings.pushAppId)
34−+
35−+ });
36−+ }
37−+ catch {
38−+ console.log("Failed to update push rules!")
39−+ }
32++ });
4033 }
4134
4235 async startClient() {
43−@@ -48,6 +62,30 @@ class InitMatrix extends EventEmitter {
36+@@ -51,6 +59,30 @@ class InitMatrix extends EventEmitter {
4437 this.matrixClient.setGlobalErrorOnUnknownDevices(false);
4538 }
4639
47−+
4840+ setPush(token, appId) {
49−+ var promises = []
41++ const promises = []
5042+
5143+ promises.push(
5244+ this.matrixClient.setPusher(
@@ -62,28 +54,16 @@ index bcf5c28..3046544 100644
6254+ "kind": "http",
6355+ "profile_tag": "xxyyzz",
6456+ "pushkey": token
65−+ },
66−+ function () {}
67−+ ))
68−+ this.matrixClient.setPushRuleEnabled('global', 'content', '.m.rule.contains_user_name', true, function () {})
57++ }
58++ ));
59++ promises.push(this.matrixClient.setPushRuleEnabled('global', 'content', '.m.rule.contains_user_name', true));
60++ console.error("Set appID " + appId + "with token " + token)
61++ return Promise.all(promises);
6962+ }
7063+
7164 setupSync() {
7265 const sync = {
7366 NULL: () => {
74−diff --git a/src/client/state/cons.js b/src/client/state/cons.js
75−index 447d000..2542131 100644
76−--- a/src/client/state/cons.js
77−+++ b/src/client/state/cons.js
78−@@ -6,7 +6,7 @@ const cons = {
79− USER_ID: 'cinny_user_id',
80− BASE_URL: 'cinny_hs_base_url',
81− },
82−- DEVICE_DISPLAY_NAME: 'Cinny Web',
83−+ DEVICE_DISPLAY_NAME: 'Cinny Ubuntu Touch',
84− IN_CINNY_SPACES: 'in.cinny.spaces',
85− tabs: {
86− HOME: 'home',
8767--
88682.30.2
8969
patches/0009--Add-credits.patch+13−13
@@ -1,6 +1,6 @@
1−From a8677dcca3567de2b8327825835c34bb83426698 Mon Sep 17 00:00:00 2001
1+From 6f98e6bba13fb7bb345fd1713ffb684756b54ecf Mon Sep 17 00:00:00 2001
22From: Marcel Alexandru Nitan <nitan.marcel@protonmail.com>
3−Date: Tue, 29 Mar 2022 01:50:53 +0300
3+Date: Mon, 4 Apr 2022 21:29:35 +0300
44Subject: [PATCH] Add credits
55
66---
@@ -8,20 +8,20 @@ Subject: [PATCH] Add credits
88 1 file changed, 4 insertions(+)
99
1010diff --git a/src/app/organisms/settings/Settings.jsx b/src/app/organisms/settings/Settings.jsx
11−index f9cc631..203f821 100644
11+index acfef5c..c55032a 100644
1212--- a/src/app/organisms/settings/Settings.jsx
1313+++ b/src/app/organisms/settings/Settings.jsx
14−@@ -223,6 +223,10 @@ function AboutSection() {
15− {/* eslint-disable-next-line react/jsx-one-expression-per-line */ }
16− <Text>The <a href="https://twemoji.twitter.com" target="_blank" rel="noreferrer noopener">Twemoji</a> emoji art is © <a href="https://twemoji.twitter.com" target="_blank" rel="noreferrer noopener">Twitter, Inc and other contributors</a> used under the terms of <a href="https://creativecommons.org/licenses/by/4.0/" target="_blank" rel="noreferrer noopener">CC-BY 4.0</a>.</Text>
17− </li>
18−+ <li>
19−+ {/* eslint-disable-next-line react/jsx-one-expression-per-line */ }
20−+ <Text>The <a href="https://github.com/nitanmarcel/cinny-click-packaging" target="_blank" rel="noreferrer noopener">cinny-click-packaging</a> for Ubuntu Touch is © <a href="https://github.com/nitanmarcel" target="_blank" rel="noreferrer noopener">Marcel Alexandru Nitan</a> used under the terms of <a href="https://www.gnu.org/licenses/gpl-3.0.en.html" target="_blank" rel="noreferrer noopener">GNU GENERAL PUBLIC LICENSE v3.0</a>.</Text>
21−+ </li>
22− </ul>
14+@@ -240,6 +240,10 @@ function AboutSection() {
15+ {/* eslint-disable-next-line react/jsx-one-expression-per-line */ }
16+ <Text>The <a href="https://material.io/design/sound/sound-resources.html" target="_blank" rel="noreferrer noopener">Material sound resources</a> are © <a href="https://google.com" target="_blank" rel="noreferrer noopener">Google</a> used under the terms of <a href="https://creativecommons.org/licenses/by/4.0/" target="_blank" rel="noreferrer noopener">CC-BY 4.0</a>.</Text>
17+ </li>
18++ <li>
19++ {/* eslint-disable-next-line react/jsx-one-expression-per-line */ }
20++ <Text>The <a href="https://github.com/nitanmarcel/cinny-click-packaging" target="_blank" rel="noreferrer noopener">cinny-click-packaging</a> for Ubuntu Touch is © <a href="https://github.com/nitanmarcel" target="_blank" rel="noreferrer noopener">Marcel Alexandru Nitan</a> used under the terms of <a href="https://www.gnu.org/licenses/gpl-3.0.en.html" target="_blank" rel="noreferrer noopener">GNU GENERAL PUBLIC LICENSE v3.0</a>.</Text>
21++ </li>
22+ </ul>
23+ </div>
2324 </div>
24− </div>
2525--
26262.30.2
2727
patches/0010-Open-SSO-login-in-a-new-window.patchnew file+25
@@ -0,0 +1,25 @@
1+From 6f942f835c6dd39054c2e37b7754f4a2bcb5b5b3 Mon Sep 17 00:00:00 2001
2+From: Marcel Alexandru Nitan <nitan.marcel@protonmail.com>
3+Date: Mon, 4 Apr 2022 22:03:21 +0300
4+Subject: [PATCH] Open SSO login in a new window
5+
6+---
7+ src/client/action/auth.js | 2 +-
8+ 1 file changed, 1 insertion(+), 1 deletion(-)
9+
10+diff --git a/src/client/action/auth.js b/src/client/action/auth.js
11+index f9be13b..f28cefb 100644
12+--- a/src/client/action/auth.js
13++++ b/src/client/action/auth.js
14+@@ -15,7 +15,7 @@ function createTemporaryClient(baseUrl) {
15+ async function startSsoLogin(baseUrl, type, idpId) {
16+ const client = createTemporaryClient(baseUrl);
17+ localStorage.setItem(cons.secretKey.BASE_URL, client.baseUrl);
18+- window.location.href = client.getSsoLoginUrl(window.location.href, type, idpId);
19++ window.open(client.getSsoLoginUrl("cinny://sso/", type, idpId));
20+ }
21+
22+ async function login(baseUrl, username, email, password) {
23+--
24+2.30.2
25+
patches/0011-Remove-unused-elements.patchnew file+37
@@ -0,0 +1,37 @@
1+From 70635ecc148c6215fdc0c556d879da739f3a1d0a Mon Sep 17 00:00:00 2001
2+From: Marcel Alexandru Nitan <nitan.marcel@protonmail.com>
3+Date: Mon, 4 Apr 2022 22:35:58 +0300
4+Subject: [PATCH] Remove unused elements
5+
6+---
7+ src/app/organisms/settings/Settings.jsx | 14 ++++++++------
8+ 1 file changed, 8 insertions(+), 6 deletions(-)
9+
10+diff --git a/src/app/organisms/settings/Settings.jsx b/src/app/organisms/settings/Settings.jsx
11+index c55032a..8c92b8c 100644
12+--- a/src/app/organisms/settings/Settings.jsx
13++++ b/src/app/organisms/settings/Settings.jsx
14+@@ -262,12 +262,14 @@ const tabItems = [{
15+ iconSrc: SunIC,
16+ disabled: false,
17+ render: () => <AppearanceSection />,
18+-}, {
19+- text: tabText.NOTIFICATIONS,
20+- iconSrc: BellIC,
21+- disabled: false,
22+- render: () => <NotificationsSection />,
23+-}, {
24++},
25++// {
26++// text: tabText.NOTIFICATIONS,
27++// iconSrc: BellIC,
28++// disabled: false,
29++// render: () => <NotificationsSection />,
30++// },
31++{
32+ text: tabText.SECURITY,
33+ iconSrc: LockIC,
34+ disabled: false,
35+--
36+2.30.2
37+
patches/0012-Rename-session-name-to-Cinny-Ubuntu-Touch.patchnew file+25
@@ -0,0 +1,25 @@
1+From 4f199154c309bfe6e89f3882605e4ae993a547cb Mon Sep 17 00:00:00 2001
2+From: Marcel Alexandru Nitan <nitan.marcel@protonmail.com>
3+Date: Sun, 24 Apr 2022 22:42:06 +0300
4+Subject: [PATCH] Rename session name to 'Cinny Ubuntu Touch'
5+
6+---
7+ src/client/state/cons.js | 2 +-
8+ 1 file changed, 1 insertion(+), 1 deletion(-)
9+
10+diff --git a/src/client/state/cons.js b/src/client/state/cons.js
11+index 34a3a92..825f010 100644
12+--- a/src/client/state/cons.js
13++++ b/src/client/state/cons.js
14+@@ -6,7 +6,7 @@ const cons = {
15+ USER_ID: 'cinny_user_id',
16+ BASE_URL: 'cinny_hs_base_url',
17+ },
18+- DEVICE_DISPLAY_NAME: 'Cinny Web',
19++ DEVICE_DISPLAY_NAME: 'Cinny Ubuntu Touch',
20+ IN_CINNY_SPACES: 'in.cinny.spaces',
21+ tabs: {
22+ HOME: 'home',
23+--
24+2.30.2
25+
patches/0013-Disable-cinny-s-notification-sound.patchnew file+36
@@ -0,0 +1,36 @@
1+From 39642c26fb08db515272c070c512ed477df0d228 Mon Sep 17 00:00:00 2001
2+From: Marcel Alexandru Nitan <nitan.marcel@protonmail.com>
3+Date: Thu, 16 Jun 2022 16:09:35 +0300
4+Subject: [PATCH] Disable cinny's notification sound
5+
6+This is controlled by the matrix push server now and not by cinny
7+---
8+ src/client/state/settings.js | 11 ++++++-----
9+ 1 file changed, 6 insertions(+), 5 deletions(-)
10+
11+diff --git a/src/client/state/settings.js b/src/client/state/settings.js
12+index 7454be3..71521a5 100644
13+--- a/src/client/state/settings.js
14++++ b/src/client/state/settings.js
15+@@ -136,12 +136,13 @@ class Settings extends EventEmitter {
16+ }
17+
18+ getIsNotificationSounds() {
19+- if (typeof this.isNotificationSounds === 'boolean') return this.isNotificationSounds;
20++ return false;
21++ // if (typeof this.isNotificationSounds === 'boolean') return this.isNotificationSounds;
22+
23+- const settings = getSettings();
24+- if (settings === null) return true;
25+- if (typeof settings.isNotificationSounds === 'undefined') return true;
26+- return settings.isNotificationSounds;
27++ // const settings = getSettings();
28++ // if (settings === null) return true;
29++ // if (typeof settings.isNotificationSounds === 'undefined') return true;
30++ // return settings.isNotificationSounds;
31+ }
32+
33+ setter(action) {
34+--
35+2.30.2
36+
po/cinny.nitanmarcel.pot+10−6
@@ -8,7 +8,7 @@ msgid ""
88msgstr ""
99"Project-Id-Version: cinny.nitanmarcel\n"
1010"Report-Msgid-Bugs-To: \n"
11−"POT-Creation-Date: 2022-04-01 20:14+0000\n"
11+"POT-Creation-Date: 2022-06-16 14:04+0000\n"
1212"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1313"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1414"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -17,26 +17,30 @@ msgstr ""
1717"Content-Type: text/plain; charset=CHARSET\n"
1818"Content-Transfer-Encoding: 8bit\n"
1919
20−#: ../qml/DownloadPage.qml:35 ../qml/UploadPage.qml:37
21−msgid "Content Picker"
20+#: ../qml/DownloadPage.qml:35
21+msgid "Save With"
2222msgstr ""
2323
2424#: ../qml/DownloadPage.qml:40 ../qml/UploadPage.qml:42
2525msgid "Back"
2626msgstr ""
2727
28−#: ../qml/Main.qml:180
28+#: ../qml/Main.qml:203
2929msgid "Javascript Dialog"
3030msgstr ""
3131
32−#: ../qml/Main.qml:192
32+#: ../qml/Main.qml:215
3333msgid "Yes"
3434msgstr ""
3535
36−#: ../qml/Main.qml:197
36+#: ../qml/Main.qml:220
3737msgid "Cancel"
3838msgstr ""
3939
40+#: ../qml/UploadPage.qml:37
41+msgid "Chose"
42+msgstr ""
43+
4044#: cinny.desktop.in.h:1
4145msgid "Cinny"
4246msgstr ""
prebuild.sh+11−3
@@ -3,17 +3,20 @@
33set -e
44
55export REPO_NAME="cinny"
6−export REPO_URL="https://github.com/C0ffeeCode/cinny"
7−export REPO_BRANCH="adapt-mobile-width"
6+export REPO_URL="https://github.com/cinnyapp/cinny"
7+export REPO_BRANCH="dev"
88export APP_TARGET="dist"
99
10+export REPO_VERSION="2.0.4"
11+export CLICK_VERSION_PREFIX="notificationfix1"
12+
1013if [ -d "${ROOT}/${REPO_NAME}" ]; then
1114 echo "Cleaning up"
1215 rm -rf "${ROOT}/${REPO_NAME}" "${ROOT}/target"
1316fi
1417echo "Cloning source repo"
1518
16−git clone "${REPO_URL}" -b "${REPO_BRANCH}" "${ROOT}/${REPO_NAME}" --depth=1
19+git clone "${REPO_URL}" -b "${REPO_BRANCH}" "${ROOT}/${REPO_NAME}" --depth=1 --branch="v${REPO_VERSION}"
1720cd "${ROOT}/${REPO_NAME}"
1821
1922if [ -d "${ROOT}/patches" ]; then
@@ -33,4 +36,9 @@ echo "Run npm build"
3336npm run build
3437echo "Copying ${APP_TARGET}"
3538cp -r "${APP_TARGET}" "${ROOT}/target"
39+
40+sed -i "s/@CLICK_VERSION@/$REPO_VERSION$CLICK_VERSION_PREFIX/g" "${ROOT}/manifest.json.in"
41+
42+cat "${ROOT}/manifest.json.in"
43+
3644echo "Done. Creating click package."
qml/Main.qml+11−81
@@ -21,6 +21,7 @@ import Ubuntu.Components.Popups 1.3
2121import Ubuntu.PushNotifications 0.1
2222import Ubuntu.Content 1.3
2323import Ubuntu.DownloadManager 1.2
24+import QtQuick.Window 2.12
2425import QtQuick.Layouts 1.3
2526import Qt.labs.settings 1.0
2627import QtQml 2.12
@@ -42,7 +43,7 @@ MainView {
4243 ? UbuntuApplication
4344 .inputMethod
4445 .keyboardRectangle
45− .height / (units.gridUnit / 8)
46+ .height / Screen.devicePixelRatio
4647 : 0
4748 Behavior on bottomMargin {
4849 NumberAnimation {
@@ -62,11 +63,8 @@ MainView {
6263 }
6364
6465 Component.onCompleted: function () {
65− theme.name = "" // set system theme
66+ theme.name = ""
6667 appSettings.systemTheme = theme.name.substring(theme.name.lastIndexOf(".")+1)
67−
68− //appSettings.pushAppId = 'cinny.nitanmarcel_cinny'
69− console.log("appSettings.pushAppId " + appSettings.pushAppId)
7068 }
7169 onActiveChanged: () => {appSettings.windowActive = mainView.active}
7270
@@ -96,9 +94,8 @@ MainView {
9694 id : webView
9795 anchors.fill : parent
9896 focus : true
99− url : Qt.resolvedUrl(Backend.getIndexPath())
97+ url : "http://localhost:19999/"
10098 webChannel: channel
101− //zoomFactor : 2.5
10299 settings.pluginsEnabled : true
103100 settings.javascriptEnabled : true
104101 profile : WebEngineProfile {
@@ -107,8 +104,6 @@ MainView {
107104 persistentStoragePath : "/home/phablet/.local/share/cinny.nitanmarcel/QWebEngine"
108105
109106 onDownloadRequested: function (download) {
110− console.log("Downloading")
111− console.log(download.path)
112107 download.accept()
113108 }
114109
@@ -130,20 +125,16 @@ MainView {
130125 })
131126 }
132127
133− onJavaScriptDialogRequested: function (request) {
134− request.accepted = true;
135− var popup = PopupUtils.open(jsDialogComponent, this, {"title": request.title, "message": request.message})
136− popup.dialogAccepted.connect(function () {
137− request.dialogAccept()
138− PopupUtils.close(popup)
139− })
140− popup.dialogRejected.connect(function () {
141− request.dialogReject()
142− PopupUtils.close(popup)
143− })
128+ onFullScreenRequested : function (request) {
129+ request.accept()
130+ if (request.toggleOn)
131+ window.showFullScreen()
132+ else
133+ window.showNormal()
144134 }
145135
146136 }
137+
147138 WebChannel {
148139 id: channel
149140 registeredObjects: [webChannelObject]
@@ -168,36 +159,6 @@ MainView {
168159 setCurrentTheme(themeName)
169160 }
170161 }
171−
172− Component {
173− id: jsDialogComponent
174−
175− Dialog {
176−
177− id: jsDialog
178−
179− title: i18n.tr("Javascript Dialog")
180− property var message
181−
182− signal dialogAccepted()
183− signal dialogRejected()
184−
185− Label {
186− wrapMode: Text.WordWrap
187− text: jsDialog.message
188− }
189−
190− Button {
191− text: i18n.tr("Yes")
192− color: UbuntuColors.green
193− onClicked: () => dialogAccepted()
194− }
195− Button {
196− text: i18n.tr("Cancel")
197− onClicked: () => dialogRejected()
198− }
199− }
200− }
201162 }
202163 }
203164
@@ -209,36 +170,5 @@ MainView {
209170 appSettings.pushToken = token
210171 webChannelObject.matrixPushTokenChanged();
211172 }
212−
213− function sendPushNotification(icon, title, body) {
214− var req = new XMLHttpRequest();
215− req.open("post", "https://push.ubports.com/notify", true);
216− req.setRequestHeader("Content-type", "application/json");
217− req.onreadystatechange = function() {
218− if ( req.readyState === XMLHttpRequest.DONE ) {
219− console.log("✍ Answer:", req.responseText);
220− }
221− }
222− var approxExpire = new Date ();
223− approxExpire.setUTCMinutes(approxExpire.getUTCMinutes()+10);
224− req.send(JSON.stringify({
225− "appid" : "cinny.nitanmarcel_cinny",
226− "expire_on": approxExpire.toISOString(),
227− "token": appSettings.pushToken,
228− "data": {
229− "notification": {
230− "card": {
231− "icon": icon,
232− "summary": title,
233− "body": body,
234− "popup": true,
235− "persist": true
236− },
237− "vibrate": true,
238− "sound": true
239− }
240− }
241− }));
242− }
243173 }
244174}
qml/qml.qrc.dependsdeleted−7
@@ -1,7 +0,0 @@
1−<RCC>
2− <qresource prefix="/">
3− <file>Main.qml</file>
4− <file>DownloadPage.qml</file>
5− <file>UploadPage.qml</file>
6− </qresource>
7−</RCC>
svg/cinny_18.svg+64−19
@@ -1,19 +1,64 @@
1−<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In -->
2−<svg version="1.1"
3− xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
4− x="0px" y="0px" width="18px" height="18px" viewBox="0 0 18 18" enable-background="new 0 0 18 18" xml:space="preserve">
5−<defs>
6−</defs>
7−<g>
8− <g>
9− <circle fill="#E95420" cx="9" cy="9" r="8.5"/>
10− </g>
11− <g>
12− <path d="M9,0C4,0,0,4,0,9c0,5,4,9,9,9c5,0,9-4,9-9C18,4,14,0,9,0z M1.2,10.8l3.5-2.3c0-0.1,0-0.2,0-0.3c0-1.8,1.3-3.2,3.1-3.4
13− c0.1,0,0.2,0,0.4,0c1.2,0,2.3,0.6,2.9,1.6c0.3-0.1,0.6-0.1,0.9-0.1c0.4,0,0.8,0,1.2,0.1c0.7,0.2,1.4,0.5,2,0.9
14− C14.6,7.1,14,7,13.3,7c-1.2,0-2.2,0.4-2.9,1.4c-0.7,0.9-1.1,2-1.1,3.2c0,1.5-0.4,2.9-1.3,4.2c-0.3,0.4-0.5,0.7-0.8,1
15− C4.2,16.1,1.9,13.8,1.2,10.8z"/>
16− <circle cx="9.5" cy="6.4" r="0.5"/>
17− </g>
18−</g>
19−</svg>
1+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2+<svg
3+ version="1.1"
4+ id="Layer_1"
5+ x="0px"
6+ y="0px"
7+ width="18px"
8+ height="18px"
9+ viewBox="0 0 512 512"
10+ enable-background="new 0 0 512 512"
11+ xml:space="preserve"
12+ sodipodi:docname="cinny_18.svg"
13+ inkscape:version="1.1.2 (b8e25be833, 2022-02-05)"
14+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
15+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
16+ xmlns="http://www.w3.org/2000/svg"
17+ xmlns:svg="http://www.w3.org/2000/svg"><defs
18+ id="defs856" /><sodipodi:namedview
19+ id="namedview854"
20+ pagecolor="#505050"
21+ bordercolor="#eeeeee"
22+ borderopacity="1"
23+ inkscape:pageshadow="0"
24+ inkscape:pageopacity="0"
25+ inkscape:pagecheckerboard="0"
26+ showgrid="false"
27+ inkscape:zoom="42.722222"
28+ inkscape:cx="9"
29+ inkscape:cy="9"
30+ inkscape:window-width="1920"
31+ inkscape:window-height="991"
32+ inkscape:window-x="-9"
33+ inkscape:window-y="-9"
34+ inkscape:window-maximized="1"
35+ inkscape:current-layer="Layer_1" />
36+<rect
37+ fill="#fdb714"
38+ width="512"
39+ height="512.71198"
40+ id="rect841"
41+ x="0"
42+ y="0"
43+ style="stroke-width:31.714" />
44+<polyline
45+ fill="#FFD05C"
46+ points="0,511.289 512,-0.711 512,512.712 "
47+ id="polyline843" />
48+<g
49+ id="g851">
50+ <g
51+ id="g849">
52+ <path
53+ fill="#FEFFFF"
54+ d="M14,512.712 M0,512V341.5l147.689-99.01c0-2.844,0-5.689,0-8.533c0-51.2,36.978-91.022,88.178-96.711 c2.844,0,5.689,0,11.378,0c34.132,0,65.421,17.067,82.488,45.511c8.533-2.844,17.066-2.844,25.6-2.844 c11.379,0,22.756,0,34.135,2.844c19.91,5.689,39.822,14.222,56.889,25.6c-17.066-5.689-34.133-8.533-54.045-8.533 c-34.133,0-62.578,11.377-82.488,39.822c-19.912,25.6-31.289,56.889-31.289,91.021c0,42.667-11.377,82.489-36.978,119.467 C233.022,461.512,176.75,512,176.75,512H0z"
55+ id="path845" />
56+ <circle
57+ fill="#FDB714"
58+ cx="284.445"
59+ cy="182.756"
60+ r="14.222"
61+ id="circle847" />
62+ </g>
63+</g>
64+</svg>